From: Tejun Heo <htejun@gmail.com>
To: jgarzik@pobox.com, mlord@pobox.com, albertcc@tw.ibm.com,
alan@lxorguk.ukuu.org.uk, axboe@suse.de, forrest.zhao@intel.com,
linux-ide@vger.kernel.org
Cc: Tejun Heo <htejun@gmail.com>
Subject: [PATCH 07/13] libata-hp: implement unload-unplug
Date: Mon, 29 May 2006 15:38:56 +0900 [thread overview]
Message-ID: <1148884736485-git-send-email-htejun@gmail.com> (raw)
In-Reply-To: <11488847352050-git-send-email-htejun@gmail.com>
Implement unload unplug - driver unloading / PCI removal via hot
unplug path. This is done by ata_port_detach() which requests detach
of all devices, schedules EH and wait for it to complete. EH path is
slightly modified to handle this (e.g. force zero eh_info during
unloading). With this patch, EH and unloading are properly
synchronized and unloading should be safe under any circumstances.
Signed-off-by: Tejun Heo <htejun@gmail.com>
---
drivers/scsi/ahci.c | 10 ++-----
drivers/scsi/libata-core.c | 59 ++++++++++++++++++++++++++++++++++++++++----
drivers/scsi/libata-eh.c | 7 +++--
include/linux/libata.h | 1 +
4 files changed, 61 insertions(+), 16 deletions(-)
dc54139a72085d78f1fc35a721cff16cdeb38ef9
diff --git a/drivers/scsi/ahci.c b/drivers/scsi/ahci.c
index afb3805..60f455b 100644
--- a/drivers/scsi/ahci.c
+++ b/drivers/scsi/ahci.c
@@ -1389,21 +1389,17 @@ static void ahci_remove_one (struct pci_
struct device *dev = pci_dev_to_dev(pdev);
struct ata_host_set *host_set = dev_get_drvdata(dev);
struct ahci_host_priv *hpriv = host_set->private_data;
- struct ata_port *ap;
unsigned int i;
int have_msi;
- for (i = 0; i < host_set->n_ports; i++) {
- ap = host_set->ports[i];
-
- scsi_remove_host(ap->host);
- }
+ for (i = 0; i < host_set->n_ports; i++)
+ ata_port_detach(host_set->ports[i]);
have_msi = hpriv->flags & AHCI_FLAG_MSI;
free_irq(host_set->irq, host_set);
for (i = 0; i < host_set->n_ports; i++) {
- ap = host_set->ports[i];
+ struct ata_port *ap = host_set->ports[i];
ata_scsi_release(ap->host);
scsi_host_put(ap->host);
diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c
index f45e04f..b622c61 100644
--- a/drivers/scsi/libata-core.c
+++ b/drivers/scsi/libata-core.c
@@ -5613,6 +5613,55 @@ err_free_ret:
}
/**
+ * ata_port_detach - Detach ATA port in prepration of device removal
+ * @ap: ATA port to be detached
+ *
+ * Detach all ATA devices and the associated SCSI devices of @ap;
+ * then, remove the associated SCSI host. @ap is guaranteed to
+ * be quiescent on return from this function.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep).
+ */
+void ata_port_detach(struct ata_port *ap)
+{
+ unsigned long flags;
+ int i;
+
+ if (!ap->ops->error_handler)
+ return;
+
+ /* tell EH to self-destruct */
+ spin_lock_irqsave(&ap->host_set->lock, flags);
+
+ ap->flags |= ATA_FLAG_UNLOADING;
+ for (i = 0; i < ATA_MAX_DEVICES; i++)
+ ap->device[i].flags |= ATA_DFLAG_DETACH;
+
+ ata_port_schedule_eh(ap);
+
+ spin_unlock_irqrestore(&ap->host_set->lock, flags);
+
+ /* wait for EH */
+ while (scsi_host_in_recovery(ap->host))
+ msleep(100);
+
+ /* Flush hotplug task. The sequence is similar to
+ * ata_port_flush_task(). ATA_FLAG_UNLOADING prevents further
+ * queueing of hotplug_task.
+ */
+ flush_workqueue(ata_scsi_wq);
+ cancel_delayed_work(&ap->hotplug_task);
+ flush_workqueue(ata_scsi_wq);
+
+ /* freeze the port */
+ ata_eh_freeze_port(ap);
+
+ /* remove the associated SCSI host */
+ scsi_remove_host(ap->host);
+}
+
+/**
* ata_host_set_remove - PCI layer callback for device removal
* @host_set: ATA host set that was removed
*
@@ -5625,18 +5674,15 @@ err_free_ret:
void ata_host_set_remove(struct ata_host_set *host_set)
{
- struct ata_port *ap;
unsigned int i;
- for (i = 0; i < host_set->n_ports; i++) {
- ap = host_set->ports[i];
- scsi_remove_host(ap->host);
- }
+ for (i = 0; i < host_set->n_ports; i++)
+ ata_port_detach(host_set->ports[i]);
free_irq(host_set->irq, host_set);
for (i = 0; i < host_set->n_ports; i++) {
- ap = host_set->ports[i];
+ struct ata_port *ap = host_set->ports[i];
ata_scsi_release(ap->host);
@@ -5904,6 +5950,7 @@ EXPORT_SYMBOL_GPL(sata_deb_timing_before
EXPORT_SYMBOL_GPL(ata_std_bios_param);
EXPORT_SYMBOL_GPL(ata_std_ports);
EXPORT_SYMBOL_GPL(ata_device_add);
+EXPORT_SYMBOL_GPL(ata_port_detach);
EXPORT_SYMBOL_GPL(ata_host_set_remove);
EXPORT_SYMBOL_GPL(ata_sg_init);
EXPORT_SYMBOL_GPL(ata_sg_init_one);
diff --git a/drivers/scsi/libata-eh.c b/drivers/scsi/libata-eh.c
index 7b5cb02..9eb73bb 100644
--- a/drivers/scsi/libata-eh.c
+++ b/drivers/scsi/libata-eh.c
@@ -234,7 +234,8 @@ void ata_scsi_error(struct Scsi_Host *ho
spin_lock_irqsave(hs_lock, flags);
memset(&ap->eh_context, 0, sizeof(ap->eh_context));
- ap->eh_context.i = ap->eh_info;
+ if (!(ap->flags & ATA_FLAG_UNLOADING))
+ ap->eh_context.i = ap->eh_info;
memset(&ap->eh_info, 0, sizeof(ap->eh_info));
ap->flags &= ~ATA_FLAG_EH_PENDING;
@@ -290,7 +291,7 @@ void ata_scsi_error(struct Scsi_Host *ho
int bit = fls(ATA_FLAG_LOADING) - 1;
clear_bit(bit, &ap->flags);
wake_up_bit(&ap->flags, bit);
- } else {
+ } else if (!(ap->flags & ATA_FLAG_UNLOADING)) {
if (ap->flags & ATA_FLAG_SCSI_HOTPLUG)
queue_work(ata_scsi_wq, &ap->hotplug_task);
if (ap->flags & ATA_FLAG_RECOVERED)
@@ -1769,7 +1770,7 @@ void ata_do_eh(struct ata_port *ap, ata_
ata_reset_fn_t softreset, ata_reset_fn_t hardreset,
ata_postreset_fn_t postreset)
{
- if (!(ap->flags & ATA_FLAG_LOADING)) {
+ if (!(ap->flags & (ATA_FLAG_LOADING | ATA_FLAG_UNLOADING))) {
ata_eh_autopsy(ap);
ata_eh_report(ap);
}
diff --git a/include/linux/libata.h b/include/linux/libata.h
index b216400..99a2b68 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -647,6 +647,7 @@ extern int ata_pci_device_resume(struct
extern int ata_pci_clear_simplex(struct pci_dev *pdev);
#endif /* CONFIG_PCI */
extern int ata_device_add(const struct ata_probe_ent *ent);
+extern void ata_port_detach(struct ata_port *ap);
extern void ata_host_set_remove(struct ata_host_set *host_set);
extern int ata_scsi_detect(struct scsi_host_template *sht);
extern int ata_scsi_ioctl(struct scsi_device *dev, int cmd, void __user *arg);
--
1.3.2
next prev parent reply other threads:[~2006-05-29 6:39 UTC|newest]
Thread overview: 34+ messages / expand[flat|nested] mbox.gz Atom feed top
2006-05-29 6:38 [PATCHSET 03/03] add hotplug support, take 4 Tejun Heo
2006-05-29 6:38 ` [PATCH 03/13] libata-hp: implement SCSI part of hotplug Tejun Heo
2006-05-29 6:38 ` [PATCH 01/13] libata-hp: implement ata_eh_detach_dev() Tejun Heo
2006-05-30 4:17 ` Jeff Garzik
2006-05-29 6:38 ` [PATCH 02/13] libata-hp: implement hotplug Tejun Heo
2006-05-30 4:18 ` Jeff Garzik
2006-05-30 4:44 ` Tejun Heo
2006-05-29 6:38 ` [PATCH 12/13] libata-hp: killl ops->probe_reset Tejun Heo
2006-05-29 6:38 ` [PATCH 10/13] ahci: convert to new probing mechanism and add hotplug support Tejun Heo
2006-05-30 4:27 ` Jeff Garzik
2006-05-29 6:38 ` [PATCH 11/13] sata_sil24: " Tejun Heo
2006-05-30 4:28 ` Jeff Garzik
2006-05-29 6:38 ` Tejun Heo [this message]
2006-05-30 4:24 ` [PATCH 07/13] libata-hp: implement unload-unplug Jeff Garzik
2006-05-30 4:37 ` Tejun Heo
2006-05-30 4:44 ` Jeff Garzik
2006-05-29 6:38 ` [PATCH 05/13] libata-hp: hook warmplug Tejun Heo
2006-05-30 4:21 ` Jeff Garzik
2006-05-29 6:38 ` [PATCH 08/13] ata_piix: convert ata_piix to new probing mechanism Tejun Heo
2006-05-29 6:38 ` [PATCH 13/13] libata-hp: move ata_do_reset() to libata-eh.c Tejun Heo
2006-05-30 4:28 ` Jeff Garzik
2006-05-29 6:38 ` [PATCH 09/13] sata_sil: convert to new probing mechanism and add hotplug support Tejun Heo
2006-05-30 4:26 ` Jeff Garzik
2006-05-29 6:38 ` [PATCH 04/13] libata-hp: implement warmplug Tejun Heo
2006-05-29 6:38 ` [PATCH 06/13] libata-hp: implement bootplug Tejun Heo
2006-05-30 4:23 ` Jeff Garzik
2006-05-30 4:29 ` Tejun Heo
2006-05-30 4:34 ` Jeff Garzik
2006-05-30 4:40 ` Tejun Heo
2006-05-30 4:43 ` Jeff Garzik
-- strict thread matches above, loose matches on Subject: below --
2006-05-19 15:48 [PATCHSET 03/03] add hotplug support, take 3 Tejun Heo
2006-05-19 15:48 ` [PATCH 07/13] libata-hp: implement unload-unplug Tejun Heo
2006-05-19 16:10 ` Jeff Garzik
2006-05-23 14:53 ` Tejun Heo
2006-05-11 15:32 [PATCHSET 08/11] add hotplug support, take 2 Tejun Heo
2006-05-11 15:32 ` [PATCH 07/13] libata-hp: implement unload-unplug Tejun Heo
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1148884736485-git-send-email-htejun@gmail.com \
--to=htejun@gmail.com \
--cc=alan@lxorguk.ukuu.org.uk \
--cc=albertcc@tw.ibm.com \
--cc=axboe@suse.de \
--cc=forrest.zhao@intel.com \
--cc=jgarzik@pobox.com \
--cc=linux-ide@vger.kernel.org \
--cc=mlord@pobox.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.