[PATCH] libata: BMDMA handling updates
authorAlan Cox <alan@lxorguk.ukuu.org.uk>
Mon, 27 Mar 2006 17:42:40 +0000 (18:42 +0100)
committerJeff Garzik <jeff@garzik.org>
Thu, 30 Mar 2006 00:30:27 +0000 (19:30 -0500)
This is the minimal patch set to enable the current code to be used with
a controller following SFF (ie any PATA and early SATA controllers)
safely without crashes if there is no BMDMA area or if BMDMA is not
assigned by the BIOS for some reason.

Simplex status is recorded but not acted upon in this change, this isn't
a problem with the current drivers as none of them are for simplex
hardware. A following diff will deal with that.

The flags in the probe structure remain ->host_set_flags although Jeff
asked me to rename them, simply because the rename would break the usual
Linux rules that old code should break when there are changes. not
compile and run and then blow up/eat your computer/etc. Renaming this
later is a trivial exercise once a better name is chosen.

Signed-off-by: Jeff Garzik <jeff@garzik.org>
drivers/scsi/libata-bmdma.c
include/linux/libata.h

index 95d81d86d8b7be373b881fd884c92bc93f768483..835dff0bafdc95673064414c3554a5927b9ecd76 100644 (file)
@@ -703,6 +703,7 @@ ata_pci_init_native_mode(struct pci_dev *pdev, struct ata_port_info **port, int
        struct ata_probe_ent *probe_ent =
                ata_probe_ent_alloc(pci_dev_to_dev(pdev), port[0]);
        int p = 0;
+       unsigned long bmdma;
 
        if (!probe_ent)
                return NULL;
@@ -716,7 +717,12 @@ ata_pci_init_native_mode(struct pci_dev *pdev, struct ata_port_info **port, int
                probe_ent->port[p].altstatus_addr =
                probe_ent->port[p].ctl_addr =
                        pci_resource_start(pdev, 1) | ATA_PCI_CTL_OFS;
-               probe_ent->port[p].bmdma_addr = pci_resource_start(pdev, 4);
+               bmdma = pci_resource_start(pdev, 4);
+               if (bmdma) {
+                       if (inb(bmdma + 2) & 0x80)
+                               probe_ent->host_set_flags |= ATA_HOST_SIMPLEX;
+                       probe_ent->port[p].bmdma_addr = bmdma;
+               }
                ata_std_ports(&probe_ent->port[p]);
                p++;
        }
@@ -726,7 +732,13 @@ ata_pci_init_native_mode(struct pci_dev *pdev, struct ata_port_info **port, int
                probe_ent->port[p].altstatus_addr =
                probe_ent->port[p].ctl_addr =
                        pci_resource_start(pdev, 3) | ATA_PCI_CTL_OFS;
-               probe_ent->port[p].bmdma_addr = pci_resource_start(pdev, 4) + 8;
+               bmdma = pci_resource_start(pdev, 4);
+               if (bmdma) {
+                       bmdma += 8;
+                       if(inb(bmdma + 2) & 0x80)
+                       probe_ent->host_set_flags |= ATA_HOST_SIMPLEX;
+                       probe_ent->port[p].bmdma_addr = bmdma;
+               }
                ata_std_ports(&probe_ent->port[p]);
                p++;
        }
@@ -740,6 +752,7 @@ static struct ata_probe_ent *ata_pci_init_legacy_port(struct pci_dev *pdev,
                                struct ata_port_info *port, int port_num)
 {
        struct ata_probe_ent *probe_ent;
+       unsigned long bmdma;
 
        probe_ent = ata_probe_ent_alloc(pci_dev_to_dev(pdev), port);
        if (!probe_ent)
@@ -766,8 +779,13 @@ static struct ata_probe_ent *ata_pci_init_legacy_port(struct pci_dev *pdev,
                        break;
        }
 
-       probe_ent->port[0].bmdma_addr =
-               pci_resource_start(pdev, 4) + 8 * port_num;
+       bmdma = pci_resource_start(pdev, 4);
+       if (bmdma != 0) {
+               bmdma += 8 * port_num;
+               probe_ent->port[0].bmdma_addr = bmdma;
+               if (inb(bmdma + 2) & 0x80)
+                       probe_ent->host_set_flags |= ATA_HOST_SIMPLEX;
+       }
        ata_std_ports(&probe_ent->port[0]);
 
        return probe_ent;
index 9fcc061e3adff2924e786a45079629a936ea2bc0..a5c213ce97c9c3452742df27cfeff38edeb00876 100644 (file)
@@ -160,6 +160,9 @@ enum {
        ATA_QCFLAG_DMAMAP       = ATA_QCFLAG_SG | ATA_QCFLAG_SINGLE,
        ATA_QCFLAG_EH_SCHEDULED = (1 << 5), /* EH scheduled */
 
+       /* host set flags */
+       ATA_HOST_SIMPLEX        = (1 << 0),     /* Host is simplex, one DMA channel per host_set only */
+       
        /* various lengths of time */
        ATA_TMOUT_PIO           = 30 * HZ,
        ATA_TMOUT_BOOT          = 30 * HZ,      /* heuristic */
@@ -278,6 +281,7 @@ struct ata_probe_ent {
        unsigned long           irq;
        unsigned int            irq_flags;
        unsigned long           host_flags;
+       unsigned long           host_set_flags;
        void __iomem            *mmio_base;
        void                    *private_data;
 };