in fusion/mptsas.c [3060:3305]
static int mptsas_probe_one_phy(struct device *dev,
struct mptsas_phyinfo *phy_info, int index, int local)
{
MPT_ADAPTER *ioc;
struct sas_phy *phy;
struct sas_port *port;
int error = 0;
VirtTarget *vtarget;
if (!dev) {
error = -ENODEV;
goto out;
}
if (!phy_info->phy) {
phy = sas_phy_alloc(dev, index);
if (!phy) {
error = -ENOMEM;
goto out;
}
} else
phy = phy_info->phy;
mptsas_parse_device_info(&phy->identify, &phy_info->identify);
/*
* Set Negotiated link rate.
*/
switch (phy_info->negotiated_link_rate) {
case MPI_SAS_IOUNIT0_RATE_PHY_DISABLED:
phy->negotiated_linkrate = SAS_PHY_DISABLED;
break;
case MPI_SAS_IOUNIT0_RATE_FAILED_SPEED_NEGOTIATION:
phy->negotiated_linkrate = SAS_LINK_RATE_FAILED;
break;
case MPI_SAS_IOUNIT0_RATE_1_5:
phy->negotiated_linkrate = SAS_LINK_RATE_1_5_GBPS;
break;
case MPI_SAS_IOUNIT0_RATE_3_0:
phy->negotiated_linkrate = SAS_LINK_RATE_3_0_GBPS;
break;
case MPI_SAS_IOUNIT0_RATE_6_0:
phy->negotiated_linkrate = SAS_LINK_RATE_6_0_GBPS;
break;
case MPI_SAS_IOUNIT0_RATE_SATA_OOB_COMPLETE:
case MPI_SAS_IOUNIT0_RATE_UNKNOWN:
default:
phy->negotiated_linkrate = SAS_LINK_RATE_UNKNOWN;
break;
}
/*
* Set Max hardware link rate.
*/
switch (phy_info->hw_link_rate & MPI_SAS_PHY0_PRATE_MAX_RATE_MASK) {
case MPI_SAS_PHY0_HWRATE_MAX_RATE_1_5:
phy->maximum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS;
break;
case MPI_SAS_PHY0_PRATE_MAX_RATE_3_0:
phy->maximum_linkrate_hw = SAS_LINK_RATE_3_0_GBPS;
break;
default:
break;
}
/*
* Set Max programmed link rate.
*/
switch (phy_info->programmed_link_rate &
MPI_SAS_PHY0_PRATE_MAX_RATE_MASK) {
case MPI_SAS_PHY0_PRATE_MAX_RATE_1_5:
phy->maximum_linkrate = SAS_LINK_RATE_1_5_GBPS;
break;
case MPI_SAS_PHY0_PRATE_MAX_RATE_3_0:
phy->maximum_linkrate = SAS_LINK_RATE_3_0_GBPS;
break;
default:
break;
}
/*
* Set Min hardware link rate.
*/
switch (phy_info->hw_link_rate & MPI_SAS_PHY0_HWRATE_MIN_RATE_MASK) {
case MPI_SAS_PHY0_HWRATE_MIN_RATE_1_5:
phy->minimum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS;
break;
case MPI_SAS_PHY0_PRATE_MIN_RATE_3_0:
phy->minimum_linkrate_hw = SAS_LINK_RATE_3_0_GBPS;
break;
default:
break;
}
/*
* Set Min programmed link rate.
*/
switch (phy_info->programmed_link_rate &
MPI_SAS_PHY0_PRATE_MIN_RATE_MASK) {
case MPI_SAS_PHY0_PRATE_MIN_RATE_1_5:
phy->minimum_linkrate = SAS_LINK_RATE_1_5_GBPS;
break;
case MPI_SAS_PHY0_PRATE_MIN_RATE_3_0:
phy->minimum_linkrate = SAS_LINK_RATE_3_0_GBPS;
break;
default:
break;
}
if (!phy_info->phy) {
error = sas_phy_add(phy);
if (error) {
sas_phy_free(phy);
goto out;
}
phy_info->phy = phy;
}
if (!phy_info->attached.handle ||
!phy_info->port_details)
goto out;
port = mptsas_get_port(phy_info);
ioc = phy_to_ioc(phy_info->phy);
if (phy_info->sas_port_add_phy) {
if (!port) {
port = sas_port_alloc_num(dev);
if (!port) {
error = -ENOMEM;
goto out;
}
error = sas_port_add(port);
if (error) {
dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
"%s: exit at line=%d\n", ioc->name,
__func__, __LINE__));
goto out;
}
mptsas_set_port(ioc, phy_info, port);
devtprintk(ioc, dev_printk(KERN_DEBUG, &port->dev,
MYIOC_s_FMT "add port %d, sas_addr (0x%llx)\n",
ioc->name, port->port_identifier,
(unsigned long long)phy_info->
attached.sas_address));
}
dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT
"sas_port_add_phy: phy_id=%d\n",
ioc->name, phy_info->phy_id));
sas_port_add_phy(port, phy_info->phy);
phy_info->sas_port_add_phy = 0;
devtprintk(ioc, dev_printk(KERN_DEBUG, &phy_info->phy->dev,
MYIOC_s_FMT "add phy %d, phy-obj (0x%p)\n", ioc->name,
phy_info->phy_id, phy_info->phy));
}
if (!mptsas_get_rphy(phy_info) && port && !port->rphy) {
struct sas_rphy *rphy;
struct device *parent;
struct sas_identify identify;
parent = dev->parent->parent;
/*
* Let the hotplug_work thread handle processing
* the adding/removing of devices that occur
* after start of day.
*/
if (mptsas_is_end_device(&phy_info->attached) &&
phy_info->attached.handle_parent) {
goto out;
}
mptsas_parse_device_info(&identify, &phy_info->attached);
if (scsi_is_host_device(parent)) {
struct mptsas_portinfo *port_info;
int i;
port_info = ioc->hba_port_info;
for (i = 0; i < port_info->num_phys; i++)
if (port_info->phy_info[i].identify.sas_address ==
identify.sas_address) {
sas_port_mark_backlink(port);
goto out;
}
} else if (scsi_is_sas_rphy(parent)) {
struct sas_rphy *parent_rphy = dev_to_rphy(parent);
if (identify.sas_address ==
parent_rphy->identify.sas_address) {
sas_port_mark_backlink(port);
goto out;
}
}
switch (identify.device_type) {
case SAS_END_DEVICE:
rphy = sas_end_device_alloc(port);
break;
case SAS_EDGE_EXPANDER_DEVICE:
case SAS_FANOUT_EXPANDER_DEVICE:
rphy = sas_expander_alloc(port, identify.device_type);
break;
default:
rphy = NULL;
break;
}
if (!rphy) {
dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
"%s: exit at line=%d\n", ioc->name,
__func__, __LINE__));
goto out;
}
rphy->identify = identify;
error = sas_rphy_add(rphy);
if (error) {
dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
"%s: exit at line=%d\n", ioc->name,
__func__, __LINE__));
sas_rphy_free(rphy);
goto out;
}
mptsas_set_rphy(ioc, phy_info, rphy);
if (identify.device_type == SAS_EDGE_EXPANDER_DEVICE ||
identify.device_type == SAS_FANOUT_EXPANDER_DEVICE)
mptsas_exp_repmanufacture_info(ioc,
identify.sas_address,
rphy_to_expander_device(rphy));
}
/* If the device exists, verify it wasn't previously flagged
as a missing device. If so, clear it */
vtarget = mptsas_find_vtarget(ioc,
phy_info->attached.channel,
phy_info->attached.id);
if (vtarget && vtarget->inDMD) {
printk(KERN_INFO "Device returned, unsetting inDMD\n");
vtarget->inDMD = 0;
}
out:
return error;
}