1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause OR GPL-2.0
3  *
4  * This file is provided under a dual BSD/GPLv2 license.  When using or
5  * redistributing this file, you may do so under either license.
6  *
7  * GPL LICENSE SUMMARY
8  *
9  * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
10  *
11  * This program is free software; you can redistribute it and/or modify
12  * it under the terms of version 2 of the GNU General Public License as
13  * published by the Free Software Foundation.
14  *
15  * This program is distributed in the hope that it will be useful, but
16  * WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18  * General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
23  * The full GNU General Public License is included in this distribution
24  * in the file called LICENSE.GPL.
25  *
26  * BSD LICENSE
27  *
28  * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
29  * All rights reserved.
30  *
31  * Redistribution and use in source and binary forms, with or without
32  * modification, are permitted provided that the following conditions
33  * are met:
34  *
35  *   * Redistributions of source code must retain the above copyright
36  *     notice, this list of conditions and the following disclaimer.
37  *   * Redistributions in binary form must reproduce the above copyright
38  *     notice, this list of conditions and the following disclaimer in
39  *     the documentation and/or other materials provided with the
40  *     distribution.
41  *
42  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
43  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
44  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
45  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
46  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
47  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
48  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
49  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
50  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
51  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
52  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
53  */
54 
55 #include <sys/cdefs.h>
56 __FBSDID("$FreeBSD$");
57 
58 /**
59  * @file
60  *
61  * @brief This file contains the task management request object
62  *        (SCIF_SAS_TASK_REQUEST) method implementations.
63  */
64 
65 
66 #include <dev/isci/scil/intel_sas.h>
67 
68 #include <dev/isci/scil/scic_task_request.h>
69 #include <dev/isci/scil/scic_remote_device.h>
70 #include <dev/isci/scil/scic_user_callback.h>
71 #include <dev/isci/scil/scic_controller.h>
72 #include <dev/isci/scil/scif_user_callback.h>
73 
74 #include <dev/isci/scil/scif_sas_request.h>
75 #include <dev/isci/scil/scif_sas_task_request.h>
76 #include <dev/isci/scil/scif_sas_stp_task_request.h>
77 #include <dev/isci/scil/scif_sas_logger.h>
78 #include <dev/isci/scil/scif_sas_controller.h>
79 #include <dev/isci/scil/scif_sas_domain.h>
80 #include <dev/isci/scil/scif_sas_remote_device.h>
81 #include <dev/isci/scil/scif_sas_smp_io_request.h>
82 
83 //******************************************************************************
84 //* P U B L I C   M E T H O D S
85 //******************************************************************************
86 
87 U32 scif_task_request_get_object_size(
88    void
89 )
90 {
91    return (sizeof(SCIF_SAS_TASK_REQUEST_T) + scic_task_request_get_object_size());
92 }
93 
94 // ---------------------------------------------------------------------------
95 
96 U8 scif_sas_task_request_get_function(
97    SCIF_SAS_TASK_REQUEST_T *fw_task
98 )
99 {
100    return fw_task->function;
101 }
102 
103 // ---------------------------------------------------------------------------
104 
105 static
106 SCI_STATUS scif_sas_task_request_generic_construct(
107    SCI_CONTROLLER_HANDLE_T      scif_controller,
108    SCI_REMOTE_DEVICE_HANDLE_T   scif_remote_device,
109    U16                          io_tag,
110    void                       * user_task_request_object,
111    void                       * task_request_memory,
112    SCI_TASK_REQUEST_HANDLE_T  * scif_task_request,
113    U8                           task_function
114 )
115 {
116    SCI_STATUS                 status;
117    SCIF_SAS_CONTROLLER_T    * fw_controller   = (SCIF_SAS_CONTROLLER_T*)
118                                                 scif_controller;
119    SCIF_SAS_TASK_REQUEST_T  * fw_task         = (SCIF_SAS_TASK_REQUEST_T*)
120                                                 task_request_memory;
121    SCIF_SAS_REMOTE_DEVICE_T * fw_device       = (SCIF_SAS_REMOTE_DEVICE_T*)
122                                                 scif_remote_device;
123    U8                       * core_request_memory;
124 
125    SCIF_LOG_TRACE((
126       sci_base_object_get_logger(fw_controller),
127       SCIF_LOG_OBJECT_TASK_MANAGEMENT,
128       "scif_task_request_construct(0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x) enter\n",
129       scif_controller, scif_remote_device, io_tag, user_task_request_object,
130       task_request_memory, scif_task_request
131    ));
132 
133    // Initialize the user's handle to the framework task request.
134    *scif_task_request = fw_task;
135 
136    // initialize affected request count
137    fw_task->affected_request_count = 0;
138    fw_task->io_tag_to_manage = SCI_CONTROLLER_INVALID_IO_TAG;
139    fw_task->function = task_function;
140 
141    if (task_function == SCI_SAS_HARD_RESET )
142    {
143       if (fw_device->containing_device != NULL )
144       {// Target Reset is for an expander attached device,
145        // go down to construct smp Phy Control request.
146          scif_sas_smp_request_construct_phy_control(
147             fw_controller,
148             fw_device->containing_device,
149             PHY_OPERATION_HARD_RESET,
150             fw_device->expander_phy_identifier,
151             user_task_request_object,
152             task_request_memory
153          );
154       }
155       else
156       {
157          scif_sas_request_construct(
158             &fw_task->parent,
159             fw_device,
160             sci_base_object_get_logger(fw_controller),
161             scif_sas_task_request_state_table
162          );
163 
164          // If target reset is for a DA device, don't build task at all.
165          // Just set object association.
166          sci_object_set_association(fw_task, user_task_request_object);
167       }
168 
169       return SCI_SUCCESS;
170    }
171 
172    // Construct the parent object first in order to ensure logging can
173    // function.
174    scif_sas_request_construct(
175       &fw_task->parent,
176       fw_device,
177       sci_base_object_get_logger(fw_controller),
178       scif_sas_task_request_state_table
179    );
180 
181    core_request_memory = (U8 *)task_request_memory + sizeof(SCIF_SAS_TASK_REQUEST_T);
182 
183    status = scic_task_request_construct(
184                fw_controller->core_object,
185                fw_device->core_object,
186                io_tag,
187                fw_task,
188                core_request_memory,
189                &fw_task->parent.core_object
190             );
191 
192    if (status == SCI_SUCCESS)
193    {
194       SMP_DISCOVER_RESPONSE_PROTOCOLS_T  dev_protocols;
195 
196       // These associations must be set early for the core io request
197       // object construction to complete correctly as there will be
198       // callbacks into the user driver framework during core construction
199       sci_object_set_association(fw_task, user_task_request_object);
200       sci_object_set_association(fw_task->parent.core_object, fw_task);
201 
202       // Perform protocol specific core IO request construction.
203       scic_remote_device_get_protocols(fw_device->core_object, &dev_protocols);
204       if (dev_protocols.u.bits.attached_ssp_target)
205          status = scic_task_request_construct_ssp(fw_task->parent.core_object);
206       else if (dev_protocols.u.bits.attached_stp_target)
207          status = scif_sas_stp_task_request_construct(fw_task);
208       else
209          status = SCI_FAILURE_UNSUPPORTED_PROTOCOL;
210 
211       if (status == SCI_SUCCESS)
212       {
213          sci_base_state_machine_logger_initialize(
214             &fw_task->parent.parent.state_machine_logger,
215             &fw_task->parent.parent.state_machine,
216             &fw_task->parent.parent.parent,
217             scif_cb_logger_log_states,
218             "SCIF_SAS_TASK_REQUEST_T", "base_state_machine",
219             SCIF_LOG_OBJECT_TASK_MANAGEMENT
220          );
221       }
222       else
223       {
224          SCIF_LOG_WARNING((
225             sci_base_object_get_logger(fw_task),
226             SCIF_LOG_OBJECT_TASK_MANAGEMENT,
227             "Device:0x%x TaskRequest:0x%x Function:0x%x construct failed\n",
228             fw_device, fw_task, scif_sas_task_request_get_function(fw_task)
229          ));
230       }
231    }
232 
233    return status;
234 }
235 
236 // ---------------------------------------------------------------------------
237 
238 SCI_STATUS scif_sas_internal_task_request_construct(
239    SCI_CONTROLLER_HANDLE_T      scif_controller,
240    SCI_REMOTE_DEVICE_HANDLE_T   scif_remote_device,
241    U16                          io_tag,
242    void                       * task_request_memory,
243    SCI_TASK_REQUEST_HANDLE_T  * scif_task_request,
244    U8                           task_function
245 )
246 {
247    SCI_STATUS                 status;
248    SCIF_SAS_TASK_REQUEST_T *  fw_task;
249 
250    status = scif_sas_task_request_generic_construct(
251                scif_controller,
252                scif_remote_device,
253                io_tag,
254                NULL,
255                task_request_memory,
256                scif_task_request,
257                task_function
258             );
259 
260    fw_task = (SCIF_SAS_TASK_REQUEST_T *)task_request_memory;
261 
262    fw_task->parent.is_internal = TRUE;
263 
264    return status;
265 }
266 
267 // ---------------------------------------------------------------------------
268 
269 SCI_STATUS scif_task_request_construct(
270    SCI_CONTROLLER_HANDLE_T      scif_controller,
271    SCI_REMOTE_DEVICE_HANDLE_T   scif_remote_device,
272    U16                          io_tag,
273    void                       * user_task_request_object,
274    void                       * task_request_memory,
275    SCI_TASK_REQUEST_HANDLE_T  * scif_task_request
276 )
277 {
278    SCI_STATUS  status;
279    U8          task_function =
280                 scif_cb_task_request_get_function(user_task_request_object);
281 
282    status = scif_sas_task_request_generic_construct(
283                scif_controller,
284                scif_remote_device,
285                io_tag,
286                user_task_request_object,
287                task_request_memory,
288                scif_task_request,
289                task_function
290             );
291 
292    return status;
293 }
294 
295 // ---------------------------------------------------------------------------
296 
297 void scif_sas_internal_task_request_destruct(
298    SCIF_SAS_TASK_REQUEST_T * fw_internal_task
299 )
300 {
301    SCIF_SAS_CONTROLLER_T * fw_controller =
302       fw_internal_task->parent.device->domain->controller;
303    scif_sas_controller_free_internal_request(fw_controller, fw_internal_task);
304 }
305 
306 // ---------------------------------------------------------------------------
307 
308 void scic_cb_task_request_complete(
309    SCI_CONTROLLER_HANDLE_T     controller,
310    SCI_REMOTE_DEVICE_HANDLE_T  remote_device,
311    SCI_TASK_REQUEST_HANDLE_T   task_request,
312    SCI_TASK_STATUS             completion_status
313 )
314 {
315    SCIF_SAS_CONTROLLER_T    * fw_controller = (SCIF_SAS_CONTROLLER_T*)
316                                          sci_object_get_association(controller);
317    SCIF_SAS_REMOTE_DEVICE_T * fw_device = (SCIF_SAS_REMOTE_DEVICE_T*)
318                                       sci_object_get_association(remote_device);
319    SCIF_SAS_TASK_REQUEST_T  * fw_task = (SCIF_SAS_TASK_REQUEST_T*)
320                                        sci_object_get_association(task_request);
321    SCI_STATUS                 status;
322 
323    SCIF_LOG_TRACE((
324       sci_base_object_get_logger(fw_controller),
325       SCIF_LOG_OBJECT_TASK_MANAGEMENT,
326       "scic_cb_task_request_complete(0x%x, 0x%x, 0x%x, 0x%x) enter\n",
327       controller, remote_device, task_request, completion_status
328    ));
329 
330    status = fw_task->parent.state_handlers->complete_handler(
331                &fw_task->parent.parent
332             );
333 
334    if (status == SCI_SUCCESS)
335    {
336       if (fw_task->parent.protocol_complete_handler != NULL)
337       {
338          status = fw_task->parent.protocol_complete_handler(
339             fw_controller, fw_device, &fw_task->parent, (SCI_STATUS *)&completion_status
340          );
341       }
342 
343       if (status == SCI_SUCCESS)
344       {
345          SCIF_LOG_WARNING((
346             sci_base_object_get_logger(fw_task),
347             SCIF_LOG_OBJECT_TASK_MANAGEMENT,
348             "RemoteDevice:0x%x TaskRequest:0x%x Function:0x%x CompletionStatus:0x%x "
349             "completed\n",
350             fw_device, fw_task,
351             scif_sas_task_request_get_function(fw_task),
352             completion_status
353          ));
354 
355          // If this isn't an internal framework IO request, then simply pass the
356          // notification up to the SCIF user.  Otherwise, immediately complete the
357          // task since there is no SCIF user to notify.
358          if (fw_task->parent.is_internal == FALSE)
359          {
360             scif_cb_task_request_complete(
361                fw_controller, fw_device, fw_task, completion_status
362             );
363          }
364          else
365          {
366             scif_controller_complete_task(
367                fw_controller,
368                fw_device,
369                fw_task
370             );
371          }
372       }
373    }
374 }
375 
376 // ---------------------------------------------------------------------------
377 
378 U32 scic_cb_ssp_task_request_get_lun(
379    void * scic_user_task_request
380 )
381 {
382    SCIF_SAS_TASK_REQUEST_T * fw_task = (SCIF_SAS_TASK_REQUEST_T*)
383                                        scic_user_task_request;
384 
385    fw_task->parent.lun = scif_cb_task_request_get_lun(
386                             fw_task->parent.parent.parent.associated_object
387                          );
388 
389    return fw_task->parent.lun;
390 }
391 
392 // ---------------------------------------------------------------------------
393 
394 U8 scic_cb_ssp_task_request_get_function(
395    void * scic_user_task_request
396 )
397 {
398    SCIF_SAS_TASK_REQUEST_T * fw_task = (SCIF_SAS_TASK_REQUEST_T*)
399                                        scic_user_task_request;
400 
401    return scif_sas_task_request_get_function(fw_task);
402 }
403 
404 // ---------------------------------------------------------------------------
405 
406 U16 scic_cb_ssp_task_request_get_io_tag_to_manage(
407    void * scic_user_task_request
408 )
409 {
410    SCIF_SAS_TASK_REQUEST_T * fw_task = (SCIF_SAS_TASK_REQUEST_T*)
411                                        scic_user_task_request;
412 
413    fw_task->io_tag_to_manage
414       = scif_cb_task_request_get_io_tag_to_manage(
415            fw_task->parent.parent.parent.associated_object
416         );
417 
418    return fw_task->io_tag_to_manage;
419 }
420 
421 // ---------------------------------------------------------------------------
422 
423 void * scic_cb_ssp_task_request_get_response_data_address(
424    void * scic_user_task_request
425 )
426 {
427    SCIF_SAS_TASK_REQUEST_T * fw_task = (SCIF_SAS_TASK_REQUEST_T*)
428                                        scic_user_task_request;
429 
430    return scif_cb_task_request_get_response_data_address(
431                 fw_task->parent.parent.parent.associated_object
432           );
433 }
434 
435 // ---------------------------------------------------------------------------
436 
437 U32 scic_cb_ssp_task_request_get_response_data_length(
438    void * scic_user_task_request
439 )
440 {
441    SCIF_SAS_TASK_REQUEST_T * fw_task = (SCIF_SAS_TASK_REQUEST_T*)
442                                        scic_user_task_request;
443 
444    return scif_cb_task_request_get_response_data_length(
445              fw_task->parent.parent.parent.associated_object
446           );
447 }
448 
449 //******************************************************************************
450 //* P R O T E C T E D   M E T H O D S
451 //******************************************************************************
452 
453 /**
454  * @brief This method performs functionality required after a task management
455  *        operation (either a task management request or a silicon task
456  *        termination) has finished.
457  *
458  * @param[in]  fw_task This parameter specifies the request that has
459  *             the operation completing.
460  *
461  * @return none
462  */
463 void scif_sas_task_request_operation_complete(
464    SCIF_SAS_TASK_REQUEST_T * fw_task
465 )
466 {
467    SCIF_LOG_TRACE((
468       sci_base_object_get_logger(fw_task),
469       SCIF_LOG_OBJECT_TASK_MANAGEMENT,
470       "scif_sas_task_request_operation_complete(0x%x) enter\n",
471       fw_task
472    ));
473 
474    fw_task->affected_request_count--;
475 
476    SCIF_LOG_INFO((
477       sci_base_object_get_logger(fw_task),
478       SCIF_LOG_OBJECT_TASK_MANAGEMENT,
479       "TaskRequest:0x%x current affected request count:0x%x\n",
480       fw_task, fw_task->affected_request_count
481    ));
482 }
483 
484