Commit 76776955 authored by Jeff Garzik's avatar Jeff Garzik

[libata] ATAPI work - PIO xfer, completion function

Move hand-coded ATA Data register I/O from ata_pio_sector() to its
own function ata_data_xfer(), so that it may also be used to send the
ATAPI packet to hardware.

Use ata_data_xfer() in ATAPI packet send.

Separate ATA and ATAPI completion functions.
parent 5158abe2
......@@ -2059,6 +2059,43 @@ static void ata_pio_complete (struct ata_port *ap)
ata_qc_complete(qc, drv_stat);
}
static void ata_mmio_data_xfer(struct ata_port *ap, unsigned char *buf,
unsigned int buflen, int write_data)
{
unsigned int i;
unsigned int words = buflen >> 1;
u16 *buf16 = (u16 *) buf;
void *mmio = (void *)ap->ioaddr.data_addr;
if (write_data) {
for (i = 0; i < words; i++)
writew(buf16[i], mmio);
} else {
for (i = 0; i < words; i++)
buf16[i] = readw(mmio);
}
}
static void ata_pio_data_xfer(struct ata_port *ap, unsigned char *buf,
unsigned int buflen, int write_data)
{
unsigned int dwords = buflen >> 2;
if (write_data)
outsl(ap->ioaddr.data_addr, buf, dwords);
else
insl(ap->ioaddr.data_addr, buf, dwords);
}
static void ata_data_xfer(struct ata_port *ap, unsigned char *buf,
unsigned int buflen, int do_write)
{
if (ap->flags & ATA_FLAG_MMIO)
ata_mmio_data_xfer(ap, buf, buflen, do_write);
else
ata_pio_data_xfer(ap, buf, buflen, do_write);
}
/**
* ata_pio_sector -
* @ap:
......@@ -2072,6 +2109,7 @@ static void ata_pio_sector(struct ata_port *ap)
struct scatterlist *sg;
unsigned char *buf;
u8 status;
int do_write;
/*
* This is purely hueristic. This is a fast path.
......@@ -2122,25 +2160,8 @@ static void ata_pio_sector(struct ata_port *ap)
status);
/* do the actual data transfer */
if (ap->flags & ATA_FLAG_MMIO) {
unsigned int i;
unsigned int words = ATA_SECT_SIZE / 2;
u16 *buf16 = (u16 *) buf;
void *mmio = (void *)ap->ioaddr.data_addr;
if (qc->tf.flags & ATA_TFLAG_WRITE) {
for (i = 0; i < words; i++)
writew(buf16[i], mmio);
} else {
for (i = 0; i < words; i++)
buf16[i] = readw(mmio);
}
} else {
if (qc->tf.flags & ATA_TFLAG_WRITE)
outsl(ap->ioaddr.data_addr, buf, ATA_SECT_DWORDS);
else
insl(ap->ioaddr.data_addr, buf, ATA_SECT_DWORDS);
}
do_write = (qc->tf.flags & ATA_TFLAG_WRITE);
ata_data_xfer(ap, buf, ATA_SECT_SIZE, do_write);
kunmap(sg[qc->cursg].page);
}
......@@ -2778,10 +2799,8 @@ static void atapi_packet_task(void *_data)
goto err_out;
/* send SCSI cdb */
/* FIXME: mmio-ize */
DPRINTK("send cdb\n");
outsl(ap->ioaddr.data_addr,
qc->scsicmd->cmnd, ap->host->max_cmd_len / 4);
ata_data_xfer(ap, qc->scsicmd->cmnd, ap->host->max_cmd_len, 1);
/* if we are DMA'ing, irq handler takes over from here */
if (qc->tf.protocol == ATA_PROT_ATAPI_DMA)
......
......@@ -339,14 +339,10 @@ static int ata_scsi_qc_complete(struct ata_queued_cmd *qc, u8 drv_stat)
{
struct scsi_cmnd *cmd = qc->scsicmd;
if (unlikely(drv_stat & (ATA_ERR | ATA_BUSY | ATA_DRQ))) {
if (is_atapi_taskfile(&qc->tf))
cmd->result = SAM_STAT_CHECK_CONDITION;
else
ata_to_sense_error(qc);
} else {
if (unlikely(drv_stat & (ATA_ERR | ATA_BUSY | ATA_DRQ)))
ata_to_sense_error(qc);
else
cmd->result = SAM_STAT_GOOD;
}
qc->scsidone(cmd);
......@@ -964,6 +960,31 @@ void ata_scsi_badcmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *), u8
done(cmd);
}
static int atapi_qc_complete(struct ata_queued_cmd *qc, u8 drv_stat)
{
struct scsi_cmnd *cmd = qc->scsicmd;
if (unlikely(drv_stat & (ATA_ERR | ATA_BUSY | ATA_DRQ)))
cmd->result = SAM_STAT_CHECK_CONDITION;
else {
u8 *scsicmd = cmd->cmnd;
if (scsicmd[0] == INQUIRY) {
u8 *buf = NULL;
unsigned int buflen;
buflen = ata_scsi_rbuf_get(cmd, &buf);
buf[2] = 0x5;
buf[3] = (buf[3] & 0xf0) | 2;
ata_scsi_rbuf_put(cmd);
}
cmd->result = SAM_STAT_GOOD;
}
qc->scsidone(cmd);
return 0;
}
/**
* atapi_xlat - Initialize PACKET taskfile
* @qc: command structure to be initialized
......@@ -982,6 +1003,8 @@ static unsigned int atapi_xlat(struct ata_queued_cmd *qc, u8 *scsicmd)
struct ata_device *dev = qc->dev;
int using_pio = (dev->flags & ATA_DFLAG_PIO);
qc->complete_fn = atapi_qc_complete;
qc->tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
if (cmd->sc_data_direction == SCSI_DATA_WRITE) {
qc->tf.flags |= ATA_TFLAG_WRITE;
......
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