/** * sci_apc_agent_link_up - handle apc link up events * @scic: This is the controller object that receives the link up * notification. * @sci_port: This is the port object associated with the phy. If the is no * associated port this is an NULL. * @sci_phy: This is the phy object which has gone link up. * * This method handles the automatic port configuration for link up * notifications. Is it possible to get a link down notification from a phy * that has no assocoated port? */ static void sci_apc_agent_link_up(struct isci_host *ihost, struct sci_port_configuration_agent *port_agent, struct isci_port *iport, struct isci_phy *iphy) { u8 phy_index = iphy->phy_index; if (!iport) { /* the phy is not the part of this port */ port_agent->phy_ready_mask |= 1 << phy_index; sci_apc_agent_start_timer(port_agent, SCIC_SDS_APC_WAIT_LINK_UP_NOTIFICATION); } else { /* the phy is already the part of the port */ u32 port_state = iport->sm.current_state_id; /* if the PORT'S state is resetting then the link up is from * port hard reset in this case, we need to tell the port * that link up is recieved */ BUG_ON(port_state != SCI_PORT_RESETTING); port_agent->phy_ready_mask |= 1 << phy_index; sci_port_link_up(iport, iphy); } }
/** * sci_apc_agent_link_up - handle apc link up events * @scic: This is the controller object that receives the link up * notification. * @sci_port: This is the port object associated with the phy. If the is no * associated port this is an NULL. * @sci_phy: This is the phy object which has gone link up. * * This method handles the automatic port configuration for link up * notifications. Is it possible to get a link down notification from a phy * that has no assocoated port? */ static void sci_apc_agent_link_up(struct isci_host *ihost, struct sci_port_configuration_agent *port_agent, struct isci_port *iport, struct isci_phy *iphy) { u8 phy_index = iphy->phy_index; if (!iport) { /* the phy is not the part of this port */ port_agent->phy_ready_mask |= 1 << phy_index; sci_apc_agent_start_timer(port_agent, SCIC_SDS_APC_WAIT_LINK_UP_NOTIFICATION); } else { /* the phy is already the part of the port */ port_agent->phy_ready_mask |= 1 << phy_index; sci_port_link_up(iport, iphy); } }
static void sci_apc_agent_link_up(struct isci_host *ihost, struct sci_port_configuration_agent *port_agent, struct isci_port *iport, struct isci_phy *iphy) { u8 phy_index = iphy->phy_index; if (!iport) { port_agent->phy_ready_mask |= 1 << phy_index; sci_apc_agent_start_timer(port_agent, SCIC_SDS_APC_WAIT_LINK_UP_NOTIFICATION); } else { u32 port_state = iport->sm.current_state_id; BUG_ON(port_state != SCI_PORT_RESETTING); port_agent->phy_ready_mask |= 1 << phy_index; sci_port_link_up(iport, iphy); } }
static void sci_apc_agent_configure_ports(struct isci_host *ihost, struct sci_port_configuration_agent *port_agent, struct isci_phy *iphy, bool start_timer) { u8 port_index; enum sci_status status; struct isci_port *iport; enum SCIC_SDS_APC_ACTIVITY apc_activity = SCIC_SDS_APC_SKIP_PHY; iport = sci_port_configuration_agent_find_port(ihost, iphy); if (iport) { if (sci_port_is_valid_phy_assignment(iport, iphy->phy_index)) apc_activity = SCIC_SDS_APC_ADD_PHY; else apc_activity = SCIC_SDS_APC_SKIP_PHY; } else { for (port_index = port_agent->phy_valid_port_range[iphy->phy_index].min_index; port_index <= port_agent->phy_valid_port_range[iphy->phy_index].max_index; port_index++) { iport = &ihost->ports[port_index]; if (sci_port_is_valid_phy_assignment(iport, iphy->phy_index)) { if (iport->active_phy_mask > (1 << iphy->phy_index)) { apc_activity = SCIC_SDS_APC_SKIP_PHY; break; } if (iport->physical_port_index == iphy->phy_index) { if (apc_activity != SCIC_SDS_APC_START_TIMER) { apc_activity = SCIC_SDS_APC_ADD_PHY; } break; } if (iport->active_phy_mask == 0) { apc_activity = SCIC_SDS_APC_START_TIMER; } } else if (iport->active_phy_mask != 0) { apc_activity = SCIC_SDS_APC_SKIP_PHY; } } } 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 = sci_port_add_phy(iport, iphy); if (status == SCI_SUCCESS) { port_agent->phy_configured_mask |= (1 << iphy->phy_index); } break; case SCIC_SDS_APC_START_TIMER: sci_apc_agent_start_timer(port_agent, SCIC_SDS_APC_WAIT_LINK_UP_NOTIFICATION); break; case SCIC_SDS_APC_SKIP_PHY: default: break; } }
static void sci_apc_agent_configure_ports(struct isci_host *ihost, struct sci_port_configuration_agent *port_agent, struct isci_phy *iphy, bool start_timer) { u8 port_index; enum sci_status status; struct isci_port *iport; enum SCIC_SDS_APC_ACTIVITY apc_activity = SCIC_SDS_APC_SKIP_PHY; iport = sci_port_configuration_agent_find_port(ihost, iphy); if (iport) { if (sci_port_is_valid_phy_assignment(iport, iphy->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[iphy->phy_index].min_index; port_index <= port_agent->phy_valid_port_range[iphy->phy_index].max_index; port_index++) { iport = &ihost->ports[port_index]; /* First we must make sure that this PHY can be added to this Port. */ if (sci_port_is_valid_phy_assignment(iport, iphy->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 (iport->active_phy_mask > (1 << iphy->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 (iport->physical_port_index == iphy->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 (iport->active_phy_mask == 0) { apc_activity = SCIC_SDS_APC_START_TIMER; } } else if (iport->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 = sci_port_add_phy(iport, iphy); if (status == SCI_SUCCESS) { port_agent->phy_configured_mask |= (1 << iphy->phy_index); } break; case SCIC_SDS_APC_START_TIMER: sci_apc_agent_start_timer(port_agent, 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; } }