scif_sas_smp_io_request.c revision 331722
1/*-
2 * This file is provided under a dual BSD/GPLv2 license.  When using or
3 * redistributing this file, you may do so under either license.
4 *
5 * GPL LICENSE SUMMARY
6 *
7 * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of version 2 of the GNU General Public License as
11 * published by the Free Software Foundation.
12 *
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
21 * The full GNU General Public License is included in this distribution
22 * in the file called LICENSE.GPL.
23 *
24 * BSD LICENSE
25 *
26 * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
27 * All rights reserved.
28 *
29 * Redistribution and use in source and binary forms, with or without
30 * modification, are permitted provided that the following conditions
31 * are met:
32 *
33 *   * Redistributions of source code must retain the above copyright
34 *     notice, this list of conditions and the following disclaimer.
35 *   * Redistributions in binary form must reproduce the above copyright
36 *     notice, this list of conditions and the following disclaimer in
37 *     the documentation and/or other materials provided with the
38 *     distribution.
39 *
40 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
41 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
42 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
43 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
44 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
45 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
46 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
47 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
48 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
49 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
50 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
51 */
52
53#include <sys/cdefs.h>
54__FBSDID("$FreeBSD: stable/11/sys/dev/isci/scil/scif_sas_smp_io_request.c 331722 2018-03-29 02:50:57Z eadler $");
55
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 */
84void 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 */
120static
121void 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 */
150static
151void * 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 */
212void * 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 */
249void * 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 */
286void * 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 */
328void * 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 */
366void * 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 */
406void * 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 */
453SCI_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 */
532SCI_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