diff -Nru libata-dev-2.6-ori/drivers/scsi/libata-core.c libata-dev-2.6/drivers/scsi/libata-core.c --- libata-dev-2.6-ori/drivers/scsi/libata-core.c 2004-12-15 16:10:30.000000000 +0800 +++ libata-dev-2.6/drivers/scsi/libata-core.c 2004-12-15 16:15:01.000000000 +0800 @@ -1947,7 +1947,24 @@ if (idx) ap->prd[idx - 1].flags_len |= cpu_to_le32(ATA_PRD_EOT); } +/** + * ata_check_atapi_dma - Check whether ATAPI DMA can be supported + * @qc: Metadata associated with taskfile to check + * + * LOCKING: + * RETURNS: 0 when ATAPI DMA can be used + * nonzero otherwise + */ +int ata_check_atapi_dma(struct ata_queued_cmd *qc) +{ + struct ata_port *ap = qc->ap; + int rc = 1; /* Turn off ATAPI DMA by default */ + + if (ap->ops->check_atapi_dma) + rc = ap->ops->check_atapi_dma(qc); + return rc; +} /** * ata_qc_prep - Prepare taskfile for submission * @qc: Metadata associated with taskfile to be prepared diff -Nru libata-dev-2.6-ori/drivers/scsi/libata.h libata-dev-2.6/drivers/scsi/libata.h --- libata-dev-2.6-ori/drivers/scsi/libata.h 2004-11-30 12:52:28.000000000 +0800 +++ libata-dev-2.6/drivers/scsi/libata.h 2004-12-15 16:36:55.000000000 +0800 @@ -38,6 +38,7 @@ extern struct ata_queued_cmd *ata_qc_new_init(struct ata_port *ap, struct ata_device *dev); extern int ata_qc_issue(struct ata_queued_cmd *qc); +extern int ata_check_atapi_dma(struct ata_queued_cmd *qc); extern void ata_dev_select(struct ata_port *ap, unsigned int device, unsigned int wait, unsigned int can_sleep); extern void ata_tf_to_host_nolock(struct ata_port *ap, struct ata_taskfile *tf); diff -Nru libata-dev-2.6-ori/drivers/scsi/libata-scsi.c libata-dev-2.6/drivers/scsi/libata-scsi.c --- libata-dev-2.6-ori/drivers/scsi/libata-scsi.c 2004-11-30 12:52:28.000000000 +0800 +++ libata-dev-2.6/drivers/scsi/libata-scsi.c 2004-12-15 16:15:59.000000000 +0800 @@ -1558,6 +1558,11 @@ int using_pio = (dev->flags & ATA_DFLAG_PIO); int nodata = (cmd->sc_data_direction == SCSI_DATA_NONE); + if (!using_pio) + /* Check whether ATAPI DMA is safe */ + if (ata_check_atapi_dma(qc)) + using_pio = 1; + memcpy(&qc->cdb, scsicmd, qc->ap->cdb_len); qc->complete_fn = atapi_qc_complete; diff -Nru libata-dev-2.6-ori/drivers/scsi/pata_pdc2027x.c libata-dev-2.6/drivers/scsi/pata_pdc2027x.c --- libata-dev-2.6-ori/drivers/scsi/pata_pdc2027x.c 2004-11-30 12:52:28.000000000 +0800 +++ libata-dev-2.6/drivers/scsi/pata_pdc2027x.c 2004-12-15 16:21:00.000000000 +0800 @@ -29,7 +29,7 @@ #include #define DRV_NAME "pata_pdc2027x" -#define DRV_VERSION "0.53" +#define DRV_VERSION "0.54" #undef PDC_DEBUG #ifdef PDC_DEBUG @@ -51,6 +51,7 @@ static void pdc2027x_phy_reset(struct ata_port *ap); static void pdc2027x_set_piomode(struct ata_port *ap, struct ata_device *adev); static void pdc2027x_set_dmamode(struct ata_port *ap, struct ata_device *adev); +static int pdc2027x_check_atapi_dma(struct ata_queued_cmd *qc); /* * ATA Timing Tables based on 133MHz controller clock. @@ -141,6 +142,7 @@ .phy_reset = pdc2027x_phy_reset, + .check_atapi_dma = pdc2027x_check_atapi_dma, .bmdma_setup = ata_bmdma_setup, .bmdma_start = ata_bmdma_start, .qc_prep = ata_qc_prep, @@ -377,6 +379,27 @@ } } /** + * pdc2027x_check_atapi_dma - Check whether ATAPI DMA can be supported for this command + * @qc: Metadata associated with taskfile to check + * + * LOCKING: + * None (inherited from caller). + * + * RETURNS: 0 when ATAPI DMA can be used + * 1 otherwise + */ +static int pdc2027x_check_atapi_dma(struct ata_queued_cmd *qc) +{ + struct scsi_cmnd *cmd = qc->scsicmd; + int rc = 0; + + /* pdc2027x can only do ATAPI DMA for specific buffer size */ + if (cmd->request_bufflen % 256) + rc = 1; + + return rc; +} +/** * adjust_pll - Adjust the PLL input clock in Hz. * * @pdc_controller: controller specific information diff -Nru libata-dev-2.6-ori/include/linux/libata.h libata-dev-2.6/include/linux/libata.h --- libata-dev-2.6-ori/include/linux/libata.h 2004-11-30 12:52:42.000000000 +0800 +++ libata-dev-2.6/include/linux/libata.h 2004-12-15 16:17:41.000000000 +0800 @@ -339,6 +339,8 @@ void (*phy_reset) (struct ata_port *ap); void (*post_set_mode) (struct ata_port *ap); + int (*check_atapi_dma) (struct ata_queued_cmd *qc); + void (*bmdma_setup) (struct ata_queued_cmd *qc); void (*bmdma_start) (struct ata_queued_cmd *qc);