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