aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi
diff options
context:
space:
mode:
authorDan Williams <dan.j.williams@intel.com>2012-06-22 02:25:27 -0400
committerJames Bottomley <JBottomley@Parallels.com>2012-07-20 03:58:45 -0400
commite4a9c3732cea3e3c8c704aad86636090ffe6b25f (patch)
treefaea8e91b3d917dcdb4c89adbb021ac737a6cb35 /drivers/scsi
parent3b661a92e869ebe2358de8f4b3230ad84f7fce51 (diff)
[SCSI] libata, libsas: introduce sched_eh and end_eh port ops
When managing shost->host_eh_scheduled libata assumes that there is a 1:1 shost-to-ata_port relationship. libsas creates a 1:N relationship so it needs to manage host_eh_scheduled cumulatively at the host level. The sched_eh and end_eh port port ops allow libsas to track when domain devices enter/leave the "eh-pending" state under ha->lock (previously named ha->state_lock, but it is no longer just a lock for ha->state changes). Since host_eh_scheduled indicates eh without backing commands pinning the device it can be deallocated at any time. Move the taking of the domain_device reference under the port_lock to guarantee that the ata_port stays around for the duration of eh. Reviewed-by: Jacek Danecki <jacek.danecki@intel.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')
-rw-r--r--drivers/scsi/libsas/sas_ata.c38
-rw-r--r--drivers/scsi/libsas/sas_discover.c6
-rw-r--r--drivers/scsi/libsas/sas_event.c12
-rw-r--r--drivers/scsi/libsas/sas_init.c14
-rw-r--r--drivers/scsi/libsas/sas_scsi_host.c27
5 files changed, 72 insertions, 25 deletions
diff --git a/drivers/scsi/libsas/sas_ata.c b/drivers/scsi/libsas/sas_ata.c
index d109cc3a17b..b035acf1873 100644
--- a/drivers/scsi/libsas/sas_ata.c
+++ b/drivers/scsi/libsas/sas_ata.c
@@ -523,6 +523,31 @@ static void sas_ata_set_dmamode(struct ata_port *ap, struct ata_device *ata_dev)
523 i->dft->lldd_ata_set_dmamode(dev); 523 i->dft->lldd_ata_set_dmamode(dev);
524} 524}
525 525
526static void sas_ata_sched_eh(struct ata_port *ap)
527{
528 struct domain_device *dev = ap->private_data;
529 struct sas_ha_struct *ha = dev->port->ha;
530 unsigned long flags;
531
532 spin_lock_irqsave(&ha->lock, flags);
533 if (!test_and_set_bit(SAS_DEV_EH_PENDING, &dev->state))
534 ha->eh_active++;
535 ata_std_sched_eh(ap);
536 spin_unlock_irqrestore(&ha->lock, flags);
537}
538
539void sas_ata_end_eh(struct ata_port *ap)
540{
541 struct domain_device *dev = ap->private_data;
542 struct sas_ha_struct *ha = dev->port->ha;
543 unsigned long flags;
544
545 spin_lock_irqsave(&ha->lock, flags);
546 if (test_and_clear_bit(SAS_DEV_EH_PENDING, &dev->state))
547 ha->eh_active--;
548 spin_unlock_irqrestore(&ha->lock, flags);
549}
550
526static struct ata_port_operations sas_sata_ops = { 551static struct ata_port_operations sas_sata_ops = {
527 .prereset = ata_std_prereset, 552 .prereset = ata_std_prereset,
528 .hardreset = sas_ata_hard_reset, 553 .hardreset = sas_ata_hard_reset,
@@ -536,6 +561,8 @@ static struct ata_port_operations sas_sata_ops = {
536 .port_start = ata_sas_port_start, 561 .port_start = ata_sas_port_start,
537 .port_stop = ata_sas_port_stop, 562 .port_stop = ata_sas_port_stop,
538 .set_dmamode = sas_ata_set_dmamode, 563 .set_dmamode = sas_ata_set_dmamode,
564 .sched_eh = sas_ata_sched_eh,
565 .end_eh = sas_ata_end_eh,
539}; 566};
540 567
541static struct ata_port_info sata_port_info = { 568static struct ata_port_info sata_port_info = {
@@ -708,10 +735,6 @@ static void async_sas_ata_eh(void *data, async_cookie_t cookie)
708 struct ata_port *ap = dev->sata_dev.ap; 735 struct ata_port *ap = dev->sata_dev.ap;
709 struct sas_ha_struct *ha = dev->port->ha; 736 struct sas_ha_struct *ha = dev->port->ha;
710 737
711 /* hold a reference over eh since we may be racing with final
712 * remove once all commands are completed
713 */
714 kref_get(&dev->kref);
715 sas_ata_printk(KERN_DEBUG, dev, "dev error handler\n"); 738 sas_ata_printk(KERN_DEBUG, dev, "dev error handler\n");
716 ata_scsi_port_error_handler(ha->core.shost, ap); 739 ata_scsi_port_error_handler(ha->core.shost, ap);
717 sas_put_device(dev); 740 sas_put_device(dev);
@@ -742,6 +765,13 @@ void sas_ata_strategy_handler(struct Scsi_Host *shost)
742 list_for_each_entry(dev, &port->dev_list, dev_list_node) { 765 list_for_each_entry(dev, &port->dev_list, dev_list_node) {
743 if (!dev_is_sata(dev)) 766 if (!dev_is_sata(dev))
744 continue; 767 continue;
768
769 /* hold a reference over eh since we may be
770 * racing with final remove once all commands
771 * are completed
772 */
773 kref_get(&dev->kref);
774
745 async_schedule_domain(async_sas_ata_eh, dev, &async); 775 async_schedule_domain(async_sas_ata_eh, dev, &async);
746 } 776 }
747 spin_unlock(&port->dev_list_lock); 777 spin_unlock(&port->dev_list_lock);
diff --git a/drivers/scsi/libsas/sas_discover.c b/drivers/scsi/libsas/sas_discover.c
index 629a0865b13..ff497ac76cb 100644
--- a/drivers/scsi/libsas/sas_discover.c
+++ b/drivers/scsi/libsas/sas_discover.c
@@ -294,6 +294,8 @@ static void sas_unregister_common_dev(struct asd_sas_port *port, struct domain_d
294 294
295 spin_lock_irq(&port->dev_list_lock); 295 spin_lock_irq(&port->dev_list_lock);
296 list_del_init(&dev->dev_list_node); 296 list_del_init(&dev->dev_list_node);
297 if (dev_is_sata(dev))
298 sas_ata_end_eh(dev->sata_dev.ap);
297 spin_unlock_irq(&port->dev_list_lock); 299 spin_unlock_irq(&port->dev_list_lock);
298 300
299 sas_put_device(dev); 301 sas_put_device(dev);
@@ -488,9 +490,9 @@ static void sas_chain_event(int event, unsigned long *pending,
488 if (!test_and_set_bit(event, pending)) { 490 if (!test_and_set_bit(event, pending)) {
489 unsigned long flags; 491 unsigned long flags;
490 492
491 spin_lock_irqsave(&ha->state_lock, flags); 493 spin_lock_irqsave(&ha->lock, flags);
492 sas_chain_work(ha, sw); 494 sas_chain_work(ha, sw);
493 spin_unlock_irqrestore(&ha->state_lock, flags); 495 spin_unlock_irqrestore(&ha->lock, flags);
494 } 496 }
495} 497}
496 498
diff --git a/drivers/scsi/libsas/sas_event.c b/drivers/scsi/libsas/sas_event.c
index 4e4292d210c..789c4d8bb7a 100644
--- a/drivers/scsi/libsas/sas_event.c
+++ b/drivers/scsi/libsas/sas_event.c
@@ -47,9 +47,9 @@ static void sas_queue_event(int event, unsigned long *pending,
47 if (!test_and_set_bit(event, pending)) { 47 if (!test_and_set_bit(event, pending)) {
48 unsigned long flags; 48 unsigned long flags;
49 49
50 spin_lock_irqsave(&ha->state_lock, flags); 50 spin_lock_irqsave(&ha->lock, flags);
51 sas_queue_work(ha, work); 51 sas_queue_work(ha, work);
52 spin_unlock_irqrestore(&ha->state_lock, flags); 52 spin_unlock_irqrestore(&ha->lock, flags);
53 } 53 }
54} 54}
55 55
@@ -61,18 +61,18 @@ void __sas_drain_work(struct sas_ha_struct *ha)
61 61
62 set_bit(SAS_HA_DRAINING, &ha->state); 62 set_bit(SAS_HA_DRAINING, &ha->state);
63 /* flush submitters */ 63 /* flush submitters */
64 spin_lock_irq(&ha->state_lock); 64 spin_lock_irq(&ha->lock);
65 spin_unlock_irq(&ha->state_lock); 65 spin_unlock_irq(&ha->lock);
66 66
67 drain_workqueue(wq); 67 drain_workqueue(wq);
68 68
69 spin_lock_irq(&ha->state_lock); 69 spin_lock_irq(&ha->lock);
70 clear_bit(SAS_HA_DRAINING, &ha->state); 70 clear_bit(SAS_HA_DRAINING, &ha->state);
71 list_for_each_entry_safe(sw, _sw, &ha->defer_q, drain_node) { 71 list_for_each_entry_safe(sw, _sw, &ha->defer_q, drain_node) {
72 list_del_init(&sw->drain_node); 72 list_del_init(&sw->drain_node);
73 sas_queue_work(ha, sw); 73 sas_queue_work(ha, sw);
74 } 74 }
75 spin_unlock_irq(&ha->state_lock); 75 spin_unlock_irq(&ha->lock);
76} 76}
77 77
78int sas_drain_work(struct sas_ha_struct *ha) 78int sas_drain_work(struct sas_ha_struct *ha)
diff --git a/drivers/scsi/libsas/sas_init.c b/drivers/scsi/libsas/sas_init.c
index 10cb5ae3097..6909fefa32c 100644
--- a/drivers/scsi/libsas/sas_init.c
+++ b/drivers/scsi/libsas/sas_init.c
@@ -114,7 +114,7 @@ int sas_register_ha(struct sas_ha_struct *sas_ha)
114 sas_ha->lldd_queue_size = 128; /* Sanity */ 114 sas_ha->lldd_queue_size = 128; /* Sanity */
115 115
116 set_bit(SAS_HA_REGISTERED, &sas_ha->state); 116 set_bit(SAS_HA_REGISTERED, &sas_ha->state);
117 spin_lock_init(&sas_ha->state_lock); 117 spin_lock_init(&sas_ha->lock);
118 mutex_init(&sas_ha->drain_mutex); 118 mutex_init(&sas_ha->drain_mutex);
119 INIT_LIST_HEAD(&sas_ha->defer_q); 119 INIT_LIST_HEAD(&sas_ha->defer_q);
120 120
@@ -163,9 +163,9 @@ int sas_unregister_ha(struct sas_ha_struct *sas_ha)
163 * events to be queued, and flush any in-progress drainers 163 * events to be queued, and flush any in-progress drainers
164 */ 164 */
165 mutex_lock(&sas_ha->drain_mutex); 165 mutex_lock(&sas_ha->drain_mutex);
166 spin_lock_irq(&sas_ha->state_lock); 166 spin_lock_irq(&sas_ha->lock);
167 clear_bit(SAS_HA_REGISTERED, &sas_ha->state); 167 clear_bit(SAS_HA_REGISTERED, &sas_ha->state);
168 spin_unlock_irq(&sas_ha->state_lock); 168 spin_unlock_irq(&sas_ha->lock);
169 __sas_drain_work(sas_ha); 169 __sas_drain_work(sas_ha);
170 mutex_unlock(&sas_ha->drain_mutex); 170 mutex_unlock(&sas_ha->drain_mutex);
171 171
@@ -411,9 +411,9 @@ static int queue_phy_reset(struct sas_phy *phy, int hard_reset)
411 d->reset_result = 0; 411 d->reset_result = 0;
412 d->hard_reset = hard_reset; 412 d->hard_reset = hard_reset;
413 413
414 spin_lock_irq(&ha->state_lock); 414 spin_lock_irq(&ha->lock);
415 sas_queue_work(ha, &d->reset_work); 415 sas_queue_work(ha, &d->reset_work);
416 spin_unlock_irq(&ha->state_lock); 416 spin_unlock_irq(&ha->lock);
417 417
418 rc = sas_drain_work(ha); 418 rc = sas_drain_work(ha);
419 if (rc == 0) 419 if (rc == 0)
@@ -438,9 +438,9 @@ static int queue_phy_enable(struct sas_phy *phy, int enable)
438 d->enable_result = 0; 438 d->enable_result = 0;
439 d->enable = enable; 439 d->enable = enable;
440 440
441 spin_lock_irq(&ha->state_lock); 441 spin_lock_irq(&ha->lock);
442 sas_queue_work(ha, &d->enable_work); 442 sas_queue_work(ha, &d->enable_work);
443 spin_unlock_irq(&ha->state_lock); 443 spin_unlock_irq(&ha->lock);
444 444
445 rc = sas_drain_work(ha); 445 rc = sas_drain_work(ha);
446 if (rc == 0) 446 if (rc == 0)
diff --git a/drivers/scsi/libsas/sas_scsi_host.c b/drivers/scsi/libsas/sas_scsi_host.c
index f0b9b7bf188..a09da44e282 100644
--- a/drivers/scsi/libsas/sas_scsi_host.c
+++ b/drivers/scsi/libsas/sas_scsi_host.c
@@ -667,16 +667,20 @@ static void sas_eh_handle_sas_errors(struct Scsi_Host *shost, struct list_head *
667 goto out; 667 goto out;
668} 668}
669 669
670
670void sas_scsi_recover_host(struct Scsi_Host *shost) 671void sas_scsi_recover_host(struct Scsi_Host *shost)
671{ 672{
672 struct sas_ha_struct *ha = SHOST_TO_SAS_HA(shost); 673 struct sas_ha_struct *ha = SHOST_TO_SAS_HA(shost);
673 unsigned long flags;
674 LIST_HEAD(eh_work_q); 674 LIST_HEAD(eh_work_q);
675 int tries = 0;
676 bool retry;
675 677
676 spin_lock_irqsave(shost->host_lock, flags); 678retry:
679 tries++;
680 retry = true;
681 spin_lock_irq(shost->host_lock);
677 list_splice_init(&shost->eh_cmd_q, &eh_work_q); 682 list_splice_init(&shost->eh_cmd_q, &eh_work_q);
678 shost->host_eh_scheduled = 0; 683 spin_unlock_irq(shost->host_lock);
679 spin_unlock_irqrestore(shost->host_lock, flags);
680 684
681 SAS_DPRINTK("Enter %s busy: %d failed: %d\n", 685 SAS_DPRINTK("Enter %s busy: %d failed: %d\n",
682 __func__, shost->host_busy, shost->host_failed); 686 __func__, shost->host_busy, shost->host_failed);
@@ -710,8 +714,19 @@ out:
710 714
711 scsi_eh_flush_done_q(&ha->eh_done_q); 715 scsi_eh_flush_done_q(&ha->eh_done_q);
712 716
713 SAS_DPRINTK("--- Exit %s: busy: %d failed: %d\n", 717 /* check if any new eh work was scheduled during the last run */
714 __func__, shost->host_busy, shost->host_failed); 718 spin_lock_irq(&ha->lock);
719 if (ha->eh_active == 0) {
720 shost->host_eh_scheduled = 0;
721 retry = false;
722 }
723 spin_unlock_irq(&ha->lock);
724
725 if (retry)
726 goto retry;
727
728 SAS_DPRINTK("--- Exit %s: busy: %d failed: %d tries: %d\n",
729 __func__, shost->host_busy, shost->host_failed, tries);
715} 730}
716 731
717enum blk_eh_timer_return sas_scsi_timed_out(struct scsi_cmnd *cmd) 732enum blk_eh_timer_return sas_scsi_timed_out(struct scsi_cmnd *cmd)