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.pata_dma=0 Disable all PATA DMA like old IDE libata.pata_dma=1 Disk DMA only libata.pata_dma=2 ATAPI DMA only libata.pata_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 SATA is not affected - for one its not clear it makes sense to disable DMA for SATA if even always possible, for two we've seen no failure evidence to justify needing to support this kind of hammer on SATA. Signed-off-by: Alan Cox Acked-by: Tejun Heo Signed-off-by: Andrew Morton --- drivers/ata/libata-core.c | 17 +++++++++++++++++ include/linux/libata.h | 6 ++++++ 2 files changed, 23 insertions(+) diff -puN drivers/ata/libata-core.c~libata-add-a-drivers-ide-style-dma-disable drivers/ata/libata-core.c --- a/drivers/ata/libata-core.c~libata-add-a-drivers-ide-style-dma-disable +++ a/drivers/ata/libata-core.c @@ -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 ata_pata_dma = ATA_DMA_MASK_ATA|ATA_DMA_MASK_ATAPI|ATA_DMA_MASK_CFA; +module_param_named(pata_dma, ata_pata_dma, int, 0644); +MODULE_PARM_DESC(pata_dma, "Use DMA on PATA devices"); + 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)"); @@ -2896,14 +2900,27 @@ int ata_do_set_mode(struct ata_link *lin /* 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 ((ata_pata_dma & mode_mask) || ap->cbl == ATA_CBL_SATA) + 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); diff -puN include/linux/libata.h~libata-add-a-drivers-ide-style-dma-disable include/linux/libata.h --- a/include/linux/libata.h~libata-add-a-drivers-ide-style-dma-disable +++ a/include/linux/libata.h @@ -337,6 +337,12 @@ enum { ATA_HORKAGE_MAX_SEC_128 = (1 << 3), /* Limit max sects to 128 */ ATA_HORKAGE_BROKEN_HPA = (1 << 4), /* Broken HPA */ ATA_HORKAGE_SKIP_PM = (1 << 5), /* Skip PM operations */ + + /* 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 { _