diff options
Diffstat (limited to 'drivers/scsi/libsas/sas_ata.c')
-rw-r--r-- | drivers/scsi/libsas/sas_ata.c | 38 |
1 files changed, 34 insertions, 4 deletions
diff --git a/drivers/scsi/libsas/sas_ata.c b/drivers/scsi/libsas/sas_ata.c index d109cc3a17b6..b035acf18730 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 | ||
526 | static 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 | |||
539 | void 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 | |||
526 | static struct ata_port_operations sas_sata_ops = { | 551 | static 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 | ||
541 | static struct ata_port_info sata_port_info = { | 568 | static 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); |