xref: /freebsd/sys/dev/isci/scil/scif_sas_smp_io_request.c (revision d0b2dbfa0ecf2bbc9709efc5e20baf8e4b44bbbf)
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 /**
57  * @file
58  *
59  * @brief This file contains the method implementations for the
60  *        SCIF_SAS_SMP_IO_REQUEST object.  The contents will implement SMP
61  *        specific functionality.
62  */
63 
64 #include <dev/isci/scil/scif_sas_smp_io_request.h>
65 #include <dev/isci/scil/scif_sas_logger.h>
66 #include <dev/isci/scil/scif_sas_controller.h>
67 #include <dev/isci/scil/sci_controller.h>
68 
69 #include <dev/isci/scil/sci_status.h>
70 #include <dev/isci/scil/scic_io_request.h>
71 #include <dev/isci/scil/scic_user_callback.h>
72 
73 #include <dev/isci/scil/intel_sas.h>
74 
75 /**
76  * @brief This routine is to fill in the space given by core the SMP command
77  *        frame. Then it calls core's construction.
78  *
79  * @param[in] fw_io The smp io request to be constructed.
80  * @param[in] smp_command The SMP request filled according to SAS spec.
81  *
82  * @return none
83  */
84 void scif_sas_smp_request_construct(
85    SCIF_SAS_REQUEST_T * fw_request,
86    SMP_REQUEST_T * smp_command
87 )
88 {
89    void * command_iu_address =
90       scic_io_request_get_command_iu_address(fw_request->core_object);
91 
92    //copy the smp_command to the address;
93    memcpy( (char*) command_iu_address,
94            smp_command,
95            sizeof(SMP_REQUEST_T)
96           );
97 
98    scic_io_request_construct_smp(fw_request->core_object);
99 
100    fw_request->protocol_complete_handler
101       = NULL;
102 }
103 
104 /**
105  * @brief This method will perform all of the construction common to all
106  *        SMP requests (e.g. filling in the frame type, zero-out memory,
107  *        etc.).
108  *
109  * @param[out] smp_request This parameter specifies the SMP request
110  *             structure containing the SMP request to be sent to the
111  *             SMP target.
112  * @param[in]  smp_function This parameter specifies the SMP function to
113  *             sent.
114  * @param[in]  smp_response_length This parameter specifies the length of
115  *             the response (in DWORDs) that will be returned for this
116  *             SMP request.
117  * @param[in]  smp_request_length This parameter specifies the length of
118  *             the request (in DWORDs) that will be sent.
119  */
120 static
121 void scif_sas_smp_protocol_request_construct(
122    SMP_REQUEST_T * smp_request,
123    U8              smp_function,
124    U8              smp_response_length,
125    U8              smp_request_length
126 )
127 {
128    memset((char*)smp_request, 0, sizeof(SMP_REQUEST_T));
129 
130    smp_request->header.smp_frame_type            = SMP_FRAME_TYPE_REQUEST;
131    smp_request->header.function                  = smp_function;
132    smp_request->header.allocated_response_length = smp_response_length;
133    smp_request->header.request_length            = smp_request_length;
134 }
135 
136 
137 /**
138  * @brief This method will allocate the internal IO request object and
139  *        construct its contents based upon the supplied SMP request.
140  *
141  * @param[in] fw_controller This parameter specifies the controller object
142  *            from which to allocate the internal IO request.
143  * @param[in] fw_device This parameter specifies the remote device for
144  *            which the internal IO request is destined.
145  * @param[in] smp_request This parameter specifies the SMP request contents
146  *            to be sent to the SMP target.
147  *
148  * @return void * The address of built scif sas smp request.
149  */
150 static
151 void * scif_sas_smp_request_build(
152    SCIF_SAS_CONTROLLER_T    * fw_controller,
153    SCIF_SAS_REMOTE_DEVICE_T * fw_device,
154    SMP_REQUEST_T            * smp_request,
155    void                     * external_request_object,
156    void                     * external_memory
157 )
158 {
159    if (external_memory != NULL && external_request_object != NULL)
160    {
161       scif_sas_io_request_construct_smp(
162          fw_controller,
163          fw_device,
164          external_memory,
165          (char *)external_memory + sizeof(SCIF_SAS_IO_REQUEST_T),
166          SCI_CONTROLLER_INVALID_IO_TAG,
167          smp_request,
168          external_request_object
169       );
170 
171       return external_memory;
172    }
173    else
174    {
175       void * internal_io_memory;
176       internal_io_memory = scif_sas_controller_allocate_internal_request(fw_controller);
177       ASSERT(internal_io_memory != NULL);
178 
179       if (internal_io_memory != NULL)
180       {
181          //construct, only when we got valid io memory.
182          scif_sas_internal_io_request_construct_smp(
183             fw_controller,
184             fw_device,
185             internal_io_memory,
186             SCI_CONTROLLER_INVALID_IO_TAG,
187             smp_request
188          );
189       }
190       else
191       {
192          SCIF_LOG_ERROR((
193             sci_base_object_get_logger(fw_controller),
194             SCIF_LOG_OBJECT_IO_REQUEST,
195             "scif_sas_smp_request_build, no memory available!\n"
196          ));
197       }
198 
199       return internal_io_memory;
200    }
201 }
202 
203 /**
204  * @brief construct a smp Report Genernal command to the fw_device.
205  *
206  * @param[in] fw_controller The framework controller object.
207  * @param[in] fw_device the framework device that the REPORT GENERAL command
208  *       targets to.
209  *
210  * @return void * address to the built scif sas smp request.
211  */
212 void * scif_sas_smp_request_construct_report_general(
213    SCIF_SAS_CONTROLLER_T    * fw_controller,
214    SCIF_SAS_REMOTE_DEVICE_T * fw_device
215 )
216 {
217    SMP_REQUEST_T smp_report_general;
218 
219    // Build the REPORT GENERAL request.
220    scif_sas_smp_protocol_request_construct(
221       &smp_report_general,
222       SMP_FUNCTION_REPORT_GENERAL,
223       sizeof(SMP_RESPONSE_REPORT_GENERAL_T) / sizeof(U32),
224       0
225    );
226 
227    smp_report_general.request.report_general.crc = 0;
228 
229    SCIF_LOG_INFO((
230       sci_base_object_get_logger(fw_device),
231       SCIF_LOG_OBJECT_IO_REQUEST | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
232       "SMP REPORT GENERAL -  Device:0x%x\n",
233       fw_device
234    ));
235 
236    return scif_sas_smp_request_build(
237              fw_controller, fw_device, &smp_report_general, NULL, NULL);
238 }
239 
240 /**
241  * @brief construct a SMP Report Manufacturer Info request to the fw_device.
242  *
243  * @param[in] fw_controller The framework controller object.
244  * @param[in] fw_device the framework device that the REPORT MANUFACTURER
245  *            INFO targets to.
246  *
247  * @return void * address to the built scif sas smp request.
248  */
249 void * scif_sas_smp_request_construct_report_manufacturer_info(
250    SCIF_SAS_CONTROLLER_T    * fw_controller,
251    SCIF_SAS_REMOTE_DEVICE_T * fw_device
252 )
253 {
254    SMP_REQUEST_T smp_report_manufacturer_info;
255 
256    scif_sas_smp_protocol_request_construct(
257       &smp_report_manufacturer_info,
258       SMP_FUNCTION_REPORT_MANUFACTURER_INFORMATION,
259       sizeof(SMP_RESPONSE_REPORT_MANUFACTURER_INFORMATION_T) / sizeof(U32),
260       0
261    );
262 
263    smp_report_manufacturer_info.request.report_general.crc = 0;
264 
265    SCIF_LOG_INFO((
266       sci_base_object_get_logger(fw_device),
267       SCIF_LOG_OBJECT_IO_REQUEST | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
268       "SMP REPORT MANUFACTURER_INFO -  Device:0x%x\n",
269       fw_device
270    ));
271 
272    return scif_sas_smp_request_build(
273              fw_controller, fw_device, &smp_report_manufacturer_info, NULL, NULL
274           );
275 }
276 
277 /**
278  * @brief construct a smp Discover command to the fw_device.
279  * @param[in] fw_controller The framework controller object.
280  * @param[in] fw_device the framework smp device that DISCOVER command targets
281  *       to.
282  * @param[in] phy_identifier The phy index the DISCOVER command targets to.
283  *
284  * @return void * address to the built scif sas smp request.
285  */
286 void * scif_sas_smp_request_construct_discover(
287    SCIF_SAS_CONTROLLER_T    * fw_controller,
288    SCIF_SAS_REMOTE_DEVICE_T * fw_device,
289    U8                         phy_identifier,
290    void                     * external_request_object,
291    void                     * external_memory
292 )
293 {
294    SMP_REQUEST_T smp_discover;
295 
296    scif_sas_smp_protocol_request_construct(
297       &smp_discover,
298       SMP_FUNCTION_DISCOVER,
299       sizeof(SMP_RESPONSE_DISCOVER_T) / sizeof(U32),
300       sizeof(SMP_REQUEST_PHY_IDENTIFIER_T) / sizeof(U32)
301    );
302 
303    smp_discover.request.discover.phy_identifier = phy_identifier;
304 
305    SCIF_LOG_INFO((
306       sci_base_object_get_logger(fw_device),
307       SCIF_LOG_OBJECT_IO_REQUEST | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
308       "SMP DISCOVER - Device:0x%x PhyId:0x%x\n",
309       fw_device, phy_identifier
310    ));
311 
312    return scif_sas_smp_request_build(
313              fw_controller, fw_device, &smp_discover,
314              external_request_object, external_memory
315           );
316 }
317 
318 
319 /**
320  * @brief construct a smp REPORT PHY SATA command to the fw_device.
321  * @param[in] fw_controller The framework controller object.
322  * @param[in] fw_device the framework smp device that DISCOVER command targets
323  *       to.
324  * @param[in] phy_identifier The phy index the DISCOVER command targets to.
325  *
326  * @return void * address to the built scif sas smp request.
327  */
328 void * scif_sas_smp_request_construct_report_phy_sata(
329    SCIF_SAS_CONTROLLER_T    * fw_controller,
330    SCIF_SAS_REMOTE_DEVICE_T * fw_device,
331    U8                         phy_identifier
332 )
333 {
334    SMP_REQUEST_T report_phy_sata;
335 
336    scif_sas_smp_protocol_request_construct(
337       &report_phy_sata,
338       SMP_FUNCTION_REPORT_PHY_SATA,
339       sizeof(SMP_RESPONSE_REPORT_PHY_SATA_T) / sizeof(U32),
340       sizeof(SMP_REQUEST_PHY_IDENTIFIER_T) / sizeof(U32)
341    );
342 
343    report_phy_sata.request.report_phy_sata.phy_identifier = phy_identifier;
344 
345    SCIF_LOG_INFO((
346       sci_base_object_get_logger(fw_device),
347       SCIF_LOG_OBJECT_IO_REQUEST | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
348       "SMP REPORT PHY SATA - Device:0x%x PhyId:0x%x\n",
349       fw_device, phy_identifier
350    ));
351 
352    return scif_sas_smp_request_build(
353              fw_controller, fw_device, &report_phy_sata, NULL, NULL);
354 }
355 
356 
357 /**
358  * @brief construct a smp REPORT PHY SATA command to the fw_device.
359  * @param[in] fw_controller The framework controller object.
360  * @param[in] fw_device the framework smp device that PHY CONTROL command
361  *       targets to.
362  * @param[in] phy_identifier The phy index the DISCOVER command targets to.
363  *
364  * @return void * address to the built scif sas smp request.
365  */
366 void * scif_sas_smp_request_construct_phy_control(
367    SCIF_SAS_CONTROLLER_T    * fw_controller,
368    SCIF_SAS_REMOTE_DEVICE_T * fw_device,
369    U8                         phy_operation,
370    U8                         phy_identifier,
371    void                     * external_request_object,
372    void                     * external_memory
373 )
374 {
375    SMP_REQUEST_T phy_control;
376 
377    scif_sas_smp_protocol_request_construct(
378       &phy_control,
379       SMP_FUNCTION_PHY_CONTROL,
380       0,
381       sizeof(SMP_REQUEST_PHY_CONTROL_T) / sizeof(U32)
382    );
383 
384    phy_control.request.phy_control.phy_operation = phy_operation;
385    phy_control.request.phy_control.phy_identifier = phy_identifier;
386 
387    return scif_sas_smp_request_build(
388              fw_controller, fw_device, &phy_control,
389              external_request_object, external_memory
390           );
391 }
392 
393 
394 /**
395  * @brief construct a smp CONFIG ROUTE INFO command to the fw_device.
396  *
397  * @param[in] fw_controller The framework controller object.
398  * @param[in] fw_device the framework smp device that PHY CONTROL command
399  *       targets to.
400  * @param[in] phy_id The phy, whose route entry at route_index is to be configured.
401  * @param[in] route_index The index of a phy's route entry that is to be configured.
402  * @param[in] destination_sas_address A sas address for an route table entry
403  *
404  * @return void * address to the built scif sas smp request.
405  */
406 void * scif_sas_smp_request_construct_config_route_info(
407    struct SCIF_SAS_CONTROLLER    * fw_controller,
408    struct SCIF_SAS_REMOTE_DEVICE * fw_device,
409    U8                              phy_id,
410    U16                             route_index,
411    SCI_SAS_ADDRESS_T               destination_sas_address,
412    BOOL                            disable_expander_route_entry
413 )
414 {
415    SMP_REQUEST_T config_route_info;
416 
417    scif_sas_smp_protocol_request_construct(
418       &config_route_info,
419       SMP_FUNCTION_CONFIGURE_ROUTE_INFORMATION,
420       0,
421       sizeof(SMP_REQUEST_CONFIGURE_ROUTE_INFORMATION_T) / sizeof(U32)
422    );
423 
424    config_route_info.request.configure_route_information.phy_identifier = phy_id;
425    config_route_info.request.configure_route_information.expander_route_index_high =
426       ((route_index & 0xff00) >> 8);
427    config_route_info.request.configure_route_information.expander_route_index =
428       route_index & 0xff;
429    config_route_info.request.configure_route_information.routed_sas_address[0] =
430       destination_sas_address.high;
431    config_route_info.request.configure_route_information.routed_sas_address[1] =
432       destination_sas_address.low;
433 
434    if (disable_expander_route_entry == TRUE)
435       config_route_info.request.configure_route_information.disable_route_entry = 1;
436 
437    return scif_sas_smp_request_build(
438              fw_controller, fw_device, &config_route_info,
439              NULL, NULL
440           );
441 }
442 
443 /**
444  * @brief This method retry the internal smp request.
445  *
446  * @param[in] fw_device This parameter specifies the remote device for
447  *            which the internal IO request is destined.
448  * @param[in] retry_count This parameter specifies how many times the
449  *            old smp request has been retried.
450  *
451  * @return none.
452  */
453 SCI_STATUS scif_sas_smp_internal_request_retry(
454    SCIF_SAS_REMOTE_DEVICE_T * fw_device
455 )
456 {
457    SCIF_SAS_CONTROLLER_T * fw_controller;
458    SCIF_SAS_IO_REQUEST_T * new_io;
459    void                  * new_request_memory = NULL;
460    U8 retry_count = fw_device->protocol_device.smp_device.io_retry_count;
461 
462    SCIF_LOG_TRACE((
463       sci_base_object_get_logger(fw_device),
464       SCIF_LOG_OBJECT_IO_REQUEST | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
465       "scif_sas_smp_internal_request_retry(0x%x, 0x%x) time %d!\n",
466       fw_device, retry_count
467    ));
468 
469    fw_controller = fw_device->domain->controller;
470 
471    switch (fw_device->protocol_device.smp_device.current_smp_request)
472    {
473       case SMP_FUNCTION_REPORT_GENERAL:
474          new_request_memory = scif_sas_smp_request_construct_report_general(
475             fw_controller, fw_device
476          );
477          break;
478 
479       case SMP_FUNCTION_DISCOVER:
480          //We are retrying an internal io. So we are going to allocate
481          //a new memory from internal io memory pool.
482          new_request_memory = scif_sas_smp_request_construct_discover(
483             fw_controller, fw_device,
484             fw_device->protocol_device.smp_device.current_activity_phy_index,
485             NULL, NULL
486          );
487 
488          break;
489 
490       case SMP_FUNCTION_REPORT_PHY_SATA:
491          new_request_memory = scif_sas_smp_request_construct_report_phy_sata(
492             fw_controller, fw_device,
493             fw_device->protocol_device.smp_device.current_activity_phy_index
494          );
495          break;
496 
497       default:
498          //unsupported case, TBD
499          break;
500    } //end of switch
501 
502    if (new_request_memory != NULL)
503    {
504       //set the retry count to new built smp request.
505       new_io = (SCIF_SAS_IO_REQUEST_T *) new_request_memory;
506       new_io->retry_count = ++retry_count;
507 
508       //need to schedule the DPC here.
509       scif_cb_start_internal_io_task_schedule(
510             fw_controller,
511             scif_sas_controller_start_high_priority_io,
512             fw_controller
513          );
514 
515       return SCI_SUCCESS;
516    }
517    else
518       return SCI_FAILURE_INSUFFICIENT_RESOURCES;
519 
520 }
521 
522 /**
523  * @brief This method retry the external smp request.
524  *
525  * @param[in] fw_device This parameter specifies the remote device for
526  *            which the internal IO request is destined.
527  * @param[in] old_internal_io This parameter specifies the old smp request to be
528  *            retried.
529  *
530  * @return none.
531  */
532 SCI_STATUS scif_sas_smp_external_request_retry(
533    SCIF_SAS_IO_REQUEST_T    * old_io
534 )
535 {
536    SCIF_SAS_REMOTE_DEVICE_T * fw_device = old_io->parent.device;
537    SCIF_SAS_CONTROLLER_T * fw_controller;
538    SCIF_SAS_IO_REQUEST_T * new_io;
539    void                  * new_request_memory = NULL;
540    U8                      retry_count = old_io->retry_count;
541 
542    SCIF_LOG_TRACE((
543       sci_base_object_get_logger(fw_device),
544       SCIF_LOG_OBJECT_IO_REQUEST | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
545       "scif_sas_smp_external_request_retry(0x%x) time %d!\n",
546       old_io
547    ));
548 
549    fw_controller = fw_device->domain->controller;
550 
551    // Before we construct new io using the same memory, we need to
552    // remove the IO from the list of outstanding requests on the domain
553    // so that we don't damage the domain's fast list of request.
554    sci_fast_list_remove_element(&old_io->parent.list_element);
555 
556    switch (fw_device->protocol_device.smp_device.current_smp_request)
557    {
558       case SMP_FUNCTION_DISCOVER:
559          //we are retrying an external io, we are going to reuse the
560          //old io's memory. new_request_memory is same as old_io.
561          new_request_memory = scif_sas_smp_request_construct_discover(
562             fw_controller, fw_device,
563             fw_device->protocol_device.smp_device.current_activity_phy_index,
564             (void *)sci_object_get_association(old_io),
565             (void *)old_io
566          );
567 
568          break;
569 
570       case SMP_FUNCTION_PHY_CONTROL:
571          //Phy Control command always uses external io memory.
572          new_request_memory = scif_sas_smp_request_construct_phy_control(
573             fw_controller, fw_device, PHY_OPERATION_HARD_RESET,
574             fw_device->protocol_device.smp_device.current_activity_phy_index,
575             (void *)sci_object_get_association(old_io),
576             (void *)old_io
577          );
578 
579          break;
580 
581       default:
582          //unsupported case, TBD
583          return SCI_FAILURE;
584    } //end of switch
585 
586    //set the retry count to new built smp request.
587    new_io = (SCIF_SAS_IO_REQUEST_T *) new_request_memory;
588    new_io->retry_count = ++retry_count;
589 
590    //put into the high priority queue.
591    sci_pool_put(fw_controller->hprq.pool, (POINTER_UINT) new_request_memory);
592 
593    //schedule the DPC to start new io.
594    scif_cb_start_internal_io_task_schedule(
595       fw_controller, scif_sas_controller_start_high_priority_io, fw_controller
596    );
597 
598    return SCI_SUCCESS;
599 }
600 
601