libata: Add a drivers/ide style DMA disable
authorAlan Cox <alan@redhat.com>
Tue, 2 Oct 2007 16:38:26 +0000 (12:38 -0400)
committerJeff Garzik <jeff@garzik.org>
Fri, 12 Oct 2007 18:55:45 +0000 (14:55 -0400)
This is useful when debugging, handling problem systems, or for
distributions just to get the system installed so it can be sorted
out later.

This is a bit smarter than the old IDE one and lets you do

libata.dma=0 Disable all PATA DMA like old IDE
libata.dma=1 Disk DMA only
libata.dma=2 ATAPI DMA only
libata.dma=4 CF DMA only

(or combinations thereof - 0,1,3 being the useful ones I suspect)

(I've split CF as it seems to be a seperate case of pain and suffering
different to the others and caused by assorted PIO wired adapters etc)

Signed-off-by: Alan Cox <alan@redhat.com>
[edited to work on SATA too, changing name from 'pata_dma' to 'dma']
Signed-off-by: Jeff Garzik <jgarzik@redhat.com>
drivers/ata/libata-core.c
include/linux/libata.h

index 5532a6564d050d24d0f8155eea72a7da3280ac00..1501d63db2cb725a4f0ae1029cecd84711bfa652 100644 (file)
@@ -97,6 +97,10 @@ static int ata_ignore_hpa = 0;
 module_param_named(ignore_hpa, ata_ignore_hpa, int, 0644);
 MODULE_PARM_DESC(ignore_hpa, "Ignore HPA limit (0=keep BIOS limits, 1=ignore limits, using full disk)");
 
+static int libata_dma_mask = ATA_DMA_MASK_ATA|ATA_DMA_MASK_ATAPI|ATA_DMA_MASK_CFA;
+module_param_named(dma, libata_dma_mask, int, 0444);
+MODULE_PARM_DESC(dma, "DMA enable/disable (0x1==ATA, 0x2==ATAPI, 0x4==CF)");
+
 static int ata_probe_timeout = ATA_TMOUT_INTERNAL / HZ;
 module_param(ata_probe_timeout, int, 0444);
 MODULE_PARM_DESC(ata_probe_timeout, "Set ATA probing timeout (seconds)");
@@ -2917,14 +2921,27 @@ int ata_do_set_mode(struct ata_link *link, struct ata_device **r_failed_dev)
        /* step 1: calculate xfer_mask */
        ata_link_for_each_dev(dev, link) {
                unsigned int pio_mask, dma_mask;
+               unsigned int mode_mask;
 
                if (!ata_dev_enabled(dev))
                        continue;
 
+               mode_mask = ATA_DMA_MASK_ATA;
+               if (dev->class == ATA_DEV_ATAPI)
+                       mode_mask = ATA_DMA_MASK_ATAPI;
+               else if (ata_id_is_cfa(dev->id))
+                       mode_mask = ATA_DMA_MASK_CFA;
+
                ata_dev_xfermask(dev);
 
                pio_mask = ata_pack_xfermask(dev->pio_mask, 0, 0);
                dma_mask = ata_pack_xfermask(0, dev->mwdma_mask, dev->udma_mask);
+
+               if (libata_dma_mask & mode_mask)
+                       dma_mask = ata_pack_xfermask(0, dev->mwdma_mask, dev->udma_mask);
+               else
+                       dma_mask = 0;
+
                dev->pio_mode = ata_xfer_mask2mode(pio_mask);
                dev->dma_mode = ata_xfer_mask2mode(dma_mask);
 
index ca296a575c4ac904242305cecd8747ae1fc0502e..84dfc23b9d3103b3ad54919cb2eb2a4b113ac337 100644 (file)
@@ -331,6 +331,12 @@ enum {
        ATA_HORKAGE_BROKEN_HPA  = (1 << 4),     /* Broken HPA */
        ATA_HORKAGE_SKIP_PM     = (1 << 5),     /* Skip PM operations */
        ATA_HORKAGE_HPA_SIZE    = (1 << 6),     /* native size off by one */
+
+        /* DMA mask for user DMA control: User visible values; DO NOT 
+           renumber */
+       ATA_DMA_MASK_ATA        = (1 << 0),     /* DMA on ATA Disk */
+       ATA_DMA_MASK_ATAPI      = (1 << 1),     /* DMA on ATAPI */
+       ATA_DMA_MASK_CFA        = (1 << 2),     /* DMA on CF Card */
 };
 
 enum hsm_task_states {