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_domain.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 implementation of the SCIF_SAS_DOMAIN
   62  *        object.
   63  */
   64 
   65 #include <dev/isci/scil/intel_sas.h>
   66 #include <dev/isci/scil/sci_fast_list.h>
   67 #include <dev/isci/scil/scic_controller.h>
   68 #include <dev/isci/scil/scic_port.h>
   69 #include <dev/isci/scil/scic_remote_device.h>
   70 #include <dev/isci/scil/scic_io_request.h>
   71 #include <dev/isci/scil/scic_user_callback.h>
   72 #include <dev/isci/scil/scif_user_callback.h>
   73 #include <dev/isci/scil/sci_abstract_list.h>
   74 #include <dev/isci/scil/sci_base_iterator.h>
   75 
   76 #include <dev/isci/scil/scif_sas_logger.h>
   77 #include <dev/isci/scil/scif_sas_domain.h>
   78 #include <dev/isci/scil/scif_sas_controller.h>
   79 #include <dev/isci/scil/scif_sas_remote_device.h>
   80 #include <dev/isci/scil/scif_sas_smp_remote_device.h>
   81 #include <dev/isci/scil/sci_util.h>
   82 
   83 //******************************************************************************
   84 //* P R I V A T E   M E T H O D S
   85 //******************************************************************************
   86 
   87 /**
   88  * @brief This method will attempt to handle an operation timeout (i.e.
   89  *        discovery or reset).
   90  *
   91  * @param[in]  cookie This parameter specifies the domain in which the
   92  *             timeout occurred.
   93  *
   94  * @return none
   95  */
   96 static
   97 void scif_sas_domain_operation_timeout_handler(
   98    void * cookie
   99 )
  100 {
  101    SCIF_SAS_DOMAIN_T * fw_domain = (SCIF_SAS_DOMAIN_T*) cookie;
  102    U32                 state;
  103 
  104    state = sci_base_state_machine_get_state(&fw_domain->parent.state_machine);
  105 
  106    // Based upon the state of the domain, we know whether we were in the
  107    // process of performing discovery or a reset.
  108    if (state == SCI_BASE_DOMAIN_STATE_DISCOVERING)
  109    {
  110       SCIF_LOG_WARNING((
  111          sci_base_object_get_logger(fw_domain),
  112          SCIF_LOG_OBJECT_DOMAIN,
  113          "Domain:0x%x State:0x%x DISCOVER timeout!\n",
  114          fw_domain, state
  115       ));
  116 
  117       fw_domain->operation.status = SCI_FAILURE_TIMEOUT;
  118 
  119       //search all the smp devices in the domain and cancel their activities
  120       //if there is any outstanding activity remained. The smp devices will terminate
  121       //all the started internal IOs.
  122       scif_sas_domain_cancel_smp_activities(fw_domain);
  123 
  124       scif_sas_domain_continue_discover(fw_domain);
  125    }
  126    else
  127    {
  128       SCIF_LOG_ERROR((
  129          sci_base_object_get_logger(fw_domain),
  130          SCIF_LOG_OBJECT_DOMAIN,
  131          "Domain:0x%x State:0x%x operation timeout in invalid state\n",
  132          fw_domain, state
  133       ));
  134    }
  135 }
  136 
  137 //******************************************************************************
  138 //* P U B L I C   M E T H O D S
  139 //******************************************************************************
  140 
  141 SCI_PORT_HANDLE_T scif_domain_get_scic_port_handle(
  142    SCI_DOMAIN_HANDLE_T  domain
  143 )
  144 {
  145    SCIF_SAS_DOMAIN_T * fw_domain = (SCIF_SAS_DOMAIN_T*) domain;
  146 
  147    if ( (fw_domain == NULL) || (fw_domain->core_object == SCI_INVALID_HANDLE) )
  148       return SCI_INVALID_HANDLE;
  149 
  150    SCIF_LOG_WARNING((
  151       sci_base_object_get_logger(fw_domain),
  152       SCIF_LOG_OBJECT_DOMAIN,
  153       "Domain:0x%x no associated core port found\n",
  154       fw_domain
  155    ));
  156 
  157    return fw_domain->core_object;
  158 }
  159 
  160 // ---------------------------------------------------------------------------
  161 
  162 SCI_REMOTE_DEVICE_HANDLE_T scif_domain_get_device_by_sas_address(
  163    SCI_DOMAIN_HANDLE_T   domain,
  164    SCI_SAS_ADDRESS_T   * sas_address
  165 )
  166 {
  167    SCIF_SAS_DOMAIN_T        * fw_domain = (SCIF_SAS_DOMAIN_T*) domain;
  168    SCI_ABSTRACT_ELEMENT_T   * element   = sci_abstract_list_get_front(
  169                                              &fw_domain->remote_device_list
  170                                           );
  171    SCIF_SAS_REMOTE_DEVICE_T * fw_device;
  172    SCI_SAS_ADDRESS_T          fw_device_address;
  173 
  174    SCIF_LOG_TRACE((
  175       sci_base_object_get_logger(domain),
  176       SCIF_LOG_OBJECT_DOMAIN,
  177       "scif_domain_get_device_by_sas_address(0x%x, 0x%x) enter\n",
  178       domain, sas_address
  179    ));
  180 
  181    // Search the abstract list to see if there is a remote device with the
  182    // same SAS address.
  183    while (element != NULL)
  184    {
  185       fw_device = (SCIF_SAS_REMOTE_DEVICE_T*)
  186                   sci_abstract_list_get_object(element);
  187 
  188       scic_remote_device_get_sas_address(
  189          fw_device->core_object, &fw_device_address
  190       );
  191 
  192       // Check to see if this is the device for which we are searching.
  193       if (  (fw_device_address.low == sas_address->low)
  194          && (fw_device_address.high == sas_address->high) )
  195       {
  196          return fw_device;
  197       }
  198 
  199       element = sci_abstract_list_get_next(element);
  200    }
  201 
  202    return SCI_INVALID_HANDLE;
  203 }
  204 
  205 // ---------------------------------------------------------------------------
  206 
  207 #if !defined(DISABLE_SCI_ITERATORS)
  208 
  209 SCI_ITERATOR_HANDLE_T scif_domain_get_remote_device_iterator(
  210    SCI_DOMAIN_HANDLE_T   domain,
  211    void                * iterator_buffer
  212 )
  213 {
  214    SCI_ITERATOR_HANDLE_T iterator = (SCI_ITERATOR_HANDLE_T *)iterator_buffer;
  215 
  216    sci_base_iterator_construct(
  217       iterator, &((SCIF_SAS_DOMAIN_T*) domain)->remote_device_list
  218    );
  219 
  220 
  221    return iterator;
  222 }
  223 
  224 #endif // !defined(DISABLE_SCI_ITERATORS)
  225 
  226 // ---------------------------------------------------------------------------
  227 
  228 SCI_STATUS scif_domain_discover(
  229    SCI_DOMAIN_HANDLE_T   domain,
  230    U32                   discover_timeout,
  231    U32                   device_timeout
  232 )
  233 {
  234    SCIF_SAS_DOMAIN_T * fw_domain = (SCIF_SAS_DOMAIN_T*) domain;
  235    SCI_STATUS          status    = SCI_SUCCESS;
  236    SCI_STATUS          op_status = SCI_SUCCESS;
  237 
  238    SCIF_LOG_TRACE((
  239       sci_base_object_get_logger(domain),
  240       SCIF_LOG_OBJECT_DOMAIN | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
  241       "scif_domain_discover(0x%x, 0x%x, 0x%x) enter\n",
  242       domain, discover_timeout, device_timeout
  243    ));
  244 
  245    // Check to make sure the size of the domain doesn't cause potential issues
  246    // with the remote device timer and the domain timer.
  247    if ((device_timeout * sci_abstract_list_size(&fw_domain->remote_device_list))
  248         > discover_timeout)
  249       status = SCI_WARNING_TIMER_CONFLICT;
  250 
  251    op_status = fw_domain->state_handlers->discover_handler(
  252                   &fw_domain->parent, discover_timeout, device_timeout
  253                );
  254 
  255    // The status of the discover operation takes priority.
  256    if (  (status == SCI_SUCCESS)
  257       || (status != SCI_SUCCESS && op_status != SCI_SUCCESS) )
  258    {
  259       status = op_status;
  260    }
  261 
  262    return status;
  263 }
  264 
  265 // ---------------------------------------------------------------------------
  266 
  267 U32 scif_domain_get_suggested_discover_timeout(
  268    SCI_DOMAIN_HANDLE_T   domain
  269 )
  270 {
  271    U32 suggested_timeout = SCIF_DOMAIN_DISCOVER_TIMEOUT; //milli-seconds
  272    return suggested_timeout;
  273 }
  274 
  275 // ---------------------------------------------------------------------------
  276 
  277 void scic_cb_port_stop_complete(
  278    SCI_CONTROLLER_HANDLE_T  controller,
  279    SCI_PORT_HANDLE_T        port,
  280    SCI_STATUS               completion_status
  281 )
  282 {
  283    SCIF_LOG_TRACE((
  284       sci_base_object_get_logger((SCIF_SAS_DOMAIN_T*)sci_object_get_association(port)),
  285       SCIF_LOG_OBJECT_DOMAIN,
  286       "scic_cb_port_stop_complete(0x%x, 0x%x, 0x%x) enter\n",
  287       controller, port, completion_status
  288    ));
  289 }
  290 
  291 // ---------------------------------------------------------------------------
  292 
  293 void scic_cb_port_ready(
  294    SCI_CONTROLLER_HANDLE_T  controller,
  295    SCI_PORT_HANDLE_T        port
  296 )
  297 {
  298    SCIF_SAS_DOMAIN_T * fw_domain = (SCIF_SAS_DOMAIN_T*)
  299                                    sci_object_get_association(port);
  300 
  301    SCIF_LOG_TRACE((
  302       sci_base_object_get_logger(fw_domain),
  303       SCIF_LOG_OBJECT_DOMAIN,
  304       "scic_cb_port_ready(0x%x, 0x%x) enter\n",
  305       controller, port
  306    ));
  307 
  308    // The controller supplied with the port should match the controller
  309    // saved in the domain.
  310    ASSERT(sci_object_get_association(controller) == fw_domain->controller);
  311 
  312    fw_domain->is_port_ready = TRUE;
  313 
  314    fw_domain->state_handlers->port_ready_handler(&fw_domain->parent);
  315 }
  316 
  317 // ---------------------------------------------------------------------------
  318 
  319 void scic_cb_port_not_ready(
  320    SCI_CONTROLLER_HANDLE_T  controller,
  321    SCI_PORT_HANDLE_T        port,
  322    U32                      reason_code
  323 )
  324 {
  325    SCIF_SAS_DOMAIN_T * fw_domain = (SCIF_SAS_DOMAIN_T*)
  326                                    sci_object_get_association(port);
  327 
  328    SCIF_LOG_TRACE((
  329       sci_base_object_get_logger(fw_domain),
  330       SCIF_LOG_OBJECT_DOMAIN,
  331       "scic_cb_port_not_ready(0x%x, 0x%x) enter\n",
  332       controller, port
  333    ));
  334 
  335    // The controller supplied with the port should match the controller
  336    // saved in the domain.
  337    ASSERT(sci_object_get_association(controller) == fw_domain->controller);
  338 
  339    // There is no need to take action on the port reconfiguring since it is
  340    // just a change of the port width.
  341    if (reason_code != SCIC_PORT_NOT_READY_RECONFIGURING)
  342    {
  343       fw_domain->is_port_ready = FALSE;
  344 
  345       fw_domain->state_handlers->port_not_ready_handler(
  346                                     &fw_domain->parent, reason_code);
  347    }
  348 }
  349 
  350 // ---------------------------------------------------------------------------
  351 
  352 void scic_cb_port_hard_reset_complete(
  353    SCI_CONTROLLER_HANDLE_T  controller,
  354    SCI_PORT_HANDLE_T        port,
  355    SCI_STATUS               completion_status
  356 )
  357 {
  358    SCIF_SAS_DOMAIN_T        * fw_domain = (SCIF_SAS_DOMAIN_T*)
  359                                    sci_object_get_association(port);
  360    SCIF_SAS_REMOTE_DEVICE_T * fw_device;
  361    SCI_FAST_LIST_ELEMENT_T  * element = fw_domain->request_list.list_head;
  362    SCIF_SAS_TASK_REQUEST_T  * task_request = NULL;
  363 
  364    SCIF_LOG_TRACE((
  365       sci_base_object_get_logger(fw_domain),
  366       SCIF_LOG_OBJECT_DOMAIN,
  367       "scic_cb_port_hard_reset_complete(0x%x, 0x%x, 0x%x) enter\n",
  368       controller, port, completion_status
  369    ));
  370 
  371    while (element != NULL)
  372    {
  373       task_request = (SCIF_SAS_TASK_REQUEST_T*) sci_fast_list_get_object(element);
  374       element = sci_fast_list_get_next(element);
  375 
  376       if (scif_sas_task_request_get_function(task_request)
  377              == SCI_SAS_HARD_RESET)
  378       {
  379          fw_device = task_request->parent.device;
  380 
  381          if (fw_device->domain == fw_domain)
  382          {
  383             scic_remote_device_reset_complete(fw_device->core_object);
  384 
  385             scif_cb_task_request_complete(
  386                sci_object_get_association(controller),
  387                fw_device,
  388                task_request,
  389                (SCI_TASK_STATUS) completion_status
  390             );
  391 
  392             break;
  393          }
  394       }
  395    }
  396 }
  397 
  398 // ---------------------------------------------------------------------------
  399 
  400 void scic_cb_port_bc_change_primitive_recieved(
  401    SCI_CONTROLLER_HANDLE_T  controller,
  402    SCI_PORT_HANDLE_T        port,
  403    SCI_PHY_HANDLE_T         phy
  404 )
  405 {
  406    SCIF_SAS_DOMAIN_T * fw_domain = (SCIF_SAS_DOMAIN_T*)
  407                                    sci_object_get_association(port);
  408 
  409    SCIF_SAS_CONTROLLER_T * fw_controller = (SCIF_SAS_CONTROLLER_T *)
  410                                            sci_object_get_association(controller);
  411 
  412    SCIF_LOG_TRACE((
  413       sci_base_object_get_logger(fw_domain),
  414       SCIF_LOG_OBJECT_DOMAIN | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
  415       "scic_cb_port_bc_change_primitive_recieved(0x%x, 0x%x, 0x%x) enter\n",
  416       controller, port, phy
  417    ));
  418 
  419    if (fw_domain->broadcast_change_count == 0)
  420    {  // Enable the BCN detection only if the bcn_count is zero. If bcn_count is
  421       // not zero at this time, we won't enable BCN detection since all non-zero
  422       // BCN_count means same to us. Furthermore, we avoid BCN storm by not
  423       // always enabling the BCN_detection.
  424       scic_port_enable_broadcast_change_notification(fw_domain->core_object);
  425    }
  426 
  427    fw_domain->broadcast_change_count++;
  428 
  429    //if there is smp device on this domain that is in the middle of discover
  430    //process or smp target reset, don't notify the driver layer.
  431    if( ! scif_sas_domain_is_in_smp_activity(fw_domain) )
  432       // Notify the user that there is, potentially, a change to the domain.
  433       scif_cb_domain_change_notification(fw_controller, fw_domain);
  434 }
  435 
  436 // ---------------------------------------------------------------------------
  437 
  438 void scic_cb_port_bc_ses_primitive_recieved(
  439    SCI_CONTROLLER_HANDLE_T  controller,
  440    SCI_PORT_HANDLE_T        port,
  441    SCI_PHY_HANDLE_T         phy
  442 )
  443 {
  444    SCIF_LOG_TRACE((
  445       sci_base_object_get_logger(sci_object_get_association(port)),
  446       SCIF_LOG_OBJECT_DOMAIN,
  447       "scic_cb_port_bc_ses_primitive_received(0x%x, 0x%x, 0x%x) enter\n",
  448       controller, port, phy
  449    ));
  450 }
  451 
  452 // ---------------------------------------------------------------------------
  453 
  454 void scic_cb_port_bc_expander_primitive_recieved(
  455    SCI_CONTROLLER_HANDLE_T  controller,
  456    SCI_PORT_HANDLE_T        port,
  457    SCI_PHY_HANDLE_T         phy
  458 )
  459 {
  460    SCIF_LOG_TRACE((
  461       sci_base_object_get_logger(sci_object_get_association(port)),
  462       SCIF_LOG_OBJECT_DOMAIN,
  463       "scic_cb_port_bc_expander_primitive_received(0x%x, 0x%x, 0x%x) enter\n",
  464       controller, port, phy
  465    ));
  466 }
  467 
  468 // ---------------------------------------------------------------------------
  469 
  470 void scic_cb_port_bc_aen_primitive_recieved(
  471    SCI_CONTROLLER_HANDLE_T  controller,
  472    SCI_PORT_HANDLE_T        port,
  473    SCI_PHY_HANDLE_T         phy
  474 )
  475 {
  476    SCIF_LOG_TRACE((
  477       sci_base_object_get_logger(sci_object_get_association(port)),
  478       SCIF_LOG_OBJECT_DOMAIN,
  479       "scic_cb_port_bc_aen_primitive_received(0x%x, 0x%x, 0x%x) enter\n",
  480       controller, port, phy
  481    ));
  482 }
  483 
  484 // ---------------------------------------------------------------------------
  485 
  486 void scic_cb_port_link_up(
  487    SCI_CONTROLLER_HANDLE_T  controller,
  488    SCI_PORT_HANDLE_T        port,
  489    SCI_PHY_HANDLE_T         phy
  490 )
  491 {
  492    SCIF_SAS_DOMAIN_T        * fw_domain = (SCIF_SAS_DOMAIN_T*)
  493                                  sci_object_get_association(port);
  494 
  495    SCIF_LOG_TRACE((
  496       sci_base_object_get_logger(sci_object_get_association(port)),
  497       SCIF_LOG_OBJECT_DOMAIN,
  498       "scic_cb_port_link_up(0x%x, 0x%x, 0x%x) enter\n",
  499       controller, port, phy
  500    ));
  501 
  502    scif_sas_domain_update_device_port_width(fw_domain, port);
  503 }
  504 
  505 // ---------------------------------------------------------------------------
  506 
  507 void scic_cb_port_link_down(
  508    SCI_CONTROLLER_HANDLE_T  controller,
  509    SCI_PORT_HANDLE_T        port,
  510    SCI_PHY_HANDLE_T         phy
  511 )
  512 {
  513    SCIF_SAS_DOMAIN_T        * fw_domain = (SCIF_SAS_DOMAIN_T*)
  514                                  sci_object_get_association(port);
  515 
  516    SCIF_LOG_TRACE((
  517       sci_base_object_get_logger(sci_object_get_association(port)),
  518       SCIF_LOG_OBJECT_DOMAIN,
  519       "scic_cb_port_link_down(0x%x, 0x%x, 0x%x) enter\n",
  520       controller, port, phy
  521    ));
  522 
  523    scif_sas_domain_update_device_port_width(fw_domain, port);
  524 }
  525 
  526 //******************************************************************************
  527 //* P R O T E C T E D   M E T H O D S
  528 //******************************************************************************
  529 
  530 /**
  531  * @brief This method constructs the framework's SAS domain object.  During
  532  *        the construction process a linkage to the corresponding core port
  533  *        object.
  534  *
  535  * @param[in]  domain This parameter specifies the domain object to be
  536  *             constructed.
  537  * @param[in]  domain_id This parameter specifies the ID for the domain
  538  *             object.
  539  * @param[in]  fw_controller This parameter specifies the controller managing
  540  *             the domain being constructed.
  541  *
  542  * @return none
  543  */
  544 void scif_sas_domain_construct(
  545    SCIF_SAS_DOMAIN_T     * fw_domain,
  546    U8                      domain_id,
  547    SCIF_SAS_CONTROLLER_T * fw_controller
  548 )
  549 {
  550    SCIF_LOG_TRACE((
  551       sci_base_object_get_logger(fw_controller),
  552       SCIF_LOG_OBJECT_DOMAIN | SCIF_LOG_OBJECT_INITIALIZATION,
  553       "scif_sas_domain_construct(0x%x, 0x%x, 0x%x) enter\n",
  554       fw_domain, domain_id, fw_controller
  555    ));
  556 
  557    sci_base_domain_construct(
  558       &fw_domain->parent,
  559       sci_base_object_get_logger(fw_controller),
  560       scif_sas_domain_state_table
  561    );
  562 
  563    scif_sas_domain_initialize_state_logging(fw_domain);
  564 
  565    sci_abstract_list_construct(
  566       &fw_domain->remote_device_list, &fw_controller->free_remote_device_pool
  567    );
  568 
  569    // Retrieve the core's port object that directly corresponds to this
  570    // domain.
  571    scic_controller_get_port_handle(
  572       fw_controller->core_object, domain_id, &fw_domain->core_object
  573    );
  574 
  575    // Set the association in the core port to this framework domain object.
  576    sci_object_set_association(
  577       (SCI_OBJECT_HANDLE_T) fw_domain->core_object, fw_domain
  578    );
  579 
  580    sci_fast_list_init(&fw_domain->request_list);
  581 
  582    fw_domain->operation.timer = NULL;
  583 
  584    fw_domain->is_port_ready      = FALSE;
  585    fw_domain->device_start_count = 0;
  586    fw_domain->controller         = fw_controller;
  587    fw_domain->operation.status   = SCI_SUCCESS;
  588    fw_domain->is_config_route_table_needed = FALSE;
  589 }
  590 
  591 /**
  592  * @brief This method will terminate the requests outstanding in the core
  593  *        based on the supplied criteria.
  594  *        - if the all three parameters are specified then only the single
  595  *          SCIF_SAS_REQUEST object is terminated.
  596  *        - if only the SCIF_SAS_DOMAIN and SCIF_SAS_REMOTE_DEVICE are
  597  *          specified, then all SCIF_SAS_REQUEST objects outstanding at
  598  *          the device are terminated.  The one exclusion to this rule is
  599  *          that the fw_requestor is not terminated.
  600  *        - if only the SCIF_SAS_DOMAIN object is specified, then all
  601  *          SCIF_SAS_REQUEST objects outstanding in the domain are
  602  *          terminated.
  603  *
  604  * @param[in]  fw_domain This parameter specifies the domain in which to
  605  *             terminate requests.
  606  * @param[in]  fw_device This parameter specifies the remote device in
  607  *             which to terminate requests.  This parameter can be NULL
  608  *             as long as the fw_request parameter is NULL.  It is a
  609  *             required parameter if the fw_request parameter is not NULL.
  610  * @param[in]  fw_request This parameter specifies the request object to
  611  *             be terminated.  This parameter can be NULL.
  612  * @param[in]  fw_requestor This parameter specifies the task management
  613  *             request that is responsible for the termination of requests.
  614  *
  615  * @return none
  616  */
  617 void scif_sas_domain_terminate_requests(
  618    SCIF_SAS_DOMAIN_T        * fw_domain,
  619    SCIF_SAS_REMOTE_DEVICE_T * fw_device,
  620    SCIF_SAS_REQUEST_T       * fw_request,
  621    SCIF_SAS_TASK_REQUEST_T  * fw_requestor
  622 )
  623 {
  624    SCIF_LOG_TRACE((
  625       sci_base_object_get_logger(fw_domain),
  626       SCIF_LOG_OBJECT_DOMAIN | SCIF_LOG_OBJECT_TASK_MANAGEMENT,
  627       "scif_sas_domain_terminate_requests(0x%x, 0x%x, 0x%x, 0x%x) enter\n",
  628       fw_domain, fw_device, fw_request, fw_requestor
  629    ));
  630 
  631    if (fw_request != NULL)
  632    {
  633       fw_request->terminate_requestor = fw_requestor;
  634       fw_request->state_handlers->abort_handler(&fw_request->parent);
  635    }
  636    else
  637    {
  638       SCI_FAST_LIST_ELEMENT_T * element = fw_domain->request_list.list_head;
  639       SCIF_SAS_REQUEST_T      * request = NULL;
  640 
  641       // Cycle through the fast list of IO requests.  Terminate each
  642       // outstanding requests that matches the criteria supplied by the
  643       // caller.
  644       while (element != NULL)
  645       {
  646          request = (SCIF_SAS_REQUEST_T*) sci_fast_list_get_object(element);
  647          // The current element may be deleted from the list because of
  648          // IO completion so advance to the next element early
  649          element = sci_fast_list_get_next(element);
  650 
  651          // Ensure we pass the supplied criteria before terminating the
  652          // request.
  653          if (
  654                (fw_device == NULL)
  655             || (
  656                   (request->device == fw_device)
  657                && (fw_requestor != (SCIF_SAS_TASK_REQUEST_T*) request)
  658                )
  659             )
  660          {
  661             if (
  662                   (request->is_waiting_for_abort_task_set == FALSE) ||
  663                   (request->terminate_requestor == NULL)
  664                )
  665             {
  666                request->terminate_requestor = fw_requestor;
  667                request->state_handlers->abort_handler(&request->parent);
  668             }
  669          }
  670       }
  671    }
  672 }
  673 
  674 /**
  675  * @brief This method searches the domain object to find a
  676  *        SCIF_SAS_REQUEST object associated with the supplied IO tag.
  677  *
  678  * @param[in]  fw_domain This parameter specifies the domain in which to
  679  *             to find the request object.
  680  * @param[in]  io_tag This parameter specifies the IO tag value for which
  681  *             to locate the corresponding request.
  682  *
  683  * @return This method returns a pointer to the SCIF_SAS_REQUEST object
  684  *         associated with the supplied IO tag.
  685  * @retval NULL This value is returned if the IO tag does not resolve to
  686  *         a request.
  687  */
  688 SCIF_SAS_REQUEST_T * scif_sas_domain_get_request_by_io_tag(
  689    SCIF_SAS_DOMAIN_T * fw_domain,
  690    U16                 io_tag
  691 )
  692 {
  693    SCI_FAST_LIST_ELEMENT_T * element    = fw_domain->request_list.list_head;
  694    SCIF_SAS_IO_REQUEST_T   * io_request = NULL;
  695 
  696    SCIF_LOG_TRACE((
  697       sci_base_object_get_logger(fw_domain),
  698       SCIF_LOG_OBJECT_DOMAIN | SCIF_LOG_OBJECT_TASK_MANAGEMENT,
  699       "scif_sas_domain_get_request_by_io_tag(0x%x, 0x%x) enter\n",
  700       fw_domain, io_tag
  701    ));
  702 
  703    while (element != NULL)
  704    {
  705       io_request = (SCIF_SAS_IO_REQUEST_T*) sci_fast_list_get_object(element);
  706 
  707       // Check to see if we located the request with an identical IO tag.
  708       if (scic_io_request_get_io_tag(io_request->parent.core_object) == io_tag)
  709          return &io_request->parent;
  710 
  711       element = sci_fast_list_get_next(element);
  712    }
  713 
  714    return NULL;
  715 }
  716 
  717 /**
  718  * @brief This method performs domain object initialization to be done
  719  *        when the scif_controller_initialize() method is invoked.
  720  *        This includes operation timeout creation.
  721  *
  722  * @param[in]  fw_domain This parameter specifies the domain object for
  723  *             which to perform initialization.
  724  *
  725  * @return none
  726  */
  727 void scif_sas_domain_initialize(
  728    SCIF_SAS_DOMAIN_T * fw_domain
  729 )
  730 {
  731    SCIF_LOG_TRACE((
  732       sci_base_object_get_logger(fw_domain),
  733       SCIF_LOG_OBJECT_DOMAIN | SCIF_LOG_OBJECT_INITIALIZATION,
  734       "scif_sas_domain_initialize(0x%x) enter\n",
  735       fw_domain
  736    ));
  737 
  738    // Create the timer for each domain.  It is too early in the process
  739    // to allocate this during construction since the user didn't have
  740    // a chance to set it's association.
  741    if (fw_domain->operation.timer == 0)
  742    {
  743       fw_domain->operation.timer = scif_cb_timer_create(
  744                                       fw_domain->controller,
  745                                       scif_sas_domain_operation_timeout_handler,
  746                                       fw_domain
  747                                    );
  748    }
  749 }
  750 
  751 /**
  752  * @brief This method performs domain object handling for core remote
  753  *        device start complete notifications.  Core remote device starts
  754  *        and start completes are only done during discovery.  This could
  755  *        ultimately be wrapped into a handler method on the domain (they
  756  *        actually already exist).  This method will decrement the number
  757  *        of device start operations ongoing and attempt to determine if
  758  *        discovery is complete.
  759  *
  760  * @param[in]  fw_domain This parameter specifies the domain object for
  761  *             which to perform initialization.
  762  *
  763  * @return none
  764  */
  765 void scif_sas_domain_remote_device_start_complete(
  766    SCIF_SAS_DOMAIN_T        * fw_domain,
  767    SCIF_SAS_REMOTE_DEVICE_T * fw_device
  768 )
  769 {
  770    SMP_DISCOVER_RESPONSE_PROTOCOLS_T  dev_protocols;
  771 
  772    SCIF_LOG_TRACE((
  773       sci_base_object_get_logger(fw_domain),
  774       SCIF_LOG_OBJECT_DOMAIN | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
  775       "scif_sas_domain_remote_device_start_complete(0x%x, 0x%x) enter\n",
  776       fw_domain, fw_device
  777    ));
  778 
  779    // If a device is being started/start completed, then we must be
  780    // during discovery.
  781    ASSERT(fw_domain->parent.state_machine.current_state_id
  782           == SCI_BASE_DOMAIN_STATE_DISCOVERING);
  783 
  784    scic_remote_device_get_protocols(fw_device->core_object, &dev_protocols);
  785 
  786    // Decrement the number of devices being started and check to see
  787    // if all have finished being started or failed as the case may be.
  788    fw_domain->device_start_in_progress_count--;
  789 
  790    if ( dev_protocols.u.bits.attached_smp_target )
  791    {
  792       if ( fw_device->containing_device == NULL )
  793          //kick off the smp discover process if this expander is direct attached.
  794          scif_sas_smp_remote_device_start_discover(fw_device);
  795       else
  796          //mark this device, the discover process of this device will start after
  797          //its containing smp device finish discover.
  798          fw_device->protocol_device.smp_device.scheduled_activity =
  799             SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_DISCOVER;
  800    }
  801    else
  802    {
  803       fw_domain->state_handlers->device_start_complete_handler(
  804          &fw_domain->parent, &fw_device->parent
  805       );
  806    }
  807 }
  808 
  809 
  810 /**
  811  * @brief This methods check each smp device in this domain. If there is at
  812  *        least one smp device in discover or target reset activity, this
  813  *        domain is considered in smp activity. Note this routine is not
  814  *        called on fast IO path.
  815  *
  816  * @param[in] fw_domain The framework domain object
  817  *
  818  * @return BOOL value to indicate whether a domain is in SMP activity.
  819  */
  820 BOOL scif_sas_domain_is_in_smp_activity(
  821    SCIF_SAS_DOMAIN_T        * fw_domain
  822 )
  823 {
  824    SCI_ABSTRACT_ELEMENT_T * current_element =
  825       sci_abstract_list_get_front(&fw_domain->remote_device_list);
  826 
  827    SCIF_SAS_REMOTE_DEVICE_T * current_device;
  828 
  829    while ( current_element != NULL )
  830    {
  831       SMP_DISCOVER_RESPONSE_PROTOCOLS_T  dev_protocols;
  832 
  833       current_device = (SCIF_SAS_REMOTE_DEVICE_T *)
  834                        sci_abstract_list_get_object(current_element);
  835 
  836       scic_remote_device_get_protocols(current_device->core_object,
  837                                        &dev_protocols
  838       );
  839 
  840       if (dev_protocols.u.bits.attached_smp_target &&
  841           scif_sas_smp_remote_device_is_in_activity(current_device))
  842          return TRUE;
  843 
  844       current_element =
  845          sci_abstract_list_get_next(current_element);
  846    }
  847 
  848    return FALSE;
  849 }
  850 
  851 
  852 /**
  853  * @brief This methods finds a expander attached device by searching the domain's
  854  *        device list using connected expander device and expander phy id.
  855  *
  856  * @param[in] fw_domain The framework domain object
  857  * @param[in] parent_device The expander device the target device attaches to.
  858  * @param[in] expander_phy_id The expander phy id that the target device owns.
  859  *
  860  * @return found remote device or a NULL value if no device found.
  861  */
  862 SCIF_SAS_REMOTE_DEVICE_T * scif_sas_domain_get_device_by_containing_device(
  863    SCIF_SAS_DOMAIN_T        * fw_domain,
  864    SCIF_SAS_REMOTE_DEVICE_T * containing_device,
  865    U8                         expander_phy_id
  866 )
  867 {
  868    SCIF_SAS_REMOTE_DEVICE_T * fw_device;
  869    SCI_ABSTRACT_ELEMENT_T * element = sci_abstract_list_get_front(
  870                                          &fw_domain->remote_device_list
  871                                       );
  872 
  873    //parent device must not be NULL.
  874    ASSERT(containing_device != NULL);
  875 
  876    // Search the abstract list to see if there is a remote device meets the
  877    // search condition.
  878    while (element != NULL)
  879    {
  880       fw_device = (SCIF_SAS_REMOTE_DEVICE_T*)
  881                   sci_abstract_list_get_object(element);
  882 
  883       // Check to see if this is the device for which we are searching.
  884       if (
  885             (fw_device->containing_device == containing_device)
  886          && (fw_device->expander_phy_identifier == expander_phy_id)
  887          )
  888       {
  889          return fw_device;
  890       }
  891 
  892       element = sci_abstract_list_get_next(element);
  893    }
  894 
  895    return SCI_INVALID_HANDLE;
  896 }
  897 
  898 
  899 /**
  900  * @brief This methods finds the first device that is in STOPPED state and its
  901  *        connection_rate is still in SPINUP_HOLD(value 3).
  902  *
  903  * @param[in] fw_domain The framework domain object
  904  *
  905  * @return SCIF_SAS_REMOTE_DEVICE_T The device that is in SPINUP_HOLD or NULL.
  906  */
  907 SCIF_SAS_REMOTE_DEVICE_T * scif_sas_domain_find_device_in_spinup_hold(
  908    SCIF_SAS_DOMAIN_T        * fw_domain
  909 )
  910 {
  911    SCI_ABSTRACT_ELEMENT_T   * current_element;
  912    SCIF_SAS_REMOTE_DEVICE_T * current_device;
  913 
  914    SCIF_LOG_TRACE((
  915       sci_base_object_get_logger(fw_domain),
  916       SCIF_LOG_OBJECT_DOMAIN,
  917       "scif_sas_domain_find_device_in_spinup_hold(0x%x) enter\n",
  918       fw_domain
  919    ));
  920 
  921    //search throught domain's device list to find the first sata device on spinup_hold
  922    current_element = sci_abstract_list_get_front(&fw_domain->remote_device_list);
  923    while (current_element != NULL )
  924    {
  925       current_device = (SCIF_SAS_REMOTE_DEVICE_T *)
  926                        sci_abstract_list_get_object(current_element);
  927 
  928       //We must get the next element before we remove the current
  929       //device. Or else, we will get wrong next_element, since the erased
  930       //element has been put into free pool.
  931       current_element = sci_abstract_list_get_next(current_element);
  932 
  933       if ( sci_base_state_machine_get_state(&current_device->parent.state_machine) ==
  934               SCI_BASE_REMOTE_DEVICE_STATE_STOPPED
  935           && scic_remote_device_get_connection_rate(current_device->core_object) ==
  936                 SCI_SATA_SPINUP_HOLD )
  937       {
  938          return current_device;
  939       }
  940    }
  941 
  942    return NULL;
  943 }
  944 
  945 
  946 /**
  947  * @brief This methods finds the first device that has specific activity scheduled.
  948  *
  949  * @param[in] fw_domain The framework domain object
  950  * @param[in] smp_activity A specified smp activity. The valid range is [1,5].
  951  *
  952  * @return SCIF_SAS_REMOTE_DEVICE_T The device that has specified smp activity scheduled.
  953  */
  954 SCIF_SAS_REMOTE_DEVICE_T * scif_sas_domain_find_device_has_scheduled_activity(
  955    SCIF_SAS_DOMAIN_T        * fw_domain,
  956    U8                         smp_activity
  957 )
  958 {
  959    SCI_ABSTRACT_ELEMENT_T * current_element =
  960       sci_abstract_list_get_front(&fw_domain->remote_device_list);
  961 
  962    SCIF_SAS_REMOTE_DEVICE_T * current_device;
  963    SMP_DISCOVER_RESPONSE_PROTOCOLS_T  dev_protocols;
  964 
  965    //config route table activity has higher priority than discover activity.
  966    while ( current_element != NULL )
  967    {
  968       current_device = (SCIF_SAS_REMOTE_DEVICE_T *)
  969                        sci_abstract_list_get_object(current_element);
  970 
  971       scic_remote_device_get_protocols(current_device->core_object,
  972                                        &dev_protocols);
  973 
  974       current_element =
  975          sci_abstract_list_get_next(current_element);
  976 
  977       if ( dev_protocols.u.bits.attached_smp_target
  978           && current_device->protocol_device.smp_device.scheduled_activity ==
  979                 smp_activity)
  980       {
  981          return current_device;
  982       }
  983    }
  984 
  985    return NULL;
  986 }
  987 
  988 
  989 /**
  990  * @brief This methods finds the smp device that has is_config_route_table_scheduled
  991  *        flag set to TRUE, and start config route table on it. If there is no
  992  *        smp device scheduled to config route table, find the smp device has
  993  *        is_discover_scheduled and start the smp discover process on them.
  994  *
  995  * @param[in] fw_domain The framework domain that to start smp discover process.
  996  *
  997  * @return NONE
  998  */
  999 void scif_sas_domain_start_smp_activity(
 1000   SCIF_SAS_DOMAIN_T        * fw_domain
 1001 )
 1002 {
 1003    SCIF_SAS_REMOTE_DEVICE_T * device_has_scheduled_activity = NULL;
 1004 
 1005    //first, find device that has config route table activity scheduled.
 1006    //config route table activity has higher priority than Discover.
 1007    device_has_scheduled_activity =
 1008       scif_sas_domain_find_device_has_scheduled_activity(
 1009          fw_domain,
 1010          SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_CONFIG_ROUTE_TABLE
 1011       );
 1012 
 1013    if (device_has_scheduled_activity != NULL)
 1014    {
 1015       scif_sas_smp_remote_device_configure_route_table(device_has_scheduled_activity);
 1016       device_has_scheduled_activity->protocol_device.smp_device.scheduled_activity =
 1017          SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_NONE;
 1018       return;
 1019    }
 1020 
 1021    //if no device has config route table activity scheduled, search again, find
 1022    //device has discover activity scheduled.
 1023    device_has_scheduled_activity =
 1024       scif_sas_domain_find_device_has_scheduled_activity(
 1025          fw_domain,
 1026          SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_DISCOVER
 1027       );
 1028 
 1029    if (device_has_scheduled_activity != NULL)
 1030       scif_sas_smp_remote_device_start_discover(device_has_scheduled_activity);
 1031 }
 1032 
 1033 
 1034 /**
 1035  * @brief This method starts domain's smp discover process from the top level expander.
 1036  *
 1037  * @param[in] fw_domain The framework domain that to start smp discover process.
 1038  @ @param[in] top_expander The top level expander device to start smp discover process.
 1039  *
 1040  * @return None
 1041  */
 1042 void scif_sas_domain_start_smp_discover(
 1043    SCIF_SAS_DOMAIN_T        * fw_domain,
 1044    SCIF_SAS_REMOTE_DEVICE_T * top_expander
 1045 )
 1046 {
 1047    SCI_ABSTRACT_ELEMENT_T * current_element =
 1048        sci_abstract_list_get_front(&fw_domain->remote_device_list);
 1049 
 1050    SCIF_SAS_REMOTE_DEVICE_T * current_device;
 1051 
 1052    // something changed behind expander
 1053    // mark all the device behind expander to be NOT
 1054    // is_currently_discovered.
 1055    while ( current_element != NULL )
 1056    {
 1057       current_device = (SCIF_SAS_REMOTE_DEVICE_T *)
 1058                            sci_abstract_list_get_object(current_element);
 1059 
 1060       current_device->is_currently_discovered = FALSE;
 1061 
 1062       //reset all the devices' port witdh except the top expander.
 1063       if (current_device->containing_device != NULL)
 1064          current_device->device_port_width = 1;
 1065 
 1066       current_element = sci_abstract_list_get_next(current_element);
 1067    }
 1068 
 1069    //expander device itself should be set to is_currently_discovered.
 1070    top_expander->is_currently_discovered = TRUE;
 1071 
 1072    //kick off the smp discover process.
 1073    scif_sas_smp_remote_device_start_discover(top_expander);
 1074 }
 1075 
 1076 
 1077 /**
 1078  * @brief This method continues domain's smp discover process and
 1079  *        may transit to READY state if all smp activities are done.
 1080  *
 1081  * @param[in] fw_domain The framework domain that to start smp discover process.
 1082  *
 1083  * @return None
 1084  */
 1085 void scif_sas_domain_continue_discover(
 1086    SCIF_SAS_DOMAIN_T * fw_domain
 1087 )
 1088 {
 1089    SCIF_LOG_TRACE((
 1090       sci_base_object_get_logger(fw_domain),
 1091       SCIF_LOG_OBJECT_DOMAIN | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
 1092       "scif_sas_domain_continue_discover(0x%x) enter\n",
 1093       fw_domain
 1094    ));
 1095 
 1096    if ( fw_domain->device_start_in_progress_count == 0
 1097        && !scif_sas_domain_is_in_smp_activity(fw_domain) )
 1098    {
 1099       //domain scrub the remote device list to see if there is a need
 1100       //to start smp discover on expander device. There may be no
 1101       //need to start any smp discover.
 1102       scif_sas_domain_start_smp_activity(fw_domain);
 1103 
 1104       //In domain discovery timeout case, we cancel all
 1105       //the smp activities, and terminate all the smp requests, then
 1106       //this routine is called. But the smp request may not done
 1107       //terminated. We want to guard the domain trasitting to READY
 1108       //by checking outstanding smp request count. If there is outstanding
 1109       //smp request, the domain will not transit to READY. Later when
 1110       //the smp request is terminated at smp remote device, this routine
 1111       //will be called then the domain will transit to READY state.
 1112       if ( ! scif_sas_domain_is_in_smp_activity(fw_domain)
 1113           && scif_sas_domain_get_smp_request_count(fw_domain) == 0)
 1114       {
 1115          //before domain transit to READY state, domain has some clean up
 1116          //work to do, such like update domain's remote devcie list.
 1117          scif_sas_domain_finish_discover(fw_domain);
 1118       }
 1119    }
 1120 }
 1121 
 1122 
 1123 /**
 1124  * @brief This method finishes domain's smp discover process and
 1125  *        update domain's remote device list.
 1126  *
 1127  * @param[in] fw_domain The framework domain that's to finish smp discover process.
 1128  *
 1129  * @return None
 1130  */
 1131 void scif_sas_domain_finish_discover(
 1132    SCIF_SAS_DOMAIN_T * fw_domain
 1133 )
 1134 {
 1135    SCIF_SAS_REMOTE_DEVICE_T * current_device = NULL;
 1136    SCI_ABSTRACT_ELEMENT_T   * current_element = NULL;
 1137 
 1138    SCIF_LOG_TRACE((
 1139       sci_base_object_get_logger(fw_domain),
 1140       SCIF_LOG_OBJECT_DOMAIN | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
 1141       "scif_sas_domain_finish_discover(0x%x) enter\n",
 1142       fw_domain
 1143    ));
 1144 
 1145    //need to scrub all the devices behind the expander. Check each
 1146    //device's discover_status. if the is_currently_discovered is FALSE, means
 1147    //the device is not been rediscovered. this device needs to be removed.
 1148    current_element = sci_abstract_list_get_front(&fw_domain->remote_device_list);
 1149    while (current_element != NULL )
 1150    {
 1151       current_device = (SCIF_SAS_REMOTE_DEVICE_T *)
 1152                           sci_abstract_list_get_object(current_element);
 1153 
 1154       //We must get the next element before we remove the current
 1155       //device. Or else, we will get wrong next_element, since the erased
 1156       //element has been put into free pool.
 1157       current_element = sci_abstract_list_get_next(current_element);
 1158 
 1159       if ( current_device->is_currently_discovered == FALSE )
 1160       {
 1161          // Notify the framework user of the device removal.
 1162          scif_cb_domain_device_removed(
 1163             fw_domain->controller, fw_domain, current_device
 1164          );
 1165       }
 1166    }
 1167 
 1168    sci_base_state_machine_change_state(
 1169       &fw_domain->parent.state_machine, SCI_BASE_DOMAIN_STATE_READY
 1170    );
 1171 }
 1172 
 1173 
 1174 
 1175 /**
 1176  * @brief This method remove an expander device and its child devices, in order to
 1177  *        deal with a detected illeagal phy connection.
 1178  *
 1179  * @param[in] fw_domain The domain that a expander belongs to.
 1180  * @param[in] fw_device The expander device to be removed.
 1181  *
 1182  * @return none.
 1183  */
 1184 void scif_sas_domain_remove_expander_device(
 1185    SCIF_SAS_DOMAIN_T        * fw_domain,
 1186    SCIF_SAS_REMOTE_DEVICE_T * fw_device
 1187 )
 1188 {
 1189    SCIF_SAS_SMP_REMOTE_DEVICE_T * smp_remote_device =
 1190       &fw_device->protocol_device.smp_device;
 1191 
 1192    SCI_FAST_LIST_ELEMENT_T     * element = smp_remote_device->smp_phy_list.list_head;
 1193    SCIF_SAS_SMP_PHY_T          * curr_smp_phy = NULL;
 1194    SCIF_SAS_REMOTE_DEVICE_T    * current_device = NULL;
 1195 
 1196    while (element != NULL)
 1197    {
 1198       curr_smp_phy = (SCIF_SAS_SMP_PHY_T*) sci_fast_list_get_object(element);
 1199       element = sci_fast_list_get_next(element);
 1200 
 1201       if ( curr_smp_phy->attached_device_type != SMP_NO_DEVICE_ATTACHED
 1202           && curr_smp_phy->u.end_device != NULL )
 1203       {
 1204          if (curr_smp_phy->attached_device_type == SMP_END_DEVICE_ONLY)
 1205             current_device = curr_smp_phy->u.end_device;
 1206          else
 1207             current_device = curr_smp_phy->u.attached_phy->owning_device;
 1208 
 1209          scif_cb_domain_device_removed(fw_domain->controller, fw_domain, current_device);
 1210       }
 1211    }
 1212 
 1213    //remove device itself
 1214    scif_cb_domain_device_removed(fw_domain->controller, fw_domain, fw_device);
 1215 }
 1216 
 1217 
 1218 /**
 1219  * @brief This method searches the whole domain and finds all the smp devices to
 1220  *        cancel their smp activities if there is any.
 1221  *
 1222  * @param[in] fw_domain The domain that its smp activities are to be canceled.
 1223  *
 1224  * @return none.
 1225  */
 1226 void scif_sas_domain_cancel_smp_activities(
 1227    SCIF_SAS_DOMAIN_T * fw_domain
 1228 )
 1229 {
 1230    SCI_ABSTRACT_ELEMENT_T * current_element =
 1231       sci_abstract_list_get_front(&fw_domain->remote_device_list);
 1232 
 1233    SCIF_SAS_REMOTE_DEVICE_T * current_device;
 1234 
 1235    //purge all the outstanding internal IOs in HPQ.
 1236    scif_sas_high_priority_request_queue_purge_domain(
 1237       &fw_domain->controller->hprq, fw_domain
 1238    );
 1239 
 1240    while ( current_element != NULL )
 1241    {
 1242       SMP_DISCOVER_RESPONSE_PROTOCOLS_T  dev_protocols;
 1243 
 1244       current_device = (SCIF_SAS_REMOTE_DEVICE_T *)
 1245                        sci_abstract_list_get_object(current_element);
 1246 
 1247       scic_remote_device_get_protocols(current_device->core_object,
 1248                                        &dev_protocols
 1249       );
 1250 
 1251       if (dev_protocols.u.bits.attached_smp_target)
 1252       {
 1253          scif_sas_smp_remote_device_cancel_smp_activity(current_device);
 1254       }
 1255 
 1256       current_element =
 1257          sci_abstract_list_get_next(current_element);
 1258    }
 1259 }
 1260 
 1261 
 1262 /**
 1263  * @brief This method searches the domain's request list and counts outstanding
 1264  *           smp IOs.
 1265  *
 1266  * @param[in] fw_domain The domain that its request list is to be searched.
 1267  *
 1268  * @return U8 The possible return value of this routine is 0 or 1.
 1269  */
 1270 U8 scif_sas_domain_get_smp_request_count(
 1271    SCIF_SAS_DOMAIN_T * fw_domain
 1272 )
 1273 {
 1274    SCI_FAST_LIST_ELEMENT_T * element = fw_domain->request_list.list_head;
 1275    SCIF_SAS_REQUEST_T      * request = NULL;
 1276    U8                        count = 0;
 1277    SCIC_TRANSPORT_PROTOCOL   protocol;
 1278 
 1279    // Cycle through the fast list of IO requests.  Terminate each
 1280    // outstanding requests that matches the criteria supplied by the
 1281    // caller.
 1282    while (element != NULL)
 1283    {
 1284       request = (SCIF_SAS_REQUEST_T*) sci_fast_list_get_object(element);
 1285       // The current element may be deleted from the list because of
 1286       // IO completion so advance to the next element early
 1287       element = sci_fast_list_get_next(element);
 1288 
 1289       protocol = scic_io_request_get_protocol(request->core_object);
 1290 
 1291       if ( protocol == SCIC_SMP_PROTOCOL)
 1292          count++;
 1293    }
 1294 
 1295    return count;
 1296 }
 1297 
 1298 
 1299 /**
 1300  * @brief This method start clear affiliation activities for smp devices in
 1301  *           this domain.
 1302  *
 1303  * @param[in] fw_domain The domain that its smp devices are scheduled to clear
 1304  *                affiliation for all the EA SATA devices.
 1305  *
 1306  * @return none.
 1307  */
 1308 void scif_sas_domain_start_clear_affiliation(
 1309    SCIF_SAS_DOMAIN_T * fw_domain
 1310 )
 1311 {
 1312    scif_sas_domain_schedule_clear_affiliation(fw_domain);
 1313    scif_sas_domain_continue_clear_affiliation(fw_domain);
 1314 }
 1315 
 1316 
 1317 /**
 1318  * @brief This method schedule clear affiliation activities for smp devices in
 1319  *           this domain.
 1320  *
 1321  * @param[in] fw_domain The domain that its smp devices are scheduled to clear
 1322  *                affiliation for all the EA SATA devices.
 1323  *
 1324  * @return none.
 1325  */
 1326 void scif_sas_domain_schedule_clear_affiliation(
 1327    SCIF_SAS_DOMAIN_T * fw_domain
 1328 )
 1329 {
 1330    SCI_ABSTRACT_ELEMENT_T * current_element =
 1331       sci_abstract_list_get_front(&fw_domain->remote_device_list);
 1332 
 1333    SCIF_SAS_REMOTE_DEVICE_T * current_device;
 1334    SMP_DISCOVER_RESPONSE_PROTOCOLS_T  dev_protocols;
 1335 
 1336    //config route table activity has higher priority than discover activity.
 1337    while ( current_element != NULL )
 1338    {
 1339       current_device = (SCIF_SAS_REMOTE_DEVICE_T *)
 1340                        sci_abstract_list_get_object(current_element);
 1341 
 1342       scic_remote_device_get_protocols(current_device->core_object,
 1343                                        &dev_protocols);
 1344 
 1345       current_element =
 1346          sci_abstract_list_get_next(current_element);
 1347 
 1348       if ( dev_protocols.u.bits.attached_smp_target )
 1349       {
 1350          current_device->protocol_device.smp_device.scheduled_activity =
 1351             SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_CLEAR_AFFILIATION;
 1352       }
 1353    }
 1354 }
 1355 
 1356 
 1357 /**
 1358  * @brief This method carries clear affiliation activities for a smp devices in
 1359  *           this domain during controller stop process.
 1360  *
 1361  * @param[in] fw_domain The domain that its smp devices are to clear
 1362  *                affiliation for all the EA SATA devices.
 1363  *
 1364  * @return none.
 1365  */
 1366 void scif_sas_domain_continue_clear_affiliation(
 1367    SCIF_SAS_DOMAIN_T * fw_domain
 1368 )
 1369 {
 1370    SCIF_SAS_REMOTE_DEVICE_T * smp_device =
 1371       scif_sas_domain_find_device_has_scheduled_activity(
 1372          fw_domain,
 1373          SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_CLEAR_AFFILIATION
 1374       );
 1375 
 1376    if (smp_device != NULL)
 1377       scif_sas_smp_remote_device_start_clear_affiliation(smp_device);
 1378    else
 1379    {
 1380       //This domain has done clear affiliation.
 1381       SCIF_SAS_CONTROLLER_T * fw_controller = fw_domain->controller;
 1382       fw_controller->current_domain_to_clear_affiliation++;
 1383 
 1384       //let controller continue to clear affiliation on other domains.
 1385       scif_sas_controller_clear_affiliation(fw_domain->controller);
 1386    }
 1387 }
 1388 
 1389 
 1390 /**
 1391  * @brief This method releases resource for a framework domain.
 1392  *
 1393  * @param[in] fw_controller This parameter specifies the framework
 1394  *            controller, its associated domain's resources are to be released.
 1395  * @param[in] fw_domain This parameter specifies the framework
 1396  *            domain whose resources are to be released.
 1397  */
 1398 void scif_sas_domain_release_resource(
 1399    SCIF_SAS_CONTROLLER_T * fw_controller,
 1400    SCIF_SAS_DOMAIN_T     * fw_domain
 1401 )
 1402 {
 1403    if (fw_domain->operation.timer != NULL)
 1404    {
 1405       scif_cb_timer_destroy(fw_controller, fw_domain->operation.timer);
 1406       fw_domain->operation.timer = NULL;
 1407    }
 1408 }
 1409 
 1410 
 1411 /**
 1412  * @brief This method finds the a EA device that has target reset scheduled.
 1413  *
 1414  * @param[in] fw_domain The framework domain object
 1415  *
 1416  * @return SCIF_SAS_REMOTE_DEVICE_T The EA device that has target reset scheduled.
 1417  */
 1418 SCIF_SAS_REMOTE_DEVICE_T * scif_sas_domain_find_next_ea_target_reset(
 1419    SCIF_SAS_DOMAIN_T     * fw_domain
 1420 )
 1421 {
 1422    SCI_ABSTRACT_ELEMENT_T   * current_element;
 1423    SCIF_SAS_REMOTE_DEVICE_T * current_device;
 1424 
 1425    SCIF_LOG_TRACE((
 1426       sci_base_object_get_logger(fw_domain),
 1427       SCIF_LOG_OBJECT_DOMAIN,
 1428       "scif_sas_domain_find_next_ea_target_reset(0x%x) enter\n",
 1429       fw_domain
 1430    ));
 1431 
 1432    //search through domain's device list to find the first sata device on spinup_hold
 1433    current_element = sci_abstract_list_get_front(&fw_domain->remote_device_list);
 1434    while (current_element != NULL )
 1435    {
 1436       current_device = (SCIF_SAS_REMOTE_DEVICE_T *)
 1437                        sci_abstract_list_get_object(current_element);
 1438 
 1439       current_element = sci_abstract_list_get_next(current_element);
 1440 
 1441       if ( current_device->ea_target_reset_request_scheduled != NULL )
 1442       {
 1443          return current_device;
 1444       }
 1445    }
 1446 
 1447    return NULL;
 1448 }
 1449 
 1450 #if !defined(DISABLE_WIDE_PORTED_TARGETS)
 1451 /**
 1452  * @brief This method update the direct attached device port width.
 1453  *
 1454  * @param[in] fw_domain The framework domain object
 1455  * @param[in] port The associated port object which recently has link up/down
 1456  *                 event happened.
 1457  *
 1458  * @return none
 1459  */
 1460 void scif_sas_domain_update_device_port_width(
 1461    SCIF_SAS_DOMAIN_T * fw_domain,
 1462    SCI_PORT_HANDLE_T   port
 1463 )
 1464 {
 1465    SCIF_SAS_REMOTE_DEVICE_T * fw_device;
 1466    SCIC_PORT_PROPERTIES_T     properties;
 1467    U8                         new_port_width = 0;
 1468 
 1469    SCIF_LOG_TRACE((
 1470       sci_base_object_get_logger(fw_domain),
 1471       SCIF_LOG_OBJECT_DOMAIN,
 1472       "scif_sas_domain_update_device_port_width(0x%x, 0x%x) enter\n",
 1473       fw_domain, port
 1474    ));
 1475 
 1476    scic_port_get_properties(port, &properties);
 1477 
 1478    fw_device = (SCIF_SAS_REMOTE_DEVICE_T *)
 1479                   scif_domain_get_device_by_sas_address(
 1480                   fw_domain, &properties.remote.sas_address
 1481                );
 1482 
 1483    // If the device already existed in the domain, it is a wide port SSP target,
 1484    // we need to update its port width.
 1485    if (fw_device != SCI_INVALID_HANDLE)
 1486    {
 1487       SMP_DISCOVER_RESPONSE_PROTOCOLS_T  dev_protocols;
 1488       scic_remote_device_get_protocols(fw_device->core_object, &dev_protocols);
 1489 
 1490       if (dev_protocols.u.bits.attached_ssp_target)
 1491       {
 1492          //Get accurate port width from port's phy mask for a DA device.
 1493          SCI_GET_BITS_SET_COUNT(properties.phy_mask, new_port_width);
 1494 
 1495          scif_sas_remote_device_update_port_width(fw_device, new_port_width);
 1496       }
 1497    }
 1498 }
 1499 #endif //#if !defined(DISABLE_WIDE_PORTED_TARGETS)
 1500 
 1501 
 1502 #ifdef SCI_LOGGING
 1503 /**
 1504  * This method will turn on logging of domain state changes.
 1505  *
 1506  * @param[in] fw_domain The domain for which the state logging is to be turned
 1507  *       on.
 1508  */
 1509 void scif_sas_domain_initialize_state_logging(
 1510    SCIF_SAS_DOMAIN_T *fw_domain
 1511 )
 1512 {
 1513    sci_base_state_machine_logger_initialize(
 1514       &fw_domain->parent.state_machine_logger,
 1515       &fw_domain->parent.state_machine,
 1516       &fw_domain->parent.parent,
 1517       scif_cb_logger_log_states,
 1518       "SCIF_SAS_DOMAIN_T", "base state machine",
 1519       SCIF_LOG_OBJECT_DOMAIN
 1520    );
 1521 }
 1522 
 1523 /**
 1524  * This method will turn off logging of domain state changes.
 1525  *
 1526  * @param[in] fw_domain The domain for which the state logging is to be turned
 1527  *       off.
 1528  */
 1529 void scif_sas_domain_deinitialize_state_logging(
 1530    SCIF_SAS_DOMAIN_T *fw_domain
 1531 )
 1532 {
 1533    sci_base_state_machine_logger_deinitialize(
 1534       &fw_domain->parent.state_machine_logger,
 1535       &fw_domain->parent.state_machine
 1536    );
 1537 }
 1538 #endif

Cache object: 59faa7065dbc92a6a413dd2b49fe3c91


[ 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.