The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/isci/scil/scif_sas_smp_remote_device.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: 530539ffa9ca53723a753c1e8eab4702


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.