in fusion/mptsas.c [3534:3615]
static void mptsas_expander_delete(MPT_ADAPTER *ioc,
struct mptsas_portinfo *port_info, u8 force)
{
struct mptsas_portinfo *parent;
int i;
u64 expander_sas_address;
struct mptsas_phyinfo *phy_info;
struct mptsas_portinfo buffer;
struct mptsas_portinfo_details *port_details;
struct sas_port *port;
if (!port_info)
return;
/* see if expander is still there before deleting */
mptsas_sas_expander_pg0(ioc, &buffer,
(MPI_SAS_EXPAND_PGAD_FORM_HANDLE <<
MPI_SAS_EXPAND_PGAD_FORM_SHIFT),
port_info->phy_info[0].identify.handle);
if (buffer.num_phys) {
kfree(buffer.phy_info);
if (!force)
return;
}
/*
* Obtain the port_info instance to the parent port
*/
port_details = NULL;
expander_sas_address =
port_info->phy_info[0].identify.sas_address;
parent = mptsas_find_portinfo_by_handle(ioc,
port_info->phy_info[0].identify.handle_parent);
mptsas_delete_expander_siblings(ioc, parent, port_info);
if (!parent)
goto out;
/*
* Delete rphys in the parent that point
* to this expander.
*/
phy_info = parent->phy_info;
port = NULL;
for (i = 0; i < parent->num_phys; i++, phy_info++) {
if (!phy_info->phy)
continue;
if (phy_info->attached.sas_address !=
expander_sas_address)
continue;
if (!port) {
port = mptsas_get_port(phy_info);
port_details = phy_info->port_details;
}
dev_printk(KERN_DEBUG, &phy_info->phy->dev,
MYIOC_s_FMT "delete phy %d, phy-obj (0x%p)\n", ioc->name,
phy_info->phy_id, phy_info->phy);
sas_port_delete_phy(port, phy_info->phy);
}
if (port) {
dev_printk(KERN_DEBUG, &port->dev,
MYIOC_s_FMT "delete port %d, sas_addr (0x%llx)\n",
ioc->name, port->port_identifier,
(unsigned long long)expander_sas_address);
sas_port_delete(port);
mptsas_port_delete(ioc, port_details);
}
out:
printk(MYIOC_s_INFO_FMT "delete expander: num_phys %d, "
"sas_addr (0x%llx)\n", ioc->name, port_info->num_phys,
(unsigned long long)expander_sas_address);
/*
* free link
*/
list_del(&port_info->list);
kfree(port_info->phy_info);
kfree(port_info);
}