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/scic_sds_port.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 for the public and protected
   62  *        methods for the SCIC_SDS_PORT object.
   63  */
   64 
   65 #include <dev/isci/scil/scic_phy.h>
   66 #include <dev/isci/scil/scic_port.h>
   67 #include <dev/isci/scil/scic_controller.h>
   68 #include <dev/isci/scil/scic_user_callback.h>
   69 
   70 #include <dev/isci/scil/scic_sds_controller.h>
   71 #include <dev/isci/scil/scic_sds_port.h>
   72 #include <dev/isci/scil/scic_sds_phy.h>
   73 #include <dev/isci/scil/scic_sds_remote_device.h>
   74 #include <dev/isci/scil/scic_sds_request.h>
   75 #include <dev/isci/scil/scic_sds_port_registers.h>
   76 #include <dev/isci/scil/scic_sds_logger.h>
   77 #include <dev/isci/scil/scic_sds_phy_registers.h>
   78 
   79 #include <dev/isci/scil/intel_sas.h>
   80 #include <dev/isci/scil/scic_sds_remote_node_context.h>
   81 #include <dev/isci/scil/sci_util.h>
   82 
   83 #define SCIC_SDS_PORT_MIN_TIMER_COUNT  (SCI_MAX_PORTS)
   84 #define SCIC_SDS_PORT_MAX_TIMER_COUNT  (SCI_MAX_PORTS)
   85 
   86 #define SCIC_SDS_PORT_HARD_RESET_TIMEOUT  (1000)
   87 #define SCU_DUMMY_INDEX    (0xFFFF)
   88 
   89 /**
   90  * This method will return a TRUE value if the specified phy can be assigned
   91  * to this port
   92  *
   93  * The following is a list of phys for each port that are allowed:
   94  * - Port 0 - 3 2 1 0
   95  * - Port 1 -     1
   96  * - Port 2 - 3 2
   97  * - Port 3 - 3
   98  *
   99  * This method doesn't preclude all configurations.  It merely ensures
  100  * that a phy is part of the allowable set of phy identifiers for
  101  * that port.  For example, one could assign phy 3 to port 0 and no other
  102  * phys.  Please refer to scic_sds_port_is_phy_mask_valid() for
  103  * information regarding whether the phy_mask for a port can be supported.
  104  *
  105  * @param[in] this_port This is the port object to which the phy is being
  106  *       assigned.
  107  * @param[in] phy_index This is the phy index that is being assigned to the
  108  *       port.
  109  *
  110  * @return BOOL
  111  * @retval TRUE if this is a valid phy assignment for the port
  112  * @retval FALSE if this is not a valid phy assignment for the port
  113  */
  114 BOOL scic_sds_port_is_valid_phy_assignment(
  115    SCIC_SDS_PORT_T *this_port,
  116    U32              phy_index
  117 )
  118 {
  119    // Initialize to invalid value.
  120    U32  existing_phy_index = SCI_MAX_PHYS;
  121    U32  index;
  122 
  123    if ((this_port->physical_port_index == 1) && (phy_index != 1))
  124    {
  125       return FALSE;
  126    }
  127 
  128    if (this_port->physical_port_index == 3 && phy_index != 3)
  129    {
  130       return FALSE;
  131    }
  132 
  133    if (
  134           (this_port->physical_port_index == 2)
  135        && ((phy_index == 0) || (phy_index == 1))
  136       )
  137    {
  138       return FALSE;
  139    }
  140 
  141    for (index = 0; index < SCI_MAX_PHYS; index++)
  142    {
  143       if (  (this_port->phy_table[index] != NULL)
  144          && (index != phy_index) )
  145       {
  146          existing_phy_index = index;
  147       }
  148    }
  149 
  150    // Ensure that all of the phys in the port are capable of
  151    // operating at the same maximum link rate.
  152    if (
  153          (existing_phy_index < SCI_MAX_PHYS)
  154       && (this_port->owning_controller->user_parameters.sds1.phys[
  155              phy_index].max_speed_generation !=
  156           this_port->owning_controller->user_parameters.sds1.phys[
  157              existing_phy_index].max_speed_generation)
  158       )
  159       return FALSE;
  160 
  161    return TRUE;
  162 }
  163 
  164 /**
  165  * @brief This method requests a list (mask) of the phys contained in the
  166  *        supplied SAS port.
  167  *
  168  * @param[in]  this_port a handle corresponding to the SAS port for which
  169  *             to return the phy mask.
  170  *
  171  * @return Return a bit mask indicating which phys are a part of this port.
  172  *         Each bit corresponds to a phy identifier (e.g. bit 0 = phy id 0).
  173  */
  174 U32 scic_sds_port_get_phys(
  175    SCIC_SDS_PORT_T * this_port
  176 )
  177 {
  178    U32 index;
  179    U32 mask;
  180 
  181    SCIC_LOG_TRACE((
  182       sci_base_object_get_logger(this_port),
  183       SCIC_LOG_OBJECT_PORT,
  184       "scic_sds_port_get_phys(0x%x) enter\n",
  185       this_port
  186    ));
  187 
  188    mask = 0;
  189 
  190    for (index = 0; index < SCI_MAX_PHYS; index++)
  191    {
  192       if (this_port->phy_table[index] != NULL)
  193       {
  194          mask |= (1 << index);
  195       }
  196    }
  197 
  198    return mask;
  199 }
  200 
  201 /**
  202  * This method will return a TRUE value if the port's phy mask can be
  203  * supported by the SCU.
  204  *
  205  * The following is a list of valid PHY mask configurations for each
  206  * port:
  207  * - Port 0 - [[3  2] 1] 0
  208  * - Port 1 -        [1]
  209  * - Port 2 - [[3] 2]
  210  * - Port 3 -  [3]
  211  *
  212  * @param[in] this_port This is the port object for which to determine
  213  *       if the phy mask can be supported.
  214  *
  215  * @return This method returns a boolean indication specifying if the
  216  *         phy mask can be supported.
  217  * @retval TRUE if this is a valid phy assignment for the port
  218  * @retval FALSE if this is not a valid phy assignment for the port
  219  */
  220 BOOL scic_sds_port_is_phy_mask_valid(
  221    SCIC_SDS_PORT_T *this_port,
  222    U32              phy_mask
  223 )
  224 {
  225    if (this_port->physical_port_index == 0)
  226    {
  227       if (  ((phy_mask & 0x0F) == 0x0F)
  228          || ((phy_mask & 0x03) == 0x03)
  229          || ((phy_mask & 0x01) == 0x01)
  230          || (phy_mask == 0) )
  231          return TRUE;
  232    }
  233    else if (this_port->physical_port_index == 1)
  234    {
  235       if (  ((phy_mask & 0x02) == 0x02)
  236          || (phy_mask == 0) )
  237          return TRUE;
  238    }
  239    else if (this_port->physical_port_index == 2)
  240    {
  241       if (  ((phy_mask & 0x0C) == 0x0C)
  242          || ((phy_mask & 0x04) == 0x04)
  243          || (phy_mask == 0) )
  244          return TRUE;
  245    }
  246    else if (this_port->physical_port_index == 3)
  247    {
  248       if (  ((phy_mask & 0x08) == 0x08)
  249          || (phy_mask == 0) )
  250          return TRUE;
  251    }
  252 
  253    return FALSE;
  254 }
  255 
  256 /**
  257  * This method retrieves a currently active (i.e. connected) phy
  258  * contained in the port.  Currently, the lowest order phy that is
  259  * connected is returned.
  260  *
  261  * @param[in] this_port This parameter specifies the port from which
  262  *            to return a connected phy.
  263  *
  264  * @return This method returns a pointer to a SCIS_SDS_PHY object.
  265  * @retval NULL This value is returned if there are no currently
  266  *         active (i.e. connected to a remote end point) phys
  267  *         contained in the port.
  268  * @retval All other values specify a SCIC_SDS_PHY object that is
  269  *         active in the port.
  270  */
  271 SCIC_SDS_PHY_T * scic_sds_port_get_a_connected_phy(
  272    SCIC_SDS_PORT_T *this_port
  273 )
  274 {
  275    U32             index;
  276    SCIC_SDS_PHY_T *phy;
  277 
  278    for (index = 0; index < SCI_MAX_PHYS; index++)
  279    {
  280       // Ensure that the phy is both part of the port and currently
  281       // connected to the remote end-point.
  282       phy = this_port->phy_table[index];
  283       if (
  284             (phy != NULL)
  285          && scic_sds_port_active_phy(this_port, phy)
  286          )
  287       {
  288          return phy;
  289       }
  290    }
  291 
  292    return NULL;
  293 }
  294 
  295 /**
  296  * This method attempts to make the assignment of the phy to the port.
  297  * If successful the phy is assigned to the ports phy table.
  298  *
  299  * @param[in, out] port The port object to which the phy assignement
  300  *                 is being made.
  301  * @param[in, out] phy The phy which is being assigned to the port.
  302  *
  303  * @return BOOL
  304  * @retval TRUE if the phy assignment can be made.
  305  * @retval FALSE if the phy assignement can not be made.
  306  *
  307  * @note This is a functional test that only fails if the phy is currently
  308  *       assigned to a different port.
  309  */
  310 SCI_STATUS scic_sds_port_set_phy(
  311    SCIC_SDS_PORT_T *port,
  312    SCIC_SDS_PHY_T  *phy
  313 )
  314 {
  315    // Check to see if we can add this phy to a port
  316    // that means that the phy is not part of a port and that the port does
  317    // not already have a phy assigned to the phy index.
  318    if (
  319          (port->phy_table[phy->phy_index] == SCI_INVALID_HANDLE)
  320       && (scic_sds_phy_get_port(phy) == SCI_INVALID_HANDLE)
  321       && scic_sds_port_is_valid_phy_assignment(port, phy->phy_index)
  322       )
  323    {
  324       // Phy is being added in the stopped state so we are in MPC mode
  325       // make logical port index = physical port index
  326       port->logical_port_index = port->physical_port_index;
  327       port->phy_table[phy->phy_index] = phy;
  328       scic_sds_phy_set_port(phy, port);
  329 
  330       return SCI_SUCCESS;
  331    }
  332 
  333    return SCI_FAILURE;
  334 }
  335 
  336 /**
  337  * This method will clear the phy assigned to this port.  This method fails
  338  * if this phy is not currently assigned to this port.
  339  *
  340  * @param[in, out] port The port from which the phy is being cleared.
  341  * @param[in, out] phy The phy being cleared from the port.
  342  *
  343  * @return BOOL
  344  * @retval TRUE if the phy is removed from the port.
  345  * @retval FALSE if this phy is not assined to this port.
  346  */
  347 SCI_STATUS scic_sds_port_clear_phy(
  348    SCIC_SDS_PORT_T *port,
  349    SCIC_SDS_PHY_T  *phy
  350 )
  351 {
  352    // Make sure that this phy is part of this port
  353    if (
  354            (port->phy_table[phy->phy_index] == phy)
  355         && (scic_sds_phy_get_port(phy) == port)
  356       )
  357    {
  358       // Yep it is assigned to this port so remove it
  359       scic_sds_phy_set_port(
  360          phy,
  361          &scic_sds_port_get_controller(port)->port_table[SCI_MAX_PORTS]
  362       );
  363 
  364       port->phy_table[phy->phy_index] = SCI_INVALID_HANDLE;
  365 
  366       return SCI_SUCCESS;
  367    }
  368 
  369    return SCI_FAILURE;
  370 }
  371 
  372 /**
  373  * This method will add a PHY to the selected port.
  374  *
  375  * @param[in] this_port This parameter specifies the port in which the phy will
  376  *            be added.
  377  *
  378  * @param[in] the_phy This parameter is the phy which is to be added to the
  379  *            port.
  380  *
  381  * @return This method returns an SCI_STATUS.
  382  * @retval SCI_SUCCESS the phy has been added to the port.
  383  * @retval Any other status is failre to add the phy to the port.
  384  */
  385 SCI_STATUS scic_sds_port_add_phy(
  386    SCIC_SDS_PORT_T * this_port,
  387    SCIC_SDS_PHY_T  * the_phy
  388 )
  389 {
  390    return this_port->state_handlers->parent.add_phy_handler(
  391                                           &this_port->parent, &the_phy->parent);
  392 }
  393 
  394 
  395 /**
  396  * This method will remove the PHY from the selected PORT.
  397  *
  398  * @param[in] this_port This parameter specifies the port in which the phy will
  399  *            be added.
  400  *
  401  * @param[in] the_phy This parameter is the phy which is to be added to the
  402  *            port.
  403  *
  404  * @return This method returns an SCI_STATUS.
  405  * @retval SCI_SUCCESS the phy has been removed from the port.
  406  * @retval Any other status is failre to add the phy to the port.
  407  */
  408 SCI_STATUS scic_sds_port_remove_phy(
  409    SCIC_SDS_PORT_T * this_port,
  410    SCIC_SDS_PHY_T  * the_phy
  411 )
  412 {
  413    return this_port->state_handlers->parent.remove_phy_handler(
  414                                           &this_port->parent, &the_phy->parent);
  415 }
  416 
  417 /**
  418  * @brief This method requests the SAS address for the supplied SAS port
  419  *        from the SCI implementation.
  420  *
  421  * @param[in]  this_port a handle corresponding to the SAS port for which
  422  *             to return the SAS address.
  423  * @param[out] sas_address This parameter specifies a pointer to a SAS
  424  *             address structure into which the core will copy the SAS
  425  *             address for the port.
  426  *
  427  * @return none
  428  */
  429 void scic_sds_port_get_sas_address(
  430    SCIC_SDS_PORT_T   * this_port,
  431    SCI_SAS_ADDRESS_T * sas_address
  432 )
  433 {
  434    U32 index;
  435 
  436    SCIC_LOG_TRACE((
  437       sci_base_object_get_logger(this_port),
  438       SCIC_LOG_OBJECT_PORT,
  439       "scic_sds_port_get_sas_address(0x%x, 0x%x) enter\n",
  440       this_port, sas_address
  441    ));
  442 
  443    sas_address->high = 0;
  444    sas_address->low  = 0;
  445 
  446    for (index = 0; index < SCI_MAX_PHYS; index++)
  447    {
  448       if (this_port->phy_table[index] != NULL)
  449       {
  450          scic_sds_phy_get_sas_address(this_port->phy_table[index], sas_address);
  451       }
  452    }
  453 }
  454 
  455 /**
  456  * @brief This method will indicate which protocols are supported by this
  457  *        port.
  458  *
  459  * @param[in]  this_port a handle corresponding to the SAS port for which
  460  *             to return the supported protocols.
  461  * @param[out] protocols This parameter specifies a pointer to an IAF
  462  *             protocol field structure into which the core will copy
  463  *             the protocol values for the port.  The values are
  464  *             returned as part of a bit mask in order to allow for
  465  *             multi-protocol support.
  466  *
  467  * @return none
  468  */
  469 static
  470 void scic_sds_port_get_protocols(
  471    SCIC_SDS_PORT_T                            * this_port,
  472    SCI_SAS_IDENTIFY_ADDRESS_FRAME_PROTOCOLS_T * protocols
  473 )
  474 {
  475    U8 index;
  476 
  477    SCIC_LOG_TRACE((
  478       sci_base_object_get_logger(this_port),
  479       SCIC_LOG_OBJECT_PORT,
  480       "scic_sds_port_get_protocols(0x%x, 0x%x) enter\n",
  481       this_port, protocols
  482    ));
  483 
  484    protocols->u.all = 0;
  485 
  486    for (index = 0; index < SCI_MAX_PHYS; index++)
  487    {
  488       if (this_port->phy_table[index] != NULL)
  489       {
  490          scic_sds_phy_get_protocols(this_port->phy_table[index], protocols);
  491       }
  492    }
  493 }
  494 
  495 /**
  496  * @brief This method requests the SAS address for the device directly
  497  *        attached to this SAS port.
  498  *
  499  * @param[in]  this_port a handle corresponding to the SAS port for which
  500  *             to return the SAS address.
  501  * @param[out] sas_address This parameter specifies a pointer to a SAS
  502  *             address structure into which the core will copy the SAS
  503  *             address for the device directly attached to the port.
  504  *
  505  * @return none
  506  */
  507 void scic_sds_port_get_attached_sas_address(
  508    SCIC_SDS_PORT_T   * this_port,
  509    SCI_SAS_ADDRESS_T * sas_address
  510 )
  511 {
  512    SCI_SAS_IDENTIFY_ADDRESS_FRAME_PROTOCOLS_T protocols;
  513    SCIC_SDS_PHY_T  *phy;
  514 
  515    SCIC_LOG_TRACE((
  516       sci_base_object_get_logger(this_port),
  517       SCIC_LOG_OBJECT_PORT,
  518       "scic_sds_port_get_attached_sas_address(0x%x, 0x%x) enter\n",
  519       this_port, sas_address
  520    ));
  521 
  522    // Ensure that the phy is both part of the port and currently
  523    // connected to the remote end-point.
  524    phy = scic_sds_port_get_a_connected_phy(this_port);
  525    if (phy != NULL)
  526    {
  527       scic_sds_phy_get_attached_phy_protocols(phy, &protocols);
  528 
  529       if (!protocols.u.bits.stp_target)
  530       {
  531          scic_sds_phy_get_attached_sas_address(phy, sas_address);
  532       }
  533       else
  534       {
  535          scic_sds_phy_get_sas_address(phy, sas_address);
  536          sas_address->low += phy->phy_index;
  537 
  538                  //Need to make up attached STP device's SAS address in
  539                  //the same order as recorded IAF from SSP device.
  540                  sas_address->high = SCIC_SWAP_DWORD(sas_address->high);
  541                  sas_address->low = SCIC_SWAP_DWORD(sas_address->low);
  542       }
  543    }
  544    else
  545    {
  546       sas_address->high = 0;
  547       sas_address->low  = 0;
  548    }
  549 }
  550 
  551 /**
  552  * @brief This method will indicate which protocols are supported by this
  553  *        remote device.
  554  *
  555  * @param[in]  this_port a handle corresponding to the SAS port for which
  556  *             to return the supported protocols.
  557  * @param[out] protocols This parameter specifies a pointer to an IAF
  558  *             protocol field structure into which the core will copy
  559  *             the protocol values for the port.  The values are
  560  *             returned as part of a bit mask in order to allow for
  561  *             multi-protocol support.
  562  *
  563  * @return none
  564  */
  565 void scic_sds_port_get_attached_protocols(
  566    SCIC_SDS_PORT_T                            * this_port,
  567    SCI_SAS_IDENTIFY_ADDRESS_FRAME_PROTOCOLS_T * protocols
  568 )
  569 {
  570    SCIC_SDS_PHY_T  *phy;
  571 
  572    SCIC_LOG_TRACE((
  573       sci_base_object_get_logger(this_port),
  574       SCIC_LOG_OBJECT_PORT,
  575       "scic_sds_port_get_attached_protocols(0x%x, 0x%x) enter\n",
  576       this_port, protocols
  577    ));
  578 
  579    // Ensure that the phy is both part of the port and currently
  580    // connected to the remote end-point.
  581    phy = scic_sds_port_get_a_connected_phy(this_port);
  582    if (phy != NULL)
  583       scic_sds_phy_get_attached_phy_protocols(phy, protocols);
  584    else
  585       protocols->u.all = 0;
  586 }
  587 
  588 /**
  589  * @brief This method returns the amount of memory required for a port
  590  *        object.
  591  *
  592  * @return U32
  593  */
  594 U32 scic_sds_port_get_object_size(void)
  595 {
  596    return sizeof(SCIC_SDS_PORT_T);
  597 }
  598 
  599 /**
  600  * @brief This method returns the minimum number of timers required for all
  601  *        port objects.
  602  *
  603  * @return U32
  604  */
  605 U32 scic_sds_port_get_min_timer_count(void)
  606 {
  607    return SCIC_SDS_PORT_MIN_TIMER_COUNT;
  608 }
  609 
  610 /**
  611  * @brief This method returns the maximum number of timers required for all
  612  *        port objects.
  613  *
  614  * @return U32
  615  */
  616 U32 scic_sds_port_get_max_timer_count(void)
  617 {
  618    return SCIC_SDS_PORT_MAX_TIMER_COUNT;
  619 }
  620 
  621 #ifdef SCI_LOGGING
  622 void scic_sds_port_initialize_state_logging(
  623    SCIC_SDS_PORT_T *this_port
  624 )
  625 {
  626    sci_base_state_machine_logger_initialize(
  627       &this_port->parent.state_machine_logger,
  628       &this_port->parent.state_machine,
  629       &this_port->parent.parent,
  630       scic_cb_logger_log_states,
  631       "SCIC_SDS_PORT_T", "base state machine",
  632       SCIC_LOG_OBJECT_PORT
  633    );
  634 
  635    sci_base_state_machine_logger_initialize(
  636       &this_port->ready_substate_machine_logger,
  637       &this_port->ready_substate_machine,
  638       &this_port->parent.parent,
  639       scic_cb_logger_log_states,
  640       "SCIC_SDS_PORT_T", "ready substate machine",
  641       SCIC_LOG_OBJECT_PORT
  642    );
  643 }
  644 #endif
  645 
  646 /**
  647  * This routine will construct a dummy remote node context data structure
  648  * This structure will be posted to the hardware to work around a scheduler
  649  * error in the hardware.
  650  *
  651  * @param[in] this_port The logical port on which we need to create the
  652  *            remote node context.
  653  * @param[in] rni The remote node index for this remote node context.
  654  *
  655  * @return none
  656  */
  657 static
  658 void scic_sds_port_construct_dummy_rnc(
  659    SCIC_SDS_PORT_T *this_port,
  660    U16              rni
  661 )
  662 {
  663    SCU_REMOTE_NODE_CONTEXT_T * rnc;
  664 
  665    rnc = &(this_port->owning_controller->remote_node_context_table[rni]);
  666 
  667    memset(rnc, 0, sizeof(SCU_REMOTE_NODE_CONTEXT_T));
  668 
  669    rnc->ssp.remote_sas_address_hi = 0;
  670    rnc->ssp.remote_sas_address_lo = 0;
  671 
  672    rnc->ssp.remote_node_index = rni;
  673    rnc->ssp.remote_node_port_width = 1;
  674    rnc->ssp.logical_port_index = this_port->physical_port_index;
  675 
  676    rnc->ssp.nexus_loss_timer_enable = FALSE;
  677    rnc->ssp.check_bit = FALSE;
  678    rnc->ssp.is_valid = TRUE;
  679    rnc->ssp.is_remote_node_context = TRUE;
  680    rnc->ssp.function_number = 0;
  681    rnc->ssp.arbitration_wait_time = 0;
  682 }
  683 
  684 /**
  685  * This routine will construct a dummy task context data structure.  This
  686  * structure will be posted to the hardwre to work around a scheduler error
  687  * in the hardware.
  688  *
  689  * @param[in] this_port The logical port on which we need to create the
  690  *            remote node context.
  691  *            context.
  692  * @param[in] tci The remote node index for this remote node context.
  693  *
  694  */
  695 static
  696 void scic_sds_port_construct_dummy_task(
  697    SCIC_SDS_PORT_T *this_port,
  698    U16              tci
  699 )
  700 {
  701    SCU_TASK_CONTEXT_T * task_context;
  702 
  703    task_context = scic_sds_controller_get_task_context_buffer(this_port->owning_controller, tci);
  704 
  705    memset(task_context, 0, sizeof(SCU_TASK_CONTEXT_T));
  706 
  707    task_context->abort = 0;
  708    task_context->priority = 0;
  709    task_context->initiator_request = 1;
  710    task_context->connection_rate = 1;
  711    task_context->protocol_engine_index = 0;
  712    task_context->logical_port_index = this_port->physical_port_index;
  713    task_context->protocol_type = SCU_TASK_CONTEXT_PROTOCOL_SSP;
  714    task_context->task_index = scic_sds_io_tag_get_index(tci);
  715    task_context->valid = SCU_TASK_CONTEXT_VALID;
  716    task_context->context_type = SCU_TASK_CONTEXT_TYPE;
  717 
  718    task_context->remote_node_index = this_port->reserved_rni;
  719    task_context->command_code = 0;
  720 
  721    task_context->link_layer_control = 0;
  722    task_context->do_not_dma_ssp_good_response = 1;
  723    task_context->strict_ordering = 0;
  724    task_context->control_frame = 0;
  725    task_context->timeout_enable = 0;
  726    task_context->block_guard_enable = 0;
  727 
  728    task_context->address_modifier = 0;
  729 
  730    task_context->task_phase = 0x01;
  731 }
  732 
  733 /**
  734  * This routine will free any allocated dummy resources for this port.
  735  *
  736  * @param[in, out] this_port The port on which the resources are being destroyed.
  737  */
  738 static
  739 void scic_sds_port_destroy_dummy_resources(
  740    SCIC_SDS_PORT_T * this_port
  741 )
  742 {
  743    if (this_port->reserved_tci != SCU_DUMMY_INDEX)
  744    {
  745       scic_controller_free_io_tag(
  746          this_port->owning_controller, this_port->reserved_tci
  747       );
  748    }
  749 
  750    if (this_port->reserved_rni != SCU_DUMMY_INDEX)
  751    {
  752       scic_sds_remote_node_table_release_remote_node_index(
  753          &this_port->owning_controller->available_remote_nodes, 1, this_port->reserved_rni
  754       );
  755    }
  756 
  757    this_port->reserved_rni = SCU_DUMMY_INDEX;
  758    this_port->reserved_tci = SCU_DUMMY_INDEX;
  759 }
  760 
  761 /**
  762  * @brief
  763  *
  764  * @param[in] this_port
  765  * @param[in] port_index
  766  * @param[in] owning_controller
  767  */
  768 void scic_sds_port_construct(
  769    SCIC_SDS_PORT_T         *this_port,
  770    U8                      port_index,
  771    SCIC_SDS_CONTROLLER_T   *owning_controller
  772 )
  773 {
  774    U32 index;
  775 
  776    sci_base_port_construct(
  777       &this_port->parent,
  778       sci_base_object_get_logger(owning_controller),
  779       scic_sds_port_state_table
  780    );
  781 
  782    sci_base_state_machine_construct(
  783       scic_sds_port_get_ready_substate_machine(this_port),
  784       &this_port->parent.parent,
  785       scic_sds_port_ready_substate_table,
  786       SCIC_SDS_PORT_READY_SUBSTATE_WAITING
  787    );
  788 
  789    scic_sds_port_initialize_state_logging(this_port);
  790 
  791    this_port->logical_port_index  = SCIC_SDS_DUMMY_PORT;
  792    this_port->physical_port_index = port_index;
  793    this_port->active_phy_mask     = 0;
  794    this_port->enabled_phy_mask    = 0;
  795    this_port->owning_controller = owning_controller;
  796 
  797    this_port->started_request_count = 0;
  798    this_port->assigned_device_count = 0;
  799 
  800    this_port->reserved_rni = SCU_DUMMY_INDEX;
  801    this_port->reserved_tci = SCU_DUMMY_INDEX;
  802 
  803    this_port->timer_handle = SCI_INVALID_HANDLE;
  804 
  805    this_port->port_task_scheduler_registers = NULL;
  806 
  807    for (index = 0; index < SCI_MAX_PHYS; index++)
  808    {
  809       this_port->phy_table[index] = NULL;
  810    }
  811 }
  812 
  813 /**
  814  * @brief This method performs initialization of the supplied port.
  815  *        Initialization includes:
  816  *        - state machine initialization
  817  *        - member variable initialization
  818  *        - configuring the phy_mask
  819  *
  820  * @param[in] this_port
  821  * @param[in] transport_layer_registers
  822  * @param[in] port_task_scheduler_registers
  823  * @param[in] port_configuration_regsiter
  824  *
  825  * @return SCI_STATUS
  826  * @retval SCI_FAILURE_UNSUPPORTED_PORT_CONFIGURATION This value is
  827  *         returned if the phy being added to the port
  828  */
  829 SCI_STATUS scic_sds_port_initialize(
  830    SCIC_SDS_PORT_T *this_port,
  831    void            *port_task_scheduler_registers,
  832    void            *port_configuration_regsiter,
  833    void            *viit_registers
  834 )
  835 {
  836    this_port->port_task_scheduler_registers  = port_task_scheduler_registers;
  837    this_port->port_pe_configuration_register = port_configuration_regsiter;
  838    this_port->viit_registers                 = viit_registers;
  839 
  840    return SCI_SUCCESS;
  841 }
  842 
  843 /**
  844  * This method is the a general link up handler for the SCIC_SDS_PORT object.
  845  * This function will determine if this SCIC_SDS_PHY can
  846  * be assigned to this SCIC_SDS_PORT object. If the SCIC_SDS_PHY object can
  847  * is not a valid PHY for this port then the function will notify the SCIC_USER.
  848  * A PHY can only be part of a port if it's attached SAS ADDRESS is the same as
  849  * all other PHYs in the same port.
  850  *
  851  * @param[in] this_port This is the SCIC_SDS_PORT object for which has a phy
  852  *       that has gone link up.
  853  * @param[in] the_phy This is the SCIC_SDS_PHY object that has gone link up.
  854  * @param[in] do_notify_user This parameter specifies whether to inform
  855  *            the user (via scic_cb_port_link_up()) as to the fact that
  856  *            a new phy as become ready.
  857  * @param[in] do_resume_phy This parameter specifies whether to resume the phy.
  858  *            If this function is called from MPC mode, it will be always true.
  859  *            for APC, this will be false, so that phys could be resumed later
  860  *
  861  * @return none
  862  */
  863 void scic_sds_port_general_link_up_handler(
  864    SCIC_SDS_PORT_T * this_port,
  865    SCIC_SDS_PHY_T  * the_phy,
  866    BOOL              do_notify_user,
  867    BOOL              do_resume_phy
  868 )
  869 {
  870    SCI_SAS_ADDRESS_T  port_sas_address;
  871    SCI_SAS_ADDRESS_T  phy_sas_address;
  872 
  873    scic_sds_port_get_attached_sas_address(this_port, &port_sas_address);
  874    scic_sds_phy_get_attached_sas_address(the_phy, &phy_sas_address);
  875 
  876    // If the SAS address of the new phy matches the SAS address of
  877    // other phys in the port OR this is the first phy in the port,
  878    // then activate the phy and allow it to be used for operations
  879    // in this port.
  880    if (
  881          (
  882             (phy_sas_address.high == port_sas_address.high)
  883          && (phy_sas_address.low  == port_sas_address.low )
  884          )
  885          || (this_port->active_phy_mask == 0)
  886       )
  887    {
  888       scic_sds_port_activate_phy(this_port, the_phy, do_notify_user, do_resume_phy);
  889 
  890       if (this_port->parent.state_machine.current_state_id
  891           == SCI_BASE_PORT_STATE_RESETTING)
  892       {
  893          sci_base_state_machine_change_state(
  894             &this_port->parent.state_machine, SCI_BASE_PORT_STATE_READY
  895          );
  896       }
  897    }
  898    else
  899    {
  900       scic_sds_port_invalid_link_up(this_port, the_phy);
  901    }
  902 }
  903 
  904 // ---------------------------------------------------------------------------
  905 
  906 SCI_STATUS scic_port_add_phy(
  907    SCI_PORT_HANDLE_T handle,
  908    SCI_PHY_HANDLE_T phy
  909 )
  910 {
  911    #if defined (SCI_LOGGING)
  912    SCIC_SDS_PORT_T *this_port = (SCIC_SDS_PORT_T *)handle;
  913    #endif // defined (SCI_LOGGING)
  914 
  915    SCIC_LOG_TRACE((
  916       sci_base_object_get_logger(this_port),
  917       SCIC_LOG_OBJECT_PORT,
  918       "scic_port_add_phy(0x%x, 0x%x) enter\n",
  919       handle, phy
  920    ));
  921 
  922    SCIC_LOG_ERROR((
  923       sci_base_object_get_logger(this_port),
  924       SCIC_LOG_OBJECT_PORT,
  925       "Interface function scic_port_add_phy() has been deprecated. "
  926       "PORT configuration is handled through the OEM parameters.\n"
  927    ));
  928 
  929    return SCI_FAILURE_ADDING_PHY_UNSUPPORTED;
  930 
  931 }
  932 
  933 // ---------------------------------------------------------------------------
  934 
  935 SCI_STATUS scic_port_remove_phy(
  936    SCI_PORT_HANDLE_T handle,
  937    SCI_PHY_HANDLE_T phy
  938 )
  939 {
  940    #if defined (SCI_LOGGING)
  941    SCIC_SDS_PORT_T *this_port = (SCIC_SDS_PORT_T *)handle;
  942    #endif // defined (SCI_LOGGING)
  943 
  944    SCIC_LOG_TRACE((
  945       sci_base_object_get_logger(this_port),
  946       SCIC_LOG_OBJECT_PORT,
  947       "scic_port_remove_phy(0x%x, 0x%x) enter\n",
  948       handle, phy
  949    ));
  950 
  951    SCIC_LOG_ERROR((
  952       sci_base_object_get_logger(this_port),
  953       SCIC_LOG_OBJECT_PORT,
  954       "Interface function scic_port_remove_phy() has been deprecated. "
  955       "PORT configuration is handled through the OEM parameters.\n"
  956    ));
  957 
  958    return SCI_FAILURE_ADDING_PHY_UNSUPPORTED;
  959 }
  960 
  961 // ---------------------------------------------------------------------------
  962 
  963 SCI_STATUS scic_port_get_properties(
  964    SCI_PORT_HANDLE_T        port,
  965    SCIC_PORT_PROPERTIES_T * properties
  966 )
  967 {
  968    SCIC_SDS_PORT_T *this_port = (SCIC_SDS_PORT_T *)port;
  969 
  970    SCIC_LOG_TRACE((
  971       sci_base_object_get_logger(this_port),
  972       SCIC_LOG_OBJECT_PORT,
  973       "scic_port_get_properties(0x%x, 0x%x) enter\n",
  974       port, properties
  975    ));
  976 
  977    if (
  978          (port == SCI_INVALID_HANDLE)
  979       || (this_port->logical_port_index == SCIC_SDS_DUMMY_PORT)
  980       )
  981    {
  982       return SCI_FAILURE_INVALID_PORT;
  983    }
  984 
  985    properties->index    = this_port->logical_port_index;
  986    properties->phy_mask = scic_sds_port_get_phys(this_port);
  987    scic_sds_port_get_sas_address(this_port, &properties->local.sas_address);
  988    scic_sds_port_get_protocols(this_port, &properties->local.protocols);
  989    scic_sds_port_get_attached_sas_address(this_port, &properties->remote.sas_address);
  990    scic_sds_port_get_attached_protocols(this_port, &properties->remote.protocols);
  991 
  992    return SCI_SUCCESS;
  993 }
  994 
  995 // ---------------------------------------------------------------------------
  996 
  997 SCI_STATUS scic_port_hard_reset(
  998    SCI_PORT_HANDLE_T handle,
  999    U32               reset_timeout
 1000 )
 1001 {
 1002    SCIC_SDS_PORT_T * this_port = (SCIC_SDS_PORT_T *)handle;
 1003 
 1004    SCIC_LOG_TRACE((
 1005       sci_base_object_get_logger(this_port),
 1006       SCIC_LOG_OBJECT_PORT,
 1007       "scic_port_hard_reset(0x%x, 0x%x) enter\n",
 1008       handle, reset_timeout
 1009    ));
 1010 
 1011    return this_port->state_handlers->parent.reset_handler(
 1012                                        &this_port->parent,
 1013                                        reset_timeout
 1014                                      );
 1015 }
 1016 
 1017 /**
 1018  * This method assigns the direct attached device ID for this port.
 1019  *
 1020  * @param[in] this_port The port for which the direct attached device id is to
 1021  *       be assigned.
 1022  * @param[in] device_id The direct attached device ID to assign to the port.
 1023  *       This will be the RNi for the device
 1024  */
 1025 void scic_sds_port_setup_transports(
 1026    SCIC_SDS_PORT_T * this_port,
 1027    U32               device_id
 1028 )
 1029 {
 1030    U8 index;
 1031 
 1032    for (index = 0; index < SCI_MAX_PHYS; index++)
 1033    {
 1034       if (this_port->active_phy_mask & (1 << index))
 1035       {
 1036          scic_sds_phy_setup_transport(this_port->phy_table[index], device_id);
 1037       }
 1038    }
 1039 }
 1040 
 1041 /**
 1042  * This method will resume the phy which is already added in the port.
 1043  * Activation includes:
 1044  * - enabling the Protocol Engine in the silicon.
 1045  * - update the reay mask.
 1046  *
 1047  * @param[in] this_port This is the port on which the phy should be enabled.
 1048  * @return none
 1049  */
 1050 static
 1051 void scic_sds_port_resume_phy(
 1052    SCIC_SDS_PORT_T * this_port,
 1053    SCIC_SDS_PHY_T  * the_phy
 1054 )
 1055 {
 1056    scic_sds_phy_resume (the_phy);
 1057    this_port->enabled_phy_mask |= 1 << the_phy->phy_index;
 1058 }
 1059 /**
 1060  * This method will activate the phy in the port.
 1061  * Activation includes:
 1062  * - adding the phy to the port
 1063  * - enabling the Protocol Engine in the silicon.
 1064  * - notifying the user that the link is up.
 1065  *
 1066  * @param[in] this_port This is the port on which the phy should be enabled.
 1067  * @param[in] the_phy This is the specific phy which to enable.
 1068  * @param[in] do_notify_user This parameter specifies whether to inform
 1069  *            the user (via scic_cb_port_link_up()) as to the fact that
 1070  *            a new phy as become ready.
 1071  * @param[in] do_resume_phy This parameter specifies whether to resume the phy.
 1072  *            If this function is called from MPC mode, it will be always true.
 1073  *            for APC, this will be false, so that phys could be resumed later
 1074  *
 1075 
 1076  * @return none
 1077  */
 1078 void scic_sds_port_activate_phy(
 1079    SCIC_SDS_PORT_T * this_port,
 1080    SCIC_SDS_PHY_T  * the_phy,
 1081    BOOL              do_notify_user,
 1082    BOOL              do_resume_phy
 1083 )
 1084 {
 1085    SCIC_SDS_CONTROLLER_T                      * controller;
 1086    SCI_SAS_IDENTIFY_ADDRESS_FRAME_PROTOCOLS_T   protocols;
 1087 
 1088    SCIC_LOG_TRACE((
 1089       sci_base_object_get_logger(this_port),
 1090       SCIC_LOG_OBJECT_PORT,
 1091       "scic_sds_port_activate_phy(0x%x,0x%x,0x%x) enter\n",
 1092       this_port, the_phy, do_notify_user
 1093    ));
 1094 
 1095    controller = scic_sds_port_get_controller(this_port);
 1096    scic_sds_phy_get_attached_phy_protocols(the_phy, &protocols);
 1097 
 1098    // If this is sata port then the phy has already been resumed
 1099    if (!protocols.u.bits.stp_target)
 1100    {
 1101       if (do_resume_phy == TRUE)
 1102       {
 1103          scic_sds_port_resume_phy(this_port, the_phy);
 1104       }
 1105    }
 1106 
 1107    this_port->active_phy_mask |= 1 << the_phy->phy_index;
 1108 
 1109    scic_sds_controller_clear_invalid_phy(controller, the_phy);
 1110 
 1111    if (do_notify_user == TRUE)
 1112       scic_cb_port_link_up(this_port->owning_controller, this_port, the_phy);
 1113 }
 1114 
 1115 /**
 1116  * This method will deactivate the supplied phy in the port.
 1117  *
 1118  * @param[in] this_port This is the port on which the phy should be
 1119  *            deactivated.
 1120  * @param[in] the_phy This is the specific phy that is no longer
 1121  *            active in the port.
 1122  * @param[in] do_notify_user This parameter specifies whether to inform
 1123  *            the user (via scic_cb_port_link_down()) as to the fact that
 1124  *            a new phy as become ready.
 1125  *
 1126  * @return none
 1127  */
 1128 void scic_sds_port_deactivate_phy(
 1129    SCIC_SDS_PORT_T * this_port,
 1130    SCIC_SDS_PHY_T  * the_phy,
 1131    BOOL              do_notify_user
 1132 )
 1133 {
 1134    SCIC_LOG_TRACE((
 1135       sci_base_object_get_logger(this_port),
 1136       SCIC_LOG_OBJECT_PORT,
 1137       "scic_sds_port_deactivate_phy(0x%x,0x%x,0x%x) enter\n",
 1138       this_port, the_phy, do_notify_user
 1139    ));
 1140 
 1141    this_port->active_phy_mask &= ~(1 << the_phy->phy_index);
 1142    this_port->enabled_phy_mask  &= ~(1 << the_phy->phy_index);
 1143 
 1144    the_phy->max_negotiated_speed = SCI_SAS_NO_LINK_RATE;
 1145 
 1146    // Re-assign the phy back to the LP as if it were a narrow port for APC mode.
 1147    // For MPC mode, the phy will remain in the port
 1148    if (this_port->owning_controller->oem_parameters.sds1.controller.mode_type
 1149        == SCIC_PORT_AUTOMATIC_CONFIGURATION_MODE)
 1150    {
 1151    SCU_PCSPExCR_WRITE(this_port, the_phy->phy_index, the_phy->phy_index);
 1152    }
 1153 
 1154    if (do_notify_user == TRUE)
 1155       scic_cb_port_link_down(this_port->owning_controller, this_port, the_phy);
 1156 }
 1157 
 1158 /**
 1159  * This method will disable the phy and report that the phy is not valid for this
 1160  * port object.
 1161  *
 1162  * @param[in] this_port This is the port on which the phy should be disabled.
 1163  * @param[in] the_phy This is the specific phy which to disabled.
 1164  *
 1165  * @return None
 1166  */
 1167 void scic_sds_port_invalid_link_up(
 1168    SCIC_SDS_PORT_T * this_port,
 1169    SCIC_SDS_PHY_T  * the_phy
 1170 )
 1171 {
 1172    SCIC_SDS_CONTROLLER_T * controller = scic_sds_port_get_controller(this_port);
 1173 
 1174    // Check to see if we have alreay reported this link as bad and if not go
 1175    // ahead and tell the SCI_USER that we have discovered an invalid link.
 1176    if ((controller->invalid_phy_mask & (1 << the_phy->phy_index)) == 0)
 1177    {
 1178       scic_sds_controller_set_invalid_phy(controller, the_phy);
 1179 
 1180       scic_cb_port_invalid_link_up(controller, this_port, the_phy);
 1181    }
 1182 }
 1183 
 1184 /**
 1185  * @brief This method returns FALSE if the port only has a single phy object
 1186  *        assigned.  If there are no phys or more than one phy then the
 1187  *        method will return TRUE.
 1188  *
 1189  * @param[in] this_port The port for which the wide port condition is to be
 1190  *            checked.
 1191  *
 1192  * @return BOOL
 1193  * @retval TRUE Is returned if this is a wide ported port.
 1194  * @retval FALSE Is returned if this is a narrow port.
 1195  */
 1196 static
 1197 BOOL scic_sds_port_is_wide(
 1198    SCIC_SDS_PORT_T *this_port
 1199 )
 1200 {
 1201    U32 index;
 1202    U32 phy_count = 0;
 1203 
 1204    for (index = 0; index < SCI_MAX_PHYS; index++)
 1205    {
 1206       if (this_port->phy_table[index] != NULL)
 1207       {
 1208          phy_count++;
 1209       }
 1210    }
 1211 
 1212    return (phy_count != 1);
 1213 }
 1214 
 1215 /**
 1216  * @brief This method is called by the PHY object when the link is detected.
 1217  *        if the port wants the PHY to continue on to the link up state then
 1218  *        the port layer must return TRUE.  If the port object returns FALSE
 1219  *        the phy object must halt its attempt to go link up.
 1220  *
 1221  * @param[in] this_port The port associated with the phy object.
 1222  * @param[in] the_phy The phy object that is trying to go link up.
 1223  *
 1224  * @return TRUE if the phy object can continue to the link up condition.
 1225  * @retval TRUE Is returned if this phy can continue to the ready state.
 1226  * @retval FALSE Is returned if can not continue on to the ready state.
 1227  *
 1228  * @note This notification is in place for wide ports and direct attached
 1229  *       phys.  Since there are no wide ported SATA devices this could
 1230  *       become an invalid port configuration.
 1231  */
 1232 BOOL scic_sds_port_link_detected(
 1233    SCIC_SDS_PORT_T *this_port,
 1234    SCIC_SDS_PHY_T  *the_phy
 1235 )
 1236 {
 1237    SCI_SAS_IDENTIFY_ADDRESS_FRAME_PROTOCOLS_T protocols;
 1238 
 1239    scic_sds_phy_get_attached_phy_protocols(the_phy, &protocols);
 1240 
 1241    if (
 1242          (this_port->logical_port_index != SCIC_SDS_DUMMY_PORT)
 1243       && (protocols.u.bits.stp_target)
 1244       )
 1245    {
 1246       if (scic_sds_port_is_wide(this_port))
 1247       {
 1248          //direct attached Sata phy cannot be in wide port.
 1249          scic_sds_port_invalid_link_up( this_port, the_phy);
 1250       return FALSE;
 1251    }
 1252       else
 1253       {
 1254          SCIC_SDS_PORT_T *destination_port = &(this_port->owning_controller->port_table[the_phy->phy_index]);
 1255 
 1256          //add the phy to the its logical port for direct attached SATA. The phy will be added
 1257          //to port whose port_index will be the phy_index.
 1258          SCU_PCSPExCR_WRITE( destination_port, the_phy->phy_index, the_phy->phy_index);
 1259       }
 1260    }
 1261 
 1262    return TRUE;
 1263 }
 1264 
 1265 /**
 1266  * @brief This method is the entry point for the phy to inform
 1267  *        the port that it is now in a ready state
 1268  *
 1269  * @param[in] this_port
 1270  * @param[in] phy
 1271  */
 1272 void scic_sds_port_link_up(
 1273    SCIC_SDS_PORT_T *this_port,
 1274    SCIC_SDS_PHY_T  *the_phy
 1275 )
 1276 {
 1277    the_phy->is_in_link_training = FALSE;
 1278 
 1279    this_port->state_handlers->link_up_handler(this_port, the_phy);
 1280 }
 1281 
 1282 /**
 1283  * @brief This method is the entry point for the phy to inform
 1284  *        the port that it is no longer in a ready state
 1285  *
 1286  * @param[in] this_port
 1287  * @param[in] phy
 1288  */
 1289 void scic_sds_port_link_down(
 1290    SCIC_SDS_PORT_T *this_port,
 1291    SCIC_SDS_PHY_T  *the_phy
 1292 )
 1293 {
 1294    this_port->state_handlers->link_down_handler(this_port, the_phy);
 1295 }
 1296 
 1297 /**
 1298  * @brief This method is called to start an IO request on this port.
 1299  *
 1300  * @param[in] this_port
 1301  * @param[in] the_device
 1302  * @param[in] the_io_request
 1303  *
 1304  * @return SCI_STATUS
 1305  */
 1306 SCI_STATUS scic_sds_port_start_io(
 1307    SCIC_SDS_PORT_T          *this_port,
 1308    SCIC_SDS_REMOTE_DEVICE_T *the_device,
 1309    SCIC_SDS_REQUEST_T       *the_io_request
 1310 )
 1311 {
 1312    return this_port->state_handlers->start_io_handler(
 1313                                        this_port, the_device, the_io_request);
 1314 }
 1315 
 1316 /**
 1317  * @brief This method is called to complete an IO request to the port.
 1318  *
 1319  * @param[in] this_port
 1320  * @param[in] the_device
 1321  * @param[in] the_io_request
 1322  *
 1323  * @return SCI_STATUS
 1324  */
 1325 SCI_STATUS scic_sds_port_complete_io(
 1326    SCIC_SDS_PORT_T          *this_port,
 1327    SCIC_SDS_REMOTE_DEVICE_T *the_device,
 1328    SCIC_SDS_REQUEST_T       *the_io_request
 1329 )
 1330 {
 1331    return this_port->state_handlers->complete_io_handler(
 1332                                        this_port, the_device, the_io_request);
 1333 }
 1334 
 1335 /**
 1336  * @brief This method is provided to timeout requests for port operations.
 1337  *        Mostly its for the port reset operation.
 1338  *
 1339  * @param[in] port This is the parameter or cookie value that is provided
 1340  *       to the timer construct operation.
 1341  */
 1342 void scic_sds_port_timeout_handler(
 1343    void *port
 1344 )
 1345 {
 1346    U32 current_state;
 1347    SCIC_SDS_PORT_T * this_port;
 1348 
 1349    this_port = (SCIC_SDS_PORT_T *)port;
 1350    current_state = sci_base_state_machine_get_state(
 1351                            &this_port->parent.state_machine);
 1352 
 1353    if (current_state == SCI_BASE_PORT_STATE_RESETTING)
 1354    {
 1355       // if the port is still in the resetting state then the timeout fired
 1356       // before the reset completed.
 1357       sci_base_state_machine_change_state(
 1358          &this_port->parent.state_machine,
 1359          SCI_BASE_PORT_STATE_FAILED
 1360       );
 1361    }
 1362    else if (current_state == SCI_BASE_PORT_STATE_STOPPED)
 1363    {
 1364       // if the port is stopped then the start request failed
 1365       // In this case stay in the stopped state.
 1366       SCIC_LOG_ERROR((
 1367          sci_base_object_get_logger(this_port),
 1368          SCIC_LOG_OBJECT_PORT,
 1369          "SCIC Port 0x%x failed to stop before tiemout.\n",
 1370          this_port
 1371       ));
 1372    }
 1373    else if (current_state == SCI_BASE_PORT_STATE_STOPPING)
 1374    {
 1375       // if the port is still stopping then the stop has not completed
 1376       scic_cb_port_stop_complete(
 1377          scic_sds_port_get_controller(this_port),
 1378          port,
 1379          SCI_FAILURE_TIMEOUT
 1380       );
 1381    }
 1382    else
 1383    {
 1384       // The port is in the ready state and we have a timer reporting a timeout
 1385       // this should not happen.
 1386       SCIC_LOG_ERROR((
 1387          sci_base_object_get_logger(this_port),
 1388          SCIC_LOG_OBJECT_PORT,
 1389          "SCIC Port 0x%x is processing a timeout operation in state %d.\n",
 1390          this_port, current_state
 1391       ));
 1392    }
 1393 }
 1394 
 1395 // ---------------------------------------------------------------------------
 1396 
 1397 #ifdef SCIC_DEBUG_ENABLED
 1398 void scic_sds_port_decrement_request_count(
 1399    SCIC_SDS_PORT_T *this_port
 1400 )
 1401 {
 1402    if (this_port->started_request_count == 0)
 1403    {
 1404       SCIC_LOG_WARNING((
 1405          sci_base_object_get_logger(this_port),
 1406          SCIC_LOG_OBJECT_PORT,
 1407          "SCIC Port object requested to decrement started io count past zero.\n"
 1408       ));
 1409    }
 1410    else
 1411    {
 1412       this_port->started_request_count--;
 1413    }
 1414 }
 1415 #endif
 1416 
 1417 /**
 1418  * @brief This function updates the hardwares VIIT entry for this port.
 1419  *
 1420  * @param[in] this_port
 1421  */
 1422 void scic_sds_port_update_viit_entry(
 1423    SCIC_SDS_PORT_T *this_port
 1424 )
 1425 {
 1426    SCI_SAS_ADDRESS_T sas_address;
 1427 
 1428    scic_sds_port_get_sas_address(this_port, &sas_address);
 1429 
 1430    scu_port_viit_register_write(
 1431       this_port, initiator_sas_address_hi, sas_address.high);
 1432 
 1433    scu_port_viit_register_write(
 1434       this_port, initiator_sas_address_lo, sas_address.low);
 1435 
 1436    // This value get cleared just in case its not already cleared
 1437    scu_port_viit_register_write(
 1438       this_port, reserved, 0);
 1439 
 1440 
 1441    // We are required to update the status register last
 1442    scu_port_viit_register_write(
 1443       this_port, status, (
 1444            SCU_VIIT_ENTRY_ID_VIIT
 1445          | SCU_VIIT_IPPT_INITIATOR
 1446          | ((1UL << this_port->physical_port_index) << SCU_VIIT_ENTRY_LPVIE_SHIFT)
 1447          | SCU_VIIT_STATUS_ALL_VALID
 1448          )
 1449    );
 1450 }
 1451 
 1452 /**
 1453  * @brief This method returns the maximum allowed speed for data transfers
 1454  *        on this port.  This maximum allowed speed evaluates to the maximum
 1455  *        speed of the slowest phy in the port.
 1456  *
 1457  * @param[in] this_port This parameter specifies the port for which to
 1458  *            retrieve the maximum allowed speed.
 1459  *
 1460  * @return This method returns the maximum negotiated speed of the slowest
 1461  *         phy in the port.
 1462  */
 1463 SCI_SAS_LINK_RATE scic_sds_port_get_max_allowed_speed(
 1464    SCIC_SDS_PORT_T * this_port
 1465 )
 1466 {
 1467    U16                index             = 0;
 1468    SCI_SAS_LINK_RATE  max_allowed_speed = SCI_SAS_600_GB;
 1469    SCIC_SDS_PHY_T   * phy               = NULL;
 1470 
 1471    // Loop through all of the phys in this port and find the phy with the
 1472    // lowest maximum link rate.
 1473    for (index = 0; index < SCI_MAX_PHYS; index++)
 1474    {
 1475       phy = this_port->phy_table[index];
 1476       if (
 1477             (phy != NULL)
 1478          && (scic_sds_port_active_phy(this_port, phy) == TRUE)
 1479          && (phy->max_negotiated_speed < max_allowed_speed)
 1480          )
 1481          max_allowed_speed = phy->max_negotiated_speed;
 1482    }
 1483 
 1484    return max_allowed_speed;
 1485 }
 1486 
 1487 
 1488 /**
 1489  * @brief This method passes the event to core user.
 1490  * @param[in] this_port The port that a BCN happens.
 1491  * @param[in] this_phy  The phy that receives BCN.
 1492  *
 1493  * @return none
 1494  */
 1495 void scic_sds_port_broadcast_change_received(
 1496    SCIC_SDS_PORT_T * this_port,
 1497    SCIC_SDS_PHY_T * this_phy
 1498 )
 1499 {
 1500    //notify the user.
 1501    scic_cb_port_bc_change_primitive_recieved(
 1502       this_port->owning_controller, this_port, this_phy
 1503    );
 1504 }
 1505 
 1506 
 1507 /**
 1508  * @brief This API methhod enables the broadcast change notification from
 1509  *        underneath hardware.
 1510  * @param[in] this_port The port that a BCN had been disabled from.
 1511  *
 1512  * @return none
 1513  */
 1514 void scic_port_enable_broadcast_change_notification(
 1515    SCI_PORT_HANDLE_T  port
 1516 )
 1517 {
 1518    SCIC_SDS_PORT_T * this_port = (SCIC_SDS_PORT_T *)port;
 1519    SCIC_SDS_PHY_T * phy;
 1520    U32 register_value;
 1521    U8 index;
 1522 
 1523    // Loop through all of the phys to enable BCN.
 1524    for (index = 0; index < SCI_MAX_PHYS; index++)
 1525    {
 1526       phy = this_port->phy_table[index];
 1527       if ( phy != NULL)
 1528       {
 1529          register_value = SCU_SAS_LLCTL_READ(phy);
 1530 
 1531          // clear the bit by writing 1.
 1532          SCU_SAS_LLCTL_WRITE(phy, register_value);
 1533       }
 1534    }
 1535 }
 1536 
 1537 /**
 1538  * @brief This method release resources in for a scic port.
 1539  *
 1540  * @param[in] controller This parameter specifies the core controller, one of
 1541  *            its phy's resources are to be released.
 1542  * @param[in] this_port This parameter specifies the port whose resource is to
 1543  *            be released.
 1544  */
 1545 void scic_sds_port_release_resource(
 1546    SCIC_SDS_CONTROLLER_T * controller,
 1547    SCIC_SDS_PORT_T *this_port
 1548 )
 1549 {
 1550    SCIC_LOG_TRACE((
 1551       sci_base_object_get_logger(this_port),
 1552       SCIC_LOG_OBJECT_PORT,
 1553       "scic_sds_port_release_resource(0x%x, 0x%x)\n",
 1554       controller, this_port
 1555    ));
 1556 
 1557    //Currently, the only resource to be released is a timer.
 1558    if (this_port->timer_handle != NULL)
 1559    {
 1560       scic_cb_timer_destroy(controller, this_port->timer_handle);
 1561       this_port->timer_handle = NULL;
 1562    }
 1563 }
 1564 
 1565 
 1566 //******************************************************************************
 1567 //* PORT STATE MACHINE
 1568 //******************************************************************************
 1569 
 1570 //***************************************************************************
 1571 //*  DEFAULT HANDLERS
 1572 //***************************************************************************
 1573 
 1574 /**
 1575  * This is the default method for port a start request.  It will report a
 1576  * warning and exit.
 1577  *
 1578  * @param[in] port This is the SCI_BASE_PORT object which is cast into a
 1579  *       SCIC_SDS_PORT object.
 1580  *
 1581  * @return SCI_STATUS
 1582  * @retval SCI_FAILURE_INVALID_STATE
 1583  */
 1584 SCI_STATUS scic_sds_port_default_start_handler(
 1585    SCI_BASE_PORT_T *port
 1586 )
 1587 {
 1588    SCIC_LOG_WARNING((
 1589       sci_base_object_get_logger((SCIC_SDS_PORT_T *)port),
 1590       SCIC_LOG_OBJECT_PORT,
 1591       "SCIC Port 0x%08x requested to start while in invalid state %d\n",
 1592       port,
 1593       sci_base_state_machine_get_state(
 1594          scic_sds_port_get_base_state_machine((SCIC_SDS_PORT_T *)port))
 1595    ));
 1596 
 1597    return SCI_FAILURE_INVALID_STATE;
 1598 }
 1599 
 1600 /**
 1601  * This is the default method for a port stop request.  It will report a
 1602  * warning and exit.
 1603  *
 1604  * @param[in] port This is the SCI_BASE_PORT object which is cast into a
 1605  *       SCIC_SDS_PORT object.
 1606  *
 1607  * @return SCI_STATUS
 1608  * @retval SCI_FAILURE_INVALID_STATE
 1609  */
 1610 SCI_STATUS scic_sds_port_default_stop_handler(
 1611    SCI_BASE_PORT_T *port
 1612 )
 1613 {
 1614    SCIC_LOG_WARNING((
 1615       sci_base_object_get_logger((SCIC_SDS_PORT_T *)port),
 1616       SCIC_LOG_OBJECT_PORT,
 1617       "SCIC Port 0x%08x requested to stop while in invalid state %d\n",
 1618       port,
 1619       sci_base_state_machine_get_state(
 1620          scic_sds_port_get_base_state_machine((SCIC_SDS_PORT_T *)port))
 1621    ));
 1622 
 1623    return SCI_FAILURE_INVALID_STATE;
 1624 }
 1625 
 1626 /**
 1627  * This is the default method for a port destruct request.  It will report a
 1628  * warning and exit.
 1629  *
 1630  * @param[in] port This is the SCI_BASE_PORT object which is cast into a
 1631  *       SCIC_SDS_PORT object.
 1632  *
 1633  * @return SCI_STATUS
 1634  * @retval SCI_FAILURE_INVALID_STATE
 1635  */
 1636 SCI_STATUS scic_sds_port_default_destruct_handler(
 1637    SCI_BASE_PORT_T *port
 1638 )
 1639 {
 1640    SCIC_LOG_WARNING((
 1641       sci_base_object_get_logger((SCIC_SDS_PORT_T *)port),
 1642       SCIC_LOG_OBJECT_PORT,
 1643       "SCIC Port 0x%08x requested to destruct while in invalid state %d\n",
 1644       port,
 1645       sci_base_state_machine_get_state(
 1646          scic_sds_port_get_base_state_machine((SCIC_SDS_PORT_T *)port))
 1647    ));
 1648 
 1649    return SCI_FAILURE_INVALID_STATE;
 1650 }
 1651 
 1652 /**
 1653  * This is the default method for a port reset request.  It will report a
 1654  * warning and exit.
 1655  *
 1656  * @param[in] port This is the SCI_BASE_PORT object which is cast into a
 1657  *       SCIC_SDS_PORT object.
 1658  * @param[in] timeout This is the timeout for the reset request to complete.
 1659  *
 1660  * @return SCI_STATUS
 1661  * @retval SCI_FAILURE_INVALID_STATE
 1662  */
 1663 SCI_STATUS scic_sds_port_default_reset_handler(
 1664    SCI_BASE_PORT_T * port,
 1665    U32               timeout
 1666 )
 1667 {
 1668    SCIC_LOG_WARNING((
 1669       sci_base_object_get_logger((SCIC_SDS_PORT_T *)port),
 1670       SCIC_LOG_OBJECT_PORT,
 1671       "SCIC Port 0x%08x requested to reset while in invalid state %d\n",
 1672       port,
 1673       sci_base_state_machine_get_state(
 1674          scic_sds_port_get_base_state_machine((SCIC_SDS_PORT_T *)port))
 1675    ));
 1676 
 1677    return SCI_FAILURE_INVALID_STATE;
 1678 }
 1679 
 1680 /**
 1681  * This is the default method for a port add phy request.  It will report a
 1682  * warning and exit.
 1683  *
 1684  * @param[in] port This is the SCI_BASE_PORT object which is cast into a
 1685  *       SCIC_SDS_PORT object.
 1686  *
 1687  * @return SCI_STATUS
 1688  * @retval SCI_FAILURE_INVALID_STATE
 1689  */
 1690 SCI_STATUS scic_sds_port_default_add_phy_handler(
 1691    SCI_BASE_PORT_T *port,
 1692    SCI_BASE_PHY_T  *phy
 1693 )
 1694 {
 1695    SCIC_LOG_WARNING((
 1696       sci_base_object_get_logger((SCIC_SDS_PORT_T *)port),
 1697       SCIC_LOG_OBJECT_PORT,
 1698       "SCIC Port 0x%08x requested to add phy 0x%08x while in invalid state %d\n",
 1699       port, phy,
 1700       sci_base_state_machine_get_state(
 1701          scic_sds_port_get_base_state_machine((SCIC_SDS_PORT_T *)port))
 1702    ));
 1703 
 1704    return SCI_FAILURE_INVALID_STATE;
 1705 }
 1706 
 1707 /**
 1708  * This is the default method for a port remove phy request.  It will report a
 1709  * warning and exit.
 1710  *
 1711  * @param[in] port This is the SCI_BASE_PORT object which is cast into a
 1712  *       SCIC_SDS_PORT object.
 1713  *
 1714  * @return SCI_STATUS
 1715  * @retval SCI_FAILURE_INVALID_STATE
 1716  */
 1717 SCI_STATUS scic_sds_port_default_remove_phy_handler(
 1718    SCI_BASE_PORT_T *port,
 1719    SCI_BASE_PHY_T  *phy
 1720 )
 1721 {
 1722    SCIC_LOG_WARNING((
 1723       sci_base_object_get_logger((SCIC_SDS_PORT_T *)port),
 1724       SCIC_LOG_OBJECT_PORT,
 1725       "SCIC Port 0x%08x requested to remove phy 0x%08x while in invalid state %d\n",
 1726       port, phy,
 1727       sci_base_state_machine_get_state(
 1728          scic_sds_port_get_base_state_machine((SCIC_SDS_PORT_T *)port))
 1729    ));
 1730 
 1731    return SCI_FAILURE_INVALID_STATE;
 1732 }
 1733 
 1734 /**
 1735  * This is the default method for a port unsolicited frame request.  It will
 1736  * report a warning and exit.
 1737  *
 1738  * @param[in] port This is the SCI_BASE_PORT object which is cast into a
 1739  *       SCIC_SDS_PORT object.
 1740  *
 1741  * @return SCI_STATUS
 1742  * @retval SCI_FAILURE_INVALID_STATE
 1743  *
 1744  * @todo Is it even possible to receive an unsolicited frame directed to a
 1745  *       port object?  It seems possible if we implementing virtual functions
 1746  *       but until then?
 1747  */
 1748 SCI_STATUS scic_sds_port_default_frame_handler(
 1749    SCIC_SDS_PORT_T * port,
 1750    U32               frame_index
 1751 )
 1752 {
 1753    SCIC_SDS_PORT_T *this_port = (SCIC_SDS_PORT_T *)port;
 1754 
 1755    SCIC_LOG_WARNING((
 1756       sci_base_object_get_logger(this_port),
 1757       SCIC_LOG_OBJECT_PORT,
 1758       "SCIC Port 0x%08x requested to process frame %d while in invalid state %d\n",
 1759       port, frame_index,
 1760       sci_base_state_machine_get_state(
 1761          scic_sds_port_get_base_state_machine(this_port))
 1762    ));
 1763 
 1764    scic_sds_controller_release_frame(
 1765       scic_sds_port_get_controller(this_port), frame_index
 1766    );
 1767 
 1768    return SCI_FAILURE_INVALID_STATE;
 1769 }
 1770 
 1771 /**
 1772  * This is the default method for a port event request.  It will report a
 1773  * warning and exit.
 1774  *
 1775  * @param[in] port This is the SCI_BASE_PORT object which is cast into a
 1776  *       SCIC_SDS_PORT object.
 1777  *
 1778  * @return SCI_STATUS
 1779  * @retval SCI_FAILURE_INVALID_STATE
 1780  */
 1781 SCI_STATUS scic_sds_port_default_event_handler(
 1782    SCIC_SDS_PORT_T * port,
 1783    U32               event_code
 1784 )
 1785 {
 1786    SCIC_LOG_WARNING((
 1787       sci_base_object_get_logger((SCIC_SDS_PORT_T *)port),
 1788       SCIC_LOG_OBJECT_PORT,
 1789       "SCIC Port 0x%08x requested to process event 0x%08x while in invalid state %d\n",
 1790       port, event_code,
 1791       sci_base_state_machine_get_state(
 1792          scic_sds_port_get_base_state_machine((SCIC_SDS_PORT_T *)port))
 1793    ));
 1794 
 1795    return SCI_FAILURE_INVALID_STATE;
 1796 }
 1797 
 1798 /**
 1799  * This is the default method for a port link up notification.  It will report
 1800  * a warning and exit.
 1801  *
 1802  * @param[in] port This is the SCI_BASE_PORT object which is cast into a
 1803  *       SCIC_SDS_PORT object.
 1804  *
 1805  * @return SCI_STATUS
 1806  * @retval SCI_FAILURE_INVALID_STATE
 1807  */
 1808 void scic_sds_port_default_link_up_handler(
 1809    SCIC_SDS_PORT_T *this_port,
 1810    SCIC_SDS_PHY_T  *phy
 1811 )
 1812 {
 1813    SCIC_LOG_WARNING((
 1814       sci_base_object_get_logger(this_port),
 1815       SCIC_LOG_OBJECT_PORT,
 1816       "SCIC Port 0x%08x received link_up notification from phy 0x%08x while in invalid state %d\n",
 1817       this_port, phy,
 1818       sci_base_state_machine_get_state(
 1819          scic_sds_port_get_base_state_machine(this_port))
 1820    ));
 1821 }
 1822 
 1823 /**
 1824  * This is the default method for a port link down notification.  It will
 1825  * report a warning and exit.
 1826  *
 1827  * @param[in] port This is the SCI_BASE_PORT object which is cast into a
 1828  *       SCIC_SDS_PORT object.
 1829  *
 1830  * @return SCI_STATUS
 1831  * @retval SCI_FAILURE_INVALID_STATE
 1832  */
 1833 void scic_sds_port_default_link_down_handler(
 1834    SCIC_SDS_PORT_T *this_port,
 1835    SCIC_SDS_PHY_T  *phy
 1836 )
 1837 {
 1838    SCIC_LOG_WARNING((
 1839       sci_base_object_get_logger(this_port),
 1840       SCIC_LOG_OBJECT_PORT,
 1841       "SCIC Port 0x%08x received link down notification from phy 0x%08x while in invalid state %d\n",
 1842       this_port, phy,
 1843       sci_base_state_machine_get_state(
 1844          scic_sds_port_get_base_state_machine(this_port))
 1845    ));
 1846 }
 1847 
 1848 /**
 1849  * This is the default method for a port start io request.  It will report a
 1850  * warning and exit.
 1851  *
 1852  * @param[in] port This is the SCI_BASE_PORT object which is cast into a
 1853  *       SCIC_SDS_PORT object.
 1854  *
 1855  * @return SCI_STATUS
 1856  * @retval SCI_FAILURE_INVALID_STATE
 1857  */
 1858 SCI_STATUS scic_sds_port_default_start_io_handler(
 1859    SCIC_SDS_PORT_T          *this_port,
 1860    SCIC_SDS_REMOTE_DEVICE_T *device,
 1861    SCIC_SDS_REQUEST_T       *io_request
 1862 )
 1863 {
 1864    SCIC_LOG_WARNING((
 1865       sci_base_object_get_logger(this_port),
 1866       SCIC_LOG_OBJECT_PORT,
 1867       "SCIC Port 0x%08x requested to start io request 0x%08x while in invalid state %d\n",
 1868       this_port, io_request,
 1869       sci_base_state_machine_get_state(
 1870          scic_sds_port_get_base_state_machine(this_port))
 1871    ));
 1872 
 1873    return SCI_FAILURE_INVALID_STATE;
 1874 }
 1875 
 1876 /**
 1877  * This is the default method for a port complete io request.  It will report
 1878  * a warning and exit.
 1879  *
 1880  * @param[in] port This is the SCI_BASE_PORT object which is cast into a
 1881  *       SCIC_SDS_PORT object.
 1882  *
 1883  * @return SCI_STATUS
 1884  * @retval SCI_FAILURE_INVALID_STATE
 1885  */
 1886 SCI_STATUS scic_sds_port_default_complete_io_handler(
 1887    SCIC_SDS_PORT_T          *this_port,
 1888    SCIC_SDS_REMOTE_DEVICE_T *device,
 1889    SCIC_SDS_REQUEST_T       *io_request
 1890 )
 1891 {
 1892    SCIC_LOG_WARNING((
 1893       sci_base_object_get_logger(this_port),
 1894       SCIC_LOG_OBJECT_PORT,
 1895       "SCIC Port 0x%08x requested to complete io request 0x%08x while in invalid state %d\n",
 1896       this_port, io_request,
 1897       sci_base_state_machine_get_state(
 1898          scic_sds_port_get_base_state_machine(this_port))
 1899    ));
 1900 
 1901    return SCI_FAILURE_INVALID_STATE;
 1902 }
 1903 
 1904 //****************************************************************************
 1905 //* GENERAL STATE HANDLERS
 1906 //****************************************************************************
 1907 
 1908 /**
 1909  * This is a general complete io request handler for the SCIC_SDS_PORT object.
 1910  *
 1911  * @param[in] port This is the SCIC_SDS_PORT object on which the io request
 1912  *       count will be decremented.
 1913  * @param[in] device This is the SCIC_SDS_REMOTE_DEVICE object to which the io
 1914  *       request is being directed.  This parameter is not required to
 1915  *       complete this operation.
 1916  * @param[in] io_request This is the request that is being completed on this
 1917  *       port object.  This parameter is not required to complete this
 1918  *       operation.
 1919  *
 1920  * @return SCI_STATUS
 1921  * @retval SCI_SUCCESS
 1922  */
 1923 static
 1924 SCI_STATUS scic_sds_port_general_complete_io_handler(
 1925    SCIC_SDS_PORT_T          *port,
 1926    SCIC_SDS_REMOTE_DEVICE_T *device,
 1927    SCIC_SDS_REQUEST_T       *io_request
 1928 )
 1929 {
 1930    SCIC_SDS_PORT_T *this_port = (SCIC_SDS_PORT_T *)port;
 1931 
 1932    scic_sds_port_decrement_request_count(this_port);
 1933 
 1934    return SCI_SUCCESS;
 1935 }
 1936 
 1937 //****************************************************************************
 1938 //* STOPPED STATE HANDLERS
 1939 //****************************************************************************
 1940 static
 1941 BOOL scic_sds_port_requires_scheduler_workaround(
 1942    SCIC_SDS_PORT_T * this_port
 1943 )
 1944 {
 1945    if (
 1946          (
 1947            this_port->owning_controller->logical_port_entries
 1948          < this_port->owning_controller->task_context_entries
 1949          )
 1950       && (
 1951            this_port->owning_controller->logical_port_entries
 1952          < this_port->owning_controller->remote_node_entries
 1953          )
 1954       )
 1955    {
 1956       return TRUE;
 1957    }
 1958 
 1959    return FALSE;
 1960 }
 1961 
 1962 
 1963 /**
 1964  * This method takes the SCIC_SDS_PORT from a stopped state and attempts to
 1965  * start it.  To start a port it must have no assiged devices and it must have
 1966  * at least one phy assigned to it.  If those conditions are met then the port
 1967  * can transition to the ready state.
 1968  *
 1969  * @param[in] port This is the SCI_BASE_PORT object which is cast into a
 1970  *       SCIC_SDS_PORT object.
 1971  *
 1972  * @return SCI_STATUS
 1973  * @retval SCI_FAILURE_UNSUPPORTED_PORT_CONFIGURATION This SCIC_SDS_PORT
 1974  *         object could not be started because the port configuration is not
 1975  *         valid.
 1976  * @retval SCI_SUCCESS the start request is successful and the SCIC_SDS_PORT
 1977  *         object has transitioned to the SCI_BASE_PORT_STATE_READY.
 1978  */
 1979 static
 1980 SCI_STATUS scic_sds_port_stopped_state_start_handler(
 1981    SCI_BASE_PORT_T *port
 1982 )
 1983 {
 1984    U32 phy_mask;
 1985    SCI_STATUS status = SCI_SUCCESS;
 1986    SCIC_SDS_PORT_T *this_port = (SCIC_SDS_PORT_T *)port;
 1987 
 1988    if (this_port->assigned_device_count > 0)
 1989    {
 1990       /// @todo This is a start failure operation because there are still
 1991       ///       devices assigned to this port.  There must be no devices
 1992       ///       assigned to a port on a start operation.
 1993       return SCI_FAILURE_UNSUPPORTED_PORT_CONFIGURATION;
 1994    }
 1995 
 1996    this_port->timer_handle = scic_cb_timer_create(
 1997       scic_sds_port_get_controller(this_port),
 1998       scic_sds_port_timeout_handler,
 1999       this_port
 2000    );
 2001 
 2002    if (this_port->timer_handle == SCI_INVALID_HANDLE)
 2003    {
 2004       return SCI_FAILURE_INSUFFICIENT_RESOURCES;
 2005    }
 2006 
 2007    if (scic_sds_port_requires_scheduler_workaround(this_port))
 2008    {
 2009    if (this_port->reserved_rni == SCU_DUMMY_INDEX)
 2010    {
 2011       this_port->reserved_rni =
 2012          scic_sds_remote_node_table_allocate_remote_node(
 2013             &this_port->owning_controller->available_remote_nodes, 1
 2014          );
 2015 
 2016       if (this_port->reserved_rni != SCU_DUMMY_INDEX)
 2017       {
 2018          scic_sds_port_construct_dummy_rnc(
 2019             this_port,
 2020             this_port->reserved_rni
 2021          );
 2022       }
 2023       else
 2024       {
 2025          status = SCI_FAILURE_INSUFFICIENT_RESOURCES;
 2026       }
 2027    }
 2028 
 2029    if (this_port->reserved_tci == SCU_DUMMY_INDEX)
 2030    {
 2031       // Allocate a TCI and remove the sequence nibble
 2032       this_port->reserved_tci =
 2033          scic_controller_allocate_io_tag(this_port->owning_controller);
 2034 
 2035       if (this_port->reserved_tci != SCU_DUMMY_INDEX)
 2036       {
 2037          scic_sds_port_construct_dummy_task(this_port, this_port->reserved_tci);
 2038       }
 2039       else
 2040       {
 2041          status = SCI_FAILURE_INSUFFICIENT_RESOURCES;
 2042       }
 2043    }
 2044    }
 2045 
 2046    if (status == SCI_SUCCESS)
 2047    {
 2048       phy_mask = scic_sds_port_get_phys(this_port);
 2049 
 2050       // There are one or more phys assigned to this port.  Make sure
 2051       // the port's phy mask is in fact legal and supported by the
 2052       // silicon.
 2053       if (scic_sds_port_is_phy_mask_valid(this_port, phy_mask) == TRUE)
 2054       {
 2055          sci_base_state_machine_change_state(
 2056             scic_sds_port_get_base_state_machine(this_port),
 2057             SCI_BASE_PORT_STATE_READY
 2058          );
 2059       }
 2060       else
 2061       {
 2062          status = SCI_FAILURE;
 2063       }
 2064    }
 2065 
 2066    if (status != SCI_SUCCESS)
 2067    {
 2068       scic_sds_port_destroy_dummy_resources(this_port);
 2069    }
 2070 
 2071    return status;
 2072 }
 2073 
 2074 /**
 2075  * This method takes the SCIC_SDS_PORT that is in a stopped state and handles
 2076  * a stop request.  This function takes no action.
 2077  *
 2078  * @param[in] port This is the SCI_BASE_PORT object which is cast into a
 2079  *       SCIC_SDS_PORT object.
 2080  *
 2081  * @return SCI_STATUS
 2082  * @retval SCI_SUCCESS the stop request is successful as the SCIC_SDS_PORT
 2083  *         object is already stopped.
 2084  */
 2085 static
 2086 SCI_STATUS scic_sds_port_stopped_state_stop_handler(
 2087    SCI_BASE_PORT_T *port
 2088 )
 2089 {
 2090    // We are already stopped so there is nothing to do here
 2091    return SCI_SUCCESS;
 2092 }
 2093 
 2094 /**
 2095  * This method takes the SCIC_SDS_PORT that is in a stopped state and handles
 2096  * the destruct request.  The stopped state is the only state in which the
 2097  * SCIC_SDS_PORT can be destroyed.  This function causes the port object to
 2098  * transition to the SCI_BASE_PORT_STATE_FINAL.
 2099  *
 2100  * @param[in] port This is the SCI_BASE_PORT object which is cast into a
 2101  *       SCIC_SDS_PORT object.
 2102  *
 2103  * @return SCI_STATUS
 2104  * @retval SCI_SUCCESS
 2105  */
 2106 static
 2107 SCI_STATUS scic_sds_port_stopped_state_destruct_handler(
 2108    SCI_BASE_PORT_T *port
 2109 )
 2110 {
 2111    SCIC_SDS_PORT_T *this_port = (SCIC_SDS_PORT_T *)port;
 2112 
 2113    sci_base_state_machine_stop(&this_port->parent.state_machine);
 2114 
 2115    return SCI_SUCCESS;
 2116 }
 2117 
 2118 /**
 2119  * This method takes the SCIC_SDS_PORT that is in a stopped state and handles
 2120  * the add phy request.  In MPC mode the only time a phy can be added to a
 2121  * port is in the SCI_BASE_PORT_STATE_STOPPED.
 2122  *
 2123  * @param[in] port This is the SCI_BASE_PORT object which is cast into a
 2124  *       SCIC_SDS_PORT object.
 2125  * @param[in] phy This is the SCI_BASE_PHY object which is cast into a
 2126  *       SCIC_SDS_PHY object.
 2127  *
 2128  * @return SCI_STATUS
 2129  * @retval SCI_FAILURE_UNSUPPORTED_PORT_CONFIGURATION is returned when the phy
 2130  *         can not be added to the port.
 2131  * @retval SCI_SUCCESS if the phy is added to the port.
 2132  */
 2133 static
 2134 SCI_STATUS scic_sds_port_stopped_state_add_phy_handler(
 2135    SCI_BASE_PORT_T *port,
 2136    SCI_BASE_PHY_T  *phy
 2137 )
 2138 {
 2139    SCIC_SDS_PORT_T * this_port = (SCIC_SDS_PORT_T *)port;
 2140    SCIC_SDS_PHY_T  * this_phy  = (SCIC_SDS_PHY_T  *)phy;
 2141    SCI_SAS_ADDRESS_T port_sas_address;
 2142 
 2143    // Read the port assigned SAS Address if there is one
 2144    scic_sds_port_get_sas_address(this_port, &port_sas_address);
 2145 
 2146    if (port_sas_address.high != 0 && port_sas_address.low != 0)
 2147    {
 2148       SCI_SAS_ADDRESS_T phy_sas_address;
 2149 
 2150       // Make sure that the PHY SAS Address matches the SAS Address
 2151       // for this port.
 2152       scic_sds_phy_get_sas_address(this_phy, &phy_sas_address);
 2153 
 2154       if (
 2155             (port_sas_address.high != phy_sas_address.high)
 2156          || (port_sas_address.low  != phy_sas_address.low)
 2157          )
 2158       {
 2159          return SCI_FAILURE_UNSUPPORTED_PORT_CONFIGURATION;
 2160       }
 2161    }
 2162 
 2163    return scic_sds_port_set_phy(this_port, this_phy);
 2164 }
 2165 
 2166 
 2167 /**
 2168  * This method takes the SCIC_SDS_PORT that is in a stopped state and handles
 2169  * the remove phy request.  In MPC mode the only time a phy can be removed
 2170  * from a port is in the SCI_BASE_PORT_STATE_STOPPED.
 2171  *
 2172  * @param[in] port This is the SCI_BASE_PORT object which is cast into a
 2173  *       SCIC_SDS_PORT object.
 2174  * @param[in] phy This is the SCI_BASE_PHY object which is cast into a
 2175  *       SCIC_SDS_PHY object.
 2176  *
 2177  * @return SCI_STATUS
 2178  * @retval SCI_FAILURE_UNSUPPORTED_PORT_CONFIGURATION is returned when the phy
 2179  *         can not be added to the port.
 2180  * @retval SCI_SUCCESS if the phy is added to the port.
 2181  */
 2182 static
 2183 SCI_STATUS scic_sds_port_stopped_state_remove_phy_handler(
 2184    SCI_BASE_PORT_T *port,
 2185    SCI_BASE_PHY_T  *phy
 2186 )
 2187 {
 2188    SCIC_SDS_PORT_T *this_port = (SCIC_SDS_PORT_T *)port;
 2189    SCIC_SDS_PHY_T  *this_phy  = (SCIC_SDS_PHY_T  *)phy;
 2190 
 2191    return scic_sds_port_clear_phy(this_port, this_phy);
 2192 }
 2193 
 2194 //****************************************************************************
 2195 //*  READY STATE HANDLERS
 2196 //****************************************************************************
 2197 
 2198 //****************************************************************************
 2199 //*  RESETTING STATE HANDLERS
 2200 //****************************************************************************
 2201 
 2202 //****************************************************************************
 2203 //*  STOPPING STATE HANDLERS
 2204 //****************************************************************************
 2205 
 2206 /**
 2207  * This method takes the SCIC_SDS_PORT that is in a stopping state and handles
 2208  * the complete io request. Should the request count reach 0 then the port
 2209  * object will transition to the stopped state.
 2210  *
 2211  * @param[in] port This is the SCIC_SDS_PORT object on which the io request
 2212  *       count will be decremented.
 2213  * @param[in] device This is the SCIC_SDS_REMOTE_DEVICE object to which the io
 2214  *       request is being directed.  This parameter is not required to
 2215  *       complete this operation.
 2216  * @param[in] io_request This is the request that is being completed on this
 2217  *       port object.  This parameter is not required to complete this
 2218  *       operation.
 2219  *
 2220  * @return SCI_STATUS
 2221  * @retval SCI_SUCCESS
 2222  */
 2223 static
 2224 SCI_STATUS scic_sds_port_stopping_state_complete_io_handler(
 2225    SCIC_SDS_PORT_T          *port,
 2226    SCIC_SDS_REMOTE_DEVICE_T *device,
 2227    SCIC_SDS_REQUEST_T       *io_request
 2228 )
 2229 {
 2230    SCIC_SDS_PORT_T *this_port = (SCIC_SDS_PORT_T *)port;
 2231 
 2232    scic_sds_port_decrement_request_count(this_port);
 2233 
 2234    if (this_port->started_request_count == 0)
 2235    {
 2236       sci_base_state_machine_change_state(
 2237          scic_sds_port_get_base_state_machine(this_port),
 2238          SCI_BASE_PORT_STATE_STOPPED
 2239       );
 2240    }
 2241 
 2242    return SCI_SUCCESS;
 2243 }
 2244 
 2245 //****************************************************************************
 2246 //*  RESETTING STATE HANDLERS
 2247 //****************************************************************************
 2248 
 2249 /**
 2250  * This method will stop a failed port.  This causes a transition to the
 2251  * stopping state.
 2252  *
 2253  * @param[in] port This is the port object which is being requested to stop.
 2254  *
 2255  * @return SCI_STATUS
 2256  * @retval SCI_SUCCESS
 2257  */
 2258 static
 2259 SCI_STATUS scic_sds_port_reset_state_stop_handler(
 2260    SCI_BASE_PORT_T *port
 2261 )
 2262 {
 2263    SCIC_SDS_PORT_T *this_port = (SCIC_SDS_PORT_T *)port;
 2264 
 2265    sci_base_state_machine_change_state(
 2266       &this_port->parent.state_machine,
 2267       SCI_BASE_PORT_STATE_STOPPING
 2268    );
 2269 
 2270    return SCI_SUCCESS;
 2271 }
 2272 
 2273 /**
 2274  * This method will transition a failed port to its ready state.  The port
 2275  * failed because a hard reset request timed out but at some time later one or
 2276  * more phys in the port became ready.
 2277  *
 2278  * @param[in] port This is the SCI_BASE_PORT object which is cast into a
 2279  *       SCIC_SDS_PORT object.
 2280  *
 2281  * @return SCI_STATUS
 2282  * @retval SCI_SUCCESS
 2283  */
 2284 static
 2285 void scic_sds_port_reset_state_link_up_handler(
 2286    SCIC_SDS_PORT_T *this_port,
 2287    SCIC_SDS_PHY_T  *phy
 2288 )
 2289 {
 2290    /// @todo We should make sure that the phy that has gone link up is the same
 2291    ///       one on which we sent the reset.  It is possible that the phy on
 2292    ///       which we sent the reset is not the one that has gone link up and we
 2293    ///       want to make sure that phy being reset comes back.  Consider the
 2294    ///       case where a reset is sent but before the hardware processes the
 2295    ///       reset it get a link up on the port because of a hot plug event.
 2296    ///       because of the reset request this phy will go link down almost
 2297    ///       immediately.
 2298 
 2299    // In the resetting state we don't notify the user regarding
 2300    // link up and link down notifications.
 2301    scic_sds_port_general_link_up_handler(this_port, phy, FALSE, TRUE);
 2302 }
 2303 
 2304 /**
 2305  * This method process link down notifications that occur during a
 2306  * port reset operation. Link downs can occur during the reset operation.
 2307  *
 2308  * @param[in] port This is the SCI_BASE_PORT object which is cast into a
 2309  *       SCIC_SDS_PORT object.
 2310  *
 2311  * @return SCI_STATUS
 2312  * @retval SCI_SUCCESS
 2313  */
 2314 static
 2315 void scic_sds_port_reset_state_link_down_handler(
 2316    SCIC_SDS_PORT_T *this_port,
 2317    SCIC_SDS_PHY_T  *phy
 2318 )
 2319 {
 2320    // In the resetting state we don't notify the user regarding
 2321    // link up and link down notifications.
 2322    scic_sds_port_deactivate_phy(this_port, phy, FALSE);
 2323 }
 2324 
 2325 // ---------------------------------------------------------------------------
 2326 
 2327 SCIC_SDS_PORT_STATE_HANDLER_T
 2328    scic_sds_port_state_handler_table[SCI_BASE_PORT_MAX_STATES] =
 2329 {
 2330    // SCI_BASE_PORT_STATE_STOPPED
 2331    {
 2332       {
 2333          scic_sds_port_stopped_state_start_handler,
 2334          scic_sds_port_stopped_state_stop_handler,
 2335          scic_sds_port_stopped_state_destruct_handler,
 2336          scic_sds_port_default_reset_handler,
 2337          scic_sds_port_stopped_state_add_phy_handler,
 2338          scic_sds_port_stopped_state_remove_phy_handler
 2339       },
 2340       scic_sds_port_default_frame_handler,
 2341       scic_sds_port_default_event_handler,
 2342       scic_sds_port_default_link_up_handler,
 2343       scic_sds_port_default_link_down_handler,
 2344       scic_sds_port_default_start_io_handler,
 2345       scic_sds_port_default_complete_io_handler
 2346    },
 2347    // SCI_BASE_PORT_STATE_STOPPING
 2348    {
 2349       {
 2350          scic_sds_port_default_start_handler,
 2351          scic_sds_port_default_stop_handler,
 2352          scic_sds_port_default_destruct_handler,
 2353          scic_sds_port_default_reset_handler,
 2354          scic_sds_port_default_add_phy_handler,
 2355          scic_sds_port_default_remove_phy_handler
 2356       },
 2357       scic_sds_port_default_frame_handler,
 2358       scic_sds_port_default_event_handler,
 2359       scic_sds_port_default_link_up_handler,
 2360       scic_sds_port_default_link_down_handler,
 2361       scic_sds_port_default_start_io_handler,
 2362       scic_sds_port_stopping_state_complete_io_handler
 2363    },
 2364    // SCI_BASE_PORT_STATE_READY
 2365    {
 2366       {
 2367          scic_sds_port_default_start_handler,
 2368          scic_sds_port_default_stop_handler,
 2369          scic_sds_port_default_destruct_handler,
 2370          scic_sds_port_default_reset_handler,
 2371          scic_sds_port_default_add_phy_handler,
 2372          scic_sds_port_default_remove_phy_handler
 2373       },
 2374       scic_sds_port_default_frame_handler,
 2375       scic_sds_port_default_event_handler,
 2376       scic_sds_port_default_link_up_handler,
 2377       scic_sds_port_default_link_down_handler,
 2378       scic_sds_port_default_start_io_handler,
 2379       scic_sds_port_general_complete_io_handler
 2380    },
 2381    // SCI_BASE_PORT_STATE_RESETTING
 2382    {
 2383       {
 2384          scic_sds_port_default_start_handler,
 2385          scic_sds_port_reset_state_stop_handler,
 2386          scic_sds_port_default_destruct_handler,
 2387          scic_sds_port_default_reset_handler,
 2388          scic_sds_port_default_add_phy_handler,
 2389          scic_sds_port_default_remove_phy_handler
 2390       },
 2391       scic_sds_port_default_frame_handler,
 2392       scic_sds_port_default_event_handler,
 2393       scic_sds_port_reset_state_link_up_handler,
 2394       scic_sds_port_reset_state_link_down_handler,
 2395       scic_sds_port_default_start_io_handler,
 2396       scic_sds_port_general_complete_io_handler
 2397    },
 2398    // SCI_BASE_PORT_STATE_FAILED
 2399    {
 2400       {
 2401          scic_sds_port_default_start_handler,
 2402          scic_sds_port_default_stop_handler,
 2403          scic_sds_port_default_destruct_handler,
 2404          scic_sds_port_default_reset_handler,
 2405          scic_sds_port_default_add_phy_handler,
 2406          scic_sds_port_default_remove_phy_handler
 2407       },
 2408       scic_sds_port_default_frame_handler,
 2409       scic_sds_port_default_event_handler,
 2410       scic_sds_port_default_link_up_handler,
 2411       scic_sds_port_default_link_down_handler,
 2412       scic_sds_port_default_start_io_handler,
 2413       scic_sds_port_general_complete_io_handler
 2414    }
 2415 };
 2416 
 2417 //******************************************************************************
 2418 //*  PORT STATE PRIVATE METHODS
 2419 //******************************************************************************
 2420 
 2421 /**
 2422  * This method will enable the SCU Port Task Scheduler for this port object
 2423  * but will leave the port task scheduler in a suspended state.
 2424  *
 2425  * @param[in] this_port This is the port object which to suspend.
 2426  *
 2427  * @return none
 2428  */
 2429 static
 2430 void scic_sds_port_enable_port_task_scheduler(
 2431    SCIC_SDS_PORT_T *this_port
 2432 )
 2433 {
 2434    U32 pts_control_value;
 2435 
 2436    pts_control_value = scu_port_task_scheduler_read(this_port, control);
 2437 
 2438    pts_control_value |= SCU_PTSxCR_GEN_BIT(ENABLE) | SCU_PTSxCR_GEN_BIT(SUSPEND);
 2439 
 2440    scu_port_task_scheduler_write(this_port, control, pts_control_value);
 2441 }
 2442 
 2443 /**
 2444  * This method will disable the SCU port task scheduler for this port
 2445  * object.
 2446  *
 2447  * @param[in] this_port This is the port object which to resume.
 2448  *
 2449  * @return none
 2450  */
 2451 static
 2452 void scic_sds_port_disable_port_task_scheduler(
 2453    SCIC_SDS_PORT_T *this_port
 2454 )
 2455 {
 2456    U32 pts_control_value;
 2457 
 2458    pts_control_value = scu_port_task_scheduler_read(this_port, control);
 2459 
 2460    pts_control_value &= ~(   SCU_PTSxCR_GEN_BIT(ENABLE)
 2461                            | SCU_PTSxCR_GEN_BIT(SUSPEND) );
 2462 
 2463    scu_port_task_scheduler_write(this_port, control, pts_control_value);
 2464 }
 2465 
 2466 /**
 2467  *
 2468  */
 2469 static
 2470 void scic_sds_port_post_dummy_remote_node(
 2471       SCIC_SDS_PORT_T *this_port
 2472 )
 2473 {
 2474    U32 command;
 2475    SCU_REMOTE_NODE_CONTEXT_T * rnc;
 2476 
 2477    if (this_port->reserved_rni != SCU_DUMMY_INDEX)
 2478    {
 2479    rnc = &(this_port->owning_controller->remote_node_context_table[this_port->reserved_rni]);
 2480 
 2481    rnc->ssp.is_valid = TRUE;
 2482 
 2483    command = (
 2484        (SCU_CONTEXT_COMMAND_POST_RNC_32)
 2485      | (this_port->physical_port_index << SCU_CONTEXT_COMMAND_LOGICAL_PORT_SHIFT)
 2486      | (this_port->reserved_rni)
 2487    );
 2488 
 2489    scic_sds_controller_post_request(this_port->owning_controller, command);
 2490 
 2491    scic_cb_stall_execution(10);
 2492 
 2493    command = (
 2494        (SCU_CONTEXT_COMMAND_POST_RNC_SUSPEND_TX_RX)
 2495      | (this_port->physical_port_index << SCU_CONTEXT_COMMAND_LOGICAL_PORT_SHIFT)
 2496      | (this_port->reserved_rni)
 2497    );
 2498 
 2499    scic_sds_controller_post_request(this_port->owning_controller, command);
 2500 }
 2501 }
 2502 
 2503 /**
 2504  *
 2505  */
 2506 static
 2507 void scic_sds_port_invalidate_dummy_remote_node(
 2508    SCIC_SDS_PORT_T *this_port
 2509 )
 2510 {
 2511    U32 command;
 2512    SCU_REMOTE_NODE_CONTEXT_T * rnc;
 2513 
 2514    if (this_port->reserved_rni != SCU_DUMMY_INDEX)
 2515    {
 2516    rnc = &(this_port->owning_controller->remote_node_context_table[this_port->reserved_rni]);
 2517 
 2518    rnc->ssp.is_valid = FALSE;
 2519 
 2520    scic_cb_stall_execution(10);
 2521 
 2522    command = (
 2523        (SCU_CONTEXT_COMMAND_POST_RNC_INVALIDATE)
 2524      | (this_port->physical_port_index << SCU_CONTEXT_COMMAND_LOGICAL_PORT_SHIFT)
 2525      | (this_port->reserved_rni)
 2526    );
 2527 
 2528    scic_sds_controller_post_request(this_port->owning_controller, command);
 2529 }
 2530 }
 2531 
 2532 //******************************************************************************
 2533 //*  PORT STATE METHODS
 2534 //******************************************************************************
 2535 
 2536 /**
 2537  * This method will perform the actions required by the SCIC_SDS_PORT on
 2538  * entering the SCI_BASE_PORT_STATE_STOPPED. This function sets the stopped
 2539  * state handlers for the SCIC_SDS_PORT object and disables the port task
 2540  * scheduler in the hardware.
 2541  *
 2542  * @param[in] object This is the SCI_BASE_OBJECT which is cast to a
 2543  *       SCIC_SDS_PORT object.
 2544  *
 2545  * @return none
 2546  */
 2547 static
 2548 void scic_sds_port_stopped_state_enter(
 2549    SCI_BASE_OBJECT_T *object
 2550 )
 2551 {
 2552    SCIC_SDS_PORT_T *this_port;
 2553    this_port = (SCIC_SDS_PORT_T *)object;
 2554 
 2555    scic_sds_port_set_base_state_handlers(
 2556       this_port, SCI_BASE_PORT_STATE_STOPPED
 2557    );
 2558 
 2559    if (
 2560          SCI_BASE_PORT_STATE_STOPPING
 2561       == this_port->parent.state_machine.previous_state_id
 2562       )
 2563    {
 2564       // If we enter this state becasuse of a request to stop
 2565       // the port then we want to disable the hardwares port
 2566       // task scheduler.
 2567       scic_sds_port_disable_port_task_scheduler(this_port);
 2568    }
 2569 }
 2570 
 2571 /**
 2572  * This method will perform the actions required by the SCIC_SDS_PORT on
 2573  * exiting the SCI_BASE_STATE_STOPPED. This function enables the SCU hardware
 2574  * port task scheduler.
 2575  *
 2576  * @param[in] object This is the SCI_BASE_OBJECT which is cast to a
 2577  *       SCIC_SDS_PORT object.
 2578  *
 2579  * @return none
 2580  */
 2581 static
 2582 void scic_sds_port_stopped_state_exit(
 2583    SCI_BASE_OBJECT_T *object
 2584 )
 2585 {
 2586    SCIC_SDS_PORT_T *this_port;
 2587    this_port = (SCIC_SDS_PORT_T *)object;
 2588 
 2589    // Enable and suspend the port task scheduler
 2590    scic_sds_port_enable_port_task_scheduler(this_port);
 2591 }
 2592 
 2593 /**
 2594  * This method will perform the actions required by the SCIC_SDS_PORT on
 2595  * entering the SCI_BASE_PORT_STATE_READY. This function sets the ready state
 2596  * handlers for the SCIC_SDS_PORT object, reports the port object as not ready
 2597  * and starts the ready substate machine.
 2598  *
 2599  * @param[in] object This is the SCI_BASE_OBJECT which is cast to a
 2600  *       SCIC_SDS_PORT object.
 2601  *
 2602  * @return none
 2603  */
 2604 static
 2605 void scic_sds_port_ready_state_enter(
 2606    SCI_BASE_OBJECT_T *object
 2607 )
 2608 {
 2609    SCIC_SDS_PORT_T *this_port;
 2610    this_port = (SCIC_SDS_PORT_T *)object;
 2611 
 2612    // Put the ready state handlers in place though they will not be there long
 2613    scic_sds_port_set_base_state_handlers(
 2614       this_port, SCI_BASE_PORT_STATE_READY
 2615    );
 2616 
 2617    if (
 2618           SCI_BASE_PORT_STATE_RESETTING
 2619       == this_port->parent.state_machine.previous_state_id
 2620       )
 2621    {
 2622       scic_cb_port_hard_reset_complete(
 2623          scic_sds_port_get_controller(this_port),
 2624          this_port,
 2625          SCI_SUCCESS
 2626       );
 2627    }
 2628    else
 2629    {
 2630       // Notify the caller that the port is not yet ready
 2631       scic_cb_port_not_ready(
 2632          scic_sds_port_get_controller(this_port),
 2633          this_port,
 2634          SCIC_PORT_NOT_READY_NO_ACTIVE_PHYS
 2635       );
 2636    }
 2637 
 2638    // Post and suspend the dummy remote node context for this
 2639    // port.
 2640    scic_sds_port_post_dummy_remote_node(this_port);
 2641 
 2642    // Start the ready substate machine
 2643    sci_base_state_machine_start(
 2644       scic_sds_port_get_ready_substate_machine(this_port)
 2645    );
 2646 }
 2647 
 2648 /**
 2649  * This method will perform the actions required by the SCIC_SDS_PORT on
 2650  * exiting the SCI_BASE_STATE_READY. This function does nothing.
 2651  *
 2652  * @param[in] object This is the SCI_BASE_OBJECT which is cast to a
 2653  *       SCIC_SDS_PORT object.
 2654  *
 2655  * @return none
 2656  */
 2657 static
 2658 void scic_sds_port_ready_state_exit(
 2659    SCI_BASE_OBJECT_T *object
 2660 )
 2661 {
 2662    SCIC_SDS_PORT_T *this_port;
 2663    this_port = (SCIC_SDS_PORT_T *)object;
 2664 
 2665    sci_base_state_machine_stop(&this_port->ready_substate_machine);
 2666 
 2667    scic_cb_stall_execution(10);
 2668    scic_sds_port_invalidate_dummy_remote_node(this_port);
 2669 }
 2670 
 2671 /**
 2672  * This method will perform the actions required by the SCIC_SDS_PORT on
 2673  * entering the SCI_BASE_PORT_STATE_RESETTING. This function sets the
 2674  * resetting state handlers for the SCIC_SDS_PORT object.
 2675  *
 2676  * @param[in] object This is the SCI_BASE_OBJECT which is cast to a
 2677  *       SCIC_SDS_PORT object.
 2678  *
 2679  * @return none
 2680  */
 2681 static
 2682 void scic_sds_port_resetting_state_enter(
 2683    SCI_BASE_OBJECT_T *object
 2684 )
 2685 {
 2686    SCIC_SDS_PORT_T *this_port;
 2687    this_port = (SCIC_SDS_PORT_T *)object;
 2688 
 2689    scic_sds_port_set_base_state_handlers(
 2690       this_port, SCI_BASE_PORT_STATE_RESETTING
 2691    );
 2692 }
 2693 
 2694 /**
 2695  * This method will perform the actions required by the SCIC_SDS_PORT on
 2696  * exiting the SCI_BASE_STATE_RESETTING. This function does nothing.
 2697  *
 2698  * @param[in] object This is the SCI_BASE_OBJECT which is cast to a
 2699  *       SCIC_SDS_PORT object.
 2700  *
 2701  * @return none
 2702  */
 2703 static
 2704 void scic_sds_port_resetting_state_exit(
 2705    SCI_BASE_OBJECT_T *object
 2706 )
 2707 {
 2708    SCIC_SDS_PORT_T *this_port;
 2709    this_port = (SCIC_SDS_PORT_T *)object;
 2710 
 2711    scic_cb_timer_stop(
 2712       scic_sds_port_get_controller(this_port),
 2713       this_port->timer_handle
 2714    );
 2715 }
 2716 
 2717 /**
 2718  * This method will perform the actions required by the SCIC_SDS_PORT on
 2719  * entering the SCI_BASE_PORT_STATE_STOPPING. This function sets the stopping
 2720  * state handlers for the SCIC_SDS_PORT object.
 2721  *
 2722  * @param[in] object This is the SCI_BASE_OBJECT which is cast to a
 2723  *       SCIC_SDS_PORT object.
 2724  *
 2725  * @return none
 2726  */
 2727 static
 2728 void scic_sds_port_stopping_state_enter(
 2729    SCI_BASE_OBJECT_T *object
 2730 )
 2731 {
 2732    SCIC_SDS_PORT_T *this_port;
 2733    this_port = (SCIC_SDS_PORT_T *)object;
 2734 
 2735    scic_sds_port_set_base_state_handlers(
 2736       this_port, SCI_BASE_PORT_STATE_STOPPING
 2737    );
 2738 
 2739    if (this_port->started_request_count == 0)
 2740    {
 2741       sci_base_state_machine_change_state(
 2742          &this_port->parent.state_machine,
 2743          SCI_BASE_PORT_STATE_STOPPED
 2744       );
 2745    }
 2746 }
 2747 
 2748 /**
 2749  * This method will perform the actions required by the SCIC_SDS_PORT on
 2750  * exiting the SCI_BASE_STATE_STOPPING. This function does nothing.
 2751  *
 2752  * @param[in] object This is the SCI_BASE_OBJECT which is cast to a
 2753  *       SCIC_SDS_PORT object.
 2754  *
 2755  * @return none
 2756  */
 2757 static
 2758 void scic_sds_port_stopping_state_exit(
 2759    SCI_BASE_OBJECT_T *object
 2760 )
 2761 {
 2762    SCIC_SDS_PORT_T *this_port;
 2763    this_port = (SCIC_SDS_PORT_T *)object;
 2764 
 2765    scic_cb_timer_stop(
 2766       scic_sds_port_get_controller(this_port),
 2767       this_port->timer_handle
 2768    );
 2769 
 2770    scic_cb_timer_destroy(
 2771       scic_sds_port_get_controller(this_port),
 2772       this_port->timer_handle
 2773    );
 2774    this_port->timer_handle = NULL;
 2775 
 2776    scic_sds_port_destroy_dummy_resources(this_port);
 2777 }
 2778 
 2779 /**
 2780  * This method will perform the actions required by the SCIC_SDS_PORT on
 2781  * entering the SCI_BASE_PORT_STATE_STOPPING. This function sets the stopping
 2782  * state handlers for the SCIC_SDS_PORT object.
 2783  *
 2784  * @param[in] object This is the SCI_BASE_OBJECT which is cast to a
 2785  *       SCIC_SDS_PORT object.
 2786  *
 2787  * @return none
 2788  */
 2789 static
 2790 void scic_sds_port_failed_state_enter(
 2791    SCI_BASE_OBJECT_T *object
 2792 )
 2793 {
 2794    SCIC_SDS_PORT_T *this_port;
 2795    this_port = (SCIC_SDS_PORT_T *)object;
 2796 
 2797    scic_sds_port_set_base_state_handlers(
 2798       this_port,
 2799       SCI_BASE_PORT_STATE_FAILED
 2800    );
 2801 
 2802    scic_cb_port_hard_reset_complete(
 2803       scic_sds_port_get_controller(this_port),
 2804       this_port,
 2805       SCI_FAILURE_TIMEOUT
 2806    );
 2807 }
 2808 
 2809 // ---------------------------------------------------------------------------
 2810 
 2811 SCI_BASE_STATE_T scic_sds_port_state_table[SCI_BASE_PORT_MAX_STATES] =
 2812 {
 2813    {
 2814       SCI_BASE_PORT_STATE_STOPPED,
 2815       scic_sds_port_stopped_state_enter,
 2816       scic_sds_port_stopped_state_exit
 2817    },
 2818    {
 2819       SCI_BASE_PORT_STATE_STOPPING,
 2820       scic_sds_port_stopping_state_enter,
 2821       scic_sds_port_stopping_state_exit
 2822    },
 2823    {
 2824       SCI_BASE_PORT_STATE_READY,
 2825       scic_sds_port_ready_state_enter,
 2826       scic_sds_port_ready_state_exit
 2827    },
 2828    {
 2829       SCI_BASE_PORT_STATE_RESETTING,
 2830       scic_sds_port_resetting_state_enter,
 2831       scic_sds_port_resetting_state_exit
 2832    },
 2833    {
 2834       SCI_BASE_PORT_STATE_FAILED,
 2835       scic_sds_port_failed_state_enter,
 2836       NULL
 2837    }
 2838 };
 2839 
 2840 //******************************************************************************
 2841 //* PORT READY SUB-STATE MACHINE
 2842 //******************************************************************************
 2843 
 2844 //****************************************************************************
 2845 //*  READY SUBSTATE HANDLERS
 2846 //****************************************************************************
 2847 
 2848 /**
 2849  * This method is the general ready state stop handler for the SCIC_SDS_PORT
 2850  * object.  This function will transition the ready substate machine to its
 2851  * final state.
 2852  *
 2853  * @param[in] port This is the SCI_BASE_PORT object which is cast into a
 2854  *       SCIC_SDS_PORT object.
 2855  *
 2856  * @return SCI_STATUS
 2857  * @retval SCI_SUCCESS
 2858  */
 2859 static
 2860 SCI_STATUS scic_sds_port_ready_substate_stop_handler(
 2861    SCI_BASE_PORT_T *port
 2862 )
 2863 {
 2864    SCIC_SDS_PORT_T *this_port = (SCIC_SDS_PORT_T *)port;
 2865 
 2866    sci_base_state_machine_change_state(
 2867       &this_port->parent.state_machine,
 2868       SCI_BASE_PORT_STATE_STOPPING
 2869    );
 2870 
 2871    return SCI_SUCCESS;
 2872 }
 2873 
 2874 /**
 2875  * This method is the general ready substate complete io handler for the
 2876  * SCIC_SDS_PORT object.  This function decrments the outstanding request
 2877  * count for this port object.
 2878  *
 2879  * @param[in] port This is the SCI_BASE_PORT object which is cast into a
 2880  *       SCIC_SDS_PORT object.
 2881  * @param[in] device This is the SCI_BASE_REMOTE_DEVICE object which is not
 2882  *       used in this function.
 2883  * @param[in] io_request This is the SCI_BASE_REQUEST object which is not used
 2884  *       in this function.
 2885  *
 2886  * @return SCI_STATUS
 2887  * @retval SCI_SUCCESS
 2888  */
 2889 static
 2890 SCI_STATUS scic_sds_port_ready_substate_complete_io_handler(
 2891    SCIC_SDS_PORT_T               *port,
 2892    struct SCIC_SDS_REMOTE_DEVICE *device,
 2893    struct SCIC_SDS_REQUEST       *io_request
 2894 )
 2895 {
 2896    SCIC_SDS_PORT_T *this_port = (SCIC_SDS_PORT_T *)port;
 2897 
 2898    scic_sds_port_decrement_request_count(this_port);
 2899 
 2900    return SCI_SUCCESS;
 2901 }
 2902 
 2903 static
 2904 SCI_STATUS scic_sds_port_ready_substate_add_phy_handler(
 2905    SCI_BASE_PORT_T *port,
 2906    SCI_BASE_PHY_T  *phy
 2907 )
 2908 {
 2909    SCIC_SDS_PORT_T * this_port = (SCIC_SDS_PORT_T *)port;
 2910    SCIC_SDS_PHY_T  * this_phy  = (SCIC_SDS_PHY_T  *)phy;
 2911    SCI_STATUS        status;
 2912 
 2913    status = scic_sds_port_set_phy(this_port, this_phy);
 2914 
 2915    if (status == SCI_SUCCESS)
 2916    {
 2917       scic_sds_port_general_link_up_handler(this_port, this_phy, TRUE, FALSE);
 2918 
 2919       this_port->not_ready_reason = SCIC_PORT_NOT_READY_RECONFIGURING;
 2920 
 2921       sci_base_state_machine_change_state(
 2922          &this_port->ready_substate_machine,
 2923          SCIC_SDS_PORT_READY_SUBSTATE_CONFIGURING
 2924       );
 2925    }
 2926 
 2927    return status;
 2928 }
 2929 
 2930 static
 2931 SCI_STATUS scic_sds_port_ready_substate_remove_phy_handler(
 2932    SCI_BASE_PORT_T *port,
 2933    SCI_BASE_PHY_T  *phy
 2934 )
 2935 {
 2936    SCIC_SDS_PORT_T * this_port = (SCIC_SDS_PORT_T *)port;
 2937    SCIC_SDS_PHY_T  * this_phy  = (SCIC_SDS_PHY_T  *)phy;
 2938    SCI_STATUS        status;
 2939 
 2940    status = scic_sds_port_clear_phy(this_port, this_phy);
 2941 
 2942    if (status == SCI_SUCCESS)
 2943    {
 2944       scic_sds_port_deactivate_phy(this_port, this_phy, TRUE);
 2945 
 2946       this_port->not_ready_reason = SCIC_PORT_NOT_READY_RECONFIGURING;
 2947 
 2948       sci_base_state_machine_change_state(
 2949          &this_port->ready_substate_machine,
 2950          SCIC_SDS_PORT_READY_SUBSTATE_CONFIGURING
 2951       );
 2952    }
 2953 
 2954    return status;
 2955 }
 2956 
 2957 //****************************************************************************
 2958 //*  READY SUBSTATE WAITING HANDLERS
 2959 //****************************************************************************
 2960 
 2961 /**
 2962  * This method is the ready waiting substate link up handler for the
 2963  * SCIC_SDS_PORT object.  This methos will report the link up condition for
 2964  * this port and will transition to the ready operational substate.
 2965  *
 2966  * @param[in] this_port This is the SCIC_SDS_PORT object that which has a phy
 2967  *       that has gone link up.
 2968  * @param[in] the_phy This is the SCIC_SDS_PHY object that has gone link up.
 2969  *
 2970  * @return none
 2971  */
 2972 static
 2973 void scic_sds_port_ready_waiting_substate_link_up_handler(
 2974    SCIC_SDS_PORT_T *this_port,
 2975    SCIC_SDS_PHY_T  *the_phy
 2976 )
 2977 {
 2978    // Since this is the first phy going link up for the port we can just enable
 2979    // it and continue.
 2980    scic_sds_port_activate_phy(this_port, the_phy, TRUE, TRUE);
 2981 
 2982    sci_base_state_machine_change_state(
 2983       &this_port->ready_substate_machine,
 2984       SCIC_SDS_PORT_READY_SUBSTATE_OPERATIONAL
 2985    );
 2986 }
 2987 
 2988 /**
 2989  * This method is the ready waiting substate start io handler for the
 2990  * SCIC_SDS_PORT object. The port object can not accept new requests so the
 2991  * request is failed.
 2992  *
 2993  * @param[in] port This is the SCI_BASE_PORT object which is cast into a
 2994  *       SCIC_SDS_PORT object.
 2995  * @param[in] device This is the SCI_BASE_REMOTE_DEVICE object which is not
 2996  *       used in this request.
 2997  * @param[in] io_request This is the SCI_BASE_REQUEST object which is not used
 2998  *       in this function.
 2999  *
 3000  * @return SCI_STATUS
 3001  * @retval SCI_FAILURE_INVALID_STATE
 3002  */
 3003 static
 3004 SCI_STATUS scic_sds_port_ready_waiting_substate_start_io_handler(
 3005    SCIC_SDS_PORT_T          *port,
 3006    SCIC_SDS_REMOTE_DEVICE_T *device,
 3007    SCIC_SDS_REQUEST_T       *io_request
 3008 )
 3009 {
 3010    return SCI_FAILURE_INVALID_STATE;
 3011 }
 3012 
 3013 //****************************************************************************
 3014 //*  READY SUBSTATE OPERATIONAL HANDLERS
 3015 //****************************************************************************
 3016 
 3017 /**
 3018  * This method will cause the port to reset.
 3019  *
 3020  * @param[in] port This is the SCI_BASE_PORT object which is cast into a
 3021  *       SCIC_SDS_PORT object.
 3022  * @param[in] timeout This is the timeout for the reset request to complete.
 3023  *
 3024  * @return SCI_STATUS
 3025  * @retval SCI_SUCCESS
 3026  */
 3027 static
 3028 SCI_STATUS scic_sds_port_ready_operational_substate_reset_handler(
 3029    SCI_BASE_PORT_T * port,
 3030    U32               timeout
 3031 )
 3032 {
 3033    SCI_STATUS        status = SCI_FAILURE_INVALID_PHY;
 3034    U32               phy_index;
 3035    SCIC_SDS_PORT_T * this_port = (SCIC_SDS_PORT_T *)port;
 3036    SCIC_SDS_PHY_T  * selected_phy = SCI_INVALID_HANDLE;
 3037 
 3038 
 3039    // Select a phy on which we can send the hard reset request.
 3040    for (
 3041          phy_index = 0;
 3042             (phy_index < SCI_MAX_PHYS)
 3043          && (selected_phy == SCI_INVALID_HANDLE);
 3044          phy_index++
 3045        )
 3046    {
 3047       selected_phy = this_port->phy_table[phy_index];
 3048 
 3049       if (
 3050             (selected_phy != SCI_INVALID_HANDLE)
 3051          && !scic_sds_port_active_phy(this_port, selected_phy)
 3052          )
 3053       {
 3054          // We found a phy but it is not ready select different phy
 3055          selected_phy = SCI_INVALID_HANDLE;
 3056       }
 3057    }
 3058 
 3059    // If we have a phy then go ahead and start the reset procedure
 3060    if (selected_phy != SCI_INVALID_HANDLE)
 3061    {
 3062       status = scic_sds_phy_reset(selected_phy);
 3063 
 3064       if (status == SCI_SUCCESS)
 3065       {
 3066          scic_cb_timer_start(
 3067             scic_sds_port_get_controller(this_port),
 3068             this_port->timer_handle,
 3069             timeout
 3070          );
 3071 
 3072          this_port->not_ready_reason = SCIC_PORT_NOT_READY_HARD_RESET_REQUESTED;
 3073 
 3074          sci_base_state_machine_change_state(
 3075             &this_port->parent.state_machine,
 3076             SCI_BASE_PORT_STATE_RESETTING
 3077          );
 3078       }
 3079    }
 3080 
 3081    return status;
 3082 }
 3083 
 3084 /**
 3085  * This method is the ready operational substate link up handler for the
 3086  * SCIC_SDS_PORT object. This function notifies the SCI User that the phy has
 3087  * gone link up.
 3088  *
 3089  * @param[in] this_port This is the SCIC_SDS_PORT object that which has a phy
 3090  *       that has gone link up.
 3091  * @param[in] the_phy This is the SCIC_SDS_PHY object that has gone link up.
 3092  *
 3093  * @return none
 3094  */
 3095 static
 3096 void scic_sds_port_ready_operational_substate_link_up_handler(
 3097    SCIC_SDS_PORT_T *this_port,
 3098    SCIC_SDS_PHY_T  *the_phy
 3099 )
 3100 {
 3101    scic_sds_port_general_link_up_handler(this_port, the_phy, TRUE, TRUE);
 3102 }
 3103 
 3104 /**
 3105  * This method is the ready operational substate link down handler for the
 3106  * SCIC_SDS_PORT object. This function notifies the SCI User that the phy has
 3107  * gone link down and if this is the last phy in the port the port will change
 3108  * state to the ready waiting substate.
 3109  *
 3110  * @param[in] this_port This is the SCIC_SDS_PORT object that which has a phy
 3111  *       that has gone link down.
 3112  * @param[in] the_phy This is the SCIC_SDS_PHY object that has gone link down.
 3113  *
 3114  * @return none
 3115  */
 3116 static
 3117 void scic_sds_port_ready_operational_substate_link_down_handler(
 3118    SCIC_SDS_PORT_T *this_port,
 3119    SCIC_SDS_PHY_T  *the_phy
 3120 )
 3121 {
 3122    scic_sds_port_deactivate_phy(this_port, the_phy, TRUE);
 3123 
 3124    // If there are no active phys left in the port, then transition
 3125    // the port to the WAITING state until such time as a phy goes
 3126    // link up.
 3127    if (this_port->active_phy_mask == 0)
 3128    {
 3129       sci_base_state_machine_change_state(
 3130          scic_sds_port_get_ready_substate_machine(this_port),
 3131          SCIC_SDS_PORT_READY_SUBSTATE_WAITING
 3132       );
 3133    }
 3134 }
 3135 
 3136 /**
 3137  * This method is the ready operational substate start io handler for the
 3138  * SCIC_SDS_PORT object.  This function incremetns the outstanding request
 3139  * count for this port object.
 3140  *
 3141  * @param[in] port This is the SCI_BASE_PORT object which is cast into a
 3142  *       SCIC_SDS_PORT object.
 3143  * @param[in] device This is the SCI_BASE_REMOTE_DEVICE object which is not
 3144  *       used in this function.
 3145  * @param[in] io_request This is the SCI_BASE_REQUEST object which is not used
 3146  *       in this function.
 3147  *
 3148  * @return SCI_STATUS
 3149  * @retval SCI_SUCCESS
 3150  */
 3151 static
 3152 SCI_STATUS scic_sds_port_ready_operational_substate_start_io_handler(
 3153    SCIC_SDS_PORT_T          *port,
 3154    SCIC_SDS_REMOTE_DEVICE_T *device,
 3155    SCIC_SDS_REQUEST_T       *io_request
 3156 )
 3157 {
 3158    SCIC_SDS_PORT_T *this_port = (SCIC_SDS_PORT_T *)port;
 3159 
 3160    scic_sds_port_increment_request_count(this_port);
 3161 
 3162    return SCI_SUCCESS;
 3163 }
 3164 
 3165 //****************************************************************************
 3166 //*  READY SUBSTATE OPERATIONAL HANDLERS
 3167 //****************************************************************************
 3168 
 3169 /**
 3170  * This is the default method for a port add phy request.  It will report a
 3171  * warning and exit.
 3172  *
 3173  * @param[in] port This is the SCI_BASE_PORT object which is cast into a
 3174  *       SCIC_SDS_PORT object.
 3175  *
 3176  * @return SCI_STATUS
 3177  * @retval SCI_FAILURE_INVALID_STATE
 3178  */
 3179 static
 3180 SCI_STATUS scic_sds_port_ready_configuring_substate_add_phy_handler(
 3181    SCI_BASE_PORT_T *port,
 3182    SCI_BASE_PHY_T  *phy
 3183 )
 3184 {
 3185    SCIC_SDS_PORT_T * this_port = (SCIC_SDS_PORT_T *)port;
 3186    SCIC_SDS_PHY_T  * this_phy  = (SCIC_SDS_PHY_T  *)phy;
 3187    SCI_STATUS        status;
 3188 
 3189    status = scic_sds_port_set_phy(this_port, this_phy);
 3190 
 3191    if (status == SCI_SUCCESS)
 3192    {
 3193       scic_sds_port_general_link_up_handler(this_port, this_phy, TRUE, FALSE);
 3194 
 3195       // Re-enter the configuring state since this may be the last phy in
 3196       // the port.
 3197       sci_base_state_machine_change_state(
 3198          &this_port->ready_substate_machine,
 3199          SCIC_SDS_PORT_READY_SUBSTATE_CONFIGURING
 3200       );
 3201    }
 3202 
 3203    return status;
 3204 }
 3205 
 3206 /**
 3207  * This is the default method for a port remove phy request.  It will report a
 3208  * warning and exit.
 3209  *
 3210  * @param[in] port This is the SCI_BASE_PORT object which is cast into a
 3211  *       SCIC_SDS_PORT object.
 3212  *
 3213  * @return SCI_STATUS
 3214  * @retval SCI_FAILURE_INVALID_STATE
 3215  */
 3216 static
 3217 SCI_STATUS scic_sds_port_ready_configuring_substate_remove_phy_handler(
 3218    SCI_BASE_PORT_T *port,
 3219    SCI_BASE_PHY_T  *phy
 3220 )
 3221 {
 3222    SCIC_SDS_PORT_T * this_port = (SCIC_SDS_PORT_T *)port;
 3223    SCIC_SDS_PHY_T  * this_phy  = (SCIC_SDS_PHY_T  *)phy;
 3224    SCI_STATUS        status;
 3225 
 3226    status = scic_sds_port_clear_phy(this_port, this_phy);
 3227 
 3228    if (status == SCI_SUCCESS)
 3229    {
 3230       scic_sds_port_deactivate_phy(this_port, this_phy, TRUE);
 3231 
 3232       // Re-enter the configuring state since this may be the last phy in
 3233       // the port.
 3234       sci_base_state_machine_change_state(
 3235          &this_port->ready_substate_machine,
 3236          SCIC_SDS_PORT_READY_SUBSTATE_CONFIGURING
 3237       );
 3238    }
 3239 
 3240    return status;
 3241 }
 3242 
 3243 /**
 3244  * This method will decrement the outstanding request count for this port.
 3245  * If the request count goes to 0 then the port can be reprogrammed with
 3246  * its new phy data.
 3247  *
 3248  * @param[in] port This is the port that is being requested to complete
 3249  *            the io request.
 3250  * @param[in] device This is the device on which the io is completing.
 3251  * @param[in] io_request This is the io request that is completing.
 3252  */
 3253 static
 3254 SCI_STATUS scic_sds_port_ready_configuring_substate_complete_io_handler(
 3255    SCIC_SDS_PORT_T          *port,
 3256    SCIC_SDS_REMOTE_DEVICE_T *device,
 3257    SCIC_SDS_REQUEST_T       *io_request
 3258 )
 3259 {
 3260    scic_sds_port_decrement_request_count(port);
 3261 
 3262    if (port->started_request_count == 0)
 3263    {
 3264       sci_base_state_machine_change_state(
 3265          &port->ready_substate_machine,
 3266          SCIC_SDS_PORT_READY_SUBSTATE_OPERATIONAL
 3267       );
 3268    }
 3269 
 3270    return SCI_SUCCESS;
 3271 }
 3272 
 3273 // ---------------------------------------------------------------------------
 3274 
 3275 SCIC_SDS_PORT_STATE_HANDLER_T
 3276    scic_sds_port_ready_substate_handler_table[SCIC_SDS_PORT_READY_MAX_SUBSTATES] =
 3277 {
 3278    // SCIC_SDS_PORT_READY_SUBSTATE_WAITING
 3279    {
 3280       {
 3281          scic_sds_port_default_start_handler,
 3282          scic_sds_port_ready_substate_stop_handler,
 3283          scic_sds_port_default_destruct_handler,
 3284          scic_sds_port_default_reset_handler,
 3285          scic_sds_port_ready_substate_add_phy_handler,
 3286          scic_sds_port_default_remove_phy_handler
 3287       },
 3288       scic_sds_port_default_frame_handler,
 3289       scic_sds_port_default_event_handler,
 3290       scic_sds_port_ready_waiting_substate_link_up_handler,
 3291       scic_sds_port_default_link_down_handler,
 3292       scic_sds_port_ready_waiting_substate_start_io_handler,
 3293       scic_sds_port_ready_substate_complete_io_handler,
 3294    },
 3295    // SCIC_SDS_PORT_READY_SUBSTATE_OPERATIONAL
 3296    {
 3297       {
 3298          scic_sds_port_default_start_handler,
 3299          scic_sds_port_ready_substate_stop_handler,
 3300          scic_sds_port_default_destruct_handler,
 3301          scic_sds_port_ready_operational_substate_reset_handler,
 3302          scic_sds_port_ready_substate_add_phy_handler,
 3303          scic_sds_port_ready_substate_remove_phy_handler
 3304       },
 3305       scic_sds_port_default_frame_handler,
 3306       scic_sds_port_default_event_handler,
 3307       scic_sds_port_ready_operational_substate_link_up_handler,
 3308       scic_sds_port_ready_operational_substate_link_down_handler,
 3309       scic_sds_port_ready_operational_substate_start_io_handler,
 3310       scic_sds_port_ready_substate_complete_io_handler
 3311    },
 3312    // SCIC_SDS_PORT_READY_SUBSTATE_CONFIGURING
 3313    {
 3314       {
 3315          scic_sds_port_default_start_handler,
 3316          scic_sds_port_ready_substate_stop_handler,
 3317          scic_sds_port_default_destruct_handler,
 3318          scic_sds_port_default_reset_handler,
 3319          scic_sds_port_ready_configuring_substate_add_phy_handler,
 3320          scic_sds_port_ready_configuring_substate_remove_phy_handler
 3321       },
 3322       scic_sds_port_default_frame_handler,
 3323       scic_sds_port_default_event_handler,
 3324       scic_sds_port_default_link_up_handler,
 3325       scic_sds_port_default_link_down_handler,
 3326       scic_sds_port_default_start_io_handler,
 3327       scic_sds_port_ready_configuring_substate_complete_io_handler
 3328    }
 3329 };
 3330 
 3331 /**
 3332  * This macro sets the port ready substate handlers.
 3333  */
 3334 #define scic_sds_port_set_ready_state_handlers(port, state_id) \
 3335    scic_sds_port_set_state_handlers( \
 3336       port, &scic_sds_port_ready_substate_handler_table[(state_id)] \
 3337    )
 3338 
 3339 //******************************************************************************
 3340 //*  PORT STATE PRIVATE METHODS
 3341 //******************************************************************************
 3342 
 3343 /**
 3344  * This method will susped the port task scheduler for this port object.
 3345  *
 3346  * @param[in] this_port This is the SCIC_SDS_PORT object to suspend.
 3347  *
 3348  * @return none
 3349  */
 3350 void scic_sds_port_suspend_port_task_scheduler(
 3351    SCIC_SDS_PORT_T *this_port
 3352 )
 3353 {
 3354    U32 pts_control_value;
 3355 
 3356    pts_control_value = scu_port_task_scheduler_read(this_port, control);
 3357    pts_control_value |= SCU_PTSxCR_GEN_BIT(SUSPEND);
 3358    scu_port_task_scheduler_write(this_port, control, pts_control_value);
 3359 }
 3360 
 3361 /**
 3362  * This method will resume the port task scheduler for this port object.
 3363  *
 3364  * @param[in] this_port This is the SCIC_SDS_PORT object to resume.
 3365  *
 3366  * @return none
 3367  */
 3368 void scic_sds_port_resume_port_task_scheduler(
 3369    SCIC_SDS_PORT_T *this_port
 3370 )
 3371 {
 3372    U32 pts_control_value;
 3373 
 3374    pts_control_value = scu_port_task_scheduler_read(this_port, control);
 3375 
 3376    pts_control_value &= ~SCU_PTSxCR_GEN_BIT(SUSPEND);
 3377 
 3378    scu_port_task_scheduler_write(this_port, control, pts_control_value);
 3379 }
 3380 
 3381 /**
 3382  * This routine will post the dummy request.  This will prevent the hardware
 3383  * scheduler from posting new requests to the front of the scheduler queue
 3384  * causing a starvation problem for currently ongoing requests.
 3385  *
 3386  * @parm[in] this_port The port on which the task must be posted.
 3387  *
 3388  * @return none
 3389  */
 3390 static
 3391 void scic_sds_port_post_dummy_request(
 3392    SCIC_SDS_PORT_T *this_port
 3393 )
 3394 {
 3395    U32 command;
 3396    SCU_TASK_CONTEXT_T * task_context;
 3397 
 3398    if (this_port->reserved_tci != SCU_DUMMY_INDEX)
 3399    {
 3400    task_context = scic_sds_controller_get_task_context_buffer(
 3401                      this_port->owning_controller,
 3402                      this_port->reserved_tci
 3403                   );
 3404 
 3405    task_context->abort = 0;
 3406 
 3407    command = (
 3408          (SCU_CONTEXT_COMMAND_REQUEST_TYPE_POST_TC)
 3409       | (this_port->physical_port_index << SCU_CONTEXT_COMMAND_LOGICAL_PORT_SHIFT)
 3410       | (this_port->reserved_tci)
 3411    );
 3412 
 3413    scic_sds_controller_post_request(this_port->owning_controller, command);
 3414 }
 3415 }
 3416 
 3417 /**
 3418  * This routine will abort the dummy request.  This will alow the hardware to
 3419  * power down parts of the silicon to save power.
 3420  *
 3421  * @parm[in] this_port The port on which the task must be aborted.
 3422  *
 3423  * @return none
 3424  */
 3425 static
 3426 void scic_sds_port_abort_dummy_request(
 3427    SCIC_SDS_PORT_T *this_port
 3428 )
 3429 {
 3430    U32 command;
 3431    SCU_TASK_CONTEXT_T * task_context;
 3432 
 3433    if (this_port->reserved_tci != SCU_DUMMY_INDEX)
 3434    {
 3435    task_context = scic_sds_controller_get_task_context_buffer(
 3436                      this_port->owning_controller,
 3437                      this_port->reserved_tci
 3438                   );
 3439 
 3440    task_context->abort = 1;
 3441 
 3442    command = (
 3443         (SCU_CONTEXT_COMMAND_REQUEST_POST_TC_ABORT)
 3444       | (this_port->physical_port_index << SCU_CONTEXT_COMMAND_LOGICAL_PORT_SHIFT)
 3445       | (this_port->reserved_tci)
 3446    );
 3447 
 3448    scic_sds_controller_post_request(this_port->owning_controller, command);
 3449 }
 3450 }
 3451 
 3452 //******************************************************************************
 3453 //*  PORT READY SUBSTATE METHODS
 3454 //******************************************************************************
 3455 
 3456 /**
 3457  * This method will perform the actions required by the SCIC_SDS_PORT on
 3458  * entering the SCIC_SDS_PORT_READY_SUBSTATE_WAITING. This function checks the
 3459  * port for any ready phys.  If there is at least one phy in a ready state
 3460  * then the port transitions to the ready operational substate.
 3461  *
 3462  * @param[in] object This is the SCI_BASE_OBJECT which is cast to a
 3463  *       SCIC_SDS_PORT object.
 3464  *
 3465  * @return none
 3466  */
 3467 static
 3468 void scic_sds_port_ready_substate_waiting_enter(
 3469    SCI_BASE_OBJECT_T *object
 3470 )
 3471 {
 3472    SCIC_SDS_PORT_T *this_port = (SCIC_SDS_PORT_T *)object;
 3473 
 3474    scic_sds_port_set_ready_state_handlers(
 3475       this_port, SCIC_SDS_PORT_READY_SUBSTATE_WAITING
 3476    );
 3477 
 3478    scic_sds_port_suspend_port_task_scheduler(this_port);
 3479 
 3480 
 3481    this_port->not_ready_reason = SCIC_PORT_NOT_READY_NO_ACTIVE_PHYS;
 3482 
 3483    if (this_port->active_phy_mask != 0)
 3484    {
 3485       // At least one of the phys on the port is ready
 3486       sci_base_state_machine_change_state(
 3487          &this_port->ready_substate_machine,
 3488          SCIC_SDS_PORT_READY_SUBSTATE_OPERATIONAL
 3489       );
 3490    }
 3491 }
 3492 
 3493 /**
 3494  * This method will perform the actions required by the SCIC_SDS_PORT on
 3495  * exiting the SCIC_SDS_PORT_READY_SUBSTATE_WAITING. This function resume the
 3496  * PTSG that was suspended at the entry of this state.
 3497  *
 3498  * @param[in] object This is the SCI_BASE_OBJECT which is cast to a
 3499  *       SCIC_SDS_PORT object.
 3500  *
 3501  * @return none
 3502  */
 3503 static
 3504 void scic_sds_port_ready_substate_waiting_exit(
 3505    SCI_BASE_OBJECT_T *object
 3506 )
 3507 {
 3508    SCIC_SDS_PORT_T *this_port = (SCIC_SDS_PORT_T *)object;
 3509    scic_sds_port_resume_port_task_scheduler(this_port);
 3510 }
 3511 
 3512 /**
 3513  * This method will perform the actions required by the SCIC_SDS_PORT on
 3514  * entering the SCIC_SDS_PORT_READY_SUBSTATE_OPERATIONAL. This function sets
 3515  * the state handlers for the port object, notifies the SCI User that the port
 3516  * is ready, and resumes port operations.
 3517  *
 3518  * @param[in] object This is the SCI_BASE_OBJECT which is cast to a
 3519  *       SCIC_SDS_PORT object.
 3520  *
 3521  * @return none
 3522  */
 3523 static
 3524 void scic_sds_port_ready_substate_operational_enter(
 3525    SCI_BASE_OBJECT_T *object
 3526 )
 3527 {
 3528    U32 index;
 3529    SCIC_SDS_PORT_T *this_port = (SCIC_SDS_PORT_T *)object;
 3530 
 3531    scic_sds_port_set_ready_state_handlers(
 3532       this_port, SCIC_SDS_PORT_READY_SUBSTATE_OPERATIONAL
 3533    );
 3534 
 3535    scic_cb_port_ready(
 3536       scic_sds_port_get_controller(this_port), this_port
 3537    );
 3538 
 3539    for (index = 0; index < SCI_MAX_PHYS; index++)
 3540    {
 3541       if (this_port->phy_table[index] != NULL)
 3542       {
 3543          scic_sds_port_write_phy_assignment(
 3544             this_port, this_port->phy_table[index]
 3545          );
 3546 
 3547          //if the bit at the index location for active phy mask is set and
 3548          //enabled_phy_mask is not set then resume the phy
 3549          if ( ( (this_port->active_phy_mask ^ this_port->enabled_phy_mask) & (1 << index) ) != 0)
 3550          {
 3551             scic_sds_port_resume_phy (
 3552                this_port,
 3553                this_port->phy_table[index]
 3554             );
 3555          }
 3556       }
 3557    }
 3558 
 3559    scic_sds_port_update_viit_entry(this_port);
 3560 
 3561    // Post the dummy task for the port so the hardware can schedule
 3562    // io correctly
 3563    scic_sds_port_post_dummy_request(this_port);
 3564 }
 3565 
 3566 /**
 3567  * This method will perform the actions required by the SCIC_SDS_PORT on
 3568  * exiting the SCIC_SDS_PORT_READY_SUBSTATE_OPERATIONAL. This function reports
 3569  * the port not ready and suspends the port task scheduler.
 3570  *
 3571  * @param[in] object This is the SCI_BASE_OBJECT which is cast to a
 3572  *       SCIC_SDS_PORT object.
 3573  *
 3574  * @return none
 3575  */
 3576 static
 3577 void scic_sds_port_ready_substate_operational_exit(
 3578    SCI_BASE_OBJECT_T *object
 3579 )
 3580 {
 3581    SCIC_SDS_PORT_T *this_port = (SCIC_SDS_PORT_T *)object;
 3582 
 3583    // Kill the dummy task for this port if it has not yet posted
 3584    // the hardware will treat this as a NOP and just return abort
 3585    // complete.
 3586    scic_sds_port_abort_dummy_request(this_port);
 3587 
 3588    scic_cb_port_not_ready(
 3589       scic_sds_port_get_controller(this_port),
 3590       this_port,
 3591       this_port->not_ready_reason
 3592    );
 3593 }
 3594 
 3595 //******************************************************************************
 3596 //*  PORT READY CONFIGURING METHODS
 3597 //******************************************************************************
 3598 
 3599 /**
 3600  * This method will perform the actions required by the SCIC_SDS_PORT on
 3601  * exiting the SCIC_SDS_PORT_READY_SUBSTATE_OPERATIONAL. This function reports
 3602  * the port not ready and suspends the port task scheduler.
 3603  *
 3604  * @param[in] object This is the SCI_BASE_OBJECT which is cast to a
 3605  *       SCIC_SDS_PORT object.
 3606  *
 3607  * @return none
 3608  */
 3609 static
 3610 void scic_sds_port_ready_substate_configuring_enter(
 3611    SCI_BASE_OBJECT_T *object
 3612 )
 3613 {
 3614    SCIC_SDS_PORT_T *this_port = (SCIC_SDS_PORT_T *)object;
 3615 
 3616    scic_sds_port_set_ready_state_handlers(
 3617       this_port, SCIC_SDS_PORT_READY_SUBSTATE_CONFIGURING
 3618    );
 3619 
 3620    if (this_port->active_phy_mask == 0)
 3621    {
 3622       scic_cb_port_not_ready(
 3623          scic_sds_port_get_controller(this_port),
 3624          this_port,
 3625          SCIC_PORT_NOT_READY_NO_ACTIVE_PHYS
 3626       );
 3627 
 3628       sci_base_state_machine_change_state(
 3629          &this_port->ready_substate_machine,
 3630          SCIC_SDS_PORT_READY_SUBSTATE_WAITING
 3631       );
 3632    }
 3633    //do not wait for IO to go to 0 in this state.
 3634    else
 3635    {
 3636       sci_base_state_machine_change_state(
 3637          &this_port->ready_substate_machine,
 3638          SCIC_SDS_PORT_READY_SUBSTATE_OPERATIONAL
 3639       );
 3640    }
 3641 }
 3642 
 3643 // ---------------------------------------------------------------------------
 3644 
 3645 SCI_BASE_STATE_T
 3646    scic_sds_port_ready_substate_table[SCIC_SDS_PORT_READY_MAX_SUBSTATES] =
 3647 {
 3648    {
 3649       SCIC_SDS_PORT_READY_SUBSTATE_WAITING,
 3650       scic_sds_port_ready_substate_waiting_enter,
 3651       scic_sds_port_ready_substate_waiting_exit
 3652    },
 3653    {
 3654       SCIC_SDS_PORT_READY_SUBSTATE_OPERATIONAL,
 3655       scic_sds_port_ready_substate_operational_enter,
 3656       scic_sds_port_ready_substate_operational_exit
 3657    },
 3658    {
 3659       SCIC_SDS_PORT_READY_SUBSTATE_CONFIGURING,
 3660       scic_sds_port_ready_substate_configuring_enter,
 3661       NULL
 3662    }
 3663 };
 3664 

Cache object: 18e3ea226e41b73645a927a08ed69756


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