diff options
author | Dan Williams <dan.j.williams@intel.com> | 2012-01-18 23:47:01 -0500 |
---|---|---|
committer | James Bottomley <JBottomley@Parallels.com> | 2012-02-29 16:35:41 -0500 |
commit | 9508a66f898d46e726a318469312b45e0b1d078b (patch) | |
tree | e6b61e6c2a7dc8b40fdc0fe34901ff3db4af47a9 /drivers/scsi/libsas | |
parent | 92625f9bff3853951cc75f5bc084ee67c1317d2f (diff) |
[SCSI] libsas: async ata scanning
libsas ata error handling is already async but this does not help the
scan case. Move initial link recovery out from under host->scan_mutex,
and delay synchronization with eh until after all port probe/recovery
work has been queued.
Device ordering is maintained with scan order by still calling
sas_rphy_add() in order of domain discovery.
Since we now scan the domain list when invoking libata-eh we need to be
careful to check for fully initialized ata ports.
Acked-by: Jack Wang <jack_wang@usish.com>
Acked-by: Jeff Garzik <jgarzik@redhat.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: James Bottomley <JBottomley@Parallels.com>
Diffstat (limited to 'drivers/scsi/libsas')
-rw-r--r-- | drivers/scsi/libsas/sas_ata.c | 74 | ||||
-rw-r--r-- | drivers/scsi/libsas/sas_discover.c | 22 | ||||
-rw-r--r-- | drivers/scsi/libsas/sas_internal.h | 9 | ||||
-rw-r--r-- | drivers/scsi/libsas/sas_scsi_host.c | 18 |
4 files changed, 83 insertions, 40 deletions
diff --git a/drivers/scsi/libsas/sas_ata.c b/drivers/scsi/libsas/sas_ata.c index a9ec1643ee93..eb8b77c86169 100644 --- a/drivers/scsi/libsas/sas_ata.c +++ b/drivers/scsi/libsas/sas_ata.c | |||
@@ -585,11 +585,10 @@ static struct ata_port_info sata_port_info = { | |||
585 | .port_ops = &sas_sata_ops | 585 | .port_ops = &sas_sata_ops |
586 | }; | 586 | }; |
587 | 587 | ||
588 | int sas_ata_init_host_and_port(struct domain_device *found_dev, | 588 | int sas_ata_init_host_and_port(struct domain_device *found_dev) |
589 | struct scsi_target *starget) | ||
590 | { | 589 | { |
591 | struct Scsi_Host *shost = dev_to_shost(&starget->dev); | 590 | struct sas_ha_struct *ha = found_dev->port->ha; |
592 | struct sas_ha_struct *ha = SHOST_TO_SAS_HA(shost); | 591 | struct Scsi_Host *shost = ha->core.shost; |
593 | struct ata_port *ap; | 592 | struct ata_port *ap; |
594 | 593 | ||
595 | ata_host_init(&found_dev->sata_dev.ata_host, | 594 | ata_host_init(&found_dev->sata_dev.ata_host, |
@@ -607,6 +606,8 @@ int sas_ata_init_host_and_port(struct domain_device *found_dev, | |||
607 | ap->private_data = found_dev; | 606 | ap->private_data = found_dev; |
608 | ap->cbl = ATA_CBL_SATA; | 607 | ap->cbl = ATA_CBL_SATA; |
609 | ap->scsi_host = shost; | 608 | ap->scsi_host = shost; |
609 | /* publish initialized ata port */ | ||
610 | smp_wmb(); | ||
610 | found_dev->sata_dev.ap = ap; | 611 | found_dev->sata_dev.ap = ap; |
611 | 612 | ||
612 | return 0; | 613 | return 0; |
@@ -683,6 +684,38 @@ static void sas_get_ata_command_set(struct domain_device *dev) | |||
683 | dev->sata_dev.command_set = ATAPI_COMMAND_SET; | 684 | dev->sata_dev.command_set = ATAPI_COMMAND_SET; |
684 | } | 685 | } |
685 | 686 | ||
687 | void sas_probe_sata(struct asd_sas_port *port) | ||
688 | { | ||
689 | struct domain_device *dev, *n; | ||
690 | int err; | ||
691 | |||
692 | mutex_lock(&port->ha->disco_mutex); | ||
693 | list_for_each_entry_safe(dev, n, &port->disco_list, disco_list_node) { | ||
694 | if (!dev_is_sata(dev)) | ||
695 | continue; | ||
696 | |||
697 | err = sas_ata_init_host_and_port(dev); | ||
698 | if (err) | ||
699 | sas_fail_probe(dev, __func__, err); | ||
700 | else | ||
701 | ata_sas_async_port_init(dev->sata_dev.ap); | ||
702 | } | ||
703 | mutex_unlock(&port->ha->disco_mutex); | ||
704 | |||
705 | list_for_each_entry_safe(dev, n, &port->disco_list, disco_list_node) { | ||
706 | if (!dev_is_sata(dev)) | ||
707 | continue; | ||
708 | |||
709 | sas_ata_wait_eh(dev); | ||
710 | |||
711 | /* if libata could not bring the link up, don't surface | ||
712 | * the device | ||
713 | */ | ||
714 | if (ata_dev_disabled(sas_to_ata_dev(dev))) | ||
715 | sas_fail_probe(dev, __func__, -ENODEV); | ||
716 | } | ||
717 | } | ||
718 | |||
686 | /** | 719 | /** |
687 | * sas_discover_sata -- discover an STP/SATA domain device | 720 | * sas_discover_sata -- discover an STP/SATA domain device |
688 | * @dev: pointer to struct domain_device of interest | 721 | * @dev: pointer to struct domain_device of interest |
@@ -724,11 +757,23 @@ static void async_sas_ata_eh(void *data, async_cookie_t cookie) | |||
724 | sas_put_device(dev); | 757 | sas_put_device(dev); |
725 | } | 758 | } |
726 | 759 | ||
760 | static bool sas_ata_dev_eh_valid(struct domain_device *dev) | ||
761 | { | ||
762 | struct ata_port *ap; | ||
763 | |||
764 | if (!dev_is_sata(dev)) | ||
765 | return false; | ||
766 | ap = dev->sata_dev.ap; | ||
767 | /* consume fully initialized ata ports */ | ||
768 | smp_rmb(); | ||
769 | return !!ap; | ||
770 | } | ||
771 | |||
727 | void sas_ata_strategy_handler(struct Scsi_Host *shost) | 772 | void sas_ata_strategy_handler(struct Scsi_Host *shost) |
728 | { | 773 | { |
729 | struct scsi_device *sdev; | ||
730 | struct sas_ha_struct *sas_ha = SHOST_TO_SAS_HA(shost); | 774 | struct sas_ha_struct *sas_ha = SHOST_TO_SAS_HA(shost); |
731 | LIST_HEAD(async); | 775 | LIST_HEAD(async); |
776 | int i; | ||
732 | 777 | ||
733 | /* it's ok to defer revalidation events during ata eh, these | 778 | /* it's ok to defer revalidation events during ata eh, these |
734 | * disks are in one of three states: | 779 | * disks are in one of three states: |
@@ -740,14 +785,21 @@ void sas_ata_strategy_handler(struct Scsi_Host *shost) | |||
740 | */ | 785 | */ |
741 | sas_disable_revalidation(sas_ha); | 786 | sas_disable_revalidation(sas_ha); |
742 | 787 | ||
743 | shost_for_each_device(sdev, shost) { | 788 | spin_lock_irq(&sas_ha->phy_port_lock); |
744 | struct domain_device *ddev = sdev_to_domain_dev(sdev); | 789 | for (i = 0; i < sas_ha->num_phys; i++) { |
745 | 790 | struct asd_sas_port *port = sas_ha->sas_port[i]; | |
746 | if (!dev_is_sata(ddev)) | 791 | struct domain_device *dev; |
747 | continue; | ||
748 | 792 | ||
749 | async_schedule_domain(async_sas_ata_eh, ddev, &async); | 793 | spin_lock(&port->dev_list_lock); |
794 | list_for_each_entry(dev, &port->dev_list, dev_list_node) { | ||
795 | if (!sas_ata_dev_eh_valid(dev)) | ||
796 | continue; | ||
797 | async_schedule_domain(async_sas_ata_eh, dev, &async); | ||
798 | } | ||
799 | spin_unlock(&port->dev_list_lock); | ||
750 | } | 800 | } |
801 | spin_unlock_irq(&sas_ha->phy_port_lock); | ||
802 | |||
751 | async_synchronize_full_domain(&async); | 803 | async_synchronize_full_domain(&async); |
752 | 804 | ||
753 | sas_enable_revalidation(sas_ha); | 805 | sas_enable_revalidation(sas_ha); |
diff --git a/drivers/scsi/libsas/sas_discover.c b/drivers/scsi/libsas/sas_discover.c index 18fa364aa00f..0d58a8beaa3d 100644 --- a/drivers/scsi/libsas/sas_discover.c +++ b/drivers/scsi/libsas/sas_discover.c | |||
@@ -207,22 +207,22 @@ static void sas_probe_devices(struct work_struct *work) | |||
207 | 207 | ||
208 | clear_bit(DISCE_PROBE, &port->disc.pending); | 208 | clear_bit(DISCE_PROBE, &port->disc.pending); |
209 | 209 | ||
210 | list_for_each_entry_safe(dev, n, &port->disco_list, disco_list_node) { | 210 | /* devices must be domain members before link recovery and probe */ |
211 | int err; | 211 | list_for_each_entry(dev, &port->disco_list, disco_list_node) { |
212 | |||
213 | spin_lock_irq(&port->dev_list_lock); | 212 | spin_lock_irq(&port->dev_list_lock); |
214 | list_add_tail(&dev->dev_list_node, &port->dev_list); | 213 | list_add_tail(&dev->dev_list_node, &port->dev_list); |
215 | spin_unlock_irq(&port->dev_list_lock); | 214 | spin_unlock_irq(&port->dev_list_lock); |
215 | } | ||
216 | 216 | ||
217 | err = sas_rphy_add(dev->rphy); | 217 | sas_probe_sata(port); |
218 | 218 | ||
219 | if (err) { | 219 | list_for_each_entry_safe(dev, n, &port->disco_list, disco_list_node) { |
220 | SAS_DPRINTK("%s: for %s device %16llx returned %d\n", | 220 | int err; |
221 | __func__, dev->parent ? "exp-attached" : | 221 | |
222 | "direct-attached", | 222 | err = sas_rphy_add(dev->rphy); |
223 | SAS_ADDR(dev->sas_addr), err); | 223 | if (err) |
224 | sas_unregister_dev(port, dev); | 224 | sas_fail_probe(dev, __func__, err); |
225 | } else | 225 | else |
226 | list_del_init(&dev->disco_list_node); | 226 | list_del_init(&dev->disco_list_node); |
227 | } | 227 | } |
228 | } | 228 | } |
diff --git a/drivers/scsi/libsas/sas_internal.h b/drivers/scsi/libsas/sas_internal.h index e028d7a44202..d0d9bf10f79c 100644 --- a/drivers/scsi/libsas/sas_internal.h +++ b/drivers/scsi/libsas/sas_internal.h | |||
@@ -113,6 +113,15 @@ static inline int sas_smp_host_handler(struct Scsi_Host *shost, | |||
113 | } | 113 | } |
114 | #endif | 114 | #endif |
115 | 115 | ||
116 | static inline void sas_fail_probe(struct domain_device *dev, const char *func, int err) | ||
117 | { | ||
118 | SAS_DPRINTK("%s: for %s device %16llx returned %d\n", | ||
119 | func, dev->parent ? "exp-attached" : | ||
120 | "direct-attached", | ||
121 | SAS_ADDR(dev->sas_addr), err); | ||
122 | sas_unregister_dev(dev->port, dev); | ||
123 | } | ||
124 | |||
116 | static inline void sas_fill_in_rphy(struct domain_device *dev, | 125 | static inline void sas_fill_in_rphy(struct domain_device *dev, |
117 | struct sas_rphy *rphy) | 126 | struct sas_rphy *rphy) |
118 | { | 127 | { |
diff --git a/drivers/scsi/libsas/sas_scsi_host.c b/drivers/scsi/libsas/sas_scsi_host.c index e58ca50517d5..3701ff7e7267 100644 --- a/drivers/scsi/libsas/sas_scsi_host.c +++ b/drivers/scsi/libsas/sas_scsi_host.c | |||
@@ -762,17 +762,10 @@ int sas_target_alloc(struct scsi_target *starget) | |||
762 | { | 762 | { |
763 | struct sas_rphy *rphy = dev_to_rphy(starget->dev.parent); | 763 | struct sas_rphy *rphy = dev_to_rphy(starget->dev.parent); |
764 | struct domain_device *found_dev = sas_find_dev_by_rphy(rphy); | 764 | struct domain_device *found_dev = sas_find_dev_by_rphy(rphy); |
765 | int res; | ||
766 | 765 | ||
767 | if (!found_dev) | 766 | if (!found_dev) |
768 | return -ENODEV; | 767 | return -ENODEV; |
769 | 768 | ||
770 | if (dev_is_sata(found_dev)) { | ||
771 | res = sas_ata_init_host_and_port(found_dev, starget); | ||
772 | if (res) | ||
773 | return res; | ||
774 | } | ||
775 | |||
776 | kref_get(&found_dev->kref); | 769 | kref_get(&found_dev->kref); |
777 | starget->hostdata = found_dev; | 770 | starget->hostdata = found_dev; |
778 | return 0; | 771 | return 0; |
@@ -1012,16 +1005,6 @@ void sas_task_abort(struct sas_task *task) | |||
1012 | } | 1005 | } |
1013 | } | 1006 | } |
1014 | 1007 | ||
1015 | int sas_slave_alloc(struct scsi_device *scsi_dev) | ||
1016 | { | ||
1017 | struct domain_device *dev = sdev_to_domain_dev(scsi_dev); | ||
1018 | |||
1019 | if (dev_is_sata(dev)) | ||
1020 | return ata_sas_port_init(dev->sata_dev.ap); | ||
1021 | |||
1022 | return 0; | ||
1023 | } | ||
1024 | |||
1025 | void sas_target_destroy(struct scsi_target *starget) | 1008 | void sas_target_destroy(struct scsi_target *starget) |
1026 | { | 1009 | { |
1027 | struct domain_device *found_dev = starget->hostdata; | 1010 | struct domain_device *found_dev = starget->hostdata; |
@@ -1082,6 +1065,5 @@ EXPORT_SYMBOL_GPL(sas_task_abort); | |||
1082 | EXPORT_SYMBOL_GPL(sas_phy_reset); | 1065 | EXPORT_SYMBOL_GPL(sas_phy_reset); |
1083 | EXPORT_SYMBOL_GPL(sas_eh_device_reset_handler); | 1066 | EXPORT_SYMBOL_GPL(sas_eh_device_reset_handler); |
1084 | EXPORT_SYMBOL_GPL(sas_eh_bus_reset_handler); | 1067 | EXPORT_SYMBOL_GPL(sas_eh_bus_reset_handler); |
1085 | EXPORT_SYMBOL_GPL(sas_slave_alloc); | ||
1086 | EXPORT_SYMBOL_GPL(sas_target_destroy); | 1068 | EXPORT_SYMBOL_GPL(sas_target_destroy); |
1087 | EXPORT_SYMBOL_GPL(sas_ioctl); | 1069 | EXPORT_SYMBOL_GPL(sas_ioctl); |