Commit 04272d0f authored by Jeff Garzik's avatar Jeff Garzik

[libata] ATAPI work - cdb len, new taskfile protocol, cleanups

* new helper atapi_cdb_len() in linux/ata.h, use it after
IDENTIFY PACKET DEVICE command completes
* add new taskfile protocol ATA_PROT_ATAPI_NODATA
* store scsi cdb in ata_queued_cmd.  This removes another dependence
on the scsi layer, and enables us to issue an internal REQUEST SENSE.
* store cdb len in ata_port
* new constant ATAPI_CDB_LEN for max cdb length
* move ATA taskfile and SCSI cdb near the top of ata_queued_cmd, for
better cacheline friendliness.
parent 3fcfe387
......@@ -1099,10 +1099,13 @@ static void ata_dev_identify(struct ata_port *ap, unsigned int device)
if (ata_id_is_ata(dev)) /* sanity check */
goto err_out_nosup;
/* see if 16-byte commands supported */
tmp = dev->id[0] & 0x3;
if (tmp == 1)
ap->host->max_cmd_len = 16;
rc = atapi_cdb_len(dev->id);
if ((rc < 12) || (rc > ATAPI_CDB_LEN)) {
printk(KERN_WARNING "ata%u: unsupported CDB len\n", ap->id);
goto err_out_nosup;
}
ap->cdb_len = (unsigned int) rc;
ap->host->max_cmd_len = (unsigned char) ap->cdb_len;
/* print device info to dmesg */
printk(KERN_INFO "ata%u: dev %u ATAPI, max %s\n",
......@@ -2265,7 +2268,6 @@ static void ata_qc_timeout(struct ata_queued_cmd *qc)
/* fall through */
case ATA_PROT_NODATA:
default:
ata_altstatus(ap);
drv_stat = ata_chk_status(ap);
......@@ -2520,6 +2522,11 @@ int ata_qc_issue_prot(struct ata_queued_cmd *qc)
queue_work(ata_wq, &ap->packet_task);
break;
case ATA_PROT_ATAPI_NODATA:
ata_tf_to_host_nolock(ap, &qc->tf);
queue_work(ata_wq, &ap->packet_task);
break;
case ATA_PROT_ATAPI_DMA:
ap->ops->tf_load(ap, &qc->tf); /* load tf registers */
ap->ops->bmdma_setup(qc); /* set up bmdma */
......@@ -2685,6 +2692,7 @@ inline unsigned int ata_host_intr (struct ata_port *ap,
/* fall through */
case ATA_PROT_ATAPI_NODATA:
case ATA_PROT_NODATA:
/* check altstatus */
status = ata_altstatus(ap);
......@@ -2795,19 +2803,20 @@ static void atapi_packet_task(void *_data)
/* make sure DRQ is set */
status = ata_chk_status(ap);
if ((status & ATA_DRQ) == 0)
if ((status & (ATA_BUSY | ATA_DRQ)) != ATA_DRQ)
goto err_out;
/* send SCSI cdb */
DPRINTK("send cdb\n");
ata_data_xfer(ap, qc->scsicmd->cmnd, ap->host->max_cmd_len, 1);
assert(ap->cdb_len >= 12);
ata_data_xfer(ap, qc->cdb, ap->cdb_len, 1);
/* if we are DMA'ing, irq handler takes over from here */
if (qc->tf.protocol == ATA_PROT_ATAPI_DMA)
ap->ops->bmdma_start(qc); /* initiate bmdma */
/* non-data commands are also handled via irq */
else if (qc->scsicmd->sc_data_direction == SCSI_DATA_NONE) {
else if (qc->tf.protocol == ATA_PROT_ATAPI_NODATA) {
/* do nothing */
}
......
......@@ -1002,6 +1002,9 @@ static unsigned int atapi_xlat(struct ata_queued_cmd *qc, u8 *scsicmd)
struct scsi_cmnd *cmd = qc->scsicmd;
struct ata_device *dev = qc->dev;
int using_pio = (dev->flags & ATA_DFLAG_PIO);
int nodata = (cmd->sc_data_direction == SCSI_DATA_NONE);
memcpy(&qc->cdb, scsicmd, qc->ap->cdb_len);
qc->complete_fn = atapi_qc_complete;
......@@ -1013,18 +1016,18 @@ static unsigned int atapi_xlat(struct ata_queued_cmd *qc, u8 *scsicmd)
qc->tf.command = ATA_CMD_PACKET;
/* no data - interrupt-driven */
if (cmd->sc_data_direction == SCSI_DATA_NONE)
qc->tf.protocol = ATA_PROT_ATAPI;
/* PIO data xfer */
else if (using_pio) {
qc->tf.protocol = ATA_PROT_ATAPI;
/* no data, or PIO data xfer */
if (using_pio || nodata) {
if (nodata)
qc->tf.protocol = ATA_PROT_ATAPI_NODATA;
else
qc->tf.protocol = ATA_PROT_ATAPI;
qc->tf.lbam = (8 * 1024) & 0xff;
qc->tf.lbah = (8 * 1024) >> 8;
}
/* DMA data xfer */
} else {
else {
qc->tf.protocol = ATA_PROT_ATAPI_DMA;
qc->tf.feature |= ATAPI_PKT_DMA;
......
......@@ -147,6 +147,7 @@ enum {
ATAPI_PKT_DMA = (1 << 0),
ATAPI_DMADIR = (1 << 2), /* ATAPI data dir:
0=to device, 1=to host */
ATAPI_CDB_LEN = 16,
/* cable types */
ATA_CBL_NONE = 0,
......@@ -176,7 +177,8 @@ enum ata_tf_protocols {
ATA_PROT_PIO, /* PIO single sector */
ATA_PROT_PIO_MULT, /* PIO multiple sector */
ATA_PROT_DMA, /* DMA */
ATA_PROT_ATAPI, /* packet command */
ATA_PROT_ATAPI, /* packet command, PIO data xfer*/
ATA_PROT_ATAPI_NODATA, /* packet command, no data */
ATA_PROT_ATAPI_DMA, /* packet command with special DMA sauce */
};
......@@ -227,9 +229,20 @@ struct ata_taskfile {
((u64) dev->id[(n) + 1] << 16) | \
((u64) dev->id[(n) + 0]) )
static inline int atapi_cdb_len(u16 *dev_id)
{
u16 tmp = dev_id[0] & 0x3;
switch (tmp) {
case 0: return 12;
case 1: return 16;
default: return -1;
}
}
static inline int is_atapi_taskfile(struct ata_taskfile *tf)
{
return (tf->protocol == ATA_PROT_ATAPI) ||
(tf->protocol == ATA_PROT_ATAPI_NODATA) ||
(tf->protocol == ATA_PROT_ATAPI_DMA);
}
......
......@@ -218,6 +218,9 @@ struct ata_queued_cmd {
struct scsi_cmnd *scsicmd;
void (*scsidone)(struct scsi_cmnd *);
struct ata_taskfile tf;
u8 cdb[ATAPI_CDB_LEN];
unsigned long flags; /* ATA_QCFLAG_xxx */
unsigned int tag;
unsigned int n_elem;
......@@ -229,7 +232,6 @@ struct ata_queued_cmd {
unsigned int cursg;
unsigned int cursg_ofs;
struct ata_taskfile tf;
struct scatterlist sgent;
void *buf_virt;
......@@ -285,6 +287,7 @@ struct ata_port {
unsigned int mwdma_mask;
unsigned int udma_mask;
unsigned int cbl; /* cable type; ATA_CBL_xxx */
unsigned int cdb_len;
struct ata_device device[ATA_MAX_DEVICES];
......
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