diff options
author | Dan Williams <dan.j.williams@intel.com> | 2012-03-22 00:09:07 -0400 |
---|---|---|
committer | James Bottomley <JBottomley@Parallels.com> | 2012-04-23 07:11:47 -0400 |
commit | b2024459252a9d2d312ee562f86f332a1498f412 (patch) | |
tree | 751987779eee44a601a68c766ba2ff258b77d25a /drivers/scsi/libsas | |
parent | 0f3fce5cc77e1f35758ef0e46a989e76e5046a7b (diff) |
[SCSI] libsas, libata: fix start of life for a sas ata_port
This changes the ordering of initialization and probing events from:
1/ allocate rphy in PORTE_BYTES_DMAED, DISCE_REVALIDATE_DOMAIN
2/ allocate ata_port and schedule port probe in DISCE_PROBE
...to:
1/ allocate ata_port in PORTE_BYTES_DMAED, DISCE_REVALIDATE_DOMAIN
2/ allocate rphy in PORTE_BYTES_DMAED, DISCE_REVALIDATE_DOMAIN
3/ schedule port probe in DISCE_PROBE
This ordering prevents PHYE_SIGNAL_LOSS_EVENTS from sneaking in to
destrory ata devices before they have been fully initialized:
BUG: unable to handle kernel paging request at 0000000000003b10
IP: [<ffffffffa0053d7e>] sas_ata_end_eh+0x12/0x5e [libsas]
...
[<ffffffffa004d1af>] sas_unregister_common_dev+0x78/0xc9 [libsas]
[<ffffffffa004d4d4>] sas_unregister_dev+0x4f/0xad [libsas]
[<ffffffffa004d5b1>] sas_unregister_domain_devices+0x7f/0xbf [libsas]
[<ffffffffa004c487>] sas_deform_port+0x61/0x1b8 [libsas]
[<ffffffffa004bed0>] sas_phye_loss_of_signal+0x29/0x2b [libsas]
...and kills the awkward "sata domain_device briefly existing in the
domain without an ata_port" state.
Reported-by: Michal Kosciowski <michal.kosciowski@intel.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Acked-by: Jeff Garzik <jgarzik@redhat.com>
Signed-off-by: James Bottomley <JBottomley@Parallels.com>
Diffstat (limited to 'drivers/scsi/libsas')
-rw-r--r-- | drivers/scsi/libsas/sas_ata.c | 33 | ||||
-rw-r--r-- | drivers/scsi/libsas/sas_discover.c | 13 | ||||
-rw-r--r-- | drivers/scsi/libsas/sas_expander.c | 8 |
3 files changed, 25 insertions, 29 deletions
diff --git a/drivers/scsi/libsas/sas_ata.c b/drivers/scsi/libsas/sas_ata.c index bc0cecc6ad62..441d88ad99a7 100644 --- a/drivers/scsi/libsas/sas_ata.c +++ b/drivers/scsi/libsas/sas_ata.c | |||
@@ -546,11 +546,12 @@ static struct ata_port_info sata_port_info = { | |||
546 | .port_ops = &sas_sata_ops | 546 | .port_ops = &sas_sata_ops |
547 | }; | 547 | }; |
548 | 548 | ||
549 | int sas_ata_init_host_and_port(struct domain_device *found_dev) | 549 | int sas_ata_init(struct domain_device *found_dev) |
550 | { | 550 | { |
551 | struct sas_ha_struct *ha = found_dev->port->ha; | 551 | struct sas_ha_struct *ha = found_dev->port->ha; |
552 | struct Scsi_Host *shost = ha->core.shost; | 552 | struct Scsi_Host *shost = ha->core.shost; |
553 | struct ata_port *ap; | 553 | struct ata_port *ap; |
554 | int rc; | ||
554 | 555 | ||
555 | ata_host_init(&found_dev->sata_dev.ata_host, | 556 | ata_host_init(&found_dev->sata_dev.ata_host, |
556 | ha->dev, | 557 | ha->dev, |
@@ -567,8 +568,11 @@ int sas_ata_init_host_and_port(struct domain_device *found_dev) | |||
567 | ap->private_data = found_dev; | 568 | ap->private_data = found_dev; |
568 | ap->cbl = ATA_CBL_SATA; | 569 | ap->cbl = ATA_CBL_SATA; |
569 | ap->scsi_host = shost; | 570 | ap->scsi_host = shost; |
570 | /* publish initialized ata port */ | 571 | rc = ata_sas_port_init(ap); |
571 | smp_wmb(); | 572 | if (rc) { |
573 | ata_sas_port_destroy(ap); | ||
574 | return rc; | ||
575 | } | ||
572 | found_dev->sata_dev.ap = ap; | 576 | found_dev->sata_dev.ap = ap; |
573 | 577 | ||
574 | return 0; | 578 | return 0; |
@@ -648,18 +652,13 @@ static void sas_get_ata_command_set(struct domain_device *dev) | |||
648 | void sas_probe_sata(struct asd_sas_port *port) | 652 | void sas_probe_sata(struct asd_sas_port *port) |
649 | { | 653 | { |
650 | struct domain_device *dev, *n; | 654 | struct domain_device *dev, *n; |
651 | int err; | ||
652 | 655 | ||
653 | mutex_lock(&port->ha->disco_mutex); | 656 | mutex_lock(&port->ha->disco_mutex); |
654 | list_for_each_entry_safe(dev, n, &port->disco_list, disco_list_node) { | 657 | list_for_each_entry(dev, &port->disco_list, disco_list_node) { |
655 | if (!dev_is_sata(dev)) | 658 | if (!dev_is_sata(dev)) |
656 | continue; | 659 | continue; |
657 | 660 | ||
658 | err = sas_ata_init_host_and_port(dev); | 661 | ata_sas_async_probe(dev->sata_dev.ap); |
659 | if (err) | ||
660 | sas_fail_probe(dev, __func__, err); | ||
661 | else | ||
662 | ata_sas_async_port_init(dev->sata_dev.ap); | ||
663 | } | 662 | } |
664 | mutex_unlock(&port->ha->disco_mutex); | 663 | mutex_unlock(&port->ha->disco_mutex); |
665 | 664 | ||
@@ -718,18 +717,6 @@ static void async_sas_ata_eh(void *data, async_cookie_t cookie) | |||
718 | sas_put_device(dev); | 717 | sas_put_device(dev); |
719 | } | 718 | } |
720 | 719 | ||
721 | static bool sas_ata_dev_eh_valid(struct domain_device *dev) | ||
722 | { | ||
723 | struct ata_port *ap; | ||
724 | |||
725 | if (!dev_is_sata(dev)) | ||
726 | return false; | ||
727 | ap = dev->sata_dev.ap; | ||
728 | /* consume fully initialized ata ports */ | ||
729 | smp_rmb(); | ||
730 | return !!ap; | ||
731 | } | ||
732 | |||
733 | void sas_ata_strategy_handler(struct Scsi_Host *shost) | 720 | void sas_ata_strategy_handler(struct Scsi_Host *shost) |
734 | { | 721 | { |
735 | struct sas_ha_struct *sas_ha = SHOST_TO_SAS_HA(shost); | 722 | struct sas_ha_struct *sas_ha = SHOST_TO_SAS_HA(shost); |
@@ -753,7 +740,7 @@ void sas_ata_strategy_handler(struct Scsi_Host *shost) | |||
753 | 740 | ||
754 | spin_lock(&port->dev_list_lock); | 741 | spin_lock(&port->dev_list_lock); |
755 | list_for_each_entry(dev, &port->dev_list, dev_list_node) { | 742 | list_for_each_entry(dev, &port->dev_list, dev_list_node) { |
756 | if (!sas_ata_dev_eh_valid(dev)) | 743 | if (!dev_is_sata(dev)) |
757 | continue; | 744 | continue; |
758 | async_schedule_domain(async_sas_ata_eh, dev, &async); | 745 | async_schedule_domain(async_sas_ata_eh, dev, &async); |
759 | } | 746 | } |
diff --git a/drivers/scsi/libsas/sas_discover.c b/drivers/scsi/libsas/sas_discover.c index 13b5891f9961..629a0865b130 100644 --- a/drivers/scsi/libsas/sas_discover.c +++ b/drivers/scsi/libsas/sas_discover.c | |||
@@ -72,6 +72,7 @@ static int sas_get_port_device(struct asd_sas_port *port) | |||
72 | struct asd_sas_phy *phy; | 72 | struct asd_sas_phy *phy; |
73 | struct sas_rphy *rphy; | 73 | struct sas_rphy *rphy; |
74 | struct domain_device *dev; | 74 | struct domain_device *dev; |
75 | int rc = -ENODEV; | ||
75 | 76 | ||
76 | dev = sas_alloc_device(); | 77 | dev = sas_alloc_device(); |
77 | if (!dev) | 78 | if (!dev) |
@@ -110,9 +111,16 @@ static int sas_get_port_device(struct asd_sas_port *port) | |||
110 | 111 | ||
111 | sas_init_dev(dev); | 112 | sas_init_dev(dev); |
112 | 113 | ||
114 | dev->port = port; | ||
113 | switch (dev->dev_type) { | 115 | switch (dev->dev_type) { |
114 | case SAS_END_DEV: | ||
115 | case SATA_DEV: | 116 | case SATA_DEV: |
117 | rc = sas_ata_init(dev); | ||
118 | if (rc) { | ||
119 | rphy = NULL; | ||
120 | break; | ||
121 | } | ||
122 | /* fall through */ | ||
123 | case SAS_END_DEV: | ||
116 | rphy = sas_end_device_alloc(port->port); | 124 | rphy = sas_end_device_alloc(port->port); |
117 | break; | 125 | break; |
118 | case EDGE_DEV: | 126 | case EDGE_DEV: |
@@ -131,7 +139,7 @@ static int sas_get_port_device(struct asd_sas_port *port) | |||
131 | 139 | ||
132 | if (!rphy) { | 140 | if (!rphy) { |
133 | sas_put_device(dev); | 141 | sas_put_device(dev); |
134 | return -ENODEV; | 142 | return rc; |
135 | } | 143 | } |
136 | 144 | ||
137 | rphy->identify.phy_identifier = phy->phy->identify.phy_identifier; | 145 | rphy->identify.phy_identifier = phy->phy->identify.phy_identifier; |
@@ -139,7 +147,6 @@ static int sas_get_port_device(struct asd_sas_port *port) | |||
139 | sas_fill_in_rphy(dev, rphy); | 147 | sas_fill_in_rphy(dev, rphy); |
140 | sas_hash_addr(dev->hashed_sas_addr, dev->sas_addr); | 148 | sas_hash_addr(dev->hashed_sas_addr, dev->sas_addr); |
141 | port->port_dev = dev; | 149 | port->port_dev = dev; |
142 | dev->port = port; | ||
143 | dev->linkrate = port->linkrate; | 150 | dev->linkrate = port->linkrate; |
144 | dev->min_linkrate = port->linkrate; | 151 | dev->min_linkrate = port->linkrate; |
145 | dev->max_linkrate = port->linkrate; | 152 | dev->max_linkrate = port->linkrate; |
diff --git a/drivers/scsi/libsas/sas_expander.c b/drivers/scsi/libsas/sas_expander.c index c1f91b1c27c3..75247a176c6b 100644 --- a/drivers/scsi/libsas/sas_expander.c +++ b/drivers/scsi/libsas/sas_expander.c | |||
@@ -790,12 +790,14 @@ static struct domain_device *sas_ex_discover_end_dev( | |||
790 | if (res) | 790 | if (res) |
791 | goto out_free; | 791 | goto out_free; |
792 | 792 | ||
793 | sas_init_dev(child); | ||
794 | res = sas_ata_init(child); | ||
795 | if (res) | ||
796 | goto out_free; | ||
793 | rphy = sas_end_device_alloc(phy->port); | 797 | rphy = sas_end_device_alloc(phy->port); |
794 | if (unlikely(!rphy)) | 798 | if (!rphy) |
795 | goto out_free; | 799 | goto out_free; |
796 | 800 | ||
797 | sas_init_dev(child); | ||
798 | |||
799 | child->rphy = rphy; | 801 | child->rphy = rphy; |
800 | get_device(&rphy->dev); | 802 | get_device(&rphy->dev); |
801 | 803 | ||