diff options
author | Tejun Heo <htejun@gmail.com> | 2006-05-31 05:28:13 -0400 |
---|---|---|
committer | Tejun Heo <htejun@gmail.com> | 2006-05-31 05:28:13 -0400 |
commit | 720ba12620ee09dce269adf4ad50958adac7bb54 (patch) | |
tree | f31a8b3da52195610bd244baf42a5fe2e26b0a36 /drivers/scsi/libata-core.c | |
parent | 3e706399b03bd237d087d731d4b1b029e546b33d (diff) |
[PATCH] libata-hp: update unload-unplug
Update unload unplug - driver unloading / PCI removal. This is done
by ata_port_detach() which short-circuits EH, disables all devices and
freezes the port. With this patch, EH and unloading/unplugging are
properly synchronized.
Signed-off-by: Tejun Heo <htejun@gmail.com>
Diffstat (limited to 'drivers/scsi/libata-core.c')
-rw-r--r-- | drivers/scsi/libata-core.c | 67 |
1 files changed, 61 insertions, 6 deletions
diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index a42877e6b865..01f2c59536bc 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c | |||
@@ -5610,6 +5610,63 @@ err_free_ret: | |||
5610 | } | 5610 | } |
5611 | 5611 | ||
5612 | /** | 5612 | /** |
5613 | * ata_port_detach - Detach ATA port in prepration of device removal | ||
5614 | * @ap: ATA port to be detached | ||
5615 | * | ||
5616 | * Detach all ATA devices and the associated SCSI devices of @ap; | ||
5617 | * then, remove the associated SCSI host. @ap is guaranteed to | ||
5618 | * be quiescent on return from this function. | ||
5619 | * | ||
5620 | * LOCKING: | ||
5621 | * Kernel thread context (may sleep). | ||
5622 | */ | ||
5623 | void ata_port_detach(struct ata_port *ap) | ||
5624 | { | ||
5625 | unsigned long flags; | ||
5626 | int i; | ||
5627 | |||
5628 | if (!ap->ops->error_handler) | ||
5629 | return; | ||
5630 | |||
5631 | /* tell EH we're leaving & flush EH */ | ||
5632 | spin_lock_irqsave(&ap->host_set->lock, flags); | ||
5633 | ap->flags |= ATA_FLAG_UNLOADING; | ||
5634 | spin_unlock_irqrestore(&ap->host_set->lock, flags); | ||
5635 | |||
5636 | ata_port_wait_eh(ap); | ||
5637 | |||
5638 | /* EH is now guaranteed to see UNLOADING, so no new device | ||
5639 | * will be attached. Disable all existing devices. | ||
5640 | */ | ||
5641 | spin_lock_irqsave(&ap->host_set->lock, flags); | ||
5642 | |||
5643 | for (i = 0; i < ATA_MAX_DEVICES; i++) | ||
5644 | ata_dev_disable(&ap->device[i]); | ||
5645 | |||
5646 | spin_unlock_irqrestore(&ap->host_set->lock, flags); | ||
5647 | |||
5648 | /* Final freeze & EH. All in-flight commands are aborted. EH | ||
5649 | * will be skipped and retrials will be terminated with bad | ||
5650 | * target. | ||
5651 | */ | ||
5652 | spin_lock_irqsave(&ap->host_set->lock, flags); | ||
5653 | ata_port_freeze(ap); /* won't be thawed */ | ||
5654 | spin_unlock_irqrestore(&ap->host_set->lock, flags); | ||
5655 | |||
5656 | ata_port_wait_eh(ap); | ||
5657 | |||
5658 | /* Flush hotplug task. The sequence is similar to | ||
5659 | * ata_port_flush_task(). | ||
5660 | */ | ||
5661 | flush_workqueue(ata_aux_wq); | ||
5662 | cancel_delayed_work(&ap->hotplug_task); | ||
5663 | flush_workqueue(ata_aux_wq); | ||
5664 | |||
5665 | /* remove the associated SCSI host */ | ||
5666 | scsi_remove_host(ap->host); | ||
5667 | } | ||
5668 | |||
5669 | /** | ||
5613 | * ata_host_set_remove - PCI layer callback for device removal | 5670 | * ata_host_set_remove - PCI layer callback for device removal |
5614 | * @host_set: ATA host set that was removed | 5671 | * @host_set: ATA host set that was removed |
5615 | * | 5672 | * |
@@ -5622,18 +5679,15 @@ err_free_ret: | |||
5622 | 5679 | ||
5623 | void ata_host_set_remove(struct ata_host_set *host_set) | 5680 | void ata_host_set_remove(struct ata_host_set *host_set) |
5624 | { | 5681 | { |
5625 | struct ata_port *ap; | ||
5626 | unsigned int i; | 5682 | unsigned int i; |
5627 | 5683 | ||
5628 | for (i = 0; i < host_set->n_ports; i++) { | 5684 | for (i = 0; i < host_set->n_ports; i++) |
5629 | ap = host_set->ports[i]; | 5685 | ata_port_detach(host_set->ports[i]); |
5630 | scsi_remove_host(ap->host); | ||
5631 | } | ||
5632 | 5686 | ||
5633 | free_irq(host_set->irq, host_set); | 5687 | free_irq(host_set->irq, host_set); |
5634 | 5688 | ||
5635 | for (i = 0; i < host_set->n_ports; i++) { | 5689 | for (i = 0; i < host_set->n_ports; i++) { |
5636 | ap = host_set->ports[i]; | 5690 | struct ata_port *ap = host_set->ports[i]; |
5637 | 5691 | ||
5638 | ata_scsi_release(ap->host); | 5692 | ata_scsi_release(ap->host); |
5639 | 5693 | ||
@@ -5901,6 +5955,7 @@ EXPORT_SYMBOL_GPL(sata_deb_timing_before_fsrst); | |||
5901 | EXPORT_SYMBOL_GPL(ata_std_bios_param); | 5955 | EXPORT_SYMBOL_GPL(ata_std_bios_param); |
5902 | EXPORT_SYMBOL_GPL(ata_std_ports); | 5956 | EXPORT_SYMBOL_GPL(ata_std_ports); |
5903 | EXPORT_SYMBOL_GPL(ata_device_add); | 5957 | EXPORT_SYMBOL_GPL(ata_device_add); |
5958 | EXPORT_SYMBOL_GPL(ata_port_detach); | ||
5904 | EXPORT_SYMBOL_GPL(ata_host_set_remove); | 5959 | EXPORT_SYMBOL_GPL(ata_host_set_remove); |
5905 | EXPORT_SYMBOL_GPL(ata_sg_init); | 5960 | EXPORT_SYMBOL_GPL(ata_sg_init); |
5906 | EXPORT_SYMBOL_GPL(ata_sg_init_one); | 5961 | EXPORT_SYMBOL_GPL(ata_sg_init_one); |