Commit a56bb4da authored by Albert Lee's avatar Albert Lee Committed by Jeff Garzik

[libata] verify ATAPI DMA for a given request is OK

After some testing, it seems that some PATA host adapter (ex. pdc20275) cannot 
work reliably with specific request buffer sizes under ATAPI DMA mode.

Detailed test result:
4096, 2048, 1024, 512, 256: OK
384, 257, 255, 128, 96, 64, 32:  failed (irq lost)
 
It seems multiple of 256 bytes are the safe ATAPI DMA buffer sizes to use.

Attached please find the patch to fix the pdc2027x ATAPI DMA problem.

Changes:
1. Add a callback function "check_atapi_dma()" to ata_port_operations such that libata core
can ask the driver: "Can this command be processed in ATAPI DMA mode safely? " 
when the the command is received.
2. ATAPI DMA is off by default if the callback function is not provided by the driver

If the callback function is not provided by the driver, the ATAPI DMA should be as is.
The ATAPI DMA is already controlled by dev->flags.

BTW, the patch isolates the ATAPI DMA workaround to the pdc20275 driver itself,
not impacting libata core .
Signed-off-by: default avatarAlbert Lee <albertcc@tw.ibm.com>
parent 623b57b3
...@@ -1919,7 +1919,24 @@ static void ata_fill_sg(struct ata_queued_cmd *qc) ...@@ -1919,7 +1919,24 @@ static void ata_fill_sg(struct ata_queued_cmd *qc)
if (idx) if (idx)
ap->prd[idx - 1].flags_len |= cpu_to_le32(ATA_PRD_EOT); 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 = 0; /* Assume ATAPI DMA is OK by default */
if (ap->ops->check_atapi_dma)
rc = ap->ops->check_atapi_dma(qc);
return rc;
}
/** /**
* ata_qc_prep - Prepare taskfile for submission * ata_qc_prep - Prepare taskfile for submission
* @qc: Metadata associated with taskfile to be prepared * @qc: Metadata associated with taskfile to be prepared
......
...@@ -1294,6 +1294,11 @@ static unsigned int atapi_xlat(struct ata_queued_cmd *qc, u8 *scsicmd) ...@@ -1294,6 +1294,11 @@ static unsigned int atapi_xlat(struct ata_queued_cmd *qc, u8 *scsicmd)
int using_pio = (dev->flags & ATA_DFLAG_PIO); int using_pio = (dev->flags & ATA_DFLAG_PIO);
int nodata = (cmd->sc_data_direction == SCSI_DATA_NONE); 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); memcpy(&qc->cdb, scsicmd, qc->ap->cdb_len);
qc->complete_fn = atapi_qc_complete; qc->complete_fn = atapi_qc_complete;
......
...@@ -38,6 +38,7 @@ struct ata_scsi_args { ...@@ -38,6 +38,7 @@ struct ata_scsi_args {
extern struct ata_queued_cmd *ata_qc_new_init(struct ata_port *ap, extern struct ata_queued_cmd *ata_qc_new_init(struct ata_port *ap,
struct ata_device *dev); struct ata_device *dev);
extern int ata_qc_issue(struct ata_queued_cmd *qc); 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, extern void ata_dev_select(struct ata_port *ap, unsigned int device,
unsigned int wait, unsigned int can_sleep); unsigned int wait, unsigned int can_sleep);
extern void ata_tf_to_host_nolock(struct ata_port *ap, struct ata_taskfile *tf); extern void ata_tf_to_host_nolock(struct ata_port *ap, struct ata_taskfile *tf);
......
...@@ -339,6 +339,8 @@ struct ata_port_operations { ...@@ -339,6 +339,8 @@ struct ata_port_operations {
void (*phy_reset) (struct ata_port *ap); void (*phy_reset) (struct ata_port *ap);
void (*post_set_mode) (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_setup) (struct ata_queued_cmd *qc);
void (*bmdma_start) (struct ata_queued_cmd *qc); void (*bmdma_start) (struct ata_queued_cmd *qc);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment