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