[PATCH 2.6.13] libata: use common pci remove in ahci

Brett Russ
2005-09-03T07:18:59Z

Jeff,

This looked prime to cut since ahci_remove_one() was a functionally
identical to ata_pci_remove_one() except for the interrupt disable
(have_msi) bits, which fit nicely into ahci_host_stop(). However,

1) Will it work?

2) Isn't it wrong for the IRQ disable at the chip to occur *after*
free_irq() is called to disconnect the handler (independent of
question 1...since this is the case currently)? Granted, all of the
ports have gone through scsi_remove_host() but theoretically there
still is a possibility the chip could interrupt.

If I'm wrong on both counts I'll blame it on need for sleep... :-)
BR

This patch depends on the PCI INTx patch (but will probably work w/o):
http://lkml.org/lkml/2005/8/15/165

Signed-off-by: Brett Russ <russb@emc.com>

Index: linux-2.6.13/drivers/scsi/ahci.c
===================================================================
--- linux-2.6.13.orig/drivers/scsi/ahci.c
+++ linux-2.6.13/drivers/scsi/ahci.c
@@ -187,7 +187,6 @@ static void ahci_qc_prep(struct ata_queu
static u8 ahci_check_status(struct ata_port *ap);
static u8 ahci_check_err(struct ata_port *ap);
static inline int ahci_host_intr(struct ata_port *ap, struct ata_queued_cmd *qc);
-static void ahci_remove_one (struct pci_dev *pdev);

static Scsi_Host_Template ahci_sht = {
.module = THIS_MODULE,
@@ -277,7 +276,7 @@ static struct pci_driver ahci_pci_driver
.name = DRV_NAME,
.id_table = ahci_pci_tbl,
.probe = ahci_init_one,
- .remove = ahci_remove_one,
+ .remove = ata_pci_remove_one,
};

@@ -294,6 +293,13 @@ static inline void *ahci_port_base (void
static void ahci_host_stop(struct ata_host_set *host_set)
{
struct ahci_host_priv *hpriv = host_set->private_data;
+ struct pci_dev *pdev = to_pci_dev(host_set->dev);
+
+ if (hpriv->flags & AHCI_FLAG_MSI)
+ pci_disable_msi(pdev);
+ else
+ pci_intx(pdev, 0);
+
kfree(hpriv);

ata_host_stop(host_set);
@@ -1036,43 +1042,6 @@ err_out:
return rc;
}

-static void ahci_remove_one (struct pci_dev *pdev)
-{
- 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);
- }
-
- 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];
-
- ata_scsi_release(ap->host);
- scsi_host_put(ap->host);
- }
-
- host_set->ops->host_stop(host_set);
- kfree(host_set);
-
- if (have_msi)
- pci_disable_msi(pdev);
- else
- pci_intx(pdev, 0);
- pci_release_regions(pdev);
- pci_disable_device(pdev);
- dev_set_drvdata(dev, NULL);
-}
-
static int __init ahci_init(void)
{
return pci_module_init(&ahci_pci_driver);