scif_sas_smp_remote_device.c revision 230557
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$");
55
56/**
57 * @file
58 *
59 * @brief This file contains the methods for the SCIF_SAS_SMP_REMOTE_DEVICE object.
60 */
61#include <dev/isci/scil/sci_controller.h>
62#include <dev/isci/scil/scif_sas_controller.h>
63#include <dev/isci/scil/scif_sas_remote_device.h>
64#include <dev/isci/scil/scif_sas_logger.h>
65
66#include <dev/isci/scil/scif_sas_smp_remote_device.h>
67#include <dev/isci/scil/scif_sas_smp_io_request.h>
68#include <dev/isci/scil/intel_sas.h>
69#include <dev/isci/scil/scic_io_request.h>
70#include <dev/isci/scil/scic_remote_device.h>
71#include <dev/isci/scil/scif_sas_smp_phy.h>
72
73
74/**
75 * @brief This method resets all fields for a smp remote device. This is a
76 *        private method.
77 *
78 * @param[in] fw_device the framework SMP device that is being
79 *            constructed.
80 *
81 * @return none
82 */
83void scif_sas_smp_remote_device_clear(
84   SCIF_SAS_REMOTE_DEVICE_T * fw_device
85)
86{
87   //reset all fields in smp_device, indicate that the smp device is not
88   //in discovery process.
89   fw_device->protocol_device.smp_device.current_activity =
90      SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_NONE;
91
92   fw_device->protocol_device.smp_device.current_smp_request =
93      NOT_IN_SMP_ACTIVITY;
94
95   fw_device->protocol_device.smp_device.current_activity_phy_index = 0;
96
97   fw_device->protocol_device.smp_device.curr_config_route_index = 0;
98
99   fw_device->protocol_device.smp_device.config_route_smp_phy_anchor = NULL;
100
101   fw_device->protocol_device.smp_device.is_route_table_cleaned = FALSE;
102
103   fw_device->protocol_device.smp_device.curr_config_route_destination_smp_phy = NULL;
104
105   fw_device->protocol_device.smp_device.scheduled_activity =
106      SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_NONE;
107
108   fw_device->protocol_device.smp_device.io_retry_count = 0;
109
110   fw_device->protocol_device.smp_device.curr_clear_affiliation_phy = NULL;
111
112   if (fw_device->protocol_device.smp_device.smp_activity_timer != NULL)
113   {
114      //stop the timer
115      scif_cb_timer_stop(
116         fw_device->domain->controller,
117         fw_device->protocol_device.smp_device.smp_activity_timer
118      );
119
120      //destroy the timer
121      scif_cb_timer_destroy(
122         fw_device->domain->controller,
123         fw_device->protocol_device.smp_device.smp_activity_timer
124      );
125
126      fw_device->protocol_device.smp_device.smp_activity_timer = NULL;
127   }
128}
129
130
131/**
132 * @brief This method intializes a smp remote device.
133 *
134 * @param[in] fw_device the framework SMP device that is being
135 *            constructed.
136 *
137 * @return none
138 */
139void scif_sas_smp_remote_device_construct(
140   SCIF_SAS_REMOTE_DEVICE_T * fw_device
141)
142{
143   SCIF_LOG_TRACE((
144      sci_base_object_get_logger(fw_device),
145      SCIF_LOG_OBJECT_REMOTE_DEVICE,
146      "scif_sas_smp_remote_device_construct(0x%x) enter\n",
147      fw_device
148   ));
149
150   fw_device->protocol_device.smp_device.number_of_phys = 0;
151   fw_device->protocol_device.smp_device.expander_route_indexes = 0;
152   fw_device->protocol_device.smp_device.is_table_to_table_supported = FALSE;
153   fw_device->protocol_device.smp_device.is_externally_configurable  = FALSE;
154   fw_device->protocol_device.smp_device.is_able_to_config_others    = FALSE;
155
156   sci_fast_list_init(&fw_device->protocol_device.smp_device.smp_phy_list);
157
158   scif_sas_smp_remote_device_clear(fw_device);
159}
160
161
162/**
163 * @brief This method decodes a smp response to this smp device and then
164 *        continue the smp discover process.
165 *
166 * @param[in] fw_device The framework device that a SMP response targets to.
167 * @param[in] fw_request The pointer to an smp request whose response
168 *       is to be decoded.
169 * @param[in] response_data The response data passed in.
170 *
171 * @return none
172 */
173SCI_STATUS scif_sas_smp_remote_device_decode_smp_response(
174   SCIF_SAS_REMOTE_DEVICE_T * fw_device,
175   SCIF_SAS_REQUEST_T       * fw_request,
176   void                     * response_data,
177   SCI_IO_STATUS              completion_status
178)
179{
180   SMP_RESPONSE_T * smp_response = (SMP_RESPONSE_T *)response_data;
181   SCI_STATUS       status       = SCI_FAILURE_UNSUPPORTED_INFORMATION_TYPE;
182
183   if (fw_device->protocol_device.smp_device.smp_activity_timer != NULL)
184   {
185      //if there is a timer being used, recycle it now. Since we may
186      //use the timer for other purpose next.
187      scif_cb_timer_destroy(
188         fw_device->domain->controller,
189         fw_device->protocol_device.smp_device.smp_activity_timer
190      );
191
192      fw_device->protocol_device.smp_device.smp_activity_timer = NULL;
193   }
194
195   //if Core set the status of this io to be RETRY_REQUIRED, we should
196   //retry the IO without even decode the response.
197   if (completion_status == SCI_FAILURE_RETRY_REQUIRED)
198   {
199      scif_sas_smp_remote_device_continue_current_activity(
200         fw_device, fw_request, SCI_FAILURE_RETRY_REQUIRED
201      );
202
203      return SCI_FAILURE_RETRY_REQUIRED;
204   }
205
206   //check the current smp request, decide what's next smp request to issue.
207   switch (fw_device->protocol_device.smp_device.current_smp_request)
208   {
209      case SMP_FUNCTION_REPORT_GENERAL:
210      {
211         //interpret REPORT GENERAL response.
212         status = scif_sas_smp_remote_device_decode_report_general_response(
213            fw_device, smp_response
214         );
215
216         break;
217      }
218
219      case SMP_FUNCTION_REPORT_MANUFACTURER_INFORMATION:
220      {
221         // No need to perform any parsing.  Just want to see
222         // the information in a trace if necessary.
223         status = SCI_SUCCESS;
224         break;
225      }
226
227      case SMP_FUNCTION_DISCOVER:
228      {
229         if (fw_device->protocol_device.smp_device.current_activity ==
230                SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_DISCOVER)
231         {
232            //decode discover response
233            status = scif_sas_smp_remote_device_decode_initial_discover_response(
234                        fw_device, smp_response
235                     );
236         }
237         else if (fw_device->protocol_device.smp_device.current_activity ==
238                  SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_TARGET_RESET)
239         {
240            //decode discover response as a polling result for a remote device
241            //target reset.
242            status =
243               scif_sas_smp_remote_device_decode_target_reset_discover_response(
244                  fw_device, smp_response
245               );
246         }
247         else if (fw_device->protocol_device.smp_device.current_activity ==
248                SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_SATA_SPINUP_HOLD_RELEASE)
249         {
250            //decode discover response
251            status =
252               scif_sas_smp_remote_device_decode_spinup_hold_release_discover_response(
253                  fw_device, smp_response
254               );
255         }
256         else
257            ASSERT(0);
258         break;
259      }
260
261      case SMP_FUNCTION_REPORT_PHY_SATA:
262      {
263         //decode the report phy sata response.
264         status = scif_sas_smp_remote_device_decode_report_phy_sata_response(
265            fw_device, smp_response
266         );
267
268         break;
269      }
270
271      case SMP_FUNCTION_PHY_CONTROL:
272      {
273         if (fw_device->protocol_device.smp_device.current_activity ==
274                SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_DISCOVER)
275         {
276            //decode the phy control response.
277            status = scif_sas_smp_remote_device_decode_discover_phy_control_response(
278                        fw_device, smp_response
279                     );
280         }
281         else if (fw_device->protocol_device.smp_device.current_activity ==
282                     SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_TARGET_RESET)
283         {
284            //decode discover response as a polling result for a remote device
285            //target reset.
286            status = scif_sas_smp_remote_device_decode_target_reset_phy_control_response(
287                        fw_device, smp_response
288                     );
289         }
290         else if (fw_device->protocol_device.smp_device.current_activity ==
291                     SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_CLEAR_AFFILIATION)
292         {
293            //currently don't care about the status.
294            status = SCI_SUCCESS;
295         }
296         else
297            ASSERT(0);
298         break;
299      }
300
301      case SMP_FUNCTION_CONFIGURE_ROUTE_INFORMATION:
302      {
303         //Note, currently we don't expect any abnormal status from config route info response,
304         //but there is a possibility that we exceed the maximum route index. We will take care
305         //of errors later.
306         status = scif_sas_smp_remote_device_decode_config_route_info_response(
307                     fw_device, smp_response
308                  );
309         break;
310      }
311
312      default:
313         //unsupported case, TBD
314         status = SCI_FAILURE_UNSUPPORTED_INFORMATION_TYPE;
315         break;
316   } //end of switch
317
318   //Continue current activity based on response's decoding status.
319   scif_sas_smp_remote_device_continue_current_activity(
320      fw_device, fw_request, status
321   );
322
323   return status;
324}
325
326
327/**
328 * @brief This method decodes a smp Report Genernal response to this smp device
329 *        and then continue the smp discover process.
330 *
331 * @param[in] fw_device The framework device that the REPORT GENERAL command
332 *       targets to.
333 * @param[in] report_general_response The pointer to a report general response
334 *
335 * @return none
336 */
337SCI_STATUS scif_sas_smp_remote_device_decode_report_general_response(
338   SCIF_SAS_REMOTE_DEVICE_T * fw_device,
339   SMP_RESPONSE_T           * smp_response
340)
341{
342   SMP_RESPONSE_REPORT_GENERAL_T * report_general_response =
343      &smp_response->response.report_general;
344
345   SMP_RESPONSE_HEADER_T * response_header = &smp_response->header;
346
347   SCIF_LOG_TRACE((
348      sci_base_object_get_logger(fw_device),
349      SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
350      "scif_sas_smp_remote_device_decode_report_general_response(0x%x, 0x%x) enter\n",
351      fw_device, smp_response
352   ));
353
354   if (response_header->function_result != SMP_RESULT_FUNCTION_ACCEPTED)
355   {
356      /// @todo: more decoding work needed when the function_result is not
357      /// SMP_RESULT_FUNCTION_ACCEPTED. Retry might be the option for some
358      /// function result.
359      SCIF_LOG_ERROR((
360         sci_base_object_get_logger(fw_device),
361         SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
362         "Report General function result(0x%x)\n",
363         response_header->function_result
364      ));
365
366      return SCI_FAILURE;
367   }
368
369   //get info from report general response.
370   fw_device->protocol_device.smp_device.number_of_phys =
371      (U8)report_general_response->number_of_phys;
372
373   //currently there is byte swap issue in U16 data.
374   fw_device->protocol_device.smp_device.expander_route_indexes =
375      ((report_general_response->expander_route_indexes & 0xff) << 8) |
376      ((report_general_response->expander_route_indexes & 0xff00) >> 8);
377
378   fw_device->protocol_device.smp_device.is_table_to_table_supported =
379      (BOOL)report_general_response->table_to_table_supported;
380
381   fw_device->protocol_device.smp_device.is_externally_configurable =
382      (BOOL)report_general_response->configurable_route_table;
383
384   fw_device->protocol_device.smp_device.is_able_to_config_others =
385      (BOOL)report_general_response->configures_others;
386
387   //If the top level expander of a domain is able to configure others,
388   //no config route table is needed in the domain. Or else,
389   //we'll let all the externally configurable expanders in the damain
390   //configure route table.
391   if (fw_device->containing_device == NULL
392       && ! fw_device->protocol_device.smp_device.is_able_to_config_others)
393      fw_device->domain->is_config_route_table_needed = TRUE;
394
395   //knowing number of phys this expander has, we can allocate all the smp phys for
396   //this expander now if it is not done already.
397   if (fw_device->protocol_device.smp_device.smp_phy_list.element_count == 0)
398      scif_sas_smp_remote_device_populate_smp_phy_list(fw_device);
399
400   if (report_general_response->configuring)
401      return SCI_FAILURE_RETRY_REQUIRED;
402
403   return SCI_SUCCESS;
404}
405
406
407/**
408 * @brief This method decodes a smp Discover response to this smp device
409 *        and then continue the smp discover process. This is only ever
410 *        called for the very first discover stage during a given domain
411 *        discovery process.
412 *
413 * @param[in] fw_device The framework device that the DISCOVER command
414 *       targets to.
415 * @param[in] discover_response The pointer to a DISCOVER response
416 *
417 * @return none
418 */
419SCI_STATUS scif_sas_smp_remote_device_decode_initial_discover_response(
420   SCIF_SAS_REMOTE_DEVICE_T * fw_device,
421   SMP_RESPONSE_T           * smp_response
422)
423{
424   SCIF_SAS_DOMAIN_T        * fw_domain = fw_device->domain;
425   SCI_SAS_ADDRESS_T          attached_device_address;
426   SCIF_SAS_REMOTE_DEVICE_T * attached_remote_device;
427   SMP_RESPONSE_DISCOVER_T  * discover_response =
428      &smp_response->response.discover;
429   SMP_RESPONSE_HEADER_T    * response_header = &smp_response->header;
430
431   SCIF_LOG_TRACE((
432      sci_base_object_get_logger(fw_device),
433      SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
434      "scif_sas_smp_remote_device_decode_initial_discover_response(0x%x, 0x%x) enter\n",
435      fw_device, smp_response
436   ));
437
438   if (response_header->function_result == SMP_RESULT_PHY_VACANT)
439   {
440      return SCI_SUCCESS;
441   }
442   else if (response_header->function_result != SMP_RESULT_FUNCTION_ACCEPTED)
443   {
444      /// @todo: more decoding work needed when the function_result is not
445      /// SMP_RESULT_FUNCTION_ACCEPTED. Retry might be the option for some
446      /// function result.
447      SCIF_LOG_ERROR((
448         sci_base_object_get_logger(fw_device),
449         SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
450         "Discover function result(0x%x)\n",
451         response_header->function_result
452      ));
453
454      return SCI_FAILURE;
455   }
456
457   //only if there is target device attached. We don't add device that is
458   //initiator only.
459   if ( ( discover_response->u2.sas1_1.attached_device_type
460             != SMP_NO_DEVICE_ATTACHED )
461       && ( discover_response->protocols.u.bits.attached_ssp_target
462           || discover_response->protocols.u.bits.attached_stp_target
463           || discover_response->protocols.u.bits.attached_smp_target
464           || discover_response->protocols.u.bits.attached_sata_device ) )
465   {
466      attached_device_address = discover_response->attached_sas_address;
467
468      attached_remote_device = (SCIF_SAS_REMOTE_DEVICE_T *)
469         scif_domain_get_device_by_sas_address(
470            fw_domain, &attached_device_address
471         );
472
473      //need to check if the device already existed in the domian.
474      if (attached_remote_device != SCI_INVALID_HANDLE)
475      {
476#if !defined(DISABLE_WIDE_PORTED_TARGETS)
477         if ( attached_remote_device->is_currently_discovered == TRUE
478             && attached_remote_device != fw_device->containing_device )
479         {
480            //a downstream wide port target is found.
481            attached_remote_device->device_port_width++;
482         }
483         else
484#endif //#if !defined(DISABLE_WIDE_PORTED_TARGETS)
485         {
486            //The device already existed. Mark the device as discovered.
487            attached_remote_device->is_currently_discovered = TRUE;
488         }
489
490#if !defined(DISABLE_WIDE_PORTED_TARGETS)
491         if (attached_remote_device->device_port_width !=
492                scic_remote_device_get_port_width(attached_remote_device->core_object)
493             && discover_response->protocols.u.bits.attached_ssp_target
494            )
495         {
496            scif_sas_remote_device_update_port_width(
497               attached_remote_device, attached_remote_device->device_port_width);
498         }
499#endif //#if !defined(DISABLE_WIDE_PORTED_TARGETS)
500
501         if ( discover_response->protocols.u.bits.attached_smp_target
502             && attached_remote_device != fw_device->containing_device)
503         {
504            //another expander device is discovered. Its own smp discover will starts after
505            //this discover finishes.
506            attached_remote_device->protocol_device.smp_device.scheduled_activity =
507               SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_DISCOVER;
508         }
509      }
510      else
511      {
512         //report the discovery of a disk for all types of end device.
513         scif_cb_domain_ea_device_added(
514            fw_domain->controller, fw_domain, fw_device, discover_response
515         );
516
517         //get info from discover response to see what we found. And do
518         //extra work according to end device's protocol type.
519         if ( discover_response->protocols.u.bits.attached_ssp_target
520             || discover_response->protocols.u.bits.attached_smp_target)
521         {
522            //for SSP or SMP target, no extra work.
523            ;
524         }
525         else if (  (discover_response->protocols.u.bits.attached_stp_target)
526                 || (discover_response->protocols.u.bits.attached_sata_device) )
527         {
528            // We treat a SATA Device bit the same as an attached STP
529            // target.
530            discover_response->protocols.u.bits.attached_stp_target = 1;
531
532            //kick off REPORT PHY SATA to the same phy.
533            fw_device->protocol_device.smp_device.current_smp_request =
534               SMP_FUNCTION_REPORT_PHY_SATA;
535         }
536      }
537   }
538   else if( (discover_response->u2.sas1_1.negotiated_physical_link_rate == SCI_SATA_SPINUP_HOLD
539             || discover_response->u4.sas2.negotiated_physical_link_rate == SCI_SATA_SPINUP_HOLD)
540          &&(discover_response->protocols.u.bits.attached_stp_target
541             || discover_response->protocols.u.bits.attached_sata_device)
542          )
543   {
544      attached_remote_device = scif_sas_domain_get_device_by_containing_device(
545                                  fw_domain,
546                                  fw_device,
547                                  discover_response->phy_identifier
548                               );
549
550      if (attached_remote_device != SCI_INVALID_HANDLE)
551      {
552         //Here, the only reason a device already existed in domain but
553         //the initial discover rersponse shows it in SPINUP_HOLD, is that
554         //a device has been removed and coming back in SPINUP_HOLD before
555         //we detected. The possibility of this situation is very very rare.
556         //we need to remove the device then add it back using the new
557         //discover response.
558         scif_cb_domain_device_removed(
559            fw_domain->controller, fw_domain, attached_remote_device
560         );
561      }
562
563      discover_response->protocols.u.bits.attached_stp_target = 1;
564
565      //still report ea_device_added(). But this device will not be
566      //started during scif_remote_device_ea_construct().
567      scif_cb_domain_ea_device_added(
568         fw_domain->controller, fw_domain, fw_device, discover_response
569      );
570
571      //need to send Phy Control (RESET) to release the phy from spinup hold
572      //condition.
573      fw_device->protocol_device.smp_device.current_smp_request =
574         SMP_FUNCTION_PHY_CONTROL;
575   }
576
577   //update the smp phy info based on this DISCOVER response.
578   return scif_sas_smp_remote_device_save_smp_phy_info(
579             fw_device, discover_response);
580}
581
582
583/**
584 * @brief This method decodes a smp Report Phy Sata response to this
585 *        smp device and then continue the smp discover process.
586 *
587 * @param[in] fw_device The framework device that the REPORT PHY SATA
588 *       command targets to.
589 * @param[in] report_phy_sata_response The pointer to a REPORT PHY
590 *       SATA response
591 *
592 * @return none
593 */
594SCI_STATUS scif_sas_smp_remote_device_decode_report_phy_sata_response(
595   SCIF_SAS_REMOTE_DEVICE_T * fw_device,
596   SMP_RESPONSE_T           * smp_response
597)
598{
599   SMP_RESPONSE_REPORT_PHY_SATA_T * report_phy_sata_response =
600      &smp_response->response.report_phy_sata;
601
602   SMP_RESPONSE_HEADER_T * response_header = &smp_response->header;
603
604   SCIF_LOG_TRACE((
605      sci_base_object_get_logger(fw_device),
606      SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
607      "scif_sas_smp_remote_device_decode_report_phy_sata_response(0x%x, 0x%x) enter\n",
608      fw_device, smp_response
609   ));
610
611   if (response_header->function_result != SMP_RESULT_FUNCTION_ACCEPTED)
612   {
613      /// @todo: more decoding work needed when the function_result is not
614      /// SMP_RESULT_FUNCTION_ACCEPTED. Retry might be the option for some
615      /// function result.
616      SCIF_LOG_ERROR((
617         sci_base_object_get_logger(fw_device),
618         SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
619         "Report Phy Sata function result(0x%x)\n",
620         response_header->function_result
621      ));
622
623      return SCI_FAILURE;
624   }
625
626   scif_sas_remote_device_save_report_phy_sata_information(
627      report_phy_sata_response
628   );
629
630   // continue the discover process.
631   fw_device->protocol_device.smp_device.current_smp_request =
632      SMP_FUNCTION_DISCOVER;
633
634   return SCI_SUCCESS;
635}
636
637
638/**
639 * @brief This method decodes a smp Phy Control response to this smp device and
640 *        then continue the smp TARGET RESET process.
641 *
642 * @param[in] fw_device The framework device that the Phy Control command
643 *       targets to.
644 * @param[in] smp_response The pointer to a Phy Control response
645 * @param[in] fw_io The scif IO request that associates to this smp response.
646 *
647 * @return none
648 */
649SCI_STATUS scif_sas_smp_remote_device_decode_target_reset_phy_control_response(
650   SCIF_SAS_REMOTE_DEVICE_T * fw_device,
651   SMP_RESPONSE_T           * smp_response
652)
653{
654   SMP_RESPONSE_HEADER_T * response_header = &smp_response->header;
655
656   SCI_STATUS status = SCI_SUCCESS;
657
658   SCIF_LOG_TRACE((
659      sci_base_object_get_logger(fw_device),
660      SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
661      "scif_sas_smp_remote_device_decode_target_reset_phy_control_response(0x%x, 0x%x) enter\n",
662      fw_device, smp_response
663   ));
664
665   if (response_header->function_result != SMP_RESULT_FUNCTION_ACCEPTED)
666   {
667      /// @todo: more decoding work needed when the function_result is not
668      /// SMP_RESULT_FUNCTION_ACCEPTED. Retry might be the option for some
669      /// function result.
670      SCIF_LOG_ERROR((
671         sci_base_object_get_logger(fw_device),
672         SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
673         "Phy Control function unaccepted result(0x%x)\n",
674         response_header->function_result
675      ));
676
677      status = SCI_FAILURE_RETRY_REQUIRED;
678   }
679
680   // phy Control succeeded.
681   return status;
682}
683
684/**
685 * @brief This method decodes a smp Phy Control response to this smp device and
686 *        then continue the smp DISCOVER process.
687 *
688 * @param[in] fw_device The framework device that the Phy Control command
689 *       targets to.
690 * @param[in] smp_response The pointer to a Phy Control response
691 *
692 * @return Almost always SCI_SUCCESS
693 */
694SCI_STATUS scif_sas_smp_remote_device_decode_discover_phy_control_response(
695   SCIF_SAS_REMOTE_DEVICE_T * fw_device,
696   SMP_RESPONSE_T           * smp_response
697)
698{
699   SMP_RESPONSE_HEADER_T * response_header = &smp_response->header;
700
701   SCI_STATUS status = SCI_SUCCESS;
702
703   SCIF_LOG_TRACE((
704      sci_base_object_get_logger(fw_device),
705      SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
706      "scif_sas_smp_remote_device_decode_discover_phy_control_response(0x%x, 0x%x) enter\n",
707      fw_device, smp_response
708   ));
709
710   if (response_header->function_result != SMP_RESULT_FUNCTION_ACCEPTED)
711   {
712      /// @todo: more decoding work needed when the function_result is not
713      /// SMP_RESULT_FUNCTION_ACCEPTED. Retry might be the option for some
714      /// function result.
715      SCIF_LOG_ERROR((
716         sci_base_object_get_logger(fw_device),
717         SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
718         "Phy Control function unaccepted result(0x%x)\n",
719         response_header->function_result
720      ));
721
722      return SCI_FAILURE_RETRY_REQUIRED;
723   }
724
725   // continue the discover process.
726   fw_device->protocol_device.smp_device.current_smp_request =
727      SMP_FUNCTION_DISCOVER;
728
729   // phy Control succeeded.
730   return status;
731}
732
733
734/**
735 * @brief This method decodes a smp Discover response to this smp device
736 *        and then continue the smp discover process.
737 *
738 * @param[in] fw_device The framework device that the DISCOVER command
739 *       targets to.
740 * @param[in] discover_response The pointer to a DISCOVER response
741 *
742 * @return none
743 */
744SCI_STATUS scif_sas_smp_remote_device_decode_target_reset_discover_response(
745   SCIF_SAS_REMOTE_DEVICE_T * fw_device,
746   SMP_RESPONSE_T           * smp_response
747)
748{
749   SCIF_SAS_DOMAIN_T  * fw_domain;
750   SCI_SAS_ADDRESS_T attached_device_address;
751   SCIF_SAS_REMOTE_DEVICE_T * attached_remote_device;
752   SMP_RESPONSE_DISCOVER_T * discover_response =
753      &smp_response->response.discover;
754
755   SMP_RESPONSE_HEADER_T * response_header = &smp_response->header;
756
757   SCIF_LOG_TRACE((
758      sci_base_object_get_logger(fw_device),
759      SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
760      "scif_sas_smp_remote_device_decode_target_reset_discover_response(0x%x, 0x%x) enter\n",
761      fw_device, smp_response
762   ));
763
764   if (response_header->function_result != SMP_RESULT_FUNCTION_ACCEPTED)
765   {
766      /// @todo: more decoding work needed when the function_result is not
767      /// SMP_RESULT_FUNCTION_ACCEPTED. Retry might be the option for some
768      /// function result.
769      SCIF_LOG_ERROR((
770         sci_base_object_get_logger(fw_device),
771         SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
772         "Discover function result(0x%x)\n",
773         response_header->function_result
774      ));
775
776      return SCI_FAILURE_RETRY_REQUIRED;
777   }
778
779   //only if there is device attached.
780   if ( discover_response->u2.sas1_1.attached_device_type != SMP_NO_DEVICE_ATTACHED )
781   {
782      fw_domain = fw_device->domain;
783      attached_device_address = discover_response->attached_sas_address;
784
785      attached_remote_device = (SCIF_SAS_REMOTE_DEVICE_T *)
786         scif_domain_get_device_by_sas_address(
787         fw_domain, &attached_device_address
788      );
789
790      // the device should have already existed in the domian.
791      ASSERT (attached_remote_device != SCI_INVALID_HANDLE);
792      return SCI_SUCCESS;
793   }
794   else
795      return SCI_FAILURE_RETRY_REQUIRED;
796}
797
798/**
799 * @brief This method decodes a smp Discover response to this smp device
800 *        for SPINUP_HOLD_RELEASE activity. If a DISCOVER response says
801 *        SATA DEVICE ATTACHED and has a valid NPL value, we call fw_device's
802 *        start_handler(). But if a DISCOVER response still shows SPINUP
803 *        in NPL state, we need to return retry_required status
804 *
805 * @param[in] fw_device The framework device that the DISCOVER command
806 *       targets to.
807 * @param[in] discover_response The pointer to a DISCOVER response
808 *
809 * @return SCI_SUCCESS
810 *         SCI_FAILURE_RETRY_REQUIRED
811 */
812SCI_STATUS scif_sas_smp_remote_device_decode_spinup_hold_release_discover_response(
813   SCIF_SAS_REMOTE_DEVICE_T * fw_device,
814   SMP_RESPONSE_T           * smp_response
815)
816{
817   SMP_RESPONSE_DISCOVER_T * discover_response = &smp_response->response.discover;
818
819   SMP_RESPONSE_HEADER_T * response_header = &smp_response->header;
820
821   SCIF_LOG_TRACE((
822      sci_base_object_get_logger(fw_device),
823      SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
824      "scif_sas_smp_remote_device_decode_spinup_hold_release_discover_response(0x%x, 0x%x) enter\n",
825      fw_device, smp_response
826   ));
827
828   if (response_header->function_result != SMP_RESULT_FUNCTION_ACCEPTED)
829   {
830      /// @todo: more decoding work needed when the function_result is not
831      /// SMP_RESULT_FUNCTION_ACCEPTED. Retry might be the option for some
832      /// function result.
833      SCIF_LOG_ERROR((
834         sci_base_object_get_logger(fw_device),
835         SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
836         "Discover function result(0x%x)\n",
837         response_header->function_result
838      ));
839
840      return SCI_FAILURE;
841   }
842
843   if ( discover_response->u2.sas1_1.attached_device_type != SMP_NO_DEVICE_ATTACHED )
844   {
845      if (discover_response->u2.sas1_1.negotiated_physical_link_rate != SCI_SATA_SPINUP_HOLD
846          && discover_response->u4.sas2.negotiated_physical_link_rate != SCI_SATA_SPINUP_HOLD
847          && ( discover_response->protocols.u.bits.attached_stp_target
848             ||discover_response->protocols.u.bits.attached_sata_device )
849         )
850      {
851         SCIF_SAS_REMOTE_DEVICE_T * target_device =
852            scif_sas_domain_get_device_by_containing_device(
853               fw_device->domain,
854               fw_device,
855               fw_device->protocol_device.smp_device.current_activity_phy_index
856            );
857
858         //Need to update the device's connection rate. Its connection rate was SPINIP_HOLD.
859         scic_remote_device_set_max_connection_rate(
860            target_device->core_object,
861            discover_response->u2.sas1_1.negotiated_physical_link_rate
862         );
863
864         //Need to update the smp phy info too.
865         scif_sas_smp_remote_device_save_smp_phy_info(
866             fw_device, discover_response);
867
868         //This device has already constructed, only need to call start_handler
869         //of this device here.
870         return target_device->state_handlers->parent.start_handler(
871                   &target_device->parent );
872      }
873      else
874         return SCI_FAILURE_RETRY_REQUIRED;
875   }
876   else
877      return SCI_FAILURE_RETRY_REQUIRED;
878}
879
880
881/**
882 * @brief This method decodes a smp CONFIG ROUTE INFO response to this smp
883 *        device and then continue to config route table.
884 *
885 * @param[in] fw_device The framework device that the CONFIG ROUTE INFO command
886 *       targets to.
887 * @param[in] smp_response The pointer to a CONFIG ROUTE INFO response
888 *
889 * @return none
890 */
891SCI_STATUS scif_sas_smp_remote_device_decode_config_route_info_response(
892   SCIF_SAS_REMOTE_DEVICE_T * fw_device,
893   SMP_RESPONSE_T           * smp_response
894)
895{
896   SMP_RESPONSE_HEADER_T * response_header = &smp_response->header;
897
898   SCIF_LOG_TRACE((
899      sci_base_object_get_logger(fw_device),
900      SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
901      "scif_sas_smp_remote_device_decode_config_route_info_response(0x%x, 0x%x) enter\n",
902      fw_device, smp_response
903   ));
904
905   if (response_header->function_result == SMP_RESULT_INDEX_DOES_NOT_EXIST)
906   {
907      //case of exceeding max route index. We need to remove the devices that are not
908      //able to be edit to route table. The destination config route smp phy
909      //is used to remove devices.
910      scif_sas_smp_remote_device_cancel_config_route_table_activity(fw_device);
911
912      return SCI_FAILURE_EXCEED_MAX_ROUTE_INDEX;
913   }
914   else if (response_header->function_result != SMP_RESULT_FUNCTION_ACCEPTED)
915   {
916      /// @todo: more decoding work needed when the function_result is not
917      /// SMP_RESULT_FUNCTION_ACCEPTED. Retry might be the option for some
918      /// function result.
919      SCIF_LOG_ERROR((
920         sci_base_object_get_logger(fw_device),
921         SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
922         "Discover function result(0x%x)\n",
923         response_header->function_result
924      ));
925
926      return SCI_FAILURE;
927   }
928
929   return SCI_SUCCESS;
930}
931
932
933/**
934 * @brief This method starts the smp Discover process for an expander by
935 *        sending Report General request.
936 *
937 * @param[in] fw_device The framework smp device that a  command
938 *       targets to.
939 *
940 * @return none
941 */
942void scif_sas_smp_remote_device_start_discover(
943   SCIF_SAS_REMOTE_DEVICE_T * fw_device
944)
945{
946   SCIF_SAS_CONTROLLER_T * fw_controller = fw_device->domain->controller;
947
948   SCIF_LOG_TRACE((
949      sci_base_object_get_logger(fw_device),
950      SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
951      "scif_sas_smp_remote_device_start_discover(0x%x) enter\n",
952      fw_device
953   ));
954
955   //For safety, clear the device again, there may be some config route table
956   //related info are not cleared yet.
957   scif_sas_smp_remote_device_clear(fw_device);
958
959   //set current activity
960   fw_device->protocol_device.smp_device.current_activity =
961      SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_DISCOVER;
962
963   //Set current_smp_request to REPORT GENERAL.
964   fw_device->protocol_device.smp_device.current_smp_request =
965      SMP_FUNCTION_REPORT_GENERAL;
966
967   //reset discover_to_start flag.
968   fw_device->protocol_device.smp_device.scheduled_activity =
969      SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_NONE;
970
971   //build the first smp request Report Genernal.
972   scif_sas_smp_request_construct_report_general(fw_controller, fw_device);
973
974   //issue DPC to start this request.
975   scif_cb_start_internal_io_task_schedule(
976      fw_controller,
977      scif_sas_controller_start_high_priority_io,
978      fw_controller
979   );
980}
981
982
983/**
984 * @brief This method continues the smp Discover process.
985 *
986 * @param[in] fw_device The framework smp device that a DISCOVER command
987 *       targets to.
988 * @param[in] fw_request The pointer to an smp request whose response
989 *       has been decoded.
990 * @param[in] status The decoding status of the smp request's response
991 *
992 * @return none
993 */
994void scif_sas_smp_remote_device_continue_current_activity(
995   SCIF_SAS_REMOTE_DEVICE_T * fw_device,
996   SCIF_SAS_REQUEST_T       * fw_request,
997   SCI_STATUS                 status
998)
999{
1000   SCIF_SAS_IO_REQUEST_T * fw_io = (SCIF_SAS_IO_REQUEST_T *)fw_request;
1001   // save the retry count.
1002   U8 io_retry_count = fw_io->retry_count;
1003
1004   if (fw_request->is_internal)
1005   {
1006      // Complete this internal io request now. We want to free this io before
1007      // we create another SMP request, which is going to happen soon.
1008      scif_sas_internal_io_request_complete(
1009         fw_device->domain->controller,
1010         (SCIF_SAS_INTERNAL_IO_REQUEST_T *)fw_request,
1011         SCI_SUCCESS
1012      );
1013   }
1014
1015   if (fw_device->protocol_device.smp_device.current_activity ==
1016      SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_DISCOVER)
1017   {
1018      if (status == SCI_SUCCESS)
1019      {   //continue the discover process.
1020         scif_sas_smp_remote_device_continue_discover(fw_device);
1021      }
1022      else if (status == SCI_FAILURE_RETRY_REQUIRED)
1023      {
1024         //Retry the smp request. Since we are in the middle of Discover
1025         //process, all the smp requests are internal. A new smp request
1026         //will be created for retry.
1027         U32 retry_wait_duration = (SCIF_DOMAIN_DISCOVER_TIMEOUT / 2) / SCIF_SAS_IO_RETRY_LIMIT;
1028
1029         if (io_retry_count < SCIF_SAS_IO_RETRY_LIMIT)
1030            scif_sas_smp_remote_device_retry_internal_io (
1031               fw_device, io_retry_count, retry_wait_duration);
1032         else
1033            scif_sas_smp_remote_device_fail_discover(fw_device);
1034      }
1035      else if (status == SCI_FAILURE_ILLEGAL_ROUTING_ATTRIBUTE_CONFIGURATION)
1036      {
1037         //remove this expander device and its child devices. No need to
1038         //continue the discover on this device.
1039         scif_sas_domain_remove_expander_device(fw_device->domain, fw_device);
1040
1041         //continue the domain's smp discover.
1042         scif_sas_domain_continue_discover(fw_device->domain);
1043      }
1044      else
1045      {  //terminate the discover process.
1046         scif_sas_smp_remote_device_fail_discover(fw_device);
1047      }
1048   }
1049   else if (fw_device->protocol_device.smp_device.current_activity ==
1050      SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_TARGET_RESET)
1051   {
1052      if (status == SCI_SUCCESS)
1053      {   //continue the target reset process.
1054         scif_sas_smp_remote_device_continue_target_reset(
1055            fw_device, fw_request);
1056      }
1057      else if (status == SCI_FAILURE_RETRY_REQUIRED)
1058      {
1059         //Retry the same smp request. Since we are in the middle of Target
1060         //reset process, all the smp requests are using external resource.
1061         //We will use the exactly same memory to retry.
1062         if (io_retry_count < SCIF_SAS_IO_RETRY_LIMIT)
1063         {
1064            if (fw_device->protocol_device.smp_device.smp_activity_timer == NULL)
1065            {
1066               //create the timer to wait before retry.
1067               fw_device->protocol_device.smp_device.smp_activity_timer =
1068                  scif_cb_timer_create(
1069                  (SCI_CONTROLLER_HANDLE_T *)fw_device->domain->controller,
1070                  (SCI_TIMER_CALLBACK_T)scif_sas_smp_external_request_retry,
1071                  (void*)fw_request
1072               );
1073            }
1074            else
1075            {
1076               ASSERT(0);
1077            }
1078
1079            //start the timer to wait
1080            scif_cb_timer_start(
1081               (SCI_CONTROLLER_HANDLE_T)fw_device->domain->controller,
1082               fw_device->protocol_device.smp_device.smp_activity_timer,
1083               SMP_REQUEST_RETRY_WAIT_DURATION  //20 miliseconds
1084            );
1085         }
1086         else
1087            scif_sas_smp_remote_device_fail_target_reset(fw_device, fw_request);
1088      }
1089      else
1090         //terminate the discover process.
1091         scif_sas_smp_remote_device_fail_target_reset(fw_device, fw_request);
1092   }
1093   else if (fw_device->protocol_device.smp_device.current_activity ==
1094      SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_SATA_SPINUP_HOLD_RELEASE)
1095   {
1096      SCIF_SAS_REMOTE_DEVICE_T * target_device =
1097         scif_sas_domain_get_device_by_containing_device(
1098            fw_device->domain,
1099            fw_device,
1100            fw_device->protocol_device.smp_device.current_activity_phy_index
1101         );
1102
1103      if (status == SCI_SUCCESS)
1104      {
1105         //move on to next round of SPINUP_HOLD_REALSE activity.
1106         scif_sas_smp_remote_device_sata_spinup_hold_release(fw_device);
1107      }
1108      else if (status == SCI_FAILURE_RETRY_REQUIRED)
1109      {
1110         U32 delay =
1111            (scic_remote_device_get_suggested_reset_timeout(target_device->core_object) /
1112                SCIF_SAS_IO_RETRY_LIMIT);
1113
1114         //Retry the smp request. Since we are in the middle of Discover
1115         //process, all the smp requests are internal. A new smp request
1116         //will be created for retry.
1117         if (io_retry_count < SCIF_SAS_IO_RETRY_LIMIT)
1118         {
1119            scif_sas_smp_remote_device_retry_internal_io(
1120               fw_device, io_retry_count, delay);
1121         }
1122         else //give up on this target device.
1123         {
1124            scif_sas_smp_remote_device_fail_target_spinup_hold_release(
1125               fw_device , target_device);
1126         }
1127      }
1128      else //give up on this target device.
1129        scif_sas_smp_remote_device_fail_target_spinup_hold_release(
1130           fw_device, target_device);
1131   }
1132   else if (fw_device->protocol_device.smp_device.current_activity ==
1133      SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_CONFIG_ROUTE_TABLE)
1134   {
1135      SCI_FAST_LIST_ELEMENT_T * next_phy_element = sci_fast_list_get_next(
1136         &(fw_device->protocol_device.smp_device.curr_config_route_destination_smp_phy->list_element) );
1137
1138      SCI_FAST_LIST_T * destination_smp_phy_list =
1139          fw_device->protocol_device.smp_device.curr_config_route_destination_smp_phy->list_element.owning_list;
1140
1141      SCIF_SAS_SMP_PHY_T * next_phy_in_wide_port = NULL;
1142
1143      if (next_phy_element != NULL
1144          && status != SCI_FAILURE_EXCEED_MAX_ROUTE_INDEX)
1145      {
1146         fw_device->protocol_device.smp_device.curr_config_route_index++;
1147
1148         fw_device->protocol_device.smp_device.curr_config_route_destination_smp_phy =
1149            (SCIF_SAS_SMP_PHY_T *)sci_fast_list_get_object(next_phy_element);
1150
1151         // Update the anchor for config route index.
1152         fw_device->protocol_device.smp_device.config_route_smp_phy_anchor->config_route_table_index_anchor =
1153            fw_device->protocol_device.smp_device.curr_config_route_index;
1154
1155         scif_sas_smp_remote_device_configure_route_table(fw_device);
1156      }
1157      else if ( scif_sas_smp_remote_device_get_config_route_table_method(fw_device)
1158                   == SCIF_SAS_CONFIG_ROUTE_TABLE_ALL_PHYS
1159                && (next_phy_in_wide_port = scif_sas_smp_phy_find_next_phy_in_wide_port(
1160                       fw_device->protocol_device.smp_device.config_route_smp_phy_anchor)
1161                   )!= NULL
1162              )
1163      {
1164         //config the other phy in the same wide port
1165         fw_device->protocol_device.smp_device.config_route_smp_phy_anchor =
1166            next_phy_in_wide_port;
1167
1168         fw_device->protocol_device.smp_device.current_activity_phy_index =
1169            fw_device->protocol_device.smp_device.config_route_smp_phy_anchor->phy_identifier;
1170
1171         fw_device->protocol_device.smp_device.curr_config_route_destination_smp_phy =
1172            sci_fast_list_get_head(destination_smp_phy_list);
1173
1174         if (fw_device->protocol_device.smp_device.config_route_smp_phy_anchor->config_route_table_index_anchor != 0)
1175            fw_device->protocol_device.smp_device.curr_config_route_index =
1176               fw_device->protocol_device.smp_device.config_route_smp_phy_anchor->config_route_table_index_anchor + 1;
1177         else
1178            fw_device->protocol_device.smp_device.curr_config_route_index = 0;
1179
1180         scif_sas_smp_remote_device_configure_route_table(fw_device);
1181      }
1182      else if ( fw_device->protocol_device.smp_device.is_route_table_cleaned == FALSE)
1183      {
1184         fw_device->protocol_device.smp_device.current_activity =
1185            SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_CLEAN_ROUTE_TABLE;
1186
1187         scif_sas_smp_remote_device_clean_route_table(fw_device);
1188      }
1189      else
1190      {
1191         //set this device's activity to NON.
1192         fw_device->protocol_device.smp_device.current_activity =
1193            SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_NONE;
1194
1195         //we need to notify domain that this device finished config route table, domain
1196         //may pick up other activities (i.e. Discover) for other expanders.
1197         scif_sas_domain_continue_discover(fw_device->domain);
1198      }
1199   }
1200   else if (fw_device->protocol_device.smp_device.current_activity ==
1201               SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_CLEAN_ROUTE_TABLE)
1202   {
1203      scif_sas_smp_remote_device_clean_route_table(fw_device);
1204   }
1205   else if (fw_device->protocol_device.smp_device.current_activity ==
1206               SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_CLEAR_AFFILIATION)
1207   {
1208      scif_sas_smp_remote_device_continue_clear_affiliation(fw_device);
1209   }
1210}
1211
1212
1213/**
1214 * @brief This method continues the smp Discover process.
1215 *
1216 * @param[in] fw_device The framework smp device that a DISCOVER command
1217 *       targets to.
1218 *
1219 * @return none
1220 */
1221void scif_sas_smp_remote_device_continue_discover(
1222   SCIF_SAS_REMOTE_DEVICE_T * fw_device
1223)
1224{
1225   SCIF_SAS_DOMAIN_T * fw_domain = fw_device->domain;
1226
1227   SCIF_LOG_TRACE((
1228      sci_base_object_get_logger(fw_device),
1229      SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
1230      "scif_sas_smp_remote_device_continue_discover(0x%x) enter\n",
1231      fw_device
1232   ));
1233
1234   switch (fw_device->protocol_device.smp_device.current_smp_request)
1235   {
1236      case SMP_FUNCTION_REPORT_GENERAL:
1237         // send the REPORT MANUFACTURER_INFO request
1238         fw_device->protocol_device.smp_device.current_smp_request =
1239            SMP_FUNCTION_REPORT_MANUFACTURER_INFORMATION;
1240
1241         scif_sas_smp_request_construct_report_manufacturer_info(
1242            fw_domain->controller, fw_device
1243         );
1244
1245         break;
1246
1247      case SMP_FUNCTION_REPORT_MANUFACTURER_INFORMATION:
1248         //send the first SMP DISCOVER request.
1249         fw_device->protocol_device.smp_device.current_activity_phy_index = 0;
1250         fw_device->protocol_device.smp_device.current_smp_request =
1251            SMP_FUNCTION_DISCOVER;
1252
1253         scif_sas_smp_request_construct_discover(
1254            fw_domain->controller,
1255            fw_device,
1256            fw_device->protocol_device.smp_device.current_activity_phy_index,
1257            NULL, NULL
1258         );
1259         break;
1260
1261
1262      case SMP_FUNCTION_DISCOVER:
1263         fw_device->protocol_device.smp_device.current_activity_phy_index++;
1264
1265         if ( (fw_device->protocol_device.smp_device.current_activity_phy_index <
1266                  fw_device->protocol_device.smp_device.number_of_phys) )
1267         {
1268            scif_sas_smp_request_construct_discover(
1269               fw_domain->controller,
1270               fw_device,
1271               fw_device->protocol_device.smp_device.current_activity_phy_index,
1272               NULL, NULL
1273            );
1274         }
1275         else
1276            scif_sas_smp_remote_device_finish_initial_discover(fw_device);
1277         break;
1278
1279
1280      case SMP_FUNCTION_REPORT_PHY_SATA:
1281         scif_sas_smp_request_construct_report_phy_sata(
1282            fw_device->domain->controller,
1283            fw_device,
1284            fw_device->protocol_device.smp_device.current_activity_phy_index
1285         );
1286
1287         break;
1288
1289
1290      case SMP_FUNCTION_PHY_CONTROL:
1291         scif_sas_smp_request_construct_phy_control(
1292            fw_device->domain->controller,
1293            fw_device,
1294            PHY_OPERATION_HARD_RESET,
1295            fw_device->protocol_device.smp_device.current_activity_phy_index,
1296            NULL,
1297            NULL
1298         );
1299
1300         break;
1301
1302      default:
1303         break;
1304   }
1305}
1306
1307/**
1308 * @brief This method finishes the initial smp DISCOVER process. There
1309 *        may be a spinup_hold release phase following of initial discover,
1310 *        depending on whether there are SATA device in the domain
1311 *        in SATA_SPINUP_HOLD condition.
1312 *
1313 * @param[in] fw_device The framework smp device that finishes all the
1314 *       DISCOVER requests.
1315 *
1316 * @return none
1317 */
1318void scif_sas_smp_remote_device_finish_initial_discover(
1319   SCIF_SAS_REMOTE_DEVICE_T * fw_device
1320)
1321{
1322   SCIF_SAS_REMOTE_DEVICE_T * device_in_sata_spinup_hold =
1323      scif_sas_domain_find_device_in_spinup_hold(fw_device->domain);
1324
1325   SCIF_LOG_TRACE((
1326      sci_base_object_get_logger(fw_device),
1327      SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
1328      "scif_sas_smp_remote_device_finish_initial_discover(0x%x) enter\n",
1329      fw_device
1330   ));
1331
1332   if ( device_in_sata_spinup_hold != NULL )
1333   {
1334     //call the common private routine to reset all fields of this smp device.
1335     scif_sas_smp_remote_device_clear(fw_device);
1336
1337     //Move on to next activity SPINUP_HOLD_RELEASE
1338     fw_device->protocol_device.smp_device.current_activity =
1339        SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_SATA_SPINUP_HOLD_RELEASE;
1340
1341      //create the timer to delay a little bit before going to
1342      //sata spinup hold release activity.
1343      if (fw_device->protocol_device.smp_device.smp_activity_timer == NULL)
1344      {
1345      fw_device->protocol_device.smp_device.smp_activity_timer =
1346         scif_cb_timer_create(
1347            (SCI_CONTROLLER_HANDLE_T *)fw_device->domain->controller,
1348            (SCI_TIMER_CALLBACK_T)scif_sas_smp_remote_device_sata_spinup_hold_release,
1349            (void*)fw_device
1350         );
1351      }
1352      else
1353      {
1354         ASSERT (0);
1355      }
1356
1357      scif_cb_timer_start(
1358         (SCI_CONTROLLER_HANDLE_T)fw_device->domain->controller,
1359         fw_device->protocol_device.smp_device.smp_activity_timer,
1360         SMP_SPINUP_HOLD_RELEASE_WAIT_DURATION
1361      );
1362   }
1363   else
1364      scif_sas_smp_remote_device_finish_discover(fw_device);
1365}
1366
1367
1368/**
1369 * @brief This method finishes the smp DISCOVER process.
1370 *
1371 * @param[in] fw_device The framework smp device that finishes all the
1372 *       DISCOVER requests.
1373 *
1374 * @return none
1375 */
1376void scif_sas_smp_remote_device_finish_discover(
1377   SCIF_SAS_REMOTE_DEVICE_T * fw_device
1378)
1379{
1380   SCIF_SAS_DOMAIN_T * fw_domain = fw_device->domain;
1381
1382   SCIF_LOG_TRACE((
1383      sci_base_object_get_logger(fw_device),
1384      SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
1385      "scif_sas_smp_remote_device_finish_discover(0x%x) enter\n",
1386      fw_device
1387   ));
1388
1389   if ( fw_domain->is_config_route_table_needed
1390       && fw_device->protocol_device.smp_device.smp_phy_list.list_head != NULL)
1391      scif_sas_smp_remote_device_configure_upstream_expander_route_info(fw_device);
1392
1393   //call the common private routine to reset all fields of this smp device.
1394   scif_sas_smp_remote_device_clear(fw_device);
1395
1396#ifdef SCI_SMP_PHY_LIST_DEBUG_PRINT
1397   scif_sas_smp_remote_device_print_smp_phy_list(fw_device);
1398#endif
1399
1400   //notify domain this smp device's discover finishes, it's up to domain
1401   //to continue the discover process in a bigger scope.
1402   scif_sas_domain_continue_discover(fw_domain);
1403}
1404
1405
1406/**
1407 * @brief This method continues the smp Target Reset (Phy Control) process.
1408 *
1409 * @param[in] fw_device The framework smp device that a smp reset targets to.
1410 *
1411 * @return none
1412 */
1413void scif_sas_smp_remote_device_continue_target_reset(
1414   SCIF_SAS_REMOTE_DEVICE_T * fw_device,
1415   SCIF_SAS_REQUEST_T       * fw_request
1416)
1417{
1418   SCIF_SAS_CONTROLLER_T * fw_controller = fw_device->domain->controller;
1419   SCIF_SAS_REMOTE_DEVICE_T * target_device =
1420      scif_sas_domain_get_device_by_containing_device(
1421         fw_device->domain,
1422         fw_device,
1423         fw_device->protocol_device.smp_device.current_activity_phy_index
1424      );
1425
1426   SCIF_LOG_TRACE((
1427      sci_base_object_get_logger(fw_device),
1428      SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
1429      "scif_sas_smp_remote_device_continue_target_reset(0x%x, 0x%x) enter\n",
1430      fw_device, fw_request
1431   ));
1432
1433   if (fw_device->protocol_device.smp_device.current_smp_request ==
1434          SMP_FUNCTION_PHY_CONTROL)
1435   {
1436      //query the core remote device to get suggested reset timeout value
1437      //then scale down by factor of 8 to get the duration of the pause
1438      //before sending out Discover command to poll.
1439      U32 delay =
1440         (scic_remote_device_get_suggested_reset_timeout(target_device->core_object)/8);
1441
1442      //create the timer to send Discover command polling target device's
1443      //coming back.
1444      if (fw_device->protocol_device.smp_device.smp_activity_timer == NULL)
1445      {
1446         fw_device->protocol_device.smp_device.smp_activity_timer =
1447            scif_cb_timer_create(
1448               (SCI_CONTROLLER_HANDLE_T *)fw_controller,
1449               (SCI_TIMER_CALLBACK_T)scif_sas_smp_remote_device_target_reset_poll,
1450               (void*)fw_request
1451            );
1452      }
1453      else
1454      {
1455         ASSERT(0);
1456      }
1457
1458      //start the timer
1459      scif_cb_timer_start(
1460         (SCI_CONTROLLER_HANDLE_T)fw_controller,
1461         fw_device->protocol_device.smp_device.smp_activity_timer,
1462         delay
1463      );
1464   }
1465   else if (fw_device->protocol_device.smp_device.current_smp_request ==
1466          SMP_FUNCTION_DISCOVER)
1467   {
1468      //tell target reset successful
1469      scif_sas_remote_device_target_reset_complete(
1470         target_device, fw_request, SCI_SUCCESS);
1471   }
1472}
1473
1474/**
1475 * @brief This routine is invoked by timer or when 2 BCN are received
1476 *        after Phy Control command. This routine will construct a
1477 *        Discover command to the same expander phy to poll the target
1478 *        device's coming back. This new request is then put into
1479 *        high priority queue and will be started by a DPC soon.
1480 *
1481 * @param[in] fw_request The scif request for smp activities.
1482 */
1483void scif_sas_smp_remote_device_target_reset_poll(
1484   SCIF_SAS_REQUEST_T       * fw_request
1485)
1486{
1487   SCIF_SAS_REMOTE_DEVICE_T * fw_device = fw_request->device;
1488   SCIF_SAS_CONTROLLER_T * fw_controller = fw_device->domain->controller;
1489   void * new_command_handle;
1490
1491   SCIF_LOG_TRACE((
1492      sci_base_object_get_logger(fw_device),
1493      SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
1494      "scif_sas_smp_remote_device_target_reset_poll(0x%x) enter\n",
1495      fw_request
1496   ));
1497
1498   // Before we construct new io using the same memory, we need to
1499   // remove the IO from the list of outstanding requests on the domain
1500   // so that we don't damage the domain's fast list of request.
1501   sci_fast_list_remove_element(&fw_request->list_element);
1502
1503   fw_device->protocol_device.smp_device.current_smp_request =
1504      SMP_FUNCTION_DISCOVER;
1505
1506   //sent smp discover request to poll on remote device's coming back.
1507   //construct Discover command using the same memory as fw_request.
1508   new_command_handle = scif_sas_smp_request_construct_discover(
1509      fw_device->domain->controller,
1510      fw_device,
1511      fw_device->protocol_device.smp_device.current_activity_phy_index,
1512      (void *)sci_object_get_association(fw_request),
1513      (void *)fw_request
1514   );
1515
1516   //put into the high priority queue.
1517   sci_pool_put(fw_controller->hprq.pool, (POINTER_UINT) new_command_handle);
1518
1519   //schedule the DPC to start new Discover command.
1520   scif_cb_start_internal_io_task_schedule(
1521      fw_controller, scif_sas_controller_start_high_priority_io, fw_controller
1522   );
1523}
1524
1525
1526/**
1527 * @brief This method fails discover process.
1528 *
1529 * @param[in] fw_device The framework smp device that failed at current
1530 *       activity.
1531 *
1532 * @return none
1533 */
1534void scif_sas_smp_remote_device_fail_discover(
1535   SCIF_SAS_REMOTE_DEVICE_T * fw_device
1536)
1537{
1538   SCIF_LOG_TRACE((
1539      sci_base_object_get_logger(fw_device),
1540      SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
1541      "scif_sas_smp_remote_device_fail_discover(0x%x) enter\n",
1542      fw_device
1543   ));
1544
1545   switch (fw_device->protocol_device.smp_device.current_smp_request)
1546   {
1547      case SMP_FUNCTION_REPORT_GENERAL:
1548      case SMP_FUNCTION_REPORT_MANUFACTURER_INFORMATION:
1549         scif_sas_smp_remote_device_finish_discover(fw_device);
1550         break;
1551
1552      case SMP_FUNCTION_DISCOVER:
1553      case SMP_FUNCTION_REPORT_PHY_SATA:
1554         //Retry limit reached, we will continue to send DISCOVER to next phy.
1555         fw_device->protocol_device.smp_device.current_smp_request =
1556            SMP_FUNCTION_DISCOVER;
1557
1558         scif_sas_smp_remote_device_continue_discover(fw_device);
1559         break;
1560
1561      default:
1562         break;
1563   }
1564}
1565
1566
1567/**
1568 * @brief This method fails Target Reset.
1569 *
1570 * @param[in] fw_device The framework smp device that failed at current
1571 *       activity.
1572 * @param[in] fw_request The smp request created for target reset
1573 *       using external resource.
1574 *
1575 * @return none
1576 */
1577void scif_sas_smp_remote_device_fail_target_reset(
1578   SCIF_SAS_REMOTE_DEVICE_T * fw_device,
1579   SCIF_SAS_REQUEST_T       * fw_request
1580)
1581{
1582   SCIF_SAS_REMOTE_DEVICE_T * target_device =
1583      scif_sas_domain_get_device_by_containing_device(
1584         fw_device->domain,
1585         fw_device,
1586         fw_device->protocol_device.smp_device.current_activity_phy_index
1587      );
1588
1589   SCIF_LOG_TRACE((
1590      sci_base_object_get_logger(fw_device),
1591      SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
1592      "scif_sas_smp_remote_device_fail_target_reset(0x%x, 0x%x, 0x%x) enter\n",
1593      fw_device, target_device, fw_request
1594   ));
1595
1596   //tell target reset failed
1597   scif_sas_remote_device_target_reset_complete(
1598      target_device, fw_request, SCI_FAILURE);
1599}
1600
1601/**
1602 * @brief This method init or continue the SATA SPINUP_HOLD RELEASE activity.
1603 * This function searches domain's device list, find a device in STOPPED STATE
1604 * and its connection_rate is SPINIP, then send DISCOVER command to its expander
1605 * phy id to poll. But if searching the domain's device list for SATA devices on
1606 * SPINUP_HOLD finds no device, the activity SPINUP_HOLD_RELEASE is finished.
1607 * We then call fw_domain->device_start_complete_handler() for this smp-device.
1608 *
1609 * @param[in] fw_device The framework smp device that is on SATA SPINUP_HOLD_RELEASE
1610 *       activity.
1611 *
1612 * @return none
1613 */
1614void scif_sas_smp_remote_device_sata_spinup_hold_release(
1615   SCIF_SAS_REMOTE_DEVICE_T * fw_device
1616)
1617{
1618   SCIF_SAS_DOMAIN_T        * fw_domain = fw_device->domain;
1619   SCIF_SAS_CONTROLLER_T    * fw_controller = fw_domain->controller;
1620   SCIF_SAS_REMOTE_DEVICE_T * device_to_poll = NULL;
1621
1622   SCIF_LOG_TRACE((
1623      sci_base_object_get_logger(fw_device),
1624      SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
1625      "scif_sas_smp_remote_device_sata_spinup_hold_release(0x%x) enter\n",
1626      fw_device
1627   ));
1628
1629   //search throught domain's device list to find a sata device on spinup_hold
1630   //state to poll.
1631   device_to_poll = scif_sas_domain_find_device_in_spinup_hold(fw_domain);
1632
1633   if (device_to_poll != NULL)
1634   {
1635      //send DISCOVER command to this device's expaner phy.
1636      fw_device->protocol_device.smp_device.current_smp_request =
1637         SMP_FUNCTION_DISCOVER;
1638
1639      fw_device->protocol_device.smp_device.current_activity_phy_index =
1640        device_to_poll->expander_phy_identifier;
1641
1642      scif_sas_smp_request_construct_discover(
1643         fw_domain->controller,
1644         fw_device,
1645         fw_device->protocol_device.smp_device.current_activity_phy_index,
1646         NULL, NULL
1647      );
1648
1649      //schedule the DPC to start new Discover command.
1650      scif_cb_start_internal_io_task_schedule(
1651         fw_controller, scif_sas_controller_start_high_priority_io, fw_controller
1652      );
1653   }
1654   else //SATA SPINUP HOLD RELEASE activity is done.
1655      scif_sas_smp_remote_device_finish_discover (fw_device);
1656}
1657
1658
1659/**
1660 * @brief This method fail an action of SATA SPINUP_HOLD RELEASE on a single EA
1661 *        SATA device. It will remove a remote_device object for a sata device
1662 *        that fails to come out of spinup_hold.
1663 *
1664 * @param[in] fw_device The framework smp device that is on SATA SPINUP_HOLD_RELEASE
1665 *       activity.
1666 * @param[in] target_device The expander attached device failed being brought out
1667 *       of SPINUP_HOLD state.
1668 *
1669 * @return none
1670 */
1671void scif_sas_smp_remote_device_fail_target_spinup_hold_release(
1672   SCIF_SAS_REMOTE_DEVICE_T * fw_device,
1673   SCIF_SAS_REMOTE_DEVICE_T * target_device
1674)
1675{
1676   SCIF_SAS_DOMAIN_T * fw_domain = fw_device->domain;
1677
1678   SCIF_LOG_TRACE((
1679      sci_base_object_get_logger(fw_device),
1680      SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
1681      "scif_sas_smp_remote_device_fail_target_spinup_hold_release(0x%x, 0x%x) enter\n",
1682      fw_device, target_device
1683   ));
1684
1685   //need to remove the device, since we have to give up on spinup_hold_release
1686   //activity on this device.
1687   scif_cb_domain_device_removed(
1688      fw_domain->controller, fw_domain, target_device
1689   );
1690
1691   //move on to next round of SPINUP_HOLD_REALSE activity.
1692   scif_sas_smp_remote_device_sata_spinup_hold_release(fw_device);
1693}
1694
1695
1696/**
1697 * @brief This method retry only internal IO for the smp device.
1698 *
1699 * @param[in] fw_device The framework smp device that has an smp request to retry.
1700 * @param[in] io_retry_count current count for times the IO being retried.
1701 * @param[in] delay The time delay before the io gets retried.
1702 *
1703 * @return none
1704 */
1705void scif_sas_smp_remote_device_retry_internal_io(
1706   SCIF_SAS_REMOTE_DEVICE_T * fw_device,
1707   U8                         io_retry_count,
1708   U32                        delay
1709)
1710{
1711   SCIF_LOG_TRACE((
1712      sci_base_object_get_logger(fw_device),
1713      SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
1714      "scif_sas_smp_remote_device_retry_internal_io(0x%x, 0x%x, 0x%x) enter\n",
1715      fw_device, io_retry_count, delay
1716   ));
1717
1718   fw_device->protocol_device.smp_device.io_retry_count =
1719      io_retry_count;
1720
1721   //create the timer for poll target device's coming back.
1722   if (fw_device->protocol_device.smp_device.smp_activity_timer == NULL)
1723   {
1724      fw_device->protocol_device.smp_device.smp_activity_timer =
1725         scif_cb_timer_create(
1726            (SCI_CONTROLLER_HANDLE_T *)fw_device->domain->controller,
1727            (SCI_TIMER_CALLBACK_T)scif_sas_smp_internal_request_retry,
1728            (void*)fw_device
1729         );
1730   }
1731   else
1732   {
1733      ASSERT(0);
1734   }
1735   //start the timer for a purpose of waiting.
1736   scif_cb_timer_start(
1737      (SCI_CONTROLLER_HANDLE_T)fw_device->domain->controller,
1738      fw_device->protocol_device.smp_device.smp_activity_timer,
1739      delay
1740   );
1741}
1742
1743
1744/**
1745 * @brief This method indicates whether an expander device is in Discover
1746 *        process.
1747 *
1748 * @param[in] fw_device The framework smp device.
1749 *
1750 * @return Whether an expander device is in the middle of discovery process.
1751 */
1752BOOL scif_sas_smp_remote_device_is_in_activity(
1753   SCIF_SAS_REMOTE_DEVICE_T * fw_device
1754)
1755{
1756   return(fw_device->protocol_device.smp_device.current_activity
1757          != SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_NONE);
1758}
1759
1760/**
1761 * @brief This method search through the smp phy list of an expander to
1762 *        find a smp phy by its phy id of the expander.
1763 *
1764 * @param[in] phy_identifier The search criteria.
1765 * @param[in] smp_remote_device The expander that owns the smp phy list.
1766 *
1767 * @return The found smp phy or a NULL pointer to indicate no smp phy is found.
1768 */
1769SCIF_SAS_SMP_PHY_T * scif_sas_smp_remote_device_find_smp_phy_by_id(
1770   U8                             phy_identifier,
1771   SCIF_SAS_SMP_REMOTE_DEVICE_T * smp_remote_device
1772)
1773{
1774   SCI_FAST_LIST_ELEMENT_T  * element = smp_remote_device->smp_phy_list.list_head;
1775   SCIF_SAS_SMP_PHY_T * curr_smp_phy = NULL;
1776
1777   while (element != NULL)
1778   {
1779      curr_smp_phy = (SCIF_SAS_SMP_PHY_T*) sci_fast_list_get_object(element);
1780      element = sci_fast_list_get_next(element);
1781
1782      if (curr_smp_phy->phy_identifier == phy_identifier)
1783         return curr_smp_phy;
1784   }
1785
1786   return NULL;
1787}
1788
1789/**
1790 * @brief This method takes care of removing smp phy list of a smp devcie, which is
1791 *           about to be removed.
1792 *
1793 * @param[in] fw_device The expander device that is about to be removed.
1794 *
1795 * @return none.
1796 */
1797void scif_sas_smp_remote_device_removed(
1798   SCIF_SAS_REMOTE_DEVICE_T * this_device
1799)
1800{
1801   SCIF_SAS_SMP_REMOTE_DEVICE_T * smp_remote_device =
1802      &this_device->protocol_device.smp_device;
1803
1804   SCI_FAST_LIST_ELEMENT_T  * element = smp_remote_device->smp_phy_list.list_head;
1805   SCIF_SAS_SMP_PHY_T * curr_smp_phy = NULL;
1806
1807   SCIF_LOG_TRACE((
1808      sci_base_object_get_logger(this_device),
1809      SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
1810      "scif_sas_smp_remote_device_removed(0x%x) enter\n",
1811      this_device
1812   ));
1813
1814   //remove all the smp phys in this device's smp_phy_list, and the conterpart smp phys
1815   //in phy connections.
1816   while (element != NULL)
1817   {
1818      curr_smp_phy = (SCIF_SAS_SMP_PHY_T*) sci_fast_list_get_object(element);
1819      element = sci_fast_list_get_next(element);
1820
1821      scif_sas_smp_phy_destruct(curr_smp_phy);
1822   }
1823
1824   this_device->protocol_device.smp_device.number_of_phys = 0;
1825   this_device->protocol_device.smp_device.expander_route_indexes = 0;
1826   this_device->protocol_device.smp_device.is_table_to_table_supported = FALSE;
1827   this_device->protocol_device.smp_device.is_externally_configurable  = FALSE;
1828   this_device->protocol_device.smp_device.is_able_to_config_others    = FALSE;
1829
1830   scif_sas_smp_remote_device_clear(this_device);
1831}
1832
1833
1834/**
1835 * @brief This method takes care of terminated smp request to a smp device. The
1836 *        terminated smp request is most likely timeout and being aborted. A timeout
1837 *        maybe due to OPEN REJECT (NO DESTINATION).
1838 *
1839 * @param[in] fw_device The expander device that a timed out smp request towards to.
1840 * @param[in] fw_request A failed smp request that is terminated by scic.
1841 *
1842 * @return none.
1843 */
1844void scif_sas_smp_remote_device_terminated_request_handler(
1845   SCIF_SAS_REMOTE_DEVICE_T * fw_device,
1846   SCIF_SAS_REQUEST_T       * fw_request
1847)
1848{
1849   SCIF_LOG_TRACE((
1850      sci_base_object_get_logger(fw_device),
1851      SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
1852      "scif_sas_smp_remote_device_terminated_request_handler(0x%x, 0x%x) enter\n",
1853      fw_device, fw_request
1854   ));
1855
1856   scif_sas_smp_remote_device_decode_smp_response(
1857      fw_device, fw_request, NULL, SCI_FAILURE_RETRY_REQUIRED
1858   );
1859}
1860
1861
1862/**
1863 * @brief This method allocates and populates the smp phy list of a expander device.
1864 *
1865 * @param[in] fw_device The expander device, whose smp phy list is to be populated after
1866 *                      getting REPORT GENERAL response.
1867 *
1868 * @return none.
1869 */
1870void scif_sas_smp_remote_device_populate_smp_phy_list(
1871   SCIF_SAS_REMOTE_DEVICE_T * fw_device
1872)
1873{
1874   SCIF_SAS_SMP_PHY_T * this_smp_phy = NULL;
1875   U8                   expander_phy_id = 0;
1876
1877   SCIF_LOG_TRACE((
1878      sci_base_object_get_logger(fw_device),
1879      SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
1880      "scif_sas_smp_remote_device_populate_smp_phy_list(0x%x) enter\n",
1881      fw_device
1882   ));
1883
1884   for ( expander_phy_id = 0;
1885         expander_phy_id < fw_device->protocol_device.smp_device.number_of_phys;
1886         expander_phy_id++ )
1887   {
1888      this_smp_phy =
1889         scif_sas_controller_allocate_smp_phy(fw_device->domain->controller);
1890
1891      ASSERT( this_smp_phy != NULL );
1892
1893      if ( this_smp_phy != NULL )
1894         scif_sas_smp_phy_construct(this_smp_phy, fw_device, expander_phy_id);
1895   }
1896}
1897
1898
1899/**
1900 * @brief This method updates a smp phy of a expander device based on DISCOVER response.
1901 *
1902 * @param[in] fw_device The expander device, one of whose smp phys is to be updated.
1903 * @param[in] discover_response The smp DISCOVER response.
1904 *
1905 * @return SCI_STATUS If a smp phy pair between expanders has invalid routing attribute,
1906 *                    return SCI_FAILURE_ILLEGAL_ROUTING_ATTRIBUTE_CONFIGURATION, otherwise,
1907 *                    return SCI_SUCCESS
1908 */
1909SCI_STATUS scif_sas_smp_remote_device_save_smp_phy_info(
1910   SCIF_SAS_REMOTE_DEVICE_T * fw_device,
1911   SMP_RESPONSE_DISCOVER_T  * discover_response
1912)
1913{
1914   SCI_STATUS status = SCI_SUCCESS;
1915   SCIF_SAS_SMP_PHY_T * smp_phy = NULL;
1916   SCIF_SAS_REMOTE_DEVICE_T * attached_device = NULL;
1917
1918    SCIF_LOG_TRACE((
1919      sci_base_object_get_logger(fw_device),
1920      SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
1921      "scif_sas_smp_remote_device_save_smp_phy_info(0x%x, 0x%x) enter\n",
1922      fw_device, discover_response
1923   ));
1924
1925   smp_phy = scif_sas_smp_remote_device_find_smp_phy_by_id(
1926                discover_response->phy_identifier,
1927                &fw_device->protocol_device.smp_device
1928             );
1929
1930   ASSERT( smp_phy != NULL );
1931
1932   //Note, attached_device could be NULL, not all the smp phy have to connected to a device.
1933   attached_device = (SCIF_SAS_REMOTE_DEVICE_T *)
1934      scif_domain_get_device_by_sas_address(
1935         fw_device->domain, &discover_response->attached_sas_address);
1936
1937   if (smp_phy != NULL)
1938   {
1939      scif_sas_smp_phy_save_information(
1940         smp_phy, attached_device, discover_response);
1941   }
1942
1943   //handle the special case of smp phys between expanders.
1944   if ( discover_response->protocols.u.bits.attached_smp_target )
1945   {
1946       //this fw_device is a child expander, just found its parent expander.
1947       //And there is no smp_phy constructed yet, record this phy connection.
1948       if ( attached_device != NULL
1949           && attached_device == fw_device->containing_device )
1950       {
1951          //record the smp phy info, for this phy connects to a upstream smp device.
1952          //the connection of a pair of smp phys are completed.
1953          status = scif_sas_smp_phy_set_attached_phy(
1954                      smp_phy,
1955                      discover_response->attached_phy_identifier,
1956                      attached_device
1957                   );
1958
1959          if (status == SCI_SUCCESS)
1960          {
1961             //check the routing attribute for this phy and its containing device's
1962             //expander_phy_routing_attribute.
1963             if ( scif_sas_smp_phy_verify_routing_attribute(
1964                     smp_phy, smp_phy->u.attached_phy) != SCI_SUCCESS )
1965                return SCI_FAILURE_ILLEGAL_ROUTING_ATTRIBUTE_CONFIGURATION;
1966          }
1967       }
1968    }
1969
1970    return status;
1971}
1972
1973#ifdef SCI_SMP_PHY_LIST_DEBUG_PRINT
1974void scif_sas_smp_remote_device_print_smp_phy_list(
1975   SCIF_SAS_REMOTE_DEVICE_T * fw_device
1976)
1977{
1978   SCIF_SAS_SMP_REMOTE_DEVICE_T * smp_remote_device = &fw_device->protocol_device.smp_device;
1979   SCI_FAST_LIST_ELEMENT_T  * element = smp_remote_device->smp_phy_list.list_head;
1980   SCIF_SAS_SMP_PHY_T * curr_smp_phy = NULL;
1981
1982   SCIF_LOG_ERROR((
1983      sci_base_object_get_logger(fw_device),
1984      SCIF_LOG_OBJECT_REMOTE_DEVICE,
1985      "==========EXPANDER DEVICE (0x%x) smp phy list========== \n",
1986      fw_device
1987   ));
1988
1989   while (element != NULL)
1990   {
1991      curr_smp_phy = (SCIF_SAS_SMP_PHY_T*) sci_fast_list_get_object(element);
1992      element = sci_fast_list_get_next(element);
1993
1994      //print every thing about a smp phy
1995      SCIF_LOG_ERROR((
1996         sci_base_object_get_logger(fw_device),
1997         SCIF_LOG_OBJECT_REMOTE_DEVICE,
1998         "SMP_PHY_%d (0x%x), attached device(0x%x), attached_sas_address(%x%x) attached_device_type(%d), routing_attribute(%d)\n",
1999         curr_smp_phy->phy_identifier, curr_smp_phy,
2000         curr_smp_phy->u.end_device,
2001         curr_smp_phy->attached_sas_address.high, curr_smp_phy->attached_sas_address.low,
2002         curr_smp_phy->attached_device_type,
2003         curr_smp_phy->routing_attribute
2004      ));
2005   }
2006}
2007#endif
2008
2009
2010/**
2011 * @brief This method configure upstream expander(s)' (if there is any) route info.
2012 *
2013 * @param[in] this_device The expander device that is currently in discover process.
2014 *
2015 * @return none.
2016 */
2017void scif_sas_smp_remote_device_configure_upstream_expander_route_info(
2018   SCIF_SAS_REMOTE_DEVICE_T * this_device
2019)
2020{
2021   SCIF_SAS_REMOTE_DEVICE_T * curr_child_expander = this_device;
2022   SCIF_SAS_REMOTE_DEVICE_T * curr_parent_expander =
2023      scif_sas_remote_device_find_upstream_expander(this_device);
2024
2025   SCIF_SAS_REMOTE_DEVICE_T * curr_config_route_info_expander = NULL;
2026
2027   SCIF_LOG_TRACE((
2028      sci_base_object_get_logger(this_device),
2029      SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
2030      "scif_sas_smp_remote_device_configure_upstream_expander_route_info(0x%x) enter\n",
2031      this_device
2032   ));
2033
2034   //traverse back to find root device.
2035   while(curr_parent_expander != NULL )
2036   {
2037      //must set destination_smp_phy outside of find_upstream_expander() using the device
2038      //that is just about to finish the discovery.
2039      curr_parent_expander->protocol_device.smp_device.curr_config_route_destination_smp_phy =
2040         (SCIF_SAS_SMP_PHY_T*)sci_fast_list_get_object(
2041             this_device->protocol_device.smp_device.smp_phy_list.list_head);
2042
2043      curr_child_expander = curr_parent_expander;
2044      curr_parent_expander = scif_sas_remote_device_find_upstream_expander(curr_child_expander);
2045   }
2046
2047   //found the root device: curr_child_expander. configure it and its downstream expander(s) till
2048   //this_device or a self-configuring expander that configures others;
2049   curr_config_route_info_expander = curr_child_expander;
2050
2051   while ( curr_config_route_info_expander != NULL
2052          && curr_config_route_info_expander != this_device
2053          && curr_config_route_info_expander->protocol_device.smp_device.scheduled_activity
2054                == SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_NONE
2055         )
2056   {
2057      if (curr_config_route_info_expander->protocol_device.smp_device.is_externally_configurable)
2058      {
2059         SCIF_SAS_SMP_PHY_T * phy_being_config =
2060            curr_config_route_info_expander->protocol_device.smp_device.config_route_smp_phy_anchor;
2061
2062         curr_config_route_info_expander->protocol_device.smp_device.curr_config_route_index =
2063            phy_being_config->config_route_table_index_anchor;
2064
2065         if (curr_config_route_info_expander->protocol_device.smp_device.curr_config_route_index != 0)
2066            curr_config_route_info_expander->protocol_device.smp_device.curr_config_route_index++;
2067
2068         curr_config_route_info_expander->protocol_device.smp_device.scheduled_activity =
2069            SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_CONFIG_ROUTE_TABLE;
2070
2071         //Find a downstream expander that has curr_config_route_destination_smp_phy.owning device
2072         //same as curr_config_route_info_expander.
2073         curr_config_route_info_expander = scif_sas_remote_device_find_downstream_expander(
2074            curr_config_route_info_expander);
2075      }
2076      else if (curr_config_route_info_expander->protocol_device.smp_device.is_able_to_config_others)
2077      {
2078         //no need to config route table to this expander and its children.
2079         //find its downstream expander and clear the planned config route table activity.
2080         SCIF_SAS_REMOTE_DEVICE_T * curr_downstream_expander =
2081            scif_sas_remote_device_find_downstream_expander(
2082               curr_config_route_info_expander);
2083
2084         scif_sas_smp_remote_device_clear(curr_config_route_info_expander);
2085
2086         while ( curr_downstream_expander != NULL
2087                && curr_downstream_expander != this_device )
2088         {
2089            scif_sas_smp_remote_device_clear(curr_downstream_expander);
2090            curr_downstream_expander =
2091               scif_sas_remote_device_find_downstream_expander(
2092                  curr_config_route_info_expander);
2093         }
2094
2095         break;
2096      }
2097      else
2098      {
2099         // current expander is a self-configuring expander, which is not externally
2100         // configurable, and doesn't config others. we need to simply skip this expander.
2101         curr_config_route_info_expander = scif_sas_remote_device_find_downstream_expander(
2102            curr_config_route_info_expander);
2103      }
2104   }
2105}
2106
2107/**
2108 * @brief This method finds the immediate upstream expander of a given expander device.
2109 *
2110 * @param[in] this_device The given expander device, whose upstream expander is to be found.
2111 *
2112 * @return The immediate upstream expander. Or a NULL pointer if this_device is root already.
2113 */
2114SCIF_SAS_REMOTE_DEVICE_T * scif_sas_remote_device_find_upstream_expander(
2115   SCIF_SAS_REMOTE_DEVICE_T * this_device
2116)
2117{
2118   SCIF_SAS_SMP_REMOTE_DEVICE_T * smp_remote_device =
2119      &this_device->protocol_device.smp_device;
2120
2121   SCIF_SAS_REMOTE_DEVICE_T    * upstream_expander = NULL;
2122
2123   SCI_FAST_LIST_ELEMENT_T     * element = smp_remote_device->smp_phy_list.list_head;
2124   SCIF_SAS_SMP_PHY_T          * curr_smp_phy = NULL;
2125
2126   SCIF_LOG_TRACE((
2127      sci_base_object_get_logger(this_device),
2128      SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
2129      "scif_sas_smp_remote_device_configure_upstream_expander_route_info(0x%x) enter\n",
2130      this_device
2131   ));
2132
2133   while (element != NULL)
2134   {
2135      curr_smp_phy = (SCIF_SAS_SMP_PHY_T*) sci_fast_list_get_object(element);
2136      element = sci_fast_list_get_next(element);
2137
2138      if ( curr_smp_phy->routing_attribute == SUBTRACTIVE_ROUTING_ATTRIBUTE
2139          && ( curr_smp_phy->attached_device_type == SMP_EDGE_EXPANDER_DEVICE
2140              || curr_smp_phy->attached_device_type == SMP_FANOUT_EXPANDER_DEVICE)
2141          && curr_smp_phy->u.attached_phy != NULL
2142          && curr_smp_phy->u.attached_phy->routing_attribute == TABLE_ROUTING_ATTRIBUTE )
2143      {
2144         //set the current_activity and current_config_route_index for that
2145         //upstream expander.
2146         upstream_expander = curr_smp_phy->u.attached_phy->owning_device;
2147
2148         upstream_expander->protocol_device.smp_device.current_smp_request =
2149            SMP_FUNCTION_CONFIGURE_ROUTE_INFORMATION;
2150
2151         //if the upstream_expander's config route table method is config phy0 only or
2152         //config all phys, the current activity phy is found.
2153         upstream_expander->protocol_device.smp_device.config_route_smp_phy_anchor =
2154            scif_sas_smp_remote_device_find_smp_phy_by_id(
2155               curr_smp_phy->u.attached_phy->phy_identifier,
2156               &(curr_smp_phy->u.attached_phy->owning_device->protocol_device.smp_device)
2157            );
2158
2159         //if the upstream_expander's config route table method is config middle phy only
2160         //config highest phy only, the current activity phy needs a update.
2161         if ( scif_sas_smp_remote_device_get_config_route_table_method(upstream_expander)
2162                 == SCIF_SAS_CONFIG_ROUTE_TABLE_MIDDLE_PHY_ONLY )
2163         {
2164            upstream_expander->protocol_device.smp_device.config_route_smp_phy_anchor =
2165               scif_sas_smp_phy_find_middle_phy_in_wide_port (
2166                  upstream_expander->protocol_device.smp_device.config_route_smp_phy_anchor
2167               );
2168         }
2169         else if ( scif_sas_smp_remote_device_get_config_route_table_method(upstream_expander)
2170                      == SCIF_SAS_CONFIG_ROUTE_TABLE_HIGHEST_PHY_ONLY )
2171         {
2172            upstream_expander->protocol_device.smp_device.config_route_smp_phy_anchor =
2173               scif_sas_smp_phy_find_highest_phy_in_wide_port (
2174                  upstream_expander->protocol_device.smp_device.config_route_smp_phy_anchor
2175               );
2176         }
2177
2178         upstream_expander->protocol_device.smp_device.current_activity_phy_index =
2179            upstream_expander->protocol_device.smp_device.config_route_smp_phy_anchor->phy_identifier;
2180
2181         return upstream_expander;
2182      }
2183   }
2184
2185   return NULL;
2186}
2187
2188
2189/**
2190 * @brief This method finds the immediate downstream expander of a given expander device.
2191 *
2192 * @param[in] this_device The given expander device, whose downstream expander is to be found.
2193 *
2194 * @return The immediate downstream expander. Or a NULL pointer if there is none.
2195 */
2196SCIF_SAS_REMOTE_DEVICE_T * scif_sas_remote_device_find_downstream_expander(
2197   SCIF_SAS_REMOTE_DEVICE_T * this_device
2198)
2199{
2200   SCIF_SAS_SMP_REMOTE_DEVICE_T * this_smp_remote_device =
2201      &this_device->protocol_device.smp_device;
2202
2203   SCIF_SAS_REMOTE_DEVICE_T    * downstream_expander = NULL;
2204
2205   SCI_FAST_LIST_ELEMENT_T     * element = this_smp_remote_device->smp_phy_list.list_head;
2206   SCIF_SAS_SMP_PHY_T          * curr_smp_phy = NULL;
2207
2208   SCIF_LOG_TRACE((
2209      sci_base_object_get_logger(this_device),
2210      SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
2211      "scif_sas_remote_device_find_downstream_expander(0x%x) enter\n",
2212      this_device
2213   ));
2214
2215   while (element != NULL)
2216   {
2217      curr_smp_phy = (SCIF_SAS_SMP_PHY_T*) sci_fast_list_get_object(element);
2218      element = sci_fast_list_get_next(element);
2219
2220      if ( curr_smp_phy->routing_attribute == TABLE_ROUTING_ATTRIBUTE
2221          && curr_smp_phy->attached_device_type == SMP_EDGE_EXPANDER_DEVICE
2222          && curr_smp_phy->u.attached_phy != NULL)
2223      {
2224         //set the current_activity and current_config_route_index for that
2225         //upstream expander.
2226         downstream_expander = curr_smp_phy->u.attached_phy->owning_device;
2227
2228         if ( downstream_expander->protocol_device.smp_device.curr_config_route_destination_smp_phy != NULL
2229             && downstream_expander->protocol_device.smp_device.curr_config_route_destination_smp_phy->owning_device ==
2230                this_smp_remote_device->curr_config_route_destination_smp_phy->owning_device )
2231            return downstream_expander;
2232      }
2233   }
2234
2235   return NULL;
2236}
2237
2238
2239/**
2240 * @brief This method follows route table optimization rule to check if a destination_device
2241 *        should be recorded in the device_being_config's route table
2242 *
2243 * @param[in] device_being_config The upstream expander device, whose route table is being configured.
2244 * @param[in] destination_smp_phy A smp phy whose attached device is potentially to be
2245 *               recorded in route table.
2246 *
2247 * @return BOOL This method returns TRUE if a destination_device should be recorded in route table.
2248 *              This method returns FALSE if a destination_device need not to be recorded
2249 *              in route table.
2250 */
2251BOOL scif_sas_smp_remote_device_do_config_route_info(
2252   SCIF_SAS_REMOTE_DEVICE_T * device_being_config,
2253   SCIF_SAS_SMP_PHY_T       * destination_smp_phy
2254)
2255{
2256   SCI_SAS_ADDRESS_T device_being_config_sas_address;
2257
2258   SCIF_LOG_TRACE((
2259      sci_base_object_get_logger(device_being_config),
2260      SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
2261      "scif_sas_smp_remote_device_do_config_route_info(0x%x, 0x%x) enter\n",
2262      device_being_config, destination_smp_phy
2263   ));
2264
2265   scic_remote_device_get_sas_address(
2266      device_being_config->core_object, &device_being_config_sas_address
2267   );
2268
2269   //refer to SAS-2 spec 4.8.3, rule (b)
2270   if ((destination_smp_phy->attached_sas_address.low == 0
2271        && destination_smp_phy->attached_sas_address.high == 0)
2272       && (destination_smp_phy->attached_device_type == SMP_NO_DEVICE_ATTACHED))
2273   {
2274      return FALSE;
2275   }
2276
2277   //refer to SAS-2 spec 4.8.3, rule (c), self-referencing.
2278   if (destination_smp_phy->attached_sas_address.high ==
2279          device_being_config_sas_address.high
2280       && destination_smp_phy->attached_sas_address.low ==
2281             device_being_config_sas_address.low)
2282   {
2283      return FALSE;
2284   }
2285
2286   //There will be no cases that falling into rule (a), (d), (e) to be excluded,
2287   //based on our current mechanism of cofig route table.
2288
2289   return TRUE;
2290}
2291
2292
2293/**
2294 * @brief This method configures device_being_config's route table for all the enclosed devices in
2295 *           a downstream smp device, destination_device.
2296 *
2297 * @param[in] device_being_config The upstream expander device, whose route table is being configured.
2298 *
2299 * @return None
2300 */
2301void scif_sas_smp_remote_device_configure_route_table(
2302   SCIF_SAS_REMOTE_DEVICE_T * device_being_config
2303)
2304{
2305   //go through the smp phy list of this_device.
2306   SCI_FAST_LIST_ELEMENT_T     * element =
2307      &(device_being_config->protocol_device.smp_device.curr_config_route_destination_smp_phy->list_element);
2308   SCIF_SAS_SMP_PHY_T          * curr_smp_phy = NULL;
2309
2310   SCIF_LOG_TRACE((
2311      sci_base_object_get_logger(device_being_config),
2312      SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
2313      "scif_sas_smp_remote_device_configure_route_table(0x%x) enter\n",
2314      device_being_config
2315   ));
2316
2317   device_being_config->protocol_device.smp_device.current_activity =
2318      SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_CONFIG_ROUTE_TABLE;
2319
2320   while (element != NULL)
2321   {
2322      curr_smp_phy = (SCIF_SAS_SMP_PHY_T*) sci_fast_list_get_object(element);
2323      element = sci_fast_list_get_next(element);
2324
2325      //check if this phy needs to be added to the expander's route table.
2326      if (scif_sas_smp_remote_device_do_config_route_info(
2327             device_being_config, curr_smp_phy) == TRUE )
2328      {
2329         SCIF_SAS_SMP_REMOTE_DEVICE_T * smp_remote_device =
2330            &device_being_config->protocol_device.smp_device;
2331
2332         smp_remote_device->curr_config_route_destination_smp_phy =
2333            curr_smp_phy;
2334
2335         //Then config this_device's route table entry at the phy and next route_index.
2336         //send config_route_info using curr_smp_phy.phy_identifier and sas_address.
2337         scif_sas_smp_request_construct_config_route_info(
2338            device_being_config->domain->controller,
2339            device_being_config,
2340            smp_remote_device->current_activity_phy_index,
2341            smp_remote_device->curr_config_route_index,
2342            curr_smp_phy->attached_sas_address,
2343            FALSE
2344         );
2345
2346         //schedule the DPC.
2347         scif_cb_start_internal_io_task_schedule(
2348            device_being_config->domain->controller,
2349            scif_sas_controller_start_high_priority_io,
2350            device_being_config->domain->controller
2351         );
2352
2353         //stop here, we need to wait for config route info's response then send
2354         //the next one.
2355         break;
2356      }
2357   }
2358}
2359
2360
2361/**
2362 * @brief This method walks through an expander's route table to clean table
2363 *           attribute phys' route entries. This routine finds one table entry
2364 *           to clean and will be called repeatly till it finishes cleanning the
2365 *           whole table.
2366 *
2367 * @param[in] fw_device The expander device, whose route table entry is to be cleaned.
2368 *
2369 * @return None.
2370 */
2371void scif_sas_smp_remote_device_clean_route_table(
2372   SCIF_SAS_REMOTE_DEVICE_T * fw_device
2373)
2374{
2375   SCIF_SAS_SMP_PHY_T * smp_phy_being_config =
2376      scif_sas_smp_remote_device_find_smp_phy_by_id(
2377         fw_device->protocol_device.smp_device.current_activity_phy_index,
2378         &(fw_device->protocol_device.smp_device)
2379      );
2380
2381   SCIF_LOG_TRACE((
2382      sci_base_object_get_logger(fw_device),
2383      SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
2384      "scif_sas_smp_remote_device_clean_route_table(0x%x) enter\n",
2385      fw_device
2386   ));
2387
2388   //from anchors, start to clean all the other route table entries.
2389   fw_device->protocol_device.smp_device.curr_config_route_index++;
2390
2391   if ( fw_device->protocol_device.smp_device.curr_config_route_index >=
2392           fw_device->protocol_device.smp_device.expander_route_indexes )
2393   {
2394      fw_device->protocol_device.smp_device.curr_config_route_index = 0;
2395
2396      do //find next table attribute PHY.
2397      {
2398         fw_device->protocol_device.smp_device.current_activity_phy_index++;
2399         if (fw_device->protocol_device.smp_device.current_activity_phy_index ==
2400                fw_device->protocol_device.smp_device.number_of_phys)
2401            fw_device->protocol_device.smp_device.current_activity_phy_index=0;
2402
2403         //phy_index changed, so update the smp_phy_being_config.
2404         smp_phy_being_config =
2405            scif_sas_smp_remote_device_find_smp_phy_by_id(
2406               fw_device->protocol_device.smp_device.current_activity_phy_index,
2407               &(fw_device->protocol_device.smp_device)
2408            );
2409      } while( smp_phy_being_config->routing_attribute != TABLE_ROUTING_ATTRIBUTE );
2410
2411      if ( smp_phy_being_config->phy_identifier !=
2412              fw_device->protocol_device.smp_device.config_route_smp_phy_anchor->phy_identifier)
2413      {
2414         if (smp_phy_being_config->config_route_table_index_anchor != 0)
2415            fw_device->protocol_device.smp_device.curr_config_route_index =
2416               smp_phy_being_config->config_route_table_index_anchor + 1;
2417         else
2418            fw_device->protocol_device.smp_device.curr_config_route_index = 0;
2419      }
2420   }
2421
2422   if ( !(fw_device->protocol_device.smp_device.current_activity_phy_index ==
2423             fw_device->protocol_device.smp_device.config_route_smp_phy_anchor->phy_identifier
2424          && fw_device->protocol_device.smp_device.curr_config_route_index == 0)
2425      )
2426   {
2427      //clean this route entry.
2428      scif_sas_smp_remote_device_clean_route_table_entry(fw_device);
2429   }
2430   else
2431   {
2432      fw_device->protocol_device.smp_device.is_route_table_cleaned = TRUE;
2433
2434      //set this device's activity to NON.
2435      fw_device->protocol_device.smp_device.current_activity =
2436         SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_NONE;
2437
2438      //we need to notify domain that this device finished config route table, domain
2439      //may pick up other activities (i.e. Discover) for other expanders.
2440      scif_sas_domain_continue_discover(fw_device->domain);
2441   }
2442}
2443
2444/**
2445 * @brief This method cleans a device's route table antry.
2446 *
2447 * @param[in] fw_device The expander device, whose route table entry is to be cleaned.
2448 *
2449 * @return None.
2450 */
2451void scif_sas_smp_remote_device_clean_route_table_entry(
2452   SCIF_SAS_REMOTE_DEVICE_T * fw_device
2453)
2454{
2455   SCI_SAS_ADDRESS_T empty_sas_address;
2456   SCIF_SAS_SMP_REMOTE_DEVICE_T * smp_remote_device =
2457      &(fw_device->protocol_device.smp_device);
2458
2459   SCIF_LOG_TRACE((
2460      sci_base_object_get_logger(fw_device),
2461      SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
2462      "scif_sas_smp_remote_device_clean_route_table(0x%x) enter\n",
2463      fw_device
2464   ));
2465
2466   empty_sas_address.high = 0;
2467   empty_sas_address.low = 0;
2468
2469   scif_sas_smp_request_construct_config_route_info(
2470      fw_device->domain->controller,
2471      fw_device,
2472      smp_remote_device->current_activity_phy_index,
2473      smp_remote_device->curr_config_route_index,
2474      empty_sas_address,
2475      TRUE
2476   );
2477
2478   //schedule the DPC.
2479   scif_cb_start_internal_io_task_schedule(
2480      fw_device->domain->controller,
2481      scif_sas_controller_start_high_priority_io,
2482      fw_device->domain->controller
2483   );
2484}
2485
2486
2487/**
2488 * @brief This method handles the case of exceeding route index when config route table
2489 *           for a device, by removing the attached device of current config route
2490 *           destination smp phy and the rest of smp phys in the same smp phy list.
2491 *
2492 * @param[in] fw_device The expander device, whose route table to be edited but failed
2493 *               with a SMP function result of INDEX DOES NOT EXIST.
2494 *
2495 * @return None.
2496 */
2497void scif_sas_smp_remote_device_cancel_config_route_table_activity(
2498   SCIF_SAS_REMOTE_DEVICE_T * fw_device
2499)
2500{
2501   //go through the rest of the smp phy list of destination device.
2502   SCI_FAST_LIST_ELEMENT_T     * element =
2503      &(fw_device->protocol_device.smp_device.curr_config_route_destination_smp_phy->list_element);
2504   SCIF_SAS_SMP_PHY_T          * curr_smp_phy = NULL;
2505   SCIF_SAS_REMOTE_DEVICE_T    * curr_attached_device = NULL;
2506
2507   SCIF_LOG_TRACE((
2508      sci_base_object_get_logger(fw_device),
2509      SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
2510      "scif_sas_smp_remote_device_cancel_config_route_table_activity(0x%x) enter\n",
2511      fw_device
2512   ));
2513
2514   while (element != NULL)
2515   {
2516      curr_smp_phy = (SCIF_SAS_SMP_PHY_T*) sci_fast_list_get_object(element);
2517      element = sci_fast_list_get_next(element);
2518
2519      //check if this phy needs to be added to the expander's route table but can't due to
2520      //exceeding max route index.
2521      if (scif_sas_smp_remote_device_do_config_route_info(
2522             fw_device, curr_smp_phy) == TRUE )
2523      {
2524         //set the is_currently_discovered to FALSE for attached device. Then when
2525         //domain finish discover, domain will remove this device.
2526         curr_attached_device = (SCIF_SAS_REMOTE_DEVICE_T *)
2527            scif_domain_get_device_by_sas_address(
2528               fw_device->domain, &(curr_smp_phy->attached_sas_address));
2529
2530         if (curr_attached_device != NULL)
2531            curr_attached_device->is_currently_discovered = FALSE;
2532      }
2533   }
2534}
2535
2536
2537/**
2538 * @brief This method cancel current activity and terminate the outstanding internal IO
2539 *           if there is one.
2540 *
2541 * @param[in] fw_device The expander device, whose smp activity is to be canceled.
2542 *
2543 * @return None.
2544 */
2545void scif_sas_smp_remote_device_cancel_smp_activity(
2546   SCIF_SAS_REMOTE_DEVICE_T * fw_device
2547)
2548{
2549   SCIF_LOG_TRACE((
2550      sci_base_object_get_logger(fw_device),
2551      SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
2552      "scif_sas_smp_remote_device_cancel_smp_activity(0x%x) enter\n",
2553      fw_device
2554   ));
2555
2556   //Terminate all of the requests in the silicon for this device.
2557   scif_sas_domain_terminate_requests(
2558      fw_device->domain, fw_device, NULL, NULL
2559   );
2560
2561   if (fw_device->protocol_device.smp_device.current_activity ==
2562          SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_CONFIG_ROUTE_TABLE)
2563      scif_sas_smp_remote_device_cancel_config_route_table_activity(fw_device);
2564
2565   //Clear the device to stop the smp sctivity.
2566   scif_sas_smp_remote_device_clear(fw_device);
2567}
2568
2569
2570/**
2571 * @brief This method tells the way to configure route table for a expander. The
2572 *          possible ways are: configure phy 0's route table, configure middle
2573 *          phy's route table, configure highest order phy's route table,
2574 *          configure all phys.
2575 *
2576 * @param[in] fw_device The expander device, whose config route table method is
2577 *               to be chosen.
2578 *
2579 * @return one in 4 possible options.
2580 */
2581U8 scif_sas_smp_remote_device_get_config_route_table_method(
2582   SCIF_SAS_REMOTE_DEVICE_T * fw_device
2583)
2584{
2585   U8 config_route_table_method;
2586
2587   //config_route_table_method = SCIF_SAS_CONFIG_ROUTE_TABLE_MIDDLE_PHY_ONLY;
2588   config_route_table_method = SCIF_SAS_CONFIG_ROUTE_TABLE_ALL_PHYS;
2589
2590   return config_route_table_method;
2591}
2592
2593
2594/**
2595 * @brief This method starts the EA target reset process by constructing
2596 *           and starting a PHY CONTROL (hard reset) smp request.
2597 *
2598 * @param[in] expander_device The expander device, to which a PHY Control smp command is
2599 *               sent.
2600 * @param[in] target_device The expander attahced target device, to which the target reset
2601 *               request is sent.
2602 * @param[in] fw_request The target reset task request.
2603 *
2604 * @return none
2605 */
2606void scif_sas_smp_remote_device_start_target_reset(
2607   SCIF_SAS_REMOTE_DEVICE_T * expander_device,
2608   SCIF_SAS_REMOTE_DEVICE_T * target_device,
2609   SCIF_SAS_REQUEST_T       * fw_request
2610)
2611{
2612   SCIF_SAS_CONTROLLER_T * fw_controller = expander_device->domain->controller;
2613
2614   //set current_activity and current_smp_request to expander device.
2615   expander_device->protocol_device.smp_device.current_activity =
2616      SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_TARGET_RESET;
2617   expander_device->protocol_device.smp_device.current_smp_request =
2618      SMP_FUNCTION_PHY_CONTROL;
2619   expander_device->protocol_device.smp_device.current_activity_phy_index =
2620      target_device->expander_phy_identifier;
2621
2622   //A Phy Control smp request has been constructed towards parent device.
2623   //Walk the high priority io path.
2624   fw_controller->state_handlers->start_high_priority_io_handler(
2625      (SCI_BASE_CONTROLLER_T*) fw_controller,
2626      (SCI_BASE_REMOTE_DEVICE_T*) expander_device,
2627      (SCI_BASE_REQUEST_T*) fw_request,
2628      SCI_CONTROLLER_INVALID_IO_TAG
2629   );
2630}
2631
2632
2633