/**
 * This routine will find a matching port for the phy.  This means that the
 * port and phy both have the same broadcast sas address and same received
 * sas address.
 *
 * @param[in] controller The controller object used for the port search.
 * @param[in] phy The phy object to match.
 *
 * @return The port address or the SCI_INVALID_HANDLE if there is no matching
 *         port.
 *
 * @retvalue port address if the port can be found to match the phy.
 * @retvalue SCI_INVALID_HANDLE if there is no matching port for the phy.
 */
static
SCIC_SDS_PORT_T * scic_sds_port_configuration_agent_find_port(
   SCIC_SDS_CONTROLLER_T * controller,
   SCIC_SDS_PHY_T        * phy
)
{
   U8 port_index;
   SCI_PORT_HANDLE_T port_handle;
   SCI_SAS_ADDRESS_T port_sas_address;
   SCI_SAS_ADDRESS_T port_attached_device_address;
   SCI_SAS_ADDRESS_T phy_sas_address;
   SCI_SAS_ADDRESS_T phy_attached_device_address;

   SCIC_LOG_TRACE((
      sci_base_object_get_logger(controller),
      SCIC_LOG_OBJECT_CONTROLLER | SCIC_LOG_OBJECT_PORT | SCIC_LOG_OBJECT_PHY,
      "scic_sds_port_confgiruation_agent_find_port(0x%08x, 0x%08x) enter\n",
      controller, phy
   ));

   // Since this phy can be a member of a wide port check to see if one or
   // more phys match the sent and received SAS address as this phy in which
   // case it should participate in the same port.
   scic_sds_phy_get_sas_address(phy, &phy_sas_address);
   scic_sds_phy_get_attached_sas_address(phy, &phy_attached_device_address);

   for (port_index = 0; port_index < SCI_MAX_PORTS; port_index++)
   {
      if (scic_controller_get_port_handle(controller, port_index, &port_handle) == SCI_SUCCESS)
      {
         SCIC_SDS_PORT_T * port = (SCIC_SDS_PORT_T *)port_handle;

         scic_sds_port_get_sas_address(port, &port_sas_address);
         scic_sds_port_get_attached_sas_address(port, &port_attached_device_address);

         if (
               (sci_sas_address_compare(port_sas_address, phy_sas_address) == 0)
            && (sci_sas_address_compare(port_attached_device_address, phy_attached_device_address) == 0)
            )
         {
            return port;
         }
      }
   }

   return SCI_INVALID_HANDLE;
}
Exemplo n.º 2
0
/**
 * @brief This method constructs the framework's SAS domain object.  During
 *        the construction process a linkage to the corresponding core port
 *        object.
 *
 * @param[in]  domain This parameter specifies the domain object to be
 *             constructed.
 * @param[in]  domain_id This parameter specifies the ID for the domain
 *             object.
 * @param[in]  fw_controller This parameter specifies the controller managing
 *             the domain being constructed.
 *
 * @return none
 */
void scif_sas_domain_construct(
   SCIF_SAS_DOMAIN_T     * fw_domain,
   U8                      domain_id,
   SCIF_SAS_CONTROLLER_T * fw_controller
)
{
   SCIF_LOG_TRACE((
      sci_base_object_get_logger(fw_controller),
      SCIF_LOG_OBJECT_DOMAIN | SCIF_LOG_OBJECT_INITIALIZATION,
      "scif_sas_domain_construct(0x%x, 0x%x, 0x%x) enter\n",
      fw_domain, domain_id, fw_controller
   ));

   sci_base_domain_construct(
      &fw_domain->parent,
      sci_base_object_get_logger(fw_controller),
      scif_sas_domain_state_table
   );

   scif_sas_domain_initialize_state_logging(fw_domain);

   sci_abstract_list_construct(
      &fw_domain->remote_device_list, &fw_controller->free_remote_device_pool
   );

   // Retrieve the core's port object that directly corresponds to this
   // domain.
   scic_controller_get_port_handle(
      fw_controller->core_object, domain_id, &fw_domain->core_object
   );

   // Set the association in the core port to this framework domain object.
   sci_object_set_association(
      (SCI_OBJECT_HANDLE_T) fw_domain->core_object, fw_domain
   );

   sci_fast_list_init(&fw_domain->request_list);

   fw_domain->operation.timer = NULL;

   fw_domain->is_port_ready      = FALSE;
   fw_domain->device_start_count = 0;
   fw_domain->controller         = fw_controller;
   fw_domain->operation.status   = SCI_SUCCESS;
   fw_domain->is_config_route_table_needed = FALSE;
}
/**
 * This method handles the automatic port configuration for link up notifications.
 *
 * @param[in] controller This is the controller object that receives the
 *            link up notification.
 * @param[in] phy This is the phy object which has gone link up.
 * @param[in] start_timer This tells the routine if it should start the timer for
 *            any phys that might be added to a port in the future.
 */
static
void scic_sds_apc_agent_configure_ports(
   SCIC_SDS_CONTROLLER_T               * controller,
   SCIC_SDS_PORT_CONFIGURATION_AGENT_T * port_agent,
   SCIC_SDS_PHY_T                      * phy,
   BOOL                                  start_timer
)
{
   U8 port_index;
   SCI_STATUS status;
   SCIC_SDS_PORT_T * port;
   SCI_PORT_HANDLE_T port_handle;
   enum SCIC_SDS_APC_ACTIVITY apc_activity = SCIC_SDS_APC_SKIP_PHY;

   SCIC_LOG_TRACE((
      sci_base_object_get_logger(controller),
      SCIC_LOG_OBJECT_CONTROLLER | SCIC_LOG_OBJECT_PORT | SCIC_LOG_OBJECT_PHY,
      "scic_sds_apc_agent_configure_ports(0x%08x, 0x%08x, 0x%08x, %d) enter\n",
      controller, port_agent, phy, start_timer
   ));

   port = scic_sds_port_configuration_agent_find_port(controller, phy);

   if (port != SCI_INVALID_HANDLE)
   {
      if (scic_sds_port_is_valid_phy_assignment(port, phy->phy_index))
         apc_activity = SCIC_SDS_APC_ADD_PHY;
      else
         apc_activity = SCIC_SDS_APC_SKIP_PHY;
   }
   else
   {
      // There is no matching Port for this PHY so lets search through the
      // Ports and see if we can add the PHY to its own port or maybe start
      // the timer and wait to see if a wider port can be made.
      //
      // Note the break when we reach the condition of the port id == phy id
      for (
             port_index = port_agent->phy_valid_port_range[phy->phy_index].min_index;
             port_index <= port_agent->phy_valid_port_range[phy->phy_index].max_index;
             port_index++
          )
      {
         scic_controller_get_port_handle(controller, port_index, &port_handle);

         port = (SCIC_SDS_PORT_T *)port_handle;

         // First we must make sure that this PHY can be added to this Port.
         if (scic_sds_port_is_valid_phy_assignment(port, phy->phy_index))
         {
            // Port contains a PHY with a greater PHY ID than the current
            // PHY that has gone link up.  This phy can not be part of any
            // port so skip it and move on.
            if (port->active_phy_mask > (1 << phy->phy_index))
            {
               apc_activity = SCIC_SDS_APC_SKIP_PHY;
               break;
            }

            // We have reached the end of our Port list and have not found
            // any reason why we should not either add the PHY to the port
            // or wait for more phys to become active.
            if (port->physical_port_index == phy->phy_index)
            {
               // The Port either has no active PHYs.
               // Consider that if the port had any active PHYs we would have
               // or active PHYs with
               // a lower PHY Id than this PHY.
               if (apc_activity != SCIC_SDS_APC_START_TIMER)
               {
                  apc_activity = SCIC_SDS_APC_ADD_PHY;
               }

               break;
            }

            // The current Port has no active PHYs and this PHY could be part
            // of this Port.  Since we dont know as yet setup to start the
            // timer and see if there is a better configuration.
            if (port->active_phy_mask == 0)
            {
               apc_activity = SCIC_SDS_APC_START_TIMER;
            }
         }
         else if (port->active_phy_mask != 0)
         {
            // The Port has an active phy and the current Phy can not
            // participate in this port so skip the PHY and see if
            // there is a better configuration.
            apc_activity = SCIC_SDS_APC_SKIP_PHY;
         }
      }
   }

   // Check to see if the start timer operations should instead map to an
   // add phy operation.  This is caused because we have been waiting to
   // add a phy to a port but could not becuase the automatic port
   // configuration engine had a choice of possible ports for the phy.
   // Since we have gone through a timeout we are going to restrict the
   // choice to the smallest possible port.
   if (
         (start_timer == FALSE)
      && (apc_activity == SCIC_SDS_APC_START_TIMER)
      )
   {
      apc_activity = SCIC_SDS_APC_ADD_PHY;
   }

   switch (apc_activity)
   {
   case SCIC_SDS_APC_ADD_PHY:
      status = scic_sds_port_add_phy(port, phy);

      if (status == SCI_SUCCESS)
      {
         port_agent->phy_configured_mask |= (1 << phy->phy_index);
      }
      break;

   case SCIC_SDS_APC_START_TIMER:
      scic_sds_apc_agent_start_timer(
         controller, port_agent, phy, SCIC_SDS_APC_WAIT_LINK_UP_NOTIFICATION
      );
      break;

   case SCIC_SDS_APC_SKIP_PHY:
   default:
      // do nothing the PHY can not be made part of a port at this time.
      break;
   }
}