diff options
Diffstat (limited to 'drivers/scsi/libsas')
-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( | |||
597 | child->iproto = phy->attached_iproto; | 597 | child->iproto = phy->attached_iproto; |
598 | memcpy(child->sas_addr, phy->attached_sas_addr, SAS_ADDR_SIZE); | 598 | memcpy(child->sas_addr, phy->attached_sas_addr, SAS_ADDR_SIZE); |
599 | sas_hash_addr(child->hashed_sas_addr, child->sas_addr); | 599 | sas_hash_addr(child->hashed_sas_addr, child->sas_addr); |
600 | phy->port = sas_port_alloc(&parent->rphy->dev, phy_id); | 600 | if (!phy->port) { |
601 | BUG_ON(!phy->port); | 601 | phy->port = sas_port_alloc(&parent->rphy->dev, phy_id); |
602 | /* FIXME: better error handling*/ | 602 | if (unlikely(!phy->port)) |
603 | BUG_ON(sas_port_add(phy->port) != 0); | 603 | goto out_err; |
604 | if (unlikely(sas_port_add(phy->port) != 0)) { | ||
605 | sas_port_free(phy->port); | ||
606 | goto out_err; | ||
607 | } | ||
608 | } | ||
604 | sas_ex_get_linkrate(parent, child, phy); | 609 | sas_ex_get_linkrate(parent, child, phy); |
605 | 610 | ||
606 | if ((phy->attached_tproto & SAS_PROTO_STP) || phy->attached_sata_dev) { | 611 | if ((phy->attached_tproto & SAS_PROTO_STP) || phy->attached_sata_dev) { |
@@ -615,8 +620,7 @@ static struct domain_device *sas_ex_discover_end_dev( | |||
615 | SAS_DPRINTK("report phy sata to %016llx:0x%x returned " | 620 | SAS_DPRINTK("report phy sata to %016llx:0x%x returned " |
616 | "0x%x\n", SAS_ADDR(parent->sas_addr), | 621 | "0x%x\n", SAS_ADDR(parent->sas_addr), |
617 | phy_id, res); | 622 | phy_id, res); |
618 | kfree(child); | 623 | goto out_free; |
619 | return NULL; | ||
620 | } | 624 | } |
621 | memcpy(child->frame_rcvd, &child->sata_dev.rps_resp.rps.fis, | 625 | memcpy(child->frame_rcvd, &child->sata_dev.rps_resp.rps.fis, |
622 | sizeof(struct dev_to_host_fis)); | 626 | sizeof(struct dev_to_host_fis)); |
@@ -627,14 +631,14 @@ static struct domain_device *sas_ex_discover_end_dev( | |||
627 | "%016llx:0x%x returned 0x%x\n", | 631 | "%016llx:0x%x returned 0x%x\n", |
628 | SAS_ADDR(child->sas_addr), | 632 | SAS_ADDR(child->sas_addr), |
629 | SAS_ADDR(parent->sas_addr), phy_id, res); | 633 | SAS_ADDR(parent->sas_addr), phy_id, res); |
630 | kfree(child); | 634 | goto out_free; |
631 | return NULL; | ||
632 | } | 635 | } |
633 | } else if (phy->attached_tproto & SAS_PROTO_SSP) { | 636 | } else if (phy->attached_tproto & SAS_PROTO_SSP) { |
634 | child->dev_type = SAS_END_DEV; | 637 | child->dev_type = SAS_END_DEV; |
635 | rphy = sas_end_device_alloc(phy->port); | 638 | rphy = sas_end_device_alloc(phy->port); |
636 | /* FIXME: error handling */ | 639 | /* FIXME: error handling */ |
637 | BUG_ON(!rphy); | 640 | if (unlikely(!rphy)) |
641 | goto out_free; | ||
638 | child->tproto = phy->attached_tproto; | 642 | child->tproto = phy->attached_tproto; |
639 | sas_init_dev(child); | 643 | sas_init_dev(child); |
640 | 644 | ||
@@ -651,9 +655,7 @@ static struct domain_device *sas_ex_discover_end_dev( | |||
651 | "at %016llx:0x%x returned 0x%x\n", | 655 | "at %016llx:0x%x returned 0x%x\n", |
652 | SAS_ADDR(child->sas_addr), | 656 | SAS_ADDR(child->sas_addr), |
653 | SAS_ADDR(parent->sas_addr), phy_id, res); | 657 | SAS_ADDR(parent->sas_addr), phy_id, res); |
654 | /* FIXME: this kfrees list elements without removing them */ | 658 | goto out_list_del; |
655 | //kfree(child); | ||
656 | return NULL; | ||
657 | } | 659 | } |
658 | } else { | 660 | } else { |
659 | SAS_DPRINTK("target proto 0x%x at %016llx:0x%x not handled\n", | 661 | 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( | |||
663 | 665 | ||
664 | list_add_tail(&child->siblings, &parent_ex->children); | 666 | list_add_tail(&child->siblings, &parent_ex->children); |
665 | return child; | 667 | return child; |
668 | |||
669 | out_list_del: | ||
670 | list_del(&child->dev_list_node); | ||
671 | sas_rphy_free(rphy); | ||
672 | out_free: | ||
673 | sas_port_delete(phy->port); | ||
674 | out_err: | ||
675 | phy->port = NULL; | ||
676 | kfree(child); | ||
677 | return NULL; | ||
666 | } | 678 | } |
667 | 679 | ||
668 | static struct domain_device *sas_ex_discover_expander( | 680 | static struct domain_device *sas_ex_discover_expander( |