aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/libsas
diff options
context:
space:
mode:
authorDan Williams <dan.j.williams@intel.com>2012-01-18 23:47:01 -0500
committerJames Bottomley <JBottomley@Parallels.com>2012-02-29 16:35:41 -0500
commit9508a66f898d46e726a318469312b45e0b1d078b (patch)
treee6b61e6c2a7dc8b40fdc0fe34901ff3db4af47a9 /drivers/scsi/libsas
parent92625f9bff3853951cc75f5bc084ee67c1317d2f (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.c74
-rw-r--r--drivers/scsi/libsas/sas_discover.c22
-rw-r--r--drivers/scsi/libsas/sas_internal.h9
-rw-r--r--drivers/scsi/libsas/sas_scsi_host.c18
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
588int sas_ata_init_host_and_port(struct domain_device *found_dev, 588int 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
687void 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
760static 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
727void sas_ata_strategy_handler(struct Scsi_Host *shost) 772void 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
116static 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
116static inline void sas_fill_in_rphy(struct domain_device *dev, 125static 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
1015int 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
1025void sas_target_destroy(struct scsi_target *starget) 1008void 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);
1082EXPORT_SYMBOL_GPL(sas_phy_reset); 1065EXPORT_SYMBOL_GPL(sas_phy_reset);
1083EXPORT_SYMBOL_GPL(sas_eh_device_reset_handler); 1066EXPORT_SYMBOL_GPL(sas_eh_device_reset_handler);
1084EXPORT_SYMBOL_GPL(sas_eh_bus_reset_handler); 1067EXPORT_SYMBOL_GPL(sas_eh_bus_reset_handler);
1085EXPORT_SYMBOL_GPL(sas_slave_alloc);
1086EXPORT_SYMBOL_GPL(sas_target_destroy); 1068EXPORT_SYMBOL_GPL(sas_target_destroy);
1087EXPORT_SYMBOL_GPL(sas_ioctl); 1069EXPORT_SYMBOL_GPL(sas_ioctl);