scif_sas_task_request.c revision 230557
1275970Scy/*-
2275970Scy * This file is provided under a dual BSD/GPLv2 license.  When using or
3275970Scy * redistributing this file, you may do so under either license.
4275970Scy *
5275970Scy * GPL LICENSE SUMMARY
6275970Scy *
7275970Scy * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
8275970Scy *
9275970Scy * This program is free software; you can redistribute it and/or modify
10275970Scy * it under the terms of version 2 of the GNU General Public License as
11275970Scy * published by the Free Software Foundation.
12275970Scy *
13275970Scy * This program is distributed in the hope that it will be useful, but
14275970Scy * WITHOUT ANY WARRANTY; without even the implied warranty of
15275970Scy * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16275970Scy * General Public License for more details.
17275970Scy *
18275970Scy * You should have received a copy of the GNU General Public License
19275970Scy * along with this program; if not, write to the Free Software
20275970Scy * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
21275970Scy * The full GNU General Public License is included in this distribution
22275970Scy * in the file called LICENSE.GPL.
23275970Scy *
24275970Scy * BSD LICENSE
25275970Scy *
26275970Scy * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
27275970Scy * All rights reserved.
28275970Scy *
29275970Scy * Redistribution and use in source and binary forms, with or without
30275970Scy * modification, are permitted provided that the following conditions
31275970Scy * are met:
32275970Scy *
33275970Scy *   * Redistributions of source code must retain the above copyright
34275970Scy *     notice, this list of conditions and the following disclaimer.
35275970Scy *   * Redistributions in binary form must reproduce the above copyright
36275970Scy *     notice, this list of conditions and the following disclaimer in
37275970Scy *     the documentation and/or other materials provided with the
38275970Scy *     distribution.
39275970Scy *
40275970Scy * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
41275970Scy * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
42275970Scy * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
43275970Scy * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
44275970Scy * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
45275970Scy * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
46275970Scy * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
47275970Scy * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
48275970Scy * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
49275970Scy * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
50275970Scy * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
51275970Scy */
52275970Scy
53275970Scy#include <sys/cdefs.h>
54275970Scy__FBSDID("$FreeBSD$");
55275970Scy
56275970Scy/**
57275970Scy * @file
58275970Scy *
59275970Scy * @brief This file contains the task management request object
60275970Scy *        (SCIF_SAS_TASK_REQUEST) method implementations.
61275970Scy */
62275970Scy
63275970Scy
64275970Scy#include <dev/isci/scil/intel_sas.h>
65275970Scy
66275970Scy#include <dev/isci/scil/scic_task_request.h>
67275970Scy#include <dev/isci/scil/scic_remote_device.h>
68275970Scy#include <dev/isci/scil/scic_user_callback.h>
69275970Scy#include <dev/isci/scil/scic_controller.h>
70275970Scy#include <dev/isci/scil/scif_user_callback.h>
71275970Scy
72275970Scy#include <dev/isci/scil/scif_sas_request.h>
73275970Scy#include <dev/isci/scil/scif_sas_task_request.h>
74275970Scy#include <dev/isci/scil/scif_sas_stp_task_request.h>
75275970Scy#include <dev/isci/scil/scif_sas_logger.h>
76275970Scy#include <dev/isci/scil/scif_sas_controller.h>
77275970Scy#include <dev/isci/scil/scif_sas_domain.h>
78275970Scy#include <dev/isci/scil/scif_sas_remote_device.h>
79275970Scy#include <dev/isci/scil/scif_sas_smp_io_request.h>
80275970Scy
81280849Scy//******************************************************************************
82280849Scy//* P U B L I C   M E T H O D S
83280849Scy//******************************************************************************
84280849Scy
85280849ScyU32 scif_task_request_get_object_size(
86280849Scy   void
87275970Scy)
88275970Scy{
89275970Scy   return (sizeof(SCIF_SAS_TASK_REQUEST_T) + scic_task_request_get_object_size());
90275970Scy}
91275970Scy
92275970Scy// ---------------------------------------------------------------------------
93275970Scy
94275970ScyU8 scif_sas_task_request_get_function(
95275970Scy   SCIF_SAS_TASK_REQUEST_T *fw_task
96275970Scy)
97275970Scy{
98275970Scy   return fw_task->function;
99275970Scy}
100275970Scy
101275970Scy// ---------------------------------------------------------------------------
102275970Scy
103275970Scystatic
104275970ScySCI_STATUS scif_sas_task_request_generic_construct(
105275970Scy   SCI_CONTROLLER_HANDLE_T      scif_controller,
106275970Scy   SCI_REMOTE_DEVICE_HANDLE_T   scif_remote_device,
107275970Scy   U16                          io_tag,
108275970Scy   void                       * user_task_request_object,
109275970Scy   void                       * task_request_memory,
110275970Scy   SCI_TASK_REQUEST_HANDLE_T  * scif_task_request,
111275970Scy   U8                           task_function
112275970Scy)
113275970Scy{
114275970Scy   SCI_STATUS                 status;
115275970Scy   SCIF_SAS_CONTROLLER_T    * fw_controller   = (SCIF_SAS_CONTROLLER_T*)
116275970Scy                                                scif_controller;
117275970Scy   SCIF_SAS_TASK_REQUEST_T  * fw_task         = (SCIF_SAS_TASK_REQUEST_T*)
118275970Scy                                                task_request_memory;
119275970Scy   SCIF_SAS_REMOTE_DEVICE_T * fw_device       = (SCIF_SAS_REMOTE_DEVICE_T*)
120275970Scy                                                scif_remote_device;
121275970Scy   U8                       * core_request_memory;
122275970Scy
123275970Scy   SCIF_LOG_TRACE((
124275970Scy      sci_base_object_get_logger(fw_controller),
125275970Scy      SCIF_LOG_OBJECT_TASK_MANAGEMENT,
126275970Scy      "scif_task_request_construct(0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x) enter\n",
127275970Scy      scif_controller, scif_remote_device, io_tag, user_task_request_object,
128275970Scy      task_request_memory, scif_task_request
129275970Scy   ));
130275970Scy
131275970Scy   // Initialize the user's handle to the framework task request.
132275970Scy   *scif_task_request = fw_task;
133275970Scy
134275970Scy   // initialize affected request count
135275970Scy   fw_task->affected_request_count = 0;
136275970Scy   fw_task->io_tag_to_manage = SCI_CONTROLLER_INVALID_IO_TAG;
137275970Scy   fw_task->function = task_function;
138275970Scy
139275970Scy   if (task_function == SCI_SAS_HARD_RESET )
140275970Scy   {
141275970Scy      if (fw_device->containing_device != NULL )
142275970Scy      {// Target Reset is for an expander attached device,
143275970Scy       // go down to construct smp Phy Control request.
144275970Scy         scif_sas_smp_request_construct_phy_control(
145275970Scy            fw_controller,
146275970Scy            fw_device->containing_device,
147275970Scy            PHY_OPERATION_HARD_RESET,
148275970Scy            fw_device->expander_phy_identifier,
149275970Scy            user_task_request_object,
150275970Scy            task_request_memory
151275970Scy         );
152275970Scy      }
153275970Scy      else
154275970Scy      {
155275970Scy         scif_sas_request_construct(
156275970Scy            &fw_task->parent,
157275970Scy            fw_device,
158275970Scy            sci_base_object_get_logger(fw_controller),
159275970Scy            scif_sas_task_request_state_table
160275970Scy         );
161275970Scy
162275970Scy         // If target reset is for a DA device, don't build task at all.
163275970Scy         // Just set object association.
164275970Scy         sci_object_set_association(fw_task, user_task_request_object);
165275970Scy      }
166298770Sdelphij
167275970Scy      return SCI_SUCCESS;
168275970Scy   }
169275970Scy
170275970Scy   // Construct the parent object first in order to ensure logging can
171275970Scy   // function.
172275970Scy   scif_sas_request_construct(
173275970Scy      &fw_task->parent,
174275970Scy      fw_device,
175275970Scy      sci_base_object_get_logger(fw_controller),
176275970Scy      scif_sas_task_request_state_table
177275970Scy   );
178275970Scy
179275970Scy   core_request_memory = (U8 *)task_request_memory + sizeof(SCIF_SAS_TASK_REQUEST_T);
180275970Scy
181275970Scy   status = scic_task_request_construct(
182275970Scy               fw_controller->core_object,
183275970Scy               fw_device->core_object,
184275970Scy               io_tag,
185275970Scy               fw_task,
186275970Scy               core_request_memory,
187275970Scy               &fw_task->parent.core_object
188275970Scy            );
189275970Scy
190275970Scy   if (status == SCI_SUCCESS)
191275970Scy   {
192275970Scy      SMP_DISCOVER_RESPONSE_PROTOCOLS_T  dev_protocols;
193275970Scy
194275970Scy      // These associations must be set early for the core io request
195275970Scy      // object construction to complete correctly as there will be
196275970Scy      // callbacks into the user driver framework during core construction
197275970Scy      sci_object_set_association(fw_task, user_task_request_object);
198275970Scy      sci_object_set_association(fw_task->parent.core_object, fw_task);
199275970Scy
200275970Scy      // Perform protocol specific core IO request construction.
201275970Scy      scic_remote_device_get_protocols(fw_device->core_object, &dev_protocols);
202275970Scy      if (dev_protocols.u.bits.attached_ssp_target)
203275970Scy         status = scic_task_request_construct_ssp(fw_task->parent.core_object);
204275970Scy      else if (dev_protocols.u.bits.attached_stp_target)
205275970Scy         status = scif_sas_stp_task_request_construct(fw_task);
206275970Scy      else
207275970Scy         status = SCI_FAILURE_UNSUPPORTED_PROTOCOL;
208275970Scy
209275970Scy      if (status == SCI_SUCCESS)
210275970Scy      {
211275970Scy         sci_base_state_machine_logger_initialize(
212275970Scy            &fw_task->parent.parent.state_machine_logger,
213275970Scy            &fw_task->parent.parent.state_machine,
214275970Scy            &fw_task->parent.parent.parent,
215275970Scy            scif_cb_logger_log_states,
216275970Scy            "SCIF_SAS_TASK_REQUEST_T", "base_state_machine",
217275970Scy            SCIF_LOG_OBJECT_TASK_MANAGEMENT
218275970Scy         );
219275970Scy      }
220275970Scy      else
221275970Scy      {
222275970Scy         SCIF_LOG_WARNING((
223275970Scy            sci_base_object_get_logger(fw_task),
224275970Scy            SCIF_LOG_OBJECT_TASK_MANAGEMENT,
225275970Scy            "Device:0x%x TaskRequest:0x%x Function:0x%x construct failed\n",
226275970Scy            fw_device, fw_task, scif_sas_task_request_get_function(fw_task)
227275970Scy         ));
228275970Scy      }
229275970Scy   }
230275970Scy
231275970Scy   return status;
232275970Scy}
233275970Scy
234275970Scy// ---------------------------------------------------------------------------
235275970Scy
236275970ScySCI_STATUS scif_sas_internal_task_request_construct(
237275970Scy   SCI_CONTROLLER_HANDLE_T      scif_controller,
238275970Scy   SCI_REMOTE_DEVICE_HANDLE_T   scif_remote_device,
239275970Scy   U16                          io_tag,
240275970Scy   void                       * task_request_memory,
241275970Scy   SCI_TASK_REQUEST_HANDLE_T  * scif_task_request,
242275970Scy   U8                           task_function
243275970Scy)
244275970Scy{
245275970Scy   SCI_STATUS                 status;
246275970Scy   SCIF_SAS_TASK_REQUEST_T *  fw_task;
247275970Scy
248275970Scy   status = scif_sas_task_request_generic_construct(
249275970Scy               scif_controller,
250275970Scy               scif_remote_device,
251275970Scy               io_tag,
252275970Scy               NULL,
253275970Scy               task_request_memory,
254275970Scy               scif_task_request,
255275970Scy               task_function
256275970Scy            );
257275970Scy
258275970Scy   fw_task = (SCIF_SAS_TASK_REQUEST_T *)task_request_memory;
259275970Scy
260275970Scy   fw_task->parent.is_internal = TRUE;
261275970Scy
262275970Scy   return status;
263275970Scy}
264275970Scy
265275970Scy// ---------------------------------------------------------------------------
266275970Scy
267275970ScySCI_STATUS scif_task_request_construct(
268275970Scy   SCI_CONTROLLER_HANDLE_T      scif_controller,
269275970Scy   SCI_REMOTE_DEVICE_HANDLE_T   scif_remote_device,
270275970Scy   U16                          io_tag,
271275970Scy   void                       * user_task_request_object,
272275970Scy   void                       * task_request_memory,
273275970Scy   SCI_TASK_REQUEST_HANDLE_T  * scif_task_request
274275970Scy)
275275970Scy{
276275970Scy   SCI_STATUS  status;
277275970Scy   U8          task_function =
278275970Scy                scif_cb_task_request_get_function(user_task_request_object);
279275970Scy
280275970Scy   status = scif_sas_task_request_generic_construct(
281275970Scy               scif_controller,
282275970Scy               scif_remote_device,
283275970Scy               io_tag,
284275970Scy               user_task_request_object,
285275970Scy               task_request_memory,
286275970Scy               scif_task_request,
287275970Scy               task_function
288275970Scy            );
289275970Scy
290275970Scy   return status;
291275970Scy}
292275970Scy
293275970Scy// ---------------------------------------------------------------------------
294275970Scy
295275970Scyvoid scif_sas_internal_task_request_destruct(
296275970Scy   SCIF_SAS_TASK_REQUEST_T * fw_internal_task
297275970Scy)
298275970Scy{
299275970Scy   SCIF_SAS_CONTROLLER_T * fw_controller =
300275970Scy      fw_internal_task->parent.device->domain->controller;
301275970Scy   scif_sas_controller_free_internal_request(fw_controller, fw_internal_task);
302275970Scy}
303275970Scy
304275970Scy// ---------------------------------------------------------------------------
305275970Scy
306275970Scyvoid scic_cb_task_request_complete(
307275970Scy   SCI_CONTROLLER_HANDLE_T     controller,
308275970Scy   SCI_REMOTE_DEVICE_HANDLE_T  remote_device,
309275970Scy   SCI_TASK_REQUEST_HANDLE_T   task_request,
310275970Scy   SCI_TASK_STATUS             completion_status
311275970Scy)
312275970Scy{
313275970Scy   SCIF_SAS_CONTROLLER_T    * fw_controller = (SCIF_SAS_CONTROLLER_T*)
314275970Scy                                         sci_object_get_association(controller);
315275970Scy   SCIF_SAS_REMOTE_DEVICE_T * fw_device = (SCIF_SAS_REMOTE_DEVICE_T*)
316275970Scy                                      sci_object_get_association(remote_device);
317275970Scy   SCIF_SAS_TASK_REQUEST_T  * fw_task = (SCIF_SAS_TASK_REQUEST_T*)
318275970Scy                                       sci_object_get_association(task_request);
319275970Scy   SCI_STATUS                 status;
320275970Scy
321275970Scy   SCIF_LOG_TRACE((
322275970Scy      sci_base_object_get_logger(fw_controller),
323275970Scy      SCIF_LOG_OBJECT_TASK_MANAGEMENT,
324275970Scy      "scic_cb_task_request_complete(0x%x, 0x%x, 0x%x, 0x%x) enter\n",
325275970Scy      controller, remote_device, task_request, completion_status
326275970Scy   ));
327275970Scy
328275970Scy   status = fw_task->parent.state_handlers->complete_handler(
329275970Scy               &fw_task->parent.parent
330275970Scy            );
331275970Scy
332289997Sglebius   if (status == SCI_SUCCESS)
333289997Sglebius   {
334275970Scy      if (fw_task->parent.protocol_complete_handler != NULL)
335275970Scy      {
336275970Scy         status = fw_task->parent.protocol_complete_handler(
337275970Scy            fw_controller, fw_device, &fw_task->parent, (SCI_STATUS *)&completion_status
338275970Scy         );
339275970Scy      }
340275970Scy
341275970Scy      if (status == SCI_SUCCESS)
342275970Scy      {
343275970Scy         SCIF_LOG_WARNING((
344275970Scy            sci_base_object_get_logger(fw_task),
345275970Scy            SCIF_LOG_OBJECT_TASK_MANAGEMENT,
346275970Scy            "RemoteDevice:0x%x TaskRequest:0x%x Function:0x%x CompletionStatus:0x%x "
347275970Scy            "completed\n",
348275970Scy            fw_device, fw_task,
349275970Scy            scif_sas_task_request_get_function(fw_task),
350275970Scy            completion_status
351275970Scy         ));
352275970Scy
353275970Scy         // If this isn't an internal framework IO request, then simply pass the
354275970Scy         // notification up to the SCIF user.  Otherwise, immediately complete the
355275970Scy         // task since there is no SCIF user to notify.
356275970Scy         if (fw_task->parent.is_internal == FALSE)
357275970Scy         {
358275970Scy            scif_cb_task_request_complete(
359275970Scy               fw_controller, fw_device, fw_task, completion_status
360275970Scy            );
361275970Scy         }
362275970Scy         else
363275970Scy         {
364275970Scy            scif_controller_complete_task(
365275970Scy               fw_controller,
366275970Scy               fw_device,
367275970Scy               fw_task
368275970Scy            );
369275970Scy         }
370275970Scy      }
371275970Scy   }
372275970Scy}
373275970Scy
374275970Scy// ---------------------------------------------------------------------------
375275970Scy
376275970ScyU32 scic_cb_ssp_task_request_get_lun(
377275970Scy   void * scic_user_task_request
378275970Scy)
379275970Scy{
380275970Scy   SCIF_SAS_TASK_REQUEST_T * fw_task = (SCIF_SAS_TASK_REQUEST_T*)
381275970Scy                                       scic_user_task_request;
382275970Scy
383275970Scy   fw_task->parent.lun = scif_cb_task_request_get_lun(
384275970Scy                            fw_task->parent.parent.parent.associated_object
385275970Scy                         );
386275970Scy
387275970Scy   return fw_task->parent.lun;
388275970Scy}
389275970Scy
390275970Scy// ---------------------------------------------------------------------------
391275970Scy
392275970ScyU8 scic_cb_ssp_task_request_get_function(
393275970Scy   void * scic_user_task_request
394275970Scy)
395275970Scy{
396275970Scy   SCIF_SAS_TASK_REQUEST_T * fw_task = (SCIF_SAS_TASK_REQUEST_T*)
397275970Scy                                       scic_user_task_request;
398275970Scy
399275970Scy   return scif_sas_task_request_get_function(fw_task);
400275970Scy}
401275970Scy
402275970Scy// ---------------------------------------------------------------------------
403275970Scy
404275970ScyU16 scic_cb_ssp_task_request_get_io_tag_to_manage(
405275970Scy   void * scic_user_task_request
406275970Scy)
407275970Scy{
408275970Scy   SCIF_SAS_TASK_REQUEST_T * fw_task = (SCIF_SAS_TASK_REQUEST_T*)
409275970Scy                                       scic_user_task_request;
410275970Scy
411275970Scy   fw_task->io_tag_to_manage
412275970Scy      = scif_cb_task_request_get_io_tag_to_manage(
413275970Scy           fw_task->parent.parent.parent.associated_object
414275970Scy        );
415275970Scy
416275970Scy   return fw_task->io_tag_to_manage;
417275970Scy}
418275970Scy
419275970Scy// ---------------------------------------------------------------------------
420275970Scy
421275970Scyvoid * scic_cb_ssp_task_request_get_response_data_address(
422275970Scy   void * scic_user_task_request
423275970Scy)
424275970Scy{
425275970Scy   SCIF_SAS_TASK_REQUEST_T * fw_task = (SCIF_SAS_TASK_REQUEST_T*)
426275970Scy                                       scic_user_task_request;
427275970Scy
428275970Scy   return scif_cb_task_request_get_response_data_address(
429275970Scy                fw_task->parent.parent.parent.associated_object
430275970Scy          );
431275970Scy}
432275970Scy
433275970Scy// ---------------------------------------------------------------------------
434275970Scy
435275970ScyU32 scic_cb_ssp_task_request_get_response_data_length(
436275970Scy   void * scic_user_task_request
437275970Scy)
438275970Scy{
439275970Scy   SCIF_SAS_TASK_REQUEST_T * fw_task = (SCIF_SAS_TASK_REQUEST_T*)
440275970Scy                                       scic_user_task_request;
441275970Scy
442275970Scy   return scif_cb_task_request_get_response_data_length(
443275970Scy             fw_task->parent.parent.parent.associated_object
444275970Scy          );
445275970Scy}
446275970Scy
447275970Scy//******************************************************************************
448275970Scy//* P R O T E C T E D   M E T H O D S
449275970Scy//******************************************************************************
450275970Scy
451275970Scy/**
452275970Scy * @brief This method performs functionality required after a task management
453275970Scy *        operation (either a task management request or a silicon task
454275970Scy *        termination) has finished.
455275970Scy *
456275970Scy * @param[in]  fw_task This parameter specifies the request that has
457275970Scy *             the operation completing.
458275970Scy *
459275970Scy * @return none
460275970Scy */
461275970Scyvoid scif_sas_task_request_operation_complete(
462275970Scy   SCIF_SAS_TASK_REQUEST_T * fw_task
463275970Scy)
464275970Scy{
465275970Scy   SCIF_LOG_TRACE((
466275970Scy      sci_base_object_get_logger(fw_task),
467275970Scy      SCIF_LOG_OBJECT_TASK_MANAGEMENT,
468275970Scy      "scif_sas_task_request_operation_complete(0x%x) enter\n",
469275970Scy      fw_task
470275970Scy   ));
471275970Scy
472275970Scy   fw_task->affected_request_count--;
473275970Scy
474275970Scy   SCIF_LOG_INFO((
475275970Scy      sci_base_object_get_logger(fw_task),
476275970Scy      SCIF_LOG_OBJECT_TASK_MANAGEMENT,
477275970Scy      "TaskRequest:0x%x current affected request count:0x%x\n",
478275970Scy      fw_task, fw_task->affected_request_count
479275970Scy   ));
480275970Scy}
481275970Scy
482275970Scy