diff options
Diffstat (limited to 'drivers/scsi')
-rw-r--r-- | drivers/scsi/libsas/sas_expander.c | 36 |
1 files changed, 24 insertions, 12 deletions
diff --git a/drivers/scsi/libsas/sas_expander.c b/drivers/scsi/libsas/sas_expander.c index e34a93435497..d31e6fa466f7 100644 --- a/drivers/scsi/libsas/sas_expander.c +++ b/drivers/scsi/libsas/sas_expander.c @@ -597,10 +597,15 @@ static struct domain_device *sas_ex_discover_end_dev( child->iproto = phy->attached_iproto; memcpy(child->sas_addr, phy->attached_sas_addr, SAS_ADDR_SIZE); sas_hash_addr(child->hashed_sas_addr, child->sas_addr); - phy->port = sas_port_alloc(&parent->rphy->dev, phy_id); - BUG_ON(!phy->port); - /* FIXME: better error handling*/ - BUG_ON(sas_port_add(phy->port) != 0); + if (!phy->port) { + phy->port = sas_port_alloc(&parent->rphy->dev, phy_id); + if (unlikely(!phy->port)) + goto out_err; + if (unlikely(sas_port_add(phy->port) != 0)) { + sas_port_free(phy->port); + goto out_err; + } + } sas_ex_get_linkrate(parent, child, phy); if ((phy->attached_tproto & SAS_PROTO_STP) || phy->attached_sata_dev) { @@ -615,8 +620,7 @@ static struct domain_device *sas_ex_discover_end_dev( SAS_DPRINTK("report phy sata to %016llx:0x%x returned " "0x%x\n", SAS_ADDR(parent->sas_addr), phy_id, res); - kfree(child); - return NULL; + goto out_free; } memcpy(child->frame_rcvd, &child->sata_dev.rps_resp.rps.fis, sizeof(struct dev_to_host_fis)); @@ -627,14 +631,14 @@ static struct domain_device *sas_ex_discover_end_dev( "%016llx:0x%x returned 0x%x\n", SAS_ADDR(child->sas_addr), SAS_ADDR(parent->sas_addr), phy_id, res); - kfree(child); - return NULL; + goto out_free; } } else if (phy->attached_tproto & SAS_PROTO_SSP) { child->dev_type = SAS_END_DEV; rphy = sas_end_device_alloc(phy->port); /* FIXME: error handling */ - BUG_ON(!rphy); + if (unlikely(!rphy)) + goto out_free; child->tproto = phy->attached_tproto; sas_init_dev(child); @@ -651,9 +655,7 @@ static struct domain_device *sas_ex_discover_end_dev( "at %016llx:0x%x returned 0x%x\n", SAS_ADDR(child->sas_addr), SAS_ADDR(parent->sas_addr), phy_id, res); - /* FIXME: this kfrees list elements without removing them */ - //kfree(child); - return NULL; + goto out_list_del; } } else { SAS_DPRINTK("target proto 0x%x at %016llx:0x%x not handled\n", @@ -663,6 +665,16 @@ static struct domain_device *sas_ex_discover_end_dev( list_add_tail(&child->siblings, &parent_ex->children); return child; + + out_list_del: + list_del(&child->dev_list_node); + sas_rphy_free(rphy); + out_free: + sas_port_delete(phy->port); + out_err: + phy->port = NULL; + kfree(child); + return NULL; } static struct domain_device *sas_ex_discover_expander( |