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; } }
static enum sci_status sci_mpc_agent_validate_phy_configuration(struct isci_host *ihost, struct sci_port_configuration_agent *port_agent) { u32 phy_mask; u32 assigned_phy_mask; struct sci_sas_address sas_address; struct sci_sas_address phy_assigned_address; u8 port_index; u8 phy_index; assigned_phy_mask = 0; sas_address.high = 0; sas_address.low = 0; for (port_index = 0; port_index < SCI_MAX_PORTS; port_index++) { phy_mask = ihost->oem_parameters.ports[port_index].phy_mask; if (!phy_mask) continue; if ((phy_mask & ~assigned_phy_mask) == 0) { return SCI_FAILURE_UNSUPPORTED_PORT_CONFIGURATION; } for (phy_index = 0; phy_index < SCI_MAX_PHYS; phy_index++) { if ((phy_mask & (1 << phy_index)) == 0) continue; sci_phy_get_sas_address(&ihost->phys[phy_index], &sas_address); port_agent->phy_valid_port_range[phy_index].min_index = port_index; port_agent->phy_valid_port_range[phy_index].max_index = phy_index; if (phy_index != port_index) { return SCI_FAILURE_UNSUPPORTED_PORT_CONFIGURATION; } break; } while (phy_index < SCI_MAX_PHYS) { if ((phy_mask & (1 << phy_index)) == 0) continue; sci_phy_get_sas_address(&ihost->phys[phy_index], &phy_assigned_address); if (sci_sas_address_compare(sas_address, phy_assigned_address) != 0) { return SCI_FAILURE_UNSUPPORTED_PORT_CONFIGURATION; } port_agent->phy_valid_port_range[phy_index].min_index = port_index; port_agent->phy_valid_port_range[phy_index].max_index = phy_index; sci_port_add_phy(&ihost->ports[port_index], &ihost->phys[phy_index]); assigned_phy_mask |= (1 << phy_index); } phy_index++; } return sci_port_configuration_agent_validate_ports(ihost, port_agent); }
/* verify all of the phys in the same port are using the same SAS address */ static enum sci_status sci_mpc_agent_validate_phy_configuration(struct isci_host *ihost, struct sci_port_configuration_agent *port_agent) { u32 phy_mask; u32 assigned_phy_mask; struct sci_sas_address sas_address; struct sci_sas_address phy_assigned_address; u8 port_index; u8 phy_index; assigned_phy_mask = 0; sas_address.high = 0; sas_address.low = 0; for (port_index = 0; port_index < SCI_MAX_PORTS; port_index++) { phy_mask = ihost->oem_parameters.ports[port_index].phy_mask; if (!phy_mask) continue; /* * Make sure that one or more of the phys were not already assinged to * a different port. */ if ((phy_mask & ~assigned_phy_mask) == 0) { return SCI_FAILURE_UNSUPPORTED_PORT_CONFIGURATION; } /* Find the starting phy index for this round through the loop */ for (phy_index = 0; phy_index < SCI_MAX_PHYS; phy_index++) { if ((phy_mask & (1 << phy_index)) == 0) continue; sci_phy_get_sas_address(&ihost->phys[phy_index], &sas_address); /* * The phy_index can be used as the starting point for the * port range since the hardware starts all logical ports * the same as the PE index. */ port_agent->phy_valid_port_range[phy_index].min_index = port_index; port_agent->phy_valid_port_range[phy_index].max_index = phy_index; if (phy_index != port_index) { return SCI_FAILURE_UNSUPPORTED_PORT_CONFIGURATION; } break; } /* * See how many additional phys are being added to this logical port. * Note: We have not moved the current phy_index so we will actually * compare the startting phy with itself. * This is expected and required to add the phy to the port. */ while (phy_index < SCI_MAX_PHYS) { if ((phy_mask & (1 << phy_index)) == 0) continue; sci_phy_get_sas_address(&ihost->phys[phy_index], &phy_assigned_address); if (sci_sas_address_compare(sas_address, phy_assigned_address) != 0) { /* * The phy mask specified that this phy is part of the same port * as the starting phy and it is not so fail this configuration */ return SCI_FAILURE_UNSUPPORTED_PORT_CONFIGURATION; } port_agent->phy_valid_port_range[phy_index].min_index = port_index; port_agent->phy_valid_port_range[phy_index].max_index = phy_index; sci_port_add_phy(&ihost->ports[port_index], &ihost->phys[phy_index]); assigned_phy_mask |= (1 << phy_index); } phy_index++; } return sci_port_configuration_agent_validate_ports(ihost, port_agent); }