]> git.hungrycats.org Git - linux/commitdiff
[libata] Add missing hooks, to avoid oops in advanced SATA drivers
authorJeff Garzik <jgarzik@pobox.com>
Wed, 23 Feb 2005 09:47:10 +0000 (04:47 -0500)
committerJeff Garzik <jgarzik@pobox.com>
Wed, 23 Feb 2005 09:47:10 +0000 (04:47 -0500)
Advanced SATA drivers should not (and cannot) use the basic
PCI IDE hooks for checking the Status and Error registers, as these
registers are either in non-standard locations, or simply don't
exist.

In the error handling path, libata was unconditionally calling some
PCI IDE hardware bitbanging functions, which would cause an oops
in the AHCI driver and any other advanced libata driver.

drivers/scsi/ahci.c
drivers/scsi/libata-core.c
include/linux/libata.h

index a99dee8edbd9d678f361ebd8e85621ce37f810e5..9bf037efa2a2bc73558939d185e94694478d3712 100644 (file)
@@ -179,6 +179,7 @@ static void ahci_port_stop(struct ata_port *ap);
 static void ahci_host_stop(struct ata_host_set *host_set);
 static void ahci_qc_prep(struct ata_queued_cmd *qc);
 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 Scsi_Host_Template ahci_sht = {
@@ -204,6 +205,8 @@ static struct ata_port_operations ahci_ops = {
        .port_disable           = ata_port_disable,
 
        .check_status           = ahci_check_status,
+       .check_altstatus        = ahci_check_status,
+       .check_err              = ahci_check_err,
        .dev_select             = ata_noop_dev_select,
 
        .phy_reset              = ahci_phy_reset,
@@ -452,6 +455,13 @@ static u8 ahci_check_status(struct ata_port *ap)
        return readl(mmio + PORT_TFDATA) & 0xFF;
 }
 
+static u8 ahci_check_err(struct ata_port *ap)
+{
+       void *mmio = (void *) ap->ioaddr.cmd_addr;
+
+       return (readl(mmio + PORT_TFDATA) >> 8) & 0xFF;
+}
+
 static void ahci_fill_sg(struct ata_queued_cmd *qc)
 {
        struct ahci_port_priv *pp = qc->ap->private_data;
index 9635a009194db01fb8e0ba760bf29c3a6fd0c729..d74b7a4c47fdbc700a67b9954a0c9b1436489886 100644 (file)
@@ -377,7 +377,7 @@ void ata_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
 }
 
 /**
- *     ata_check_status - Read device status reg & clear interrupt
+ *     ata_check_status_pio - Read device status reg & clear interrupt
  *     @ap: port where the device is
  *
  *     Reads ATA taskfile status register for currently-selected device
@@ -415,6 +415,27 @@ u8 ata_check_status(struct ata_port *ap)
        return ata_check_status_pio(ap);
 }
 
+u8 ata_altstatus(struct ata_port *ap)
+{
+       if (ap->ops->check_altstatus)
+               return ap->ops->check_altstatus(ap);
+
+       if (ap->flags & ATA_FLAG_MMIO)
+               return readb((void __iomem *)ap->ioaddr.altstatus_addr);
+       return inb(ap->ioaddr.altstatus_addr);
+}
+
+u8 ata_chk_err(struct ata_port *ap)
+{
+       if (ap->ops->check_err)
+               return ap->ops->check_err(ap);
+
+       if (ap->flags & ATA_FLAG_MMIO) {
+               return readb((void __iomem *) ap->ioaddr.error_addr);
+       }
+       return inb(ap->ioaddr.error_addr);
+}
+
 /**
  *     ata_tf_to_fis - Convert ATA taskfile to SATA FIS structure
  *     @tf: Taskfile to convert
@@ -1161,7 +1182,6 @@ err_out_nosup:
        printk(KERN_WARNING "ata%u: dev %u not supported, ignoring\n",
               ap->id, device);
 err_out:
-       ata_irq_on(ap); /* re-enable interrupts */
        dev->class++;   /* converts ATA_DEV_xxx into ATA_DEV_xxx_UNSUP */
        DPRINTK("EXIT, err\n");
 }
@@ -1669,7 +1689,8 @@ void ata_bus_reset(struct ata_port *ap)
                ata_dev_try_classify(ap, 1);
 
        /* re-enable interrupts */
-       ata_irq_on(ap);
+       if (ap->ioaddr.ctl_addr)        /* FIXME: hack. create a hook instead */
+               ata_irq_on(ap);
 
        /* is double-select really necessary? */
        if (ap->device[1].class != ATA_DEV_NONE)
@@ -3972,6 +3993,8 @@ EXPORT_SYMBOL_GPL(ata_std_dev_select);
 EXPORT_SYMBOL_GPL(ata_tf_to_fis);
 EXPORT_SYMBOL_GPL(ata_tf_from_fis);
 EXPORT_SYMBOL_GPL(ata_check_status);
+EXPORT_SYMBOL_GPL(ata_altstatus);
+EXPORT_SYMBOL_GPL(ata_chk_err);
 EXPORT_SYMBOL_GPL(ata_exec_command);
 EXPORT_SYMBOL_GPL(ata_port_start);
 EXPORT_SYMBOL_GPL(ata_port_stop);
index 10207ce48f04fd07f63472c84c9cb07ffa805e1f..505160ab472b0198ec5393380ce7c21b2fad85d1 100644 (file)
@@ -334,6 +334,8 @@ struct ata_port_operations {
 
        void (*exec_command)(struct ata_port *ap, struct ata_taskfile *tf);
        u8   (*check_status)(struct ata_port *ap);
+       u8   (*check_altstatus)(struct ata_port *ap);
+       u8   (*check_err)(struct ata_port *ap);
        void (*dev_select)(struct ata_port *ap, unsigned int device);
 
        void (*phy_reset) (struct ata_port *ap);
@@ -403,6 +405,8 @@ extern void ata_tf_from_fis(u8 *fis, struct ata_taskfile *tf);
 extern void ata_noop_dev_select (struct ata_port *ap, unsigned int device);
 extern void ata_std_dev_select (struct ata_port *ap, unsigned int device);
 extern u8 ata_check_status(struct ata_port *ap);
+extern u8 ata_altstatus(struct ata_port *ap);
+extern u8 ata_chk_err(struct ata_port *ap);
 extern void ata_exec_command(struct ata_port *ap, struct ata_taskfile *tf);
 extern int ata_port_start (struct ata_port *ap);
 extern void ata_port_stop (struct ata_port *ap);
@@ -457,26 +461,11 @@ static inline unsigned int ata_dev_present(struct ata_device *dev)
                (dev->class == ATA_DEV_ATAPI));
 }
 
-static inline u8 ata_chk_err(struct ata_port *ap)
-{
-       if (ap->flags & ATA_FLAG_MMIO) {
-               return readb((void __iomem *) ap->ioaddr.error_addr);
-       }
-       return inb(ap->ioaddr.error_addr);
-}
-
 static inline u8 ata_chk_status(struct ata_port *ap)
 {
        return ap->ops->check_status(ap);
 }
 
-static inline u8 ata_altstatus(struct ata_port *ap)
-{
-       if (ap->flags & ATA_FLAG_MMIO)
-               return readb((void __iomem *)ap->ioaddr.altstatus_addr);
-       return inb(ap->ioaddr.altstatus_addr);
-}
-
 static inline void ata_pause(struct ata_port *ap)
 {
        ata_altstatus(ap);