* [PATCH RFC] libata: interrupt driven pio
@ 2005-09-09 16:14 Albert Lee
2005-09-09 17:35 ` Jeff Garzik
0 siblings, 1 reply; 77+ messages in thread
From: Albert Lee @ 2005-09-09 16:14 UTC (permalink / raw)
To: Jeff Garzik; +Cc: Linux IDE, Bartlomiej Zolnierkiewicz, Doug Maxey, Tejun Heo
[-- Attachment #1: Type: text/plain, Size: 742 bytes --]
Dear all,
The interrupt driven PIO draft patch is ready for your review.
Changes:
- add PIO_ST_FIRST for the state before sending ATAPI CDB or sending
"ATA PIO data out" first data block.
- remove the ATA_FLAG_NOINTR flag since the interrupt handler is now
aware of the states
- modify ata_pio_sector() and atapi_pio_bytes() to work in the interrupt
context
- modify the ata_host_intr() to handle PIO interrupts
- modify ata_qc_issue_prot() to initialize states
- atapi_packet_task() changed to handle "ATA PIO data out" first data block
- support the pre-ATA4 ATAPI device which raise interrupt when ready to
receive CDB
Patch against 2.6.13 (80ac2912f846c01d702774bb6aa7100ec71e88b9).
For your review and comment, thanks.
Albert
[-- Attachment #2: idpio.diff --]
[-- Type: text/plain, Size: 12670 bytes --]
--- linux/include/linux/ata.h 2005-09-06 16:47:16.000000000 +0800
+++ id1/include/linux/ata.h 2005-09-09 14:34:00.000000000 +0800
@@ -181,6 +181,7 @@ enum {
ATA_TFLAG_ISADDR = (1 << 1), /* enable r/w to nsect/lba regs */
ATA_TFLAG_DEVICE = (1 << 2), /* enable r/w to device reg */
ATA_TFLAG_WRITE = (1 << 3), /* data dir: host->dev==1 (write) */
+ ATA_TFLAG_POLLING = (1 << 4), /* set nIEN to 1 and use polling */
};
enum ata_tf_protocols {
@@ -250,6 +251,8 @@ struct ata_taskfile {
((u64) (id)[(n) + 1] << 16) | \
((u64) (id)[(n) + 0]) )
+#define atapi_id_cdb_intr(id) (((id)[0] & 0x60) == 0x20)
+
static inline int atapi_cdb_len(u16 *dev_id)
{
u16 tmp = dev_id[0] & 0x3;
--- linux/include/linux/libata.h 2005-09-06 16:47:17.000000000 +0800
+++ id1/include/linux/libata.h 2005-09-09 17:41:14.000000000 +0800
@@ -116,8 +116,6 @@ enum {
ATA_FLAG_MMIO = (1 << 6), /* use MMIO, not PIO */
ATA_FLAG_SATA_RESET = (1 << 7), /* use COMRESET */
ATA_FLAG_PIO_DMA = (1 << 8), /* PIO cmds via DMA */
- ATA_FLAG_NOINTR = (1 << 9), /* FIXME: Remove this once
- * proper HSM is in place. */
ATA_QCFLAG_ACTIVE = (1 << 1), /* cmd not yet ack'd to scsi lyer */
ATA_QCFLAG_SG = (1 << 3), /* have s/g table? */
@@ -166,6 +164,7 @@ enum pio_task_states {
PIO_ST_LAST,
PIO_ST_LAST_POLL,
PIO_ST_ERR,
+ PIO_ST_FIRST,
};
/* forward declarations */
--- linux/drivers/scsi/libata-core.c 2005-09-06 16:47:07.000000000 +0800
+++ id1/drivers/scsi/libata-core.c 2005-09-09 23:44:28.000000000 +0800
@@ -2401,7 +2401,6 @@ void ata_poll_qc_complete(struct ata_que
unsigned long flags;
spin_lock_irqsave(&ap->host_set->lock, flags);
- ap->flags &= ~ATA_FLAG_NOINTR;
ata_irq_on(ap);
ata_qc_complete(qc, drv_stat);
spin_unlock_irqrestore(&ap->host_set->lock, flags);
@@ -2660,7 +2659,10 @@ static void ata_pio_sector(struct ata_qu
page = nth_page(page, (offset >> PAGE_SHIFT));
offset %= PAGE_SIZE;
- buf = kmap(page) + offset;
+ if (in_atomic())
+ buf = kmap_atomic(page, KM_IRQ0) + offset;
+ else
+ buf = kmap(page) + offset;
qc->cursect++;
qc->cursg_ofs++;
@@ -2676,7 +2678,10 @@ static void ata_pio_sector(struct ata_qu
do_write = (qc->tf.flags & ATA_TFLAG_WRITE);
ata_data_xfer(ap, buf, ATA_SECT_SIZE, do_write);
- kunmap(page);
+ if (in_atomic())
+ kunmap_atomic(page, KM_IRQ0);
+ else
+ kunmap(page);
}
/**
@@ -2742,7 +2747,10 @@ next_sg:
/* don't cross page boundaries */
count = min(count, (unsigned int)PAGE_SIZE - offset);
- buf = kmap(page) + offset;
+ if (in_atomic())
+ buf = kmap_atomic(page, KM_IRQ0) + offset;
+ else
+ buf = kmap(page) + offset;
bytes -= count;
qc->curbytes += count;
@@ -2758,7 +2766,10 @@ next_sg:
/* do the actual data transfer */
ata_data_xfer(ap, buf, count, do_write);
- kunmap(page);
+ if (in_atomic())
+ kunmap_atomic(page, KM_IRQ0);
+ else
+ kunmap(page);
if (bytes)
goto next_sg;
@@ -2797,6 +2808,8 @@ static void atapi_pio_bytes(struct ata_q
if (do_write != i_write)
goto err_out;
+ VPRINTK("ata%u: xfering %d bytes\n", ap->id, bytes);
+
__atapi_pio_bytes(qc, bytes);
return;
@@ -3335,39 +3348,91 @@ int ata_qc_issue_prot(struct ata_queued_
switch (qc->tf.protocol) {
case ATA_PROT_NODATA:
+ if (qc->tf.flags & ATA_TFLAG_POLLING)
+ ata_qc_set_polling(qc);
+
ata_tf_to_host_nolock(ap, &qc->tf);
+ ap->pio_task_state = PIO_ST_LAST;
+
+ if (qc->tf.flags & ATA_TFLAG_POLLING)
+ queue_work(ata_wq, &ap->pio_task);
+
break;
case ATA_PROT_DMA:
+ assert(!(qc->tf.flags & ATA_TFLAG_POLLING));
+
ap->ops->tf_load(ap, &qc->tf); /* load tf registers */
ap->ops->bmdma_setup(qc); /* set up bmdma */
ap->ops->bmdma_start(qc); /* initiate bmdma */
+ ap->pio_task_state = PIO_ST_LAST;
break;
- case ATA_PROT_PIO: /* load tf registers, initiate polling pio */
- ata_qc_set_polling(qc);
+ case ATA_PROT_PIO:
+ if (qc->tf.flags & ATA_TFLAG_POLLING)
+ ata_qc_set_polling(qc);
+
ata_tf_to_host_nolock(ap, &qc->tf);
- ap->pio_task_state = PIO_ST;
- queue_work(ata_wq, &ap->pio_task);
+
+ if (qc->tf.flags & ATA_TFLAG_POLLING) {
+ ap->pio_task_state = PIO_ST;
+ queue_work(ata_wq, &ap->pio_task);
+ } else {
+ /* Interrupt driven PIO. */
+ if (qc->tf.flags & ATA_TFLAG_WRITE) {
+ /*
+ * PIO data out protocol
+ */
+ ap->pio_task_state = PIO_ST_FIRST;
+ queue_work(ata_wq, &ap->packet_task);
+
+ /* send first data block by polling */
+ } else {
+ ap->pio_task_state = PIO_ST;
+
+ /* interrupt handler takes over from here */
+ }
+ }
+
break;
case ATA_PROT_ATAPI:
- ata_qc_set_polling(qc);
+ if (qc->tf.flags & ATA_TFLAG_POLLING)
+ ata_qc_set_polling(qc);
+
ata_tf_to_host_nolock(ap, &qc->tf);
- queue_work(ata_wq, &ap->packet_task);
+ ap->pio_task_state = PIO_ST_FIRST;
+
+ /* send cdb by polling if no cdb interrupt */
+ if ((!atapi_id_cdb_intr(qc->dev->id)) ||
+ qc->tf.flags & ATA_TFLAG_POLLING)
+ queue_work(ata_wq, &ap->packet_task);
break;
case ATA_PROT_ATAPI_NODATA:
- ap->flags |= ATA_FLAG_NOINTR;
+ if (qc->tf.flags & ATA_TFLAG_POLLING)
+ ata_qc_set_polling(qc);
+
ata_tf_to_host_nolock(ap, &qc->tf);
- queue_work(ata_wq, &ap->packet_task);
+ ap->pio_task_state = PIO_ST_FIRST;
+
+ /* send cdb by polling if no cdb interrupt */
+ if ((!atapi_id_cdb_intr(qc->dev->id)) ||
+ qc->tf.flags & ATA_TFLAG_POLLING)
+ queue_work(ata_wq, &ap->packet_task);
break;
case ATA_PROT_ATAPI_DMA:
- ap->flags |= ATA_FLAG_NOINTR;
+ assert(!(qc->tf.flags & ATA_TFLAG_POLLING));
+
ap->ops->tf_load(ap, &qc->tf); /* load tf registers */
ap->ops->bmdma_setup(qc); /* set up bmdma */
- queue_work(ata_wq, &ap->packet_task);
+ ap->pio_task_state = PIO_ST_FIRST;
+
+ /* send cdb by polling if no cdb interrupt */
+ if ((!atapi_id_cdb_intr(qc->dev->id)) ||
+ qc->tf.flags & ATA_TFLAG_POLLING)
+ queue_work(ata_wq, &ap->packet_task);
break;
default:
@@ -3609,6 +3674,29 @@ void ata_bmdma_stop(struct ata_queued_cm
ata_altstatus(ap); /* dummy read */
}
+static void atapi_send_cdb(struct ata_port *ap, struct ata_queued_cmd *qc)
+{
+ /* send SCSI cdb */
+ DPRINTK("send cdb\n");
+ assert(ap->cdb_len >= 12);
+
+ ata_data_xfer(ap, qc->cdb, ap->cdb_len, 1);
+
+ switch (qc->tf.protocol) {
+ case ATA_PROT_ATAPI:
+ ap->pio_task_state = PIO_ST;
+ break;
+ case ATA_PROT_ATAPI_NODATA:
+ ap->pio_task_state = PIO_ST_LAST;
+ break;
+ case ATA_PROT_ATAPI_DMA:
+ ap->pio_task_state = PIO_ST_LAST;
+ /* initiate bmdma */
+ ap->ops->bmdma_start(qc);
+ break;
+ }
+}
+
/**
* ata_host_intr - Handle host interrupt for given (port, task)
* @ap: Port on which interrupt arrived (possibly...)
@@ -3630,45 +3718,132 @@ inline unsigned int ata_host_intr (struc
{
u8 status, host_stat;
- switch (qc->tf.protocol) {
-
- case ATA_PROT_DMA:
- case ATA_PROT_ATAPI_DMA:
- case ATA_PROT_ATAPI:
- /* check status of DMA engine */
- host_stat = ap->ops->bmdma_status(ap);
- VPRINTK("ata%u: host_stat 0x%X\n", ap->id, host_stat);
+ VPRINTK("ata%u: protocol %d task state %d\n",
+ ap->id, qc->tf.protocol, ap->pio_task_state);
- /* if it's not our irq... */
- if (!(host_stat & ATA_DMA_INTR))
+ /* Check whether we are expecting interrupt in this state */
+ switch (ap->pio_task_state) {
+ case PIO_ST_FIRST:
+ if (!(is_atapi_taskfile(&qc->tf) &&
+ atapi_id_cdb_intr(qc->dev->id)))
goto idle_irq;
+ break;
+ case PIO_ST_LAST:
+ if (qc->tf.protocol == ATA_PROT_DMA ||
+ qc->tf.protocol == ATA_PROT_ATAPI_DMA) {
+ /* check status of DMA engine */
+ host_stat = ap->ops->bmdma_status(ap);
+ VPRINTK("ata%u: host_stat 0x%X\n", ap->id, host_stat);
+
+ /* if it's not our irq... */
+ if (!(host_stat & ATA_DMA_INTR))
+ goto idle_irq;
- /* before we do anything else, clear DMA-Start bit */
- ap->ops->bmdma_stop(qc);
+ /* before we do anything else, clear DMA-Start bit */
+ ap->ops->bmdma_stop(qc);
+ }
+ break;
+ case PIO_ST:
+ break;
+ default:
+ goto idle_irq;
+ }
- /* fall through */
+ /* check altstatus */
+ status = ata_altstatus(ap);
+ if (status & ATA_BUSY) {
+ goto idle_irq;
+ }
- case ATA_PROT_ATAPI_NODATA:
- case ATA_PROT_NODATA:
- /* check altstatus */
- status = ata_altstatus(ap);
- if (status & ATA_BUSY)
- goto idle_irq;
+ /* check main status, clearing INTRQ */
+ status = ata_chk_status(ap);
+ if (unlikely(status & ATA_BUSY))
+ goto idle_irq;
- /* check main status, clearing INTRQ */
- status = ata_chk_status(ap);
- if (unlikely(status & ATA_BUSY))
- goto idle_irq;
- DPRINTK("ata%u: protocol %d (dev_stat 0x%X)\n",
- ap->id, qc->tf.protocol, status);
+ DPRINTK("ata%u: protocol %d task state %d (dev_stat 0x%X)\n",
+ ap->id, qc->tf.protocol, ap->pio_task_state, status);
+
+ /* check whether error */
+ if (status & ATA_ERR) {
+ ap->pio_task_state = PIO_ST_ERR;
+ }
+
+fsm_start:
+ switch (ap->pio_task_state) {
+ case PIO_ST_FIRST:
+ /* Some pre-ATAPI-4 devices assert INTRQ
+ * at this point when ready to receive CDB.
+ */
+
+ /* check device status */
+ if ((status & (ATA_BUSY | ATA_DRQ)) != ATA_DRQ) {
+ /* Wrong status. Let EH handle this */
+ ap->pio_task_state = PIO_ST_ERR;
+ goto fsm_start;
+ }
+
+ atapi_send_cdb(ap, qc);
+
+ break;
+
+ case PIO_ST:
+ /* complete command or read/write the data register */
+ if (qc->tf.protocol == ATA_PROT_ATAPI) {
+ /* ATAPI PIO protocol */
+ if ((status & ATA_DRQ) == 0) {
+ ap->pio_task_state = PIO_ST_LAST;
+ goto fsm_start;
+ }
+
+ atapi_pio_bytes(qc);
+
+ } else {
+ /* ATA PIO protocol */
+ if (unlikely((status & ATA_DRQ) == 0)) {
+ /* handle BSY=0, DRQ=0 as error */
+ ap->pio_task_state = PIO_ST_ERR;
+ goto fsm_start;
+ }
+
+ ata_pio_sector(qc);
+
+ if (ap->pio_task_state == PIO_ST_LAST &&
+ (!(qc->tf.flags & ATA_TFLAG_WRITE))) {
+ /* complete the command */
+ status = ata_altstatus(ap);
+ status = ata_chk_status(ap);
+ goto fsm_start;
+ }
+ }
+
+ break;
+
+ case PIO_ST_LAST:
+ if (status & ATA_DRQ) {
+ /* status error */
+ ap->pio_task_state = PIO_ST_ERR;
+ goto fsm_start;
+ }
+
+ /* no more data to transfer */
+ DPRINTK("ata%u: PIO complete, drv_stat 0x%x\n",
+ ap->id, status);
/* ack bmdma irq events */
ap->ops->irq_clear(ap);
+ ap->pio_task_state = PIO_ST_IDLE;
+
/* complete taskfile transaction */
ata_qc_complete(qc, status);
break;
+ case PIO_ST_ERR:
+ printk(KERN_ERR "ata%u: PIO error, drv_stat 0x%x\n",
+ ap->id, status);
+ ap->pio_task_state = PIO_ST_IDLE;
+ ata_qc_complete(qc, status | ATA_ERR);
+ break;
default:
goto idle_irq;
}
@@ -3720,7 +3895,7 @@ irqreturn_t ata_interrupt (int irq, void
ap = host_set->ports[i];
if (ap &&
- !(ap->flags & (ATA_FLAG_PORT_DISABLED | ATA_FLAG_NOINTR))) {
+ !(ap->flags & ATA_FLAG_PORT_DISABLED)) {
struct ata_queued_cmd *qc;
qc = ata_qc_from_tag(ap, ap->active_tag);
@@ -3754,6 +3929,7 @@ static void atapi_packet_task(void *_dat
struct ata_port *ap = _data;
struct ata_queued_cmd *qc;
u8 status;
+ unsigned long flags;
qc = ata_qc_from_tag(ap, ap->active_tag);
assert(qc != NULL);
@@ -3769,34 +3945,31 @@ static void atapi_packet_task(void *_dat
if ((status & (ATA_BUSY | ATA_DRQ)) != ATA_DRQ)
goto err_out;
- /* send SCSI cdb */
- DPRINTK("send cdb\n");
- assert(ap->cdb_len >= 12);
- if (qc->tf.protocol == ATA_PROT_ATAPI_DMA ||
- qc->tf.protocol == ATA_PROT_ATAPI_NODATA) {
- unsigned long flags;
-
- /* Once we're done issuing command and kicking bmdma,
- * irq handler takes over. To not lose irq, we need
- * to clear NOINTR flag before sending cdb, but
- * interrupt handler shouldn't be invoked before we're
- * finished. Hence, the following locking.
- */
+ if (is_atapi_taskfile(&qc->tf)) {
spin_lock_irqsave(&ap->host_set->lock, flags);
- ap->flags &= ~ATA_FLAG_NOINTR;
- ata_data_xfer(ap, qc->cdb, ap->cdb_len, 1);
- if (qc->tf.protocol == ATA_PROT_ATAPI_DMA)
- ap->ops->bmdma_start(qc); /* initiate bmdma */
+
+ /* send CDB */
+ atapi_send_cdb(ap, qc);
+
+ if (qc->tf.flags & ATA_TFLAG_POLLING)
+ queue_work(ata_wq, &ap->pio_task);
+
spin_unlock_irqrestore(&ap->host_set->lock, flags);
} else {
- ata_data_xfer(ap, qc->cdb, ap->cdb_len, 1);
+ /* PIO data out protocol.
+ * send first data block.
+ */
+ ata_pio_sector(qc);
- /* PIO commands are handled by polling */
+ spin_lock_irqsave(&ap->host_set->lock, flags);
ap->pio_task_state = PIO_ST;
- queue_work(ata_wq, &ap->pio_task);
+ spin_unlock_irqrestore(&ap->host_set->lock, flags);
+
+ /* interrupt handler takes over from here */
}
+
return;
err_out:
^ permalink raw reply [flat|nested] 77+ messages in thread
* Re: [PATCH RFC] libata: interrupt driven pio
2005-09-09 16:14 [PATCH RFC] libata: interrupt driven pio Albert Lee
@ 2005-09-09 17:35 ` Jeff Garzik
2005-09-09 18:14 ` Doug Maxey
2005-09-22 4:00 ` [PATCH/RFC 0/3] libata: interrupt driven pio (revised) Albert Lee
0 siblings, 2 replies; 77+ messages in thread
From: Jeff Garzik @ 2005-09-09 17:35 UTC (permalink / raw)
To: Albert Lee; +Cc: Linux IDE, Bartlomiej Zolnierkiewicz, Doug Maxey, Tejun Heo
Albert Lee wrote:
> Dear all,
>
> The interrupt driven PIO draft patch is ready for your review.
>
> Changes:
> - add PIO_ST_FIRST for the state before sending ATAPI CDB or sending
> "ATA PIO data out" first data block.
> - remove the ATA_FLAG_NOINTR flag since the interrupt handler is now
> aware of the states
> - modify ata_pio_sector() and atapi_pio_bytes() to work in the interrupt
> context
> - modify the ata_host_intr() to handle PIO interrupts
> - modify ata_qc_issue_prot() to initialize states
> - atapi_packet_task() changed to handle "ATA PIO data out" first data block
> - support the pre-ATA4 ATAPI device which raise interrupt when ready to
> receive CDB
>
> Patch against 2.6.13 (80ac2912f846c01d702774bb6aa7100ec71e88b9).
Very nice, thanks for working on this.
Comments:
1) With this work, PIO_ST_xxx is no longer an appropriate name. I
suggest s/PIO_ST_/HSM_ST_/
2) ditto with s/pio_task_state/hsm_task_state/
3) Don't bother with in_atomic(), since we mix contexts in libata.
Causes more trouble than its worth. Just use *map_atomic()
4) prefer 'ata_id_cdb_intr' to 'atapi_...'
5) please don't put braces around single-line C statements:
+ if (status & ATA_BUSY) {
+ goto idle_irq;
+ }
6) the following locking is questionable. AFAICS this should be
resolved elsewhere, and if you have to take the lock here, you already
have problems
+ /* PIO data out protocol.
+ * send first data block.
+ */
+ ata_pio_sector(qc);
- /* PIO commands are handled by polling */
+ spin_lock_irqsave(&ap->host_set->lock, flags);
ap->pio_task_state = PIO_ST;
- queue_work(ata_wq, &ap->pio_task);
+ spin_unlock_irqrestore(&ap->host_set->lock, flags);
+
+ /* interrupt handler takes over from here */
ie. why queue the task at all, if the intr handler takes over?
7) Overall, looks pretty good at first glance. This patch will require
much testing before global deployment. Once you have a final patch,
we'll let it simmer in libata-dev.git for a while, allowing -mm users
plenty of time for testing. Possibly a 2.6.16 version target.
^ permalink raw reply [flat|nested] 77+ messages in thread
* Re: [PATCH RFC] libata: interrupt driven pio
2005-09-09 17:35 ` Jeff Garzik
@ 2005-09-09 18:14 ` Doug Maxey
2005-09-22 4:00 ` [PATCH/RFC 0/3] libata: interrupt driven pio (revised) Albert Lee
1 sibling, 0 replies; 77+ messages in thread
From: Doug Maxey @ 2005-09-09 18:14 UTC (permalink / raw)
To: Jeff Garzik
Cc: Albert Lee, Linux IDE, Bartlomiej Zolnierkiewicz, Doug Maxey,
Tejun Heo
On Fri, 09 Sep 2005 13:35:25 EDT, Jeff Garzik wrote:
>Albert Lee wrote:
>> Dear all,
>>
>> The interrupt driven PIO draft patch is ready for your review.
>>
>> Changes:
>> - add PIO_ST_FIRST for the state before sending ATAPI CDB or sending
>> "ATA PIO data out" first data block.
>> - remove the ATA_FLAG_NOINTR flag since the interrupt handler is now
>> aware of the states
>> - modify ata_pio_sector() and atapi_pio_bytes() to work in the interrupt
>> context
>> - modify the ata_host_intr() to handle PIO interrupts
>> - modify ata_qc_issue_prot() to initialize states
>> - atapi_packet_task() changed to handle "ATA PIO data out" first data block
>> - support the pre-ATA4 ATAPI device which raise interrupt when ready to
>> receive CDB
>>
>> Patch against 2.6.13 (80ac2912f846c01d702774bb6aa7100ec71e88b9).
>
...
>
>6) the following locking is questionable. AFAICS this should be
>resolved elsewhere, and if you have to take the lock here, you already
>have problems
To protect this instance against being preempted on MP? Not that large
of an issue at present, but suspect that Ingo's work may affect in the
near future. I agree that this may be wrong location.
What mechanism (elsewhere) currently protects on irq handler entry?
>
>+ /* PIO data out protocol.
>+ * send first data block.
>+ */
>+ ata_pio_sector(qc);
>
>- /* PIO commands are handled by polling */
>+ spin_lock_irqsave(&ap->host_set->lock, flags);
> ap->pio_task_state = PIO_ST;
>- queue_work(ata_wq, &ap->pio_task);
>+ spin_unlock_irqrestore(&ap->host_set->lock, flags);
>+
>+ /* interrupt handler takes over from here */
>
>ie. why queue the task at all, if the intr handler takes over?
>
>
>7) Overall, looks pretty good at first glance. This patch will require
>much testing before global deployment. Once you have a final patch,
>we'll let it simmer in libata-dev.git for a while, allowing -mm users
>plenty of time for testing. Possibly a 2.6.16 version target.
>
Way to go Albert!
++doug
^ permalink raw reply [flat|nested] 77+ messages in thread
* [PATCH/RFC 0/3] libata: interrupt driven pio (revised)
2005-09-09 17:35 ` Jeff Garzik
2005-09-09 18:14 ` Doug Maxey
@ 2005-09-22 4:00 ` Albert Lee
2005-09-22 4:09 ` [PATCH/RFC 1/3] libata: interrupt driven pio for libata-core Albert Lee
` (3 more replies)
1 sibling, 4 replies; 77+ messages in thread
From: Albert Lee @ 2005-09-22 4:00 UTC (permalink / raw)
To: Jeff Garzik; +Cc: Linux IDE, Bartlomiej Zolnierkiewicz, Doug Maxey, Tejun Heo
Dear all,
The revised interrupt driven PIO draft patch is ready for your review.
Patch 1/3: interrupt driven pio patch for libata-core
Patch 2/3: s/PIO_ST_/HSM_ST_/ and s/pio_task_state/hsm_task_state/.
Patch 3/3: interrupt driven pio patch for LLD
Patch for 2.6.14-rc1 (044a500e46742d39d22f1781cfb64ba93b463e39).
Tested ok on x86 with Promise PDC20275, Seagate ST380011A and LITEON 52x
CD-ROM drive.
For your review and advice, thanks.
Albert
^ permalink raw reply [flat|nested] 77+ messages in thread
* [PATCH/RFC 1/3] libata: interrupt driven pio for libata-core
2005-09-22 4:00 ` [PATCH/RFC 0/3] libata: interrupt driven pio (revised) Albert Lee
@ 2005-09-22 4:09 ` Albert Lee
2005-09-23 9:25 ` Albert Lee
2005-09-22 4:11 ` [PATCH/RFC 2/3] libata: rename task states/variables Albert Lee
` (2 subsequent siblings)
3 siblings, 1 reply; 77+ messages in thread
From: Albert Lee @ 2005-09-22 4:09 UTC (permalink / raw)
To: Jeff Garzik; +Cc: Linux IDE, Bartlomiej Zolnierkiewicz, Doug Maxey, Tejun Heo
[-- Attachment #1: Type: text/plain, Size: 738 bytes --]
Patch 1/3: interrupt driven pio for libata-core
Changes
- add PIO_ST_FIRST for the state before sending ATAPI CDB or sending
"ATA PIO data out" first data block.
- add ATA_TFLAG_POLLING and ATA_DFLAG_CDB_INTR flags
- remove the ATA_FLAG_NOINTR flag since the interrupt handler is now
aware of the states
- modify ata_pio_sector() and atapi_pio_bytes() to work in the interrupt
context
- modify the ata_host_intr() to handle PIO interrupts
- modify ata_qc_issue_prot() to initialize states
- atapi_packet_task() changed to handle "ATA PIO data out" first data block
- support the pre-ATA4 ATAPI device which raise interrupt when ready to
receive CDB
For your review, thanks.
Albert
Signed-off-by: Albert Lee <albertcc@tw.ibm.com>
[-- Attachment #2: idpio1.diff --]
[-- Type: text/plain, Size: 15602 bytes --]
--- linux/include/linux/ata.h 2005-09-20 17:18:10.000000000 +0800
+++ id1/include/linux/ata.h 2005-09-19 16:18:45.000000000 +0800
@@ -181,6 +181,7 @@ enum {
ATA_TFLAG_ISADDR = (1 << 1), /* enable r/w to nsect/lba regs */
ATA_TFLAG_DEVICE = (1 << 2), /* enable r/w to device reg */
ATA_TFLAG_WRITE = (1 << 3), /* data dir: host->dev==1 (write) */
+ ATA_TFLAG_POLLING = (1 << 4), /* set nIEN to 1 and use polling */
};
enum ata_tf_protocols {
@@ -250,6 +251,8 @@ struct ata_taskfile {
((u64) (id)[(n) + 1] << 16) | \
((u64) (id)[(n) + 0]) )
+#define ata_id_cdb_intr(id) (((id)[0] & 0x60) == 0x20)
+
static inline int atapi_cdb_len(u16 *dev_id)
{
u16 tmp = dev_id[0] & 0x3;
--- linux/include/linux/libata.h 2005-09-20 17:18:12.000000000 +0800
+++ id1/include/linux/libata.h 2005-09-21 15:49:14.000000000 +0800
@@ -97,6 +97,7 @@ enum {
ATA_DFLAG_LBA48 = (1 << 0), /* device supports LBA48 */
ATA_DFLAG_PIO = (1 << 1), /* device currently in PIO mode */
ATA_DFLAG_LOCK_SECTORS = (1 << 2), /* don't adjust max_sectors */
+ ATA_DFLAG_CDB_INTR = (1 << 3), /* device asserts INTRQ when ready for CDB */
ATA_DEV_UNKNOWN = 0, /* unknown device */
ATA_DEV_ATA = 1, /* ATA device */
@@ -115,8 +116,6 @@ enum {
ATA_FLAG_MMIO = (1 << 6), /* use MMIO, not PIO */
ATA_FLAG_SATA_RESET = (1 << 7), /* use COMRESET */
ATA_FLAG_PIO_DMA = (1 << 8), /* PIO cmds via DMA */
- ATA_FLAG_NOINTR = (1 << 9), /* FIXME: Remove this once
- * proper HSM is in place. */
ATA_QCFLAG_ACTIVE = (1 << 1), /* cmd not yet ack'd to scsi lyer */
ATA_QCFLAG_SG = (1 << 3), /* have s/g table? */
@@ -165,6 +164,7 @@ enum pio_task_states {
PIO_ST_LAST,
PIO_ST_LAST_POLL,
PIO_ST_ERR,
+ PIO_ST_FIRST,
};
/* forward declarations */
--- linux/drivers/scsi/libata-core.c 2005-09-20 17:18:00.000000000 +0800
+++ id1/drivers/scsi/libata-core.c 2005-09-22 10:26:34.000000000 +0800
@@ -1292,6 +1292,9 @@ retry:
ap->cdb_len = (unsigned int) rc;
ap->host->max_cmd_len = (unsigned char) ap->cdb_len;
+ if (ata_id_cdb_intr(dev->id))
+ dev->flags |= ATA_DFLAG_CDB_INTR;
+
/* print device info to dmesg */
printk(KERN_INFO "ata%u: dev %u ATAPI, max %s\n",
ap->id, device,
@@ -2405,7 +2408,6 @@ void ata_poll_qc_complete(struct ata_que
unsigned long flags;
spin_lock_irqsave(&ap->host_set->lock, flags);
- ap->flags &= ~ATA_FLAG_NOINTR;
ata_irq_on(ap);
ata_qc_complete(qc, drv_stat);
spin_unlock_irqrestore(&ap->host_set->lock, flags);
@@ -2660,6 +2662,9 @@ static void ata_pio_sector(struct ata_qu
struct page *page;
unsigned int offset;
unsigned char *buf;
+#ifdef CONFIG_HIGHMEM
+ unsigned long flags;
+#endif
if (qc->cursect == (qc->nsect - 1))
ap->pio_task_state = PIO_ST_LAST;
@@ -2671,7 +2676,10 @@ static void ata_pio_sector(struct ata_qu
page = nth_page(page, (offset >> PAGE_SHIFT));
offset %= PAGE_SIZE;
- buf = kmap(page) + offset;
+#ifdef CONFIG_HIGHMEM
+ local_irq_save(flags);
+#endif
+ buf = kmap_atomic(page, KM_IRQ0) + offset;
qc->cursect++;
qc->cursg_ofs++;
@@ -2687,7 +2695,10 @@ static void ata_pio_sector(struct ata_qu
do_write = (qc->tf.flags & ATA_TFLAG_WRITE);
ata_data_xfer(ap, buf, ATA_SECT_SIZE, do_write);
- kunmap(page);
+ kunmap_atomic(buf - offset, KM_IRQ0);
+#ifdef CONFIG_HIGHMEM
+ local_irq_restore(flags);
+#endif
}
/**
@@ -2710,6 +2721,9 @@ static void __atapi_pio_bytes(struct ata
struct page *page;
unsigned char *buf;
unsigned int offset, count;
+#ifdef CONFIG_HIGHMEM
+ unsigned long flags;
+#endif
if (qc->curbytes + bytes >= qc->nbytes)
ap->pio_task_state = PIO_ST_LAST;
@@ -2753,7 +2767,10 @@ next_sg:
/* don't cross page boundaries */
count = min(count, (unsigned int)PAGE_SIZE - offset);
- buf = kmap(page) + offset;
+#ifdef CONFIG_HIGHMEM
+ local_irq_save(flags);
+#endif
+ buf = kmap_atomic(page, KM_IRQ0) + offset;
bytes -= count;
qc->curbytes += count;
@@ -2769,8 +2786,10 @@ next_sg:
/* do the actual data transfer */
ata_data_xfer(ap, buf, count, do_write);
- kunmap(page);
-
+ kunmap_atomic(buf - offset, KM_IRQ0);
+#ifdef CONFIG_HIGHMEM
+ local_irq_restore(flags);
+#endif
if (bytes)
goto next_sg;
}
@@ -2808,6 +2827,8 @@ static void atapi_pio_bytes(struct ata_q
if (do_write != i_write)
goto err_out;
+ VPRINTK("ata%u: xfering %d bytes\n", ap->id, bytes);
+
__atapi_pio_bytes(qc, bytes);
return;
@@ -3054,6 +3075,8 @@ static void ata_qc_timeout(struct ata_qu
printk(KERN_ERR "ata%u: command 0x%x timeout, stat 0x%x host_stat 0x%x\n",
ap->id, qc->tf.command, drv_stat, host_stat);
+ ap->pio_task_state = PIO_ST_IDLE;
+
/* complete taskfile transaction */
ata_qc_complete(qc, drv_stat);
break;
@@ -3348,39 +3371,90 @@ int ata_qc_issue_prot(struct ata_queued_
switch (qc->tf.protocol) {
case ATA_PROT_NODATA:
+ if (qc->tf.flags & ATA_TFLAG_POLLING)
+ ata_qc_set_polling(qc);
+
ata_tf_to_host_nolock(ap, &qc->tf);
+ ap->pio_task_state = PIO_ST_LAST;
+
+ if (qc->tf.flags & ATA_TFLAG_POLLING)
+ queue_work(ata_wq, &ap->pio_task);
+
break;
case ATA_PROT_DMA:
+ assert(!(qc->tf.flags & ATA_TFLAG_POLLING));
+
ap->ops->tf_load(ap, &qc->tf); /* load tf registers */
ap->ops->bmdma_setup(qc); /* set up bmdma */
ap->ops->bmdma_start(qc); /* initiate bmdma */
+ ap->pio_task_state = PIO_ST_LAST;
break;
- case ATA_PROT_PIO: /* load tf registers, initiate polling pio */
- ata_qc_set_polling(qc);
+ case ATA_PROT_PIO:
+ if (qc->tf.flags & ATA_TFLAG_POLLING)
+ ata_qc_set_polling(qc);
+
ata_tf_to_host_nolock(ap, &qc->tf);
- ap->pio_task_state = PIO_ST;
- queue_work(ata_wq, &ap->pio_task);
+
+ if (qc->tf.flags & ATA_TFLAG_POLLING) {
+ /* polling PIO */
+ ap->pio_task_state = PIO_ST;
+ queue_work(ata_wq, &ap->pio_task);
+ } else {
+ /* interrupt driven PIO */
+ if (qc->tf.flags & ATA_TFLAG_WRITE) {
+ /* PIO data out protocol */
+ ap->pio_task_state = PIO_ST_FIRST;
+ queue_work(ata_wq, &ap->packet_task);
+
+ /* send first data block by polling */
+ } else {
+ /* PIO data in protocol */
+ ap->pio_task_state = PIO_ST;
+
+ /* interrupt handler takes over from here */
+ }
+ }
+
break;
case ATA_PROT_ATAPI:
- ata_qc_set_polling(qc);
+ if (qc->tf.flags & ATA_TFLAG_POLLING)
+ ata_qc_set_polling(qc);
+
ata_tf_to_host_nolock(ap, &qc->tf);
- queue_work(ata_wq, &ap->packet_task);
+ ap->pio_task_state = PIO_ST_FIRST;
+
+ /* send cdb by polling if no cdb interrupt */
+ if ((!(qc->dev->flags & ATA_DFLAG_CDB_INTR)) ||
+ (qc->tf.flags & ATA_TFLAG_POLLING))
+ queue_work(ata_wq, &ap->packet_task);
break;
case ATA_PROT_ATAPI_NODATA:
- ap->flags |= ATA_FLAG_NOINTR;
+ if (qc->tf.flags & ATA_TFLAG_POLLING)
+ ata_qc_set_polling(qc);
+
ata_tf_to_host_nolock(ap, &qc->tf);
- queue_work(ata_wq, &ap->packet_task);
+ ap->pio_task_state = PIO_ST_FIRST;
+
+ /* send cdb by polling if no cdb interrupt */
+ if ((!(qc->dev->flags & ATA_DFLAG_CDB_INTR)) ||
+ (qc->tf.flags & ATA_TFLAG_POLLING))
+ queue_work(ata_wq, &ap->packet_task);
break;
case ATA_PROT_ATAPI_DMA:
- ap->flags |= ATA_FLAG_NOINTR;
+ assert(!(qc->tf.flags & ATA_TFLAG_POLLING));
+
ap->ops->tf_load(ap, &qc->tf); /* load tf registers */
ap->ops->bmdma_setup(qc); /* set up bmdma */
- queue_work(ata_wq, &ap->packet_task);
+ ap->pio_task_state = PIO_ST_FIRST;
+
+ /* send cdb by polling if no cdb interrupt */
+ if (!(qc->dev->flags & ATA_DFLAG_CDB_INTR))
+ queue_work(ata_wq, &ap->packet_task);
break;
default:
@@ -3623,6 +3697,41 @@ void ata_bmdma_stop(struct ata_queued_cm
}
/**
+ * atapi_send_cdb - Write CDB bytes to hardware
+ * @ap: Port to which ATAPI device is attached.
+ * @qc: Taskfile currently active
+ *
+ * When device has indicated its readiness to accept
+ * a CDB, this function is called. Send the CDB.
+ *
+ * LOCKING:
+ * caller.
+ */
+
+static void atapi_send_cdb(struct ata_port *ap, struct ata_queued_cmd *qc)
+{
+ /* send SCSI cdb */
+ DPRINTK("send cdb\n");
+ assert(ap->cdb_len >= 12);
+
+ ata_data_xfer(ap, qc->cdb, ap->cdb_len, 1);
+
+ switch (qc->tf.protocol) {
+ case ATA_PROT_ATAPI:
+ ap->pio_task_state = PIO_ST;
+ break;
+ case ATA_PROT_ATAPI_NODATA:
+ ap->pio_task_state = PIO_ST_LAST;
+ break;
+ case ATA_PROT_ATAPI_DMA:
+ ap->pio_task_state = PIO_ST_LAST;
+ /* initiate bmdma */
+ ap->ops->bmdma_start(qc);
+ break;
+ }
+}
+
+/**
* ata_host_intr - Handle host interrupt for given (port, task)
* @ap: Port on which interrupt arrived (possibly...)
* @qc: Taskfile currently active in engine
@@ -3641,47 +3750,141 @@ void ata_bmdma_stop(struct ata_queued_cm
inline unsigned int ata_host_intr (struct ata_port *ap,
struct ata_queued_cmd *qc)
{
- u8 status, host_stat;
+ u8 status, host_stat = 0;
- switch (qc->tf.protocol) {
+ VPRINTK("ata%u: protocol %d task_state %d\n",
+ ap->id, qc->tf.protocol, ap->pio_task_state);
- case ATA_PROT_DMA:
- case ATA_PROT_ATAPI_DMA:
- case ATA_PROT_ATAPI:
- /* check status of DMA engine */
- host_stat = ap->ops->bmdma_status(ap);
- VPRINTK("ata%u: host_stat 0x%X\n", ap->id, host_stat);
-
- /* if it's not our irq... */
- if (!(host_stat & ATA_DMA_INTR))
+ /* Check whether we are expecting interrupt in this state */
+ switch (ap->pio_task_state) {
+ case PIO_ST_FIRST:
+ /* Check the ATA_DFLAG_CDB_INTR flag is enough here.
+ * The flag was turned on only for atapi devices,
+ * no need to check is_atapi_taskfile(&qc->tf) again.
+ */
+ if (!(qc->dev->flags & ATA_DFLAG_CDB_INTR))
goto idle_irq;
+ break;
+ case PIO_ST_LAST:
+ if (qc->tf.protocol == ATA_PROT_DMA ||
+ qc->tf.protocol == ATA_PROT_ATAPI_DMA) {
+ /* check status of DMA engine */
+ host_stat = ap->ops->bmdma_status(ap);
+ VPRINTK("ata%u: host_stat 0x%X\n", ap->id, host_stat);
+
+ /* if it's not our irq... */
+ if (!(host_stat & ATA_DMA_INTR))
+ goto idle_irq;
- /* before we do anything else, clear DMA-Start bit */
- ap->ops->bmdma_stop(qc);
+ /* before we do anything else, clear DMA-Start bit */
+ ap->ops->bmdma_stop(qc);
+ }
+ break;
+ case PIO_ST:
+ break;
+ default:
+ goto idle_irq;
+ }
- /* fall through */
+ /* check altstatus */
+ status = ata_altstatus(ap);
+ if (status & ATA_BUSY)
+ goto idle_irq;
- case ATA_PROT_ATAPI_NODATA:
- case ATA_PROT_NODATA:
- /* check altstatus */
- status = ata_altstatus(ap);
- if (status & ATA_BUSY)
- goto idle_irq;
+ /* check main status, clearing INTRQ */
+ status = ata_chk_status(ap);
+ if (unlikely(status & ATA_BUSY))
+ goto idle_irq;
- /* check main status, clearing INTRQ */
- status = ata_chk_status(ap);
- if (unlikely(status & ATA_BUSY))
- goto idle_irq;
- DPRINTK("ata%u: protocol %d (dev_stat 0x%X)\n",
- ap->id, qc->tf.protocol, status);
+ DPRINTK("ata%u: protocol %d task_state %d (dev_stat 0x%X)\n",
+ ap->id, qc->tf.protocol, ap->pio_task_state, status);
- /* ack bmdma irq events */
- ap->ops->irq_clear(ap);
+ /* ack bmdma irq events */
+ ap->ops->irq_clear(ap);
+
+ /* check error */
+ if (unlikely((status & ATA_ERR) || (host_stat & ATA_DMA_ERR)))
+ ap->pio_task_state = PIO_ST_ERR;
+
+fsm_start:
+ switch (ap->pio_task_state) {
+ case PIO_ST_FIRST:
+ /* Some pre-ATAPI-4 devices assert INTRQ
+ * at this state when ready to receive CDB.
+ */
+
+ /* check device status */
+ if (unlikely((status & (ATA_BUSY | ATA_DRQ)) != ATA_DRQ)) {
+ /* Wrong status. Let EH handle this */
+ ap->pio_task_state = PIO_ST_ERR;
+ goto fsm_start;
+ }
+
+ atapi_send_cdb(ap, qc);
+
+ break;
+
+ case PIO_ST:
+ /* complete command or read/write the data register */
+ if (qc->tf.protocol == ATA_PROT_ATAPI) {
+ /* ATAPI PIO protocol */
+ if ((status & ATA_DRQ) == 0) {
+ /* no more data to transfer */
+ ap->pio_task_state = PIO_ST_LAST;
+ goto fsm_start;
+ }
+
+ atapi_pio_bytes(qc);
+
+ if (unlikely(ap->pio_task_state == PIO_ST_ERR))
+ /* bad ireason reported by device */
+ goto fsm_start;
+
+ } else {
+ /* ATA PIO protocol */
+ if (unlikely((status & ATA_DRQ) == 0)) {
+ /* handle BSY=0, DRQ=0 as error */
+ ap->pio_task_state = PIO_ST_ERR;
+ goto fsm_start;
+ }
+
+ ata_pio_sector(qc);
+
+ if (ap->pio_task_state == PIO_ST_LAST &&
+ (!(qc->tf.flags & ATA_TFLAG_WRITE))) {
+ /* all data read */
+ ata_altstatus(ap);
+ status = ata_chk_status(ap);
+ goto fsm_start;
+ }
+ }
+
+ break;
+
+ case PIO_ST_LAST:
+ if (unlikely(status & ATA_DRQ)) {
+ /* handle DRQ=1 as error */
+ ap->pio_task_state = PIO_ST_ERR;
+ goto fsm_start;
+ }
+
+ /* no more data to transfer */
+ DPRINTK("ata%u: command complete, drv_stat 0x%x\n",
+ ap->id, status);
+
+ ap->pio_task_state = PIO_ST_IDLE;
/* complete taskfile transaction */
ata_qc_complete(qc, status);
break;
+ case PIO_ST_ERR:
+ printk(KERN_ERR "ata%u: command error, drv_stat 0x%x host_stat 0x%x\n",
+ ap->id, status, host_stat);
+
+ ap->pio_task_state = PIO_ST_IDLE;
+ ata_qc_complete(qc, status | ATA_ERR);
+ break;
default:
goto idle_irq;
}
@@ -3733,11 +3936,11 @@ irqreturn_t ata_interrupt (int irq, void
ap = host_set->ports[i];
if (ap &&
- !(ap->flags & (ATA_FLAG_PORT_DISABLED | ATA_FLAG_NOINTR))) {
+ !(ap->flags & ATA_FLAG_PORT_DISABLED)) {
struct ata_queued_cmd *qc;
qc = ata_qc_from_tag(ap, ap->active_tag);
- if (qc && (!(qc->tf.ctl & ATA_NIEN)) &&
+ if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING)) &&
(qc->flags & ATA_QCFLAG_ACTIVE))
handled |= ata_host_intr(ap, qc);
}
@@ -3767,6 +3970,7 @@ static void atapi_packet_task(void *_dat
struct ata_port *ap = _data;
struct ata_queued_cmd *qc;
u8 status;
+ unsigned long flags;
qc = ata_qc_from_tag(ap, ap->active_tag);
assert(qc != NULL);
@@ -3782,38 +3986,35 @@ static void atapi_packet_task(void *_dat
if ((status & (ATA_BUSY | ATA_DRQ)) != ATA_DRQ)
goto err_out;
- /* send SCSI cdb */
- DPRINTK("send cdb\n");
- assert(ap->cdb_len >= 12);
+ /* Send the CDB (atapi) or the first data block (ata pio out).
+ * During the state transition, interrupt handler shouldn't
+ * be invoked before the data transfer is complete and
+ * pio_task_state is changed. Hence, the following locking.
+ */
+ spin_lock_irqsave(&ap->host_set->lock, flags);
- if (qc->tf.protocol == ATA_PROT_ATAPI_DMA ||
- qc->tf.protocol == ATA_PROT_ATAPI_NODATA) {
- unsigned long flags;
-
- /* Once we're done issuing command and kicking bmdma,
- * irq handler takes over. To not lose irq, we need
- * to clear NOINTR flag before sending cdb, but
- * interrupt handler shouldn't be invoked before we're
- * finished. Hence, the following locking.
- */
- spin_lock_irqsave(&ap->host_set->lock, flags);
- ap->flags &= ~ATA_FLAG_NOINTR;
- ata_data_xfer(ap, qc->cdb, ap->cdb_len, 1);
- if (qc->tf.protocol == ATA_PROT_ATAPI_DMA)
- ap->ops->bmdma_start(qc); /* initiate bmdma */
- spin_unlock_irqrestore(&ap->host_set->lock, flags);
- } else {
- ata_data_xfer(ap, qc->cdb, ap->cdb_len, 1);
+ if (is_atapi_taskfile(&qc->tf)) {
+ /* send CDB */
+ atapi_send_cdb(ap, qc);
- /* PIO commands are handled by polling */
+ if (qc->tf.flags & ATA_TFLAG_POLLING)
+ queue_work(ata_wq, &ap->pio_task);
+ } else {
+ /* PIO data out protocol.
+ * send first data block.
+ */
+ ata_pio_sector(qc);
ap->pio_task_state = PIO_ST;
- queue_work(ata_wq, &ap->pio_task);
+
+ /* interrupt handler takes over from here */
}
+ spin_unlock_irqrestore(&ap->host_set->lock, flags);
+
return;
err_out:
- ata_poll_qc_complete(qc, ATA_ERR);
+ ata_pio_error(ap);
}
^ permalink raw reply [flat|nested] 77+ messages in thread
* [PATCH/RFC 2/3] libata: rename task states/variables
2005-09-22 4:00 ` [PATCH/RFC 0/3] libata: interrupt driven pio (revised) Albert Lee
2005-09-22 4:09 ` [PATCH/RFC 1/3] libata: interrupt driven pio for libata-core Albert Lee
@ 2005-09-22 4:11 ` Albert Lee
2005-09-23 9:34 ` Albert Lee
2005-09-22 4:14 ` [PATCH/RFC 3/3] libata: interrupt driven pio for LLD Albert Lee
2005-09-23 9:46 ` [PATCH/RFC 0/3] libata: interrupt driven pio (revised) Jeff Garzik
3 siblings, 1 reply; 77+ messages in thread
From: Albert Lee @ 2005-09-22 4:11 UTC (permalink / raw)
To: Jeff Garzik; +Cc: Linux IDE, Bartlomiej Zolnierkiewicz, Doug Maxey, Tejun Heo
[-- Attachment #1: Type: text/plain, Size: 191 bytes --]
Patch 2/3: rename task states/variables
Changes:
s/PIO_ST_/HSM_ST_/ and s/pio_task_state/hsm_task_state/.
For your review, thanks.
Albert
Signed-off-by: Albert Lee <albertcc@tw.ibm.com>
[-- Attachment #2: idpio2.diff --]
[-- Type: text/plain, Size: 14359 bytes --]
--- id1/include/linux/libata.h 2005-09-21 15:49:14.000000000 +0800
+++ id2/include/linux/libata.h 2005-09-21 16:25:26.000000000 +0800
@@ -155,16 +155,16 @@ enum {
ATA_SHIFT_PIO = 11,
};
-enum pio_task_states {
- PIO_ST_UNKNOWN,
- PIO_ST_IDLE,
- PIO_ST_POLL,
- PIO_ST_TMOUT,
- PIO_ST,
- PIO_ST_LAST,
- PIO_ST_LAST_POLL,
- PIO_ST_ERR,
- PIO_ST_FIRST,
+enum hsm_task_states {
+ HSM_ST_UNKNOWN,
+ HSM_ST_IDLE,
+ HSM_ST_POLL,
+ HSM_ST_TMOUT,
+ HSM_ST,
+ HSM_ST_LAST,
+ HSM_ST_LAST_POLL,
+ HSM_ST_ERR,
+ HSM_ST_FIRST,
};
/* forward declarations */
@@ -319,7 +319,7 @@ struct ata_port {
struct work_struct packet_task;
struct work_struct pio_task;
- unsigned int pio_task_state;
+ unsigned int hsm_task_state;
unsigned long pio_task_timeout;
void *private_data;
--- id1/drivers/scsi/libata-core.c 2005-09-22 10:26:34.000000000 +0800
+++ id2/drivers/scsi/libata-core.c 2005-09-22 10:26:38.000000000 +0800
@@ -2427,20 +2427,20 @@ void ata_poll_qc_complete(struct ata_que
static unsigned long ata_pio_poll(struct ata_port *ap)
{
u8 status;
- unsigned int poll_state = PIO_ST_UNKNOWN;
- unsigned int reg_state = PIO_ST_UNKNOWN;
- const unsigned int tmout_state = PIO_ST_TMOUT;
-
- switch (ap->pio_task_state) {
- case PIO_ST:
- case PIO_ST_POLL:
- poll_state = PIO_ST_POLL;
- reg_state = PIO_ST;
- break;
- case PIO_ST_LAST:
- case PIO_ST_LAST_POLL:
- poll_state = PIO_ST_LAST_POLL;
- reg_state = PIO_ST_LAST;
+ unsigned int poll_state = HSM_ST_UNKNOWN;
+ unsigned int reg_state = HSM_ST_UNKNOWN;
+ const unsigned int tmout_state = HSM_ST_TMOUT;
+
+ switch (ap->hsm_task_state) {
+ case HSM_ST:
+ case HSM_ST_POLL:
+ poll_state = HSM_ST_POLL;
+ reg_state = HSM_ST;
+ break;
+ case HSM_ST_LAST:
+ case HSM_ST_LAST_POLL:
+ poll_state = HSM_ST_LAST_POLL;
+ reg_state = HSM_ST_LAST;
break;
default:
BUG();
@@ -2450,14 +2450,14 @@ static unsigned long ata_pio_poll(struct
status = ata_chk_status(ap);
if (status & ATA_BUSY) {
if (time_after(jiffies, ap->pio_task_timeout)) {
- ap->pio_task_state = tmout_state;
+ ap->hsm_task_state = tmout_state;
return 0;
}
- ap->pio_task_state = poll_state;
+ ap->hsm_task_state = poll_state;
return ATA_SHORT_PAUSE;
}
- ap->pio_task_state = reg_state;
+ ap->hsm_task_state = reg_state;
return 0;
}
@@ -2482,14 +2482,14 @@ static int ata_pio_complete (struct ata_
* we enter, BSY will be cleared in a chk-status or two. If not,
* the drive is probably seeking or something. Snooze for a couple
* msecs, then chk-status again. If still busy, fall back to
- * PIO_ST_POLL state.
+ * HSM_ST_POLL state.
*/
drv_stat = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 10);
if (drv_stat & (ATA_BUSY | ATA_DRQ)) {
msleep(2);
drv_stat = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 10);
if (drv_stat & (ATA_BUSY | ATA_DRQ)) {
- ap->pio_task_state = PIO_ST_LAST_POLL;
+ ap->hsm_task_state = HSM_ST_LAST_POLL;
ap->pio_task_timeout = jiffies + ATA_TMOUT_PIO;
return 0;
}
@@ -2497,14 +2497,14 @@ static int ata_pio_complete (struct ata_
drv_stat = ata_wait_idle(ap);
if (!ata_ok(drv_stat)) {
- ap->pio_task_state = PIO_ST_ERR;
+ ap->hsm_task_state = HSM_ST_ERR;
return 0;
}
qc = ata_qc_from_tag(ap, ap->active_tag);
assert(qc != NULL);
- ap->pio_task_state = PIO_ST_IDLE;
+ ap->hsm_task_state = HSM_ST_IDLE;
ata_poll_qc_complete(qc, drv_stat);
@@ -2667,7 +2667,7 @@ static void ata_pio_sector(struct ata_qu
#endif
if (qc->cursect == (qc->nsect - 1))
- ap->pio_task_state = PIO_ST_LAST;
+ ap->hsm_task_state = HSM_ST_LAST;
page = sg[qc->cursg].page;
offset = sg[qc->cursg].offset + qc->cursg_ofs * ATA_SECT_SIZE;
@@ -2726,7 +2726,7 @@ static void __atapi_pio_bytes(struct ata
#endif
if (qc->curbytes + bytes >= qc->nbytes)
- ap->pio_task_state = PIO_ST_LAST;
+ ap->hsm_task_state = HSM_ST_LAST;
next_sg:
if (unlikely(qc->cursg >= qc->n_elem)) {
@@ -2748,7 +2748,7 @@ next_sg:
for (i = 0; i < words; i++)
ata_data_xfer(ap, (unsigned char*)pad_buf, 2, do_write);
- ap->pio_task_state = PIO_ST_LAST;
+ ap->hsm_task_state = HSM_ST_LAST;
return;
}
@@ -2836,7 +2836,7 @@ static void atapi_pio_bytes(struct ata_q
err_out:
printk(KERN_INFO "ata%u: dev %u: ATAPI check failed\n",
ap->id, dev->devno);
- ap->pio_task_state = PIO_ST_ERR;
+ ap->hsm_task_state = HSM_ST_ERR;
}
/**
@@ -2858,14 +2858,14 @@ static void ata_pio_block(struct ata_por
* a chk-status or two. If not, the drive is probably seeking
* or something. Snooze for a couple msecs, then
* chk-status again. If still busy, fall back to
- * PIO_ST_POLL state.
+ * HSM_ST_POLL state.
*/
status = ata_busy_wait(ap, ATA_BUSY, 5);
if (status & ATA_BUSY) {
msleep(2);
status = ata_busy_wait(ap, ATA_BUSY, 10);
if (status & ATA_BUSY) {
- ap->pio_task_state = PIO_ST_POLL;
+ ap->hsm_task_state = HSM_ST_POLL;
ap->pio_task_timeout = jiffies + ATA_TMOUT_PIO;
return;
}
@@ -2877,7 +2877,7 @@ static void ata_pio_block(struct ata_por
if (is_atapi_taskfile(&qc->tf)) {
/* no more data to transfer or unsupported ATAPI command */
if ((status & ATA_DRQ) == 0) {
- ap->pio_task_state = PIO_ST_LAST;
+ ap->hsm_task_state = HSM_ST_LAST;
return;
}
@@ -2885,7 +2885,7 @@ static void ata_pio_block(struct ata_por
} else {
/* handle BSY=0, DRQ=0 as error */
if ((status & ATA_DRQ) == 0) {
- ap->pio_task_state = PIO_ST_ERR;
+ ap->hsm_task_state = HSM_ST_ERR;
return;
}
@@ -2905,7 +2905,7 @@ static void ata_pio_error(struct ata_por
printk(KERN_WARNING "ata%u: PIO error, drv_stat 0x%x\n",
ap->id, drv_stat);
- ap->pio_task_state = PIO_ST_IDLE;
+ ap->hsm_task_state = HSM_ST_IDLE;
ata_poll_qc_complete(qc, drv_stat | ATA_ERR);
}
@@ -2920,25 +2920,25 @@ fsm_start:
timeout = 0;
qc_completed = 0;
- switch (ap->pio_task_state) {
- case PIO_ST_IDLE:
+ switch (ap->hsm_task_state) {
+ case HSM_ST_IDLE:
return;
- case PIO_ST:
+ case HSM_ST:
ata_pio_block(ap);
break;
- case PIO_ST_LAST:
+ case HSM_ST_LAST:
qc_completed = ata_pio_complete(ap);
break;
- case PIO_ST_POLL:
- case PIO_ST_LAST_POLL:
+ case HSM_ST_POLL:
+ case HSM_ST_LAST_POLL:
timeout = ata_pio_poll(ap);
break;
- case PIO_ST_TMOUT:
- case PIO_ST_ERR:
+ case HSM_ST_TMOUT:
+ case HSM_ST_ERR:
ata_pio_error(ap);
return;
}
@@ -3075,7 +3075,7 @@ static void ata_qc_timeout(struct ata_qu
printk(KERN_ERR "ata%u: command 0x%x timeout, stat 0x%x host_stat 0x%x\n",
ap->id, qc->tf.command, drv_stat, host_stat);
- ap->pio_task_state = PIO_ST_IDLE;
+ ap->hsm_task_state = HSM_ST_IDLE;
/* complete taskfile transaction */
ata_qc_complete(qc, drv_stat);
@@ -3375,7 +3375,7 @@ int ata_qc_issue_prot(struct ata_queued_
ata_qc_set_polling(qc);
ata_tf_to_host_nolock(ap, &qc->tf);
- ap->pio_task_state = PIO_ST_LAST;
+ ap->hsm_task_state = HSM_ST_LAST;
if (qc->tf.flags & ATA_TFLAG_POLLING)
queue_work(ata_wq, &ap->pio_task);
@@ -3388,7 +3388,7 @@ int ata_qc_issue_prot(struct ata_queued_
ap->ops->tf_load(ap, &qc->tf); /* load tf registers */
ap->ops->bmdma_setup(qc); /* set up bmdma */
ap->ops->bmdma_start(qc); /* initiate bmdma */
- ap->pio_task_state = PIO_ST_LAST;
+ ap->hsm_task_state = HSM_ST_LAST;
break;
case ATA_PROT_PIO:
@@ -3399,19 +3399,19 @@ int ata_qc_issue_prot(struct ata_queued_
if (qc->tf.flags & ATA_TFLAG_POLLING) {
/* polling PIO */
- ap->pio_task_state = PIO_ST;
+ ap->hsm_task_state = HSM_ST;
queue_work(ata_wq, &ap->pio_task);
} else {
/* interrupt driven PIO */
if (qc->tf.flags & ATA_TFLAG_WRITE) {
/* PIO data out protocol */
- ap->pio_task_state = PIO_ST_FIRST;
+ ap->hsm_task_state = HSM_ST_FIRST;
queue_work(ata_wq, &ap->packet_task);
/* send first data block by polling */
} else {
/* PIO data in protocol */
- ap->pio_task_state = PIO_ST;
+ ap->hsm_task_state = HSM_ST;
/* interrupt handler takes over from here */
}
@@ -3424,7 +3424,7 @@ int ata_qc_issue_prot(struct ata_queued_
ata_qc_set_polling(qc);
ata_tf_to_host_nolock(ap, &qc->tf);
- ap->pio_task_state = PIO_ST_FIRST;
+ ap->hsm_task_state = HSM_ST_FIRST;
/* send cdb by polling if no cdb interrupt */
if ((!(qc->dev->flags & ATA_DFLAG_CDB_INTR)) ||
@@ -3437,7 +3437,7 @@ int ata_qc_issue_prot(struct ata_queued_
ata_qc_set_polling(qc);
ata_tf_to_host_nolock(ap, &qc->tf);
- ap->pio_task_state = PIO_ST_FIRST;
+ ap->hsm_task_state = HSM_ST_FIRST;
/* send cdb by polling if no cdb interrupt */
if ((!(qc->dev->flags & ATA_DFLAG_CDB_INTR)) ||
@@ -3450,7 +3450,7 @@ int ata_qc_issue_prot(struct ata_queued_
ap->ops->tf_load(ap, &qc->tf); /* load tf registers */
ap->ops->bmdma_setup(qc); /* set up bmdma */
- ap->pio_task_state = PIO_ST_FIRST;
+ ap->hsm_task_state = HSM_ST_FIRST;
/* send cdb by polling if no cdb interrupt */
if (!(qc->dev->flags & ATA_DFLAG_CDB_INTR))
@@ -3660,7 +3660,7 @@ u8 ata_bmdma_status(struct ata_port *ap)
void __iomem *mmio = (void __iomem *) ap->ioaddr.bmdma_addr;
host_stat = readb(mmio + ATA_DMA_STATUS);
} else
- host_stat = inb(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS);
+ host_stat = inb(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS);
return host_stat;
}
@@ -3718,13 +3718,13 @@ static void atapi_send_cdb(struct ata_po
switch (qc->tf.protocol) {
case ATA_PROT_ATAPI:
- ap->pio_task_state = PIO_ST;
+ ap->hsm_task_state = HSM_ST;
break;
case ATA_PROT_ATAPI_NODATA:
- ap->pio_task_state = PIO_ST_LAST;
+ ap->hsm_task_state = HSM_ST_LAST;
break;
case ATA_PROT_ATAPI_DMA:
- ap->pio_task_state = PIO_ST_LAST;
+ ap->hsm_task_state = HSM_ST_LAST;
/* initiate bmdma */
ap->ops->bmdma_start(qc);
break;
@@ -3753,11 +3753,11 @@ inline unsigned int ata_host_intr (struc
u8 status, host_stat = 0;
VPRINTK("ata%u: protocol %d task_state %d\n",
- ap->id, qc->tf.protocol, ap->pio_task_state);
+ ap->id, qc->tf.protocol, ap->hsm_task_state);
/* Check whether we are expecting interrupt in this state */
- switch (ap->pio_task_state) {
- case PIO_ST_FIRST:
+ switch (ap->hsm_task_state) {
+ case HSM_ST_FIRST:
/* Check the ATA_DFLAG_CDB_INTR flag is enough here.
* The flag was turned on only for atapi devices,
* no need to check is_atapi_taskfile(&qc->tf) again.
@@ -3765,7 +3765,7 @@ inline unsigned int ata_host_intr (struc
if (!(qc->dev->flags & ATA_DFLAG_CDB_INTR))
goto idle_irq;
break;
- case PIO_ST_LAST:
+ case HSM_ST_LAST:
if (qc->tf.protocol == ATA_PROT_DMA ||
qc->tf.protocol == ATA_PROT_ATAPI_DMA) {
/* check status of DMA engine */
@@ -3780,7 +3780,7 @@ inline unsigned int ata_host_intr (struc
ap->ops->bmdma_stop(qc);
}
break;
- case PIO_ST:
+ case HSM_ST:
break;
default:
goto idle_irq;
@@ -3797,18 +3797,18 @@ inline unsigned int ata_host_intr (struc
goto idle_irq;
DPRINTK("ata%u: protocol %d task_state %d (dev_stat 0x%X)\n",
- ap->id, qc->tf.protocol, ap->pio_task_state, status);
+ ap->id, qc->tf.protocol, ap->hsm_task_state, status);
/* ack bmdma irq events */
ap->ops->irq_clear(ap);
/* check error */
if (unlikely((status & ATA_ERR) || (host_stat & ATA_DMA_ERR)))
- ap->pio_task_state = PIO_ST_ERR;
+ ap->hsm_task_state = HSM_ST_ERR;
fsm_start:
- switch (ap->pio_task_state) {
- case PIO_ST_FIRST:
+ switch (ap->hsm_task_state) {
+ case HSM_ST_FIRST:
/* Some pre-ATAPI-4 devices assert INTRQ
* at this state when ready to receive CDB.
*/
@@ -3816,7 +3816,7 @@ fsm_start:
/* check device status */
if (unlikely((status & (ATA_BUSY | ATA_DRQ)) != ATA_DRQ)) {
/* Wrong status. Let EH handle this */
- ap->pio_task_state = PIO_ST_ERR;
+ ap->hsm_task_state = HSM_ST_ERR;
goto fsm_start;
}
@@ -3824,19 +3824,19 @@ fsm_start:
break;
- case PIO_ST:
+ case HSM_ST:
/* complete command or read/write the data register */
if (qc->tf.protocol == ATA_PROT_ATAPI) {
/* ATAPI PIO protocol */
if ((status & ATA_DRQ) == 0) {
/* no more data to transfer */
- ap->pio_task_state = PIO_ST_LAST;
+ ap->hsm_task_state = HSM_ST_LAST;
goto fsm_start;
}
atapi_pio_bytes(qc);
- if (unlikely(ap->pio_task_state == PIO_ST_ERR))
+ if (unlikely(ap->hsm_task_state == HSM_ST_ERR))
/* bad ireason reported by device */
goto fsm_start;
@@ -3844,13 +3844,13 @@ fsm_start:
/* ATA PIO protocol */
if (unlikely((status & ATA_DRQ) == 0)) {
/* handle BSY=0, DRQ=0 as error */
- ap->pio_task_state = PIO_ST_ERR;
+ ap->hsm_task_state = HSM_ST_ERR;
goto fsm_start;
}
ata_pio_sector(qc);
- if (ap->pio_task_state == PIO_ST_LAST &&
+ if (ap->hsm_task_state == HSM_ST_LAST &&
(!(qc->tf.flags & ATA_TFLAG_WRITE))) {
/* all data read */
ata_altstatus(ap);
@@ -3861,10 +3861,10 @@ fsm_start:
break;
- case PIO_ST_LAST:
+ case HSM_ST_LAST:
if (unlikely(status & ATA_DRQ)) {
/* handle DRQ=1 as error */
- ap->pio_task_state = PIO_ST_ERR;
+ ap->hsm_task_state = HSM_ST_ERR;
goto fsm_start;
}
@@ -3872,17 +3872,17 @@ fsm_start:
DPRINTK("ata%u: command complete, drv_stat 0x%x\n",
ap->id, status);
- ap->pio_task_state = PIO_ST_IDLE;
+ ap->hsm_task_state = HSM_ST_IDLE;
/* complete taskfile transaction */
ata_qc_complete(qc, status);
break;
- case PIO_ST_ERR:
+ case HSM_ST_ERR:
printk(KERN_ERR "ata%u: command error, drv_stat 0x%x host_stat 0x%x\n",
ap->id, status, host_stat);
- ap->pio_task_state = PIO_ST_IDLE;
+ ap->hsm_task_state = HSM_ST_IDLE;
ata_qc_complete(qc, status | ATA_ERR);
break;
default:
@@ -3989,7 +3989,7 @@ static void atapi_packet_task(void *_dat
/* Send the CDB (atapi) or the first data block (ata pio out).
* During the state transition, interrupt handler shouldn't
* be invoked before the data transfer is complete and
- * pio_task_state is changed. Hence, the following locking.
+ * hsm_task_state is changed. Hence, the following locking.
*/
spin_lock_irqsave(&ap->host_set->lock, flags);
@@ -4004,7 +4004,7 @@ static void atapi_packet_task(void *_dat
* send first data block.
*/
ata_pio_sector(qc);
- ap->pio_task_state = PIO_ST;
+ ap->hsm_task_state = HSM_ST;
/* interrupt handler takes over from here */
}
^ permalink raw reply [flat|nested] 77+ messages in thread
* [PATCH/RFC 3/3] libata: interrupt driven pio for LLD
2005-09-22 4:00 ` [PATCH/RFC 0/3] libata: interrupt driven pio (revised) Albert Lee
2005-09-22 4:09 ` [PATCH/RFC 1/3] libata: interrupt driven pio for libata-core Albert Lee
2005-09-22 4:11 ` [PATCH/RFC 2/3] libata: rename task states/variables Albert Lee
@ 2005-09-22 4:14 ` Albert Lee
2005-09-22 12:56 ` Mark Lord
2005-09-23 9:46 ` [PATCH/RFC 0/3] libata: interrupt driven pio (revised) Jeff Garzik
3 siblings, 1 reply; 77+ messages in thread
From: Albert Lee @ 2005-09-22 4:14 UTC (permalink / raw)
To: Jeff Garzik
Cc: Linux IDE, Bartlomiej Zolnierkiewicz, Doug Maxey, Tejun Heo,
Mark Lord, Brett Russ
[-- Attachment #1: Type: text/plain, Size: 444 bytes --]
Patch 3/3: interrupt driven pio patch for LLD
Changes:
sata_nv.c:
sata_vsc.c:
irq handler is wrapper around ata_host_intr(), only minor change.
sata_promise.c:
sata_sx4.c:
sata_mv.c:
sata_qstor.c:
Private irq handler, need modification to handle interrupt driven mode
in the future.
Use polling mode for the unsupported protocols for the time being.
For your review, thanks.
Albert
Signed-off-by: Albert Lee <albertcc@tw.ibm.com>
[-- Attachment #2: idpio3.diff --]
[-- Type: text/plain, Size: 6479 bytes --]
--- linux/drivers/scsi/sata_promise.c 2005-09-20 17:18:01.000000000 +0800
+++ id1/drivers/scsi/sata_promise.c 2005-09-21 14:54:52.000000000 +0800
@@ -438,11 +438,11 @@ static inline unsigned int pdc_host_intr
break;
default:
- ap->stats.idle_irq++;
- break;
+ ap->stats.idle_irq++;
+ break;
}
- return handled;
+ return handled;
}
static void pdc_irq_clear(struct ata_port *ap)
@@ -493,11 +493,11 @@ static irqreturn_t pdc_interrupt (int ir
ap = host_set->ports[i];
tmp = mask & (1 << (i + 1));
if (tmp && ap &&
- !(ap->flags & (ATA_FLAG_PORT_DISABLED | ATA_FLAG_NOINTR))) {
+ !(ap->flags & ATA_FLAG_PORT_DISABLED)) {
struct ata_queued_cmd *qc;
qc = ata_qc_from_tag(ap, ap->active_tag);
- if (qc && (!(qc->tf.ctl & ATA_NIEN)))
+ if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING)))
handled += pdc_host_intr(ap, qc);
}
}
@@ -540,6 +540,11 @@ static int pdc_qc_issue_prot(struct ata_
break;
default:
+ /* FIXME: pdc_host_intr() doesn't handle
+ * interrupt driven pio/atapi cdb intr yet.
+ * Use polling for these protocols.
+ */
+ qc->tf.flags |= ATA_TFLAG_POLLING;
break;
}
--- linux/drivers/scsi/sata_sx4.c 2005-09-20 17:18:01.000000000 +0800
+++ id1/drivers/scsi/sata_sx4.c 2005-09-21 14:55:13.000000000 +0800
@@ -691,6 +691,11 @@ static int pdc20621_qc_issue_prot(struct
break;
default:
+ /* FIXME: pdc20621_host_intr() doesn't handle
+ * interrupt driven pio/atapi cdb intr yet.
+ * Use polling for these protocols.
+ */
+ qc->tf.flags |= ATA_TFLAG_POLLING;
break;
}
@@ -832,11 +837,11 @@ static irqreturn_t pdc20621_interrupt (i
tmp = mask & (1 << i);
VPRINTK("seq %u, port_no %u, ap %p, tmp %x\n", i, port_no, ap, tmp);
if (tmp && ap &&
- !(ap->flags & (ATA_FLAG_PORT_DISABLED | ATA_FLAG_NOINTR))) {
+ !(ap->flags & ATA_FLAG_PORT_DISABLED)) {
struct ata_queued_cmd *qc;
qc = ata_qc_from_tag(ap, ap->active_tag);
- if (qc && (!(qc->tf.ctl & ATA_NIEN)))
+ if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING)))
handled += pdc20621_host_intr(ap, qc, (i > 4),
mmio_base);
}
--- linux/drivers/scsi/sata_qstor.c 2005-09-20 17:18:01.000000000 +0800
+++ id1/drivers/scsi/sata_qstor.c 2005-09-21 16:14:37.000000000 +0800
@@ -356,11 +356,19 @@ static int qs_qc_issue(struct ata_queued
qs_packet_start(qc);
return 0;
+ case ATA_PROT_NODATA:
+ break;
+
case ATA_PROT_ATAPI_DMA:
BUG();
break;
default:
+ /* FIXME: qs_intr_mmio() doesn't handle
+ * interrupt driven pio/atapi cdb intr yet.
+ * Use polling for these protocols.
+ */
+ qc->tf.flags |= ATA_TFLAG_POLLING;
break;
}
@@ -389,14 +397,13 @@ static inline unsigned int qs_intr_pkt(s
DPRINTK("SFF=%08x%08x: sCHAN=%u sHST=%d sDST=%02x\n",
sff1, sff0, port_no, sHST, sDST);
handled = 1;
- if (ap && !(ap->flags &
- (ATA_FLAG_PORT_DISABLED|ATA_FLAG_NOINTR))) {
+ if (ap && !(ap->flags & ATA_FLAG_PORT_DISABLED)) {
struct ata_queued_cmd *qc;
struct qs_port_priv *pp = ap->private_data;
if (!pp || pp->state != qs_state_pkt)
continue;
qc = ata_qc_from_tag(ap, ap->active_tag);
- if (qc && (!(qc->tf.ctl & ATA_NIEN))) {
+ if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING))) {
switch (sHST) {
case 0: /* sucessful CPB */
case 3: /* device error */
@@ -422,13 +429,13 @@ static inline unsigned int qs_intr_mmio(
struct ata_port *ap;
ap = host_set->ports[port_no];
if (ap &&
- !(ap->flags & (ATA_FLAG_PORT_DISABLED | ATA_FLAG_NOINTR))) {
+ !(ap->flags & ATA_FLAG_PORT_DISABLED)) {
struct ata_queued_cmd *qc;
struct qs_port_priv *pp = ap->private_data;
if (!pp || pp->state != qs_state_mmio)
continue;
qc = ata_qc_from_tag(ap, ap->active_tag);
- if (qc && (!(qc->tf.ctl & ATA_NIEN))) {
+ if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING))) {
/* check main status, clearing INTRQ */
u8 status = ata_chk_status(ap);
--- linux/drivers/scsi/sata_mv.c 2005-09-20 17:18:01.000000000 +0800
+++ id1/drivers/scsi/sata_mv.c 2005-09-21 16:14:42.000000000 +0800
@@ -189,6 +189,7 @@ static int mv_master_reset(void __iomem
static irqreturn_t mv_interrupt(int irq, void *dev_instance,
struct pt_regs *regs);
static int mv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
+static int mv_qc_issue_prot(struct ata_queued_cmd *qc);
static Scsi_Host_Template mv_sht = {
.module = THIS_MODULE,
@@ -222,7 +223,7 @@ static struct ata_port_operations mv_ops
.phy_reset = mv_phy_reset,
.qc_prep = ata_qc_prep,
- .qc_issue = ata_qc_issue_prot,
+ .qc_issue = mv_qc_issue_prot,
.eng_timeout = ata_eng_timeout,
@@ -448,6 +449,25 @@ static int mv_master_reset(void __iomem
return rc;
}
+static int mv_qc_issue_prot(struct ata_queued_cmd *qc)
+{
+ switch (qc->tf.protocol) {
+ case ATA_PROT_DMA:
+ case ATA_PROT_NODATA:
+ break;
+
+ default:
+ /* FIXME: mv_host_intr() doesn't handle
+ * interrupt driven pio/atapi cdb intr yet.
+ * Use polling for these protocols.
+ */
+ qc->tf.flags |= ATA_TFLAG_POLLING;
+ break;
+ }
+
+ return ata_qc_issue_prot(qc);
+}
+
static void mv_err_intr(struct ata_port *ap)
{
void __iomem *port_mmio;
--- linux/drivers/scsi/sata_vsc.c 2005-09-20 17:18:01.000000000 +0800
+++ id1/drivers/scsi/sata_vsc.c 2005-09-21 17:21:17.000000000 +0800
@@ -193,12 +193,12 @@ static irqreturn_t vsc_sata_interrupt (i
struct ata_port *ap;
ap = host_set->ports[i];
- if (ap && !(ap->flags &
- (ATA_FLAG_PORT_DISABLED|ATA_FLAG_NOINTR))) {
+ if (ap &&
+ !(ap->flags & ATA_FLAG_PORT_DISABLED)) {
struct ata_queued_cmd *qc;
qc = ata_qc_from_tag(ap, ap->active_tag);
- if (qc && (!(qc->tf.ctl & ATA_NIEN)))
+ if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING)))
handled += ata_host_intr(ap, qc);
}
}
--- linux/drivers/scsi/sata_nv.c 2005-09-20 17:18:01.000000000 +0800
+++ id1/drivers/scsi/sata_nv.c 2005-09-21 17:21:02.000000000 +0800
@@ -302,11 +302,11 @@ static irqreturn_t nv_interrupt (int irq
ap = host_set->ports[i];
if (ap &&
- !(ap->flags & (ATA_FLAG_PORT_DISABLED | ATA_FLAG_NOINTR))) {
+ !(ap->flags & ATA_FLAG_PORT_DISABLED)) {
struct ata_queued_cmd *qc;
qc = ata_qc_from_tag(ap, ap->active_tag);
- if (qc && (!(qc->tf.ctl & ATA_NIEN)))
+ if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING)))
handled += ata_host_intr(ap, qc);
}
^ permalink raw reply [flat|nested] 77+ messages in thread
* Re: [PATCH/RFC 3/3] libata: interrupt driven pio for LLD
2005-09-22 4:14 ` [PATCH/RFC 3/3] libata: interrupt driven pio for LLD Albert Lee
@ 2005-09-22 12:56 ` Mark Lord
2005-09-23 2:40 ` Albert Lee
0 siblings, 1 reply; 77+ messages in thread
From: Mark Lord @ 2005-09-22 12:56 UTC (permalink / raw)
To: Albert Lee
Cc: Jeff Garzik, Linux IDE, Bartlomiej Zolnierkiewicz, Doug Maxey,
Tejun Heo, Brett Russ
Albert Lee wrote:
> Patch 3/3: interrupt driven pio patch for LLD
>
> sata_qstor.c:
> Private irq handler, need modification to handle interrupt driven mode
> in the future.
> Use polling mode for the unsupported protocols for the time being.
...
default:
+ /* FIXME: qs_intr_mmio() doesn't handle
+ * interrupt driven pio/atapi cdb intr yet.
The qs_intr_mmio() handler is set up for interrupt driven
pio/atapi usage, and should already be usable for that.
How do I cause a command to use "interrupt driven" PIO mode
with these patches? I could try it to make sure it still works.
Cheers
Mark
^ permalink raw reply [flat|nested] 77+ messages in thread
* Re: [PATCH/RFC 3/3] libata: interrupt driven pio for LLD
2005-09-22 12:56 ` Mark Lord
@ 2005-09-23 2:40 ` Albert Lee
0 siblings, 0 replies; 77+ messages in thread
From: Albert Lee @ 2005-09-23 2:40 UTC (permalink / raw)
To: Mark Lord
Cc: Jeff Garzik, Linux IDE, Bartlomiej Zolnierkiewicz, Doug Maxey,
Tejun Heo, Brett Russ
Hi Mark:
> Albert Lee wrote:
>
>> Patch 3/3: interrupt driven pio patch for LLD
>>
>> sata_qstor.c:
>> Private irq handler, need modification to handle interrupt driven
>> mode in the future.
>> Use polling mode for the unsupported protocols for the time being.
>
> ...
> default:
> + /* FIXME: qs_intr_mmio() doesn't handle
> + * interrupt driven pio/atapi cdb intr yet.
>
> The qs_intr_mmio() handler is set up for interrupt driven
> pio/atapi usage, and should already be usable for that.
>
> How do I cause a command to use "interrupt driven" PIO mode
> with these patches? I could try it to make sure it still works.
>
Please apply the following patch 1/3:
http://marc.theaimsgroup.com/?l=linux-ide&m=112736217011430&w=2
The ata_qc_issue_prot() is changed. So qs_intr_mmio() will be called not
only to complete a command, but also for PIO data transfer, atapi cdb
intr, etc.
Albert
^ permalink raw reply [flat|nested] 77+ messages in thread
* Re: [PATCH/RFC 1/3] libata: interrupt driven pio for libata-core
2005-09-22 4:09 ` [PATCH/RFC 1/3] libata: interrupt driven pio for libata-core Albert Lee
@ 2005-09-23 9:25 ` Albert Lee
0 siblings, 0 replies; 77+ messages in thread
From: Albert Lee @ 2005-09-23 9:25 UTC (permalink / raw)
To: Jeff Garzik
Cc: Linux IDE, Bartlomiej Zolnierkiewicz, Doug Maxey, Tejun Heo,
Mark Lord, Brett Russ
[-- Attachment #1: Type: text/plain, Size: 1319 bytes --]
> Patch 1/3: interrupt driven pio for libata-core
>
> Changes
> - add PIO_ST_FIRST for the state before sending ATAPI CDB or sending
> "ATA PIO data out" first data block.
> - add ATA_TFLAG_POLLING and ATA_DFLAG_CDB_INTR flags
> - remove the ATA_FLAG_NOINTR flag since the interrupt handler is now
> aware of the states
> - modify ata_pio_sector() and atapi_pio_bytes() to work in the
> interrupt context
> - modify the ata_host_intr() to handle PIO interrupts
> - modify ata_qc_issue_prot() to initialize states
> - atapi_packet_task() changed to handle "ATA PIO data out" first data
> block
> - support the pre-ATA4 ATAPI device which raise interrupt when ready
> to receive CDB
>
>
>------------------------------------------------------------------------
>
>
>- /* PIO commands are handled by polling */
>+ if (qc->tf.flags & ATA_TFLAG_POLLING)
>+ queue_work(ata_wq, &ap->pio_task);
>+ } else {
>+ /* PIO data out protocol.
>+ * send first data block.
>+ */
>+ ata_pio_sector(qc);
> ap->pio_task_state = PIO_ST;
>- queue_work(ata_wq, &ap->pio_task);
>
>
Sorry, there is a bug here:
"ap->pio_task_state = PIO_ST;" should be before "ata_pio_sector(qc);"
because ata_pio_sector() might change the state to PIO_ST_LAST.
Attached please find the revised patch for your review, thanks.
Albert
[-- Attachment #2: idpio1.diff --]
[-- Type: text/plain, Size: 15723 bytes --]
--- linux/include/linux/ata.h 2005-09-20 17:18:10.000000000 +0800
+++ id1/include/linux/ata.h 2005-09-19 16:18:45.000000000 +0800
@@ -181,6 +181,7 @@ enum {
ATA_TFLAG_ISADDR = (1 << 1), /* enable r/w to nsect/lba regs */
ATA_TFLAG_DEVICE = (1 << 2), /* enable r/w to device reg */
ATA_TFLAG_WRITE = (1 << 3), /* data dir: host->dev==1 (write) */
+ ATA_TFLAG_POLLING = (1 << 4), /* set nIEN to 1 and use polling */
};
enum ata_tf_protocols {
@@ -250,6 +251,8 @@ struct ata_taskfile {
((u64) (id)[(n) + 1] << 16) | \
((u64) (id)[(n) + 0]) )
+#define ata_id_cdb_intr(id) (((id)[0] & 0x60) == 0x20)
+
static inline int atapi_cdb_len(u16 *dev_id)
{
u16 tmp = dev_id[0] & 0x3;
--- linux/include/linux/libata.h 2005-09-20 17:18:12.000000000 +0800
+++ id1/include/linux/libata.h 2005-09-21 15:49:14.000000000 +0800
@@ -97,6 +97,7 @@ enum {
ATA_DFLAG_LBA48 = (1 << 0), /* device supports LBA48 */
ATA_DFLAG_PIO = (1 << 1), /* device currently in PIO mode */
ATA_DFLAG_LOCK_SECTORS = (1 << 2), /* don't adjust max_sectors */
+ ATA_DFLAG_CDB_INTR = (1 << 3), /* device asserts INTRQ when ready for CDB */
ATA_DEV_UNKNOWN = 0, /* unknown device */
ATA_DEV_ATA = 1, /* ATA device */
@@ -115,8 +116,6 @@ enum {
ATA_FLAG_MMIO = (1 << 6), /* use MMIO, not PIO */
ATA_FLAG_SATA_RESET = (1 << 7), /* use COMRESET */
ATA_FLAG_PIO_DMA = (1 << 8), /* PIO cmds via DMA */
- ATA_FLAG_NOINTR = (1 << 9), /* FIXME: Remove this once
- * proper HSM is in place. */
ATA_QCFLAG_ACTIVE = (1 << 1), /* cmd not yet ack'd to scsi lyer */
ATA_QCFLAG_SG = (1 << 3), /* have s/g table? */
@@ -165,6 +164,7 @@ enum pio_task_states {
PIO_ST_LAST,
PIO_ST_LAST_POLL,
PIO_ST_ERR,
+ PIO_ST_FIRST,
};
/* forward declarations */
--- linux/drivers/scsi/libata-core.c 2005-09-20 17:18:00.000000000 +0800
+++ id1/drivers/scsi/libata-core.c 2005-09-23 13:47:41.000000000 +0800
@@ -1292,6 +1292,9 @@ retry:
ap->cdb_len = (unsigned int) rc;
ap->host->max_cmd_len = (unsigned char) ap->cdb_len;
+ if (ata_id_cdb_intr(dev->id))
+ dev->flags |= ATA_DFLAG_CDB_INTR;
+
/* print device info to dmesg */
printk(KERN_INFO "ata%u: dev %u ATAPI, max %s\n",
ap->id, device,
@@ -2405,7 +2408,6 @@ void ata_poll_qc_complete(struct ata_que
unsigned long flags;
spin_lock_irqsave(&ap->host_set->lock, flags);
- ap->flags &= ~ATA_FLAG_NOINTR;
ata_irq_on(ap);
ata_qc_complete(qc, drv_stat);
spin_unlock_irqrestore(&ap->host_set->lock, flags);
@@ -2660,6 +2662,9 @@ static void ata_pio_sector(struct ata_qu
struct page *page;
unsigned int offset;
unsigned char *buf;
+#ifdef CONFIG_HIGHMEM
+ unsigned long flags;
+#endif
if (qc->cursect == (qc->nsect - 1))
ap->pio_task_state = PIO_ST_LAST;
@@ -2671,7 +2676,10 @@ static void ata_pio_sector(struct ata_qu
page = nth_page(page, (offset >> PAGE_SHIFT));
offset %= PAGE_SIZE;
- buf = kmap(page) + offset;
+#ifdef CONFIG_HIGHMEM
+ local_irq_save(flags);
+#endif
+ buf = kmap_atomic(page, KM_IRQ0) + offset;
qc->cursect++;
qc->cursg_ofs++;
@@ -2687,7 +2695,10 @@ static void ata_pio_sector(struct ata_qu
do_write = (qc->tf.flags & ATA_TFLAG_WRITE);
ata_data_xfer(ap, buf, ATA_SECT_SIZE, do_write);
- kunmap(page);
+ kunmap_atomic(buf - offset, KM_IRQ0);
+#ifdef CONFIG_HIGHMEM
+ local_irq_restore(flags);
+#endif
}
/**
@@ -2710,6 +2721,9 @@ static void __atapi_pio_bytes(struct ata
struct page *page;
unsigned char *buf;
unsigned int offset, count;
+#ifdef CONFIG_HIGHMEM
+ unsigned long flags;
+#endif
if (qc->curbytes + bytes >= qc->nbytes)
ap->pio_task_state = PIO_ST_LAST;
@@ -2753,7 +2767,10 @@ next_sg:
/* don't cross page boundaries */
count = min(count, (unsigned int)PAGE_SIZE - offset);
- buf = kmap(page) + offset;
+#ifdef CONFIG_HIGHMEM
+ local_irq_save(flags);
+#endif
+ buf = kmap_atomic(page, KM_IRQ0) + offset;
bytes -= count;
qc->curbytes += count;
@@ -2769,8 +2786,10 @@ next_sg:
/* do the actual data transfer */
ata_data_xfer(ap, buf, count, do_write);
- kunmap(page);
-
+ kunmap_atomic(buf - offset, KM_IRQ0);
+#ifdef CONFIG_HIGHMEM
+ local_irq_restore(flags);
+#endif
if (bytes)
goto next_sg;
}
@@ -2808,6 +2827,8 @@ static void atapi_pio_bytes(struct ata_q
if (do_write != i_write)
goto err_out;
+ VPRINTK("ata%u: xfering %d bytes\n", ap->id, bytes);
+
__atapi_pio_bytes(qc, bytes);
return;
@@ -3054,6 +3075,8 @@ static void ata_qc_timeout(struct ata_qu
printk(KERN_ERR "ata%u: command 0x%x timeout, stat 0x%x host_stat 0x%x\n",
ap->id, qc->tf.command, drv_stat, host_stat);
+ ap->pio_task_state = PIO_ST_IDLE;
+
/* complete taskfile transaction */
ata_qc_complete(qc, drv_stat);
break;
@@ -3348,39 +3371,90 @@ int ata_qc_issue_prot(struct ata_queued_
switch (qc->tf.protocol) {
case ATA_PROT_NODATA:
+ if (qc->tf.flags & ATA_TFLAG_POLLING)
+ ata_qc_set_polling(qc);
+
ata_tf_to_host_nolock(ap, &qc->tf);
+ ap->pio_task_state = PIO_ST_LAST;
+
+ if (qc->tf.flags & ATA_TFLAG_POLLING)
+ queue_work(ata_wq, &ap->pio_task);
+
break;
case ATA_PROT_DMA:
+ assert(!(qc->tf.flags & ATA_TFLAG_POLLING));
+
ap->ops->tf_load(ap, &qc->tf); /* load tf registers */
ap->ops->bmdma_setup(qc); /* set up bmdma */
ap->ops->bmdma_start(qc); /* initiate bmdma */
+ ap->pio_task_state = PIO_ST_LAST;
break;
- case ATA_PROT_PIO: /* load tf registers, initiate polling pio */
- ata_qc_set_polling(qc);
+ case ATA_PROT_PIO:
+ if (qc->tf.flags & ATA_TFLAG_POLLING)
+ ata_qc_set_polling(qc);
+
ata_tf_to_host_nolock(ap, &qc->tf);
- ap->pio_task_state = PIO_ST;
- queue_work(ata_wq, &ap->pio_task);
+
+ if (qc->tf.flags & ATA_TFLAG_POLLING) {
+ /* polling PIO */
+ ap->pio_task_state = PIO_ST;
+ queue_work(ata_wq, &ap->pio_task);
+ } else {
+ /* interrupt driven PIO */
+ if (qc->tf.flags & ATA_TFLAG_WRITE) {
+ /* PIO data out protocol */
+ ap->pio_task_state = PIO_ST_FIRST;
+ queue_work(ata_wq, &ap->packet_task);
+
+ /* send first data block by polling */
+ } else {
+ /* PIO data in protocol */
+ ap->pio_task_state = PIO_ST;
+
+ /* interrupt handler takes over from here */
+ }
+ }
+
break;
case ATA_PROT_ATAPI:
- ata_qc_set_polling(qc);
+ if (qc->tf.flags & ATA_TFLAG_POLLING)
+ ata_qc_set_polling(qc);
+
ata_tf_to_host_nolock(ap, &qc->tf);
- queue_work(ata_wq, &ap->packet_task);
+ ap->pio_task_state = PIO_ST_FIRST;
+
+ /* send cdb by polling if no cdb interrupt */
+ if ((!(qc->dev->flags & ATA_DFLAG_CDB_INTR)) ||
+ (qc->tf.flags & ATA_TFLAG_POLLING))
+ queue_work(ata_wq, &ap->packet_task);
break;
case ATA_PROT_ATAPI_NODATA:
- ap->flags |= ATA_FLAG_NOINTR;
+ if (qc->tf.flags & ATA_TFLAG_POLLING)
+ ata_qc_set_polling(qc);
+
ata_tf_to_host_nolock(ap, &qc->tf);
- queue_work(ata_wq, &ap->packet_task);
+ ap->pio_task_state = PIO_ST_FIRST;
+
+ /* send cdb by polling if no cdb interrupt */
+ if ((!(qc->dev->flags & ATA_DFLAG_CDB_INTR)) ||
+ (qc->tf.flags & ATA_TFLAG_POLLING))
+ queue_work(ata_wq, &ap->packet_task);
break;
case ATA_PROT_ATAPI_DMA:
- ap->flags |= ATA_FLAG_NOINTR;
+ assert(!(qc->tf.flags & ATA_TFLAG_POLLING));
+
ap->ops->tf_load(ap, &qc->tf); /* load tf registers */
ap->ops->bmdma_setup(qc); /* set up bmdma */
- queue_work(ata_wq, &ap->packet_task);
+ ap->pio_task_state = PIO_ST_FIRST;
+
+ /* send cdb by polling if no cdb interrupt */
+ if (!(qc->dev->flags & ATA_DFLAG_CDB_INTR))
+ queue_work(ata_wq, &ap->packet_task);
break;
default:
@@ -3623,6 +3697,41 @@ void ata_bmdma_stop(struct ata_queued_cm
}
/**
+ * atapi_send_cdb - Write CDB bytes to hardware
+ * @ap: Port to which ATAPI device is attached.
+ * @qc: Taskfile currently active
+ *
+ * When device has indicated its readiness to accept
+ * a CDB, this function is called. Send the CDB.
+ *
+ * LOCKING:
+ * caller.
+ */
+
+static void atapi_send_cdb(struct ata_port *ap, struct ata_queued_cmd *qc)
+{
+ /* send SCSI cdb */
+ DPRINTK("send cdb\n");
+ assert(ap->cdb_len >= 12);
+
+ ata_data_xfer(ap, qc->cdb, ap->cdb_len, 1);
+
+ switch (qc->tf.protocol) {
+ case ATA_PROT_ATAPI:
+ ap->pio_task_state = PIO_ST;
+ break;
+ case ATA_PROT_ATAPI_NODATA:
+ ap->pio_task_state = PIO_ST_LAST;
+ break;
+ case ATA_PROT_ATAPI_DMA:
+ ap->pio_task_state = PIO_ST_LAST;
+ /* initiate bmdma */
+ ap->ops->bmdma_start(qc);
+ break;
+ }
+}
+
+/**
* ata_host_intr - Handle host interrupt for given (port, task)
* @ap: Port on which interrupt arrived (possibly...)
* @qc: Taskfile currently active in engine
@@ -3641,47 +3750,141 @@ void ata_bmdma_stop(struct ata_queued_cm
inline unsigned int ata_host_intr (struct ata_port *ap,
struct ata_queued_cmd *qc)
{
- u8 status, host_stat;
+ u8 status, host_stat = 0;
- switch (qc->tf.protocol) {
+ VPRINTK("ata%u: protocol %d task_state %d\n",
+ ap->id, qc->tf.protocol, ap->pio_task_state);
- case ATA_PROT_DMA:
- case ATA_PROT_ATAPI_DMA:
- case ATA_PROT_ATAPI:
- /* check status of DMA engine */
- host_stat = ap->ops->bmdma_status(ap);
- VPRINTK("ata%u: host_stat 0x%X\n", ap->id, host_stat);
-
- /* if it's not our irq... */
- if (!(host_stat & ATA_DMA_INTR))
+ /* Check whether we are expecting interrupt in this state */
+ switch (ap->pio_task_state) {
+ case PIO_ST_FIRST:
+ /* Check the ATA_DFLAG_CDB_INTR flag is enough here.
+ * The flag was turned on only for atapi devices,
+ * no need to check is_atapi_taskfile(&qc->tf) again.
+ */
+ if (!(qc->dev->flags & ATA_DFLAG_CDB_INTR))
goto idle_irq;
+ break;
+ case PIO_ST_LAST:
+ if (qc->tf.protocol == ATA_PROT_DMA ||
+ qc->tf.protocol == ATA_PROT_ATAPI_DMA) {
+ /* check status of DMA engine */
+ host_stat = ap->ops->bmdma_status(ap);
+ VPRINTK("ata%u: host_stat 0x%X\n", ap->id, host_stat);
+
+ /* if it's not our irq... */
+ if (!(host_stat & ATA_DMA_INTR))
+ goto idle_irq;
- /* before we do anything else, clear DMA-Start bit */
- ap->ops->bmdma_stop(qc);
+ /* before we do anything else, clear DMA-Start bit */
+ ap->ops->bmdma_stop(qc);
+ }
+ break;
+ case PIO_ST:
+ break;
+ default:
+ goto idle_irq;
+ }
- /* fall through */
+ /* check altstatus */
+ status = ata_altstatus(ap);
+ if (status & ATA_BUSY)
+ goto idle_irq;
- case ATA_PROT_ATAPI_NODATA:
- case ATA_PROT_NODATA:
- /* check altstatus */
- status = ata_altstatus(ap);
- if (status & ATA_BUSY)
- goto idle_irq;
+ /* check main status, clearing INTRQ */
+ status = ata_chk_status(ap);
+ if (unlikely(status & ATA_BUSY))
+ goto idle_irq;
- /* check main status, clearing INTRQ */
- status = ata_chk_status(ap);
- if (unlikely(status & ATA_BUSY))
- goto idle_irq;
- DPRINTK("ata%u: protocol %d (dev_stat 0x%X)\n",
- ap->id, qc->tf.protocol, status);
+ DPRINTK("ata%u: protocol %d task_state %d (dev_stat 0x%X)\n",
+ ap->id, qc->tf.protocol, ap->pio_task_state, status);
- /* ack bmdma irq events */
- ap->ops->irq_clear(ap);
+ /* ack bmdma irq events */
+ ap->ops->irq_clear(ap);
+
+ /* check error */
+ if (unlikely((status & ATA_ERR) || (host_stat & ATA_DMA_ERR)))
+ ap->pio_task_state = PIO_ST_ERR;
+
+fsm_start:
+ switch (ap->pio_task_state) {
+ case PIO_ST_FIRST:
+ /* Some pre-ATAPI-4 devices assert INTRQ
+ * at this state when ready to receive CDB.
+ */
+
+ /* check device status */
+ if (unlikely((status & (ATA_BUSY | ATA_DRQ)) != ATA_DRQ)) {
+ /* Wrong status. Let EH handle this */
+ ap->pio_task_state = PIO_ST_ERR;
+ goto fsm_start;
+ }
+
+ atapi_send_cdb(ap, qc);
+
+ break;
+
+ case PIO_ST:
+ /* complete command or read/write the data register */
+ if (qc->tf.protocol == ATA_PROT_ATAPI) {
+ /* ATAPI PIO protocol */
+ if ((status & ATA_DRQ) == 0) {
+ /* no more data to transfer */
+ ap->pio_task_state = PIO_ST_LAST;
+ goto fsm_start;
+ }
+
+ atapi_pio_bytes(qc);
+
+ if (unlikely(ap->pio_task_state == PIO_ST_ERR))
+ /* bad ireason reported by device */
+ goto fsm_start;
+
+ } else {
+ /* ATA PIO protocol */
+ if (unlikely((status & ATA_DRQ) == 0)) {
+ /* handle BSY=0, DRQ=0 as error */
+ ap->pio_task_state = PIO_ST_ERR;
+ goto fsm_start;
+ }
+
+ ata_pio_sector(qc);
+
+ if (ap->pio_task_state == PIO_ST_LAST &&
+ (!(qc->tf.flags & ATA_TFLAG_WRITE))) {
+ /* all data read */
+ ata_altstatus(ap);
+ status = ata_chk_status(ap);
+ goto fsm_start;
+ }
+ }
+
+ break;
+
+ case PIO_ST_LAST:
+ if (unlikely(status & ATA_DRQ)) {
+ /* handle DRQ=1 as error */
+ ap->pio_task_state = PIO_ST_ERR;
+ goto fsm_start;
+ }
+
+ /* no more data to transfer */
+ DPRINTK("ata%u: command complete, drv_stat 0x%x\n",
+ ap->id, status);
+
+ ap->pio_task_state = PIO_ST_IDLE;
/* complete taskfile transaction */
ata_qc_complete(qc, status);
break;
+ case PIO_ST_ERR:
+ printk(KERN_ERR "ata%u: command error, drv_stat 0x%x host_stat 0x%x\n",
+ ap->id, status, host_stat);
+
+ ap->pio_task_state = PIO_ST_IDLE;
+ ata_qc_complete(qc, status | ATA_ERR);
+ break;
default:
goto idle_irq;
}
@@ -3733,11 +3936,11 @@ irqreturn_t ata_interrupt (int irq, void
ap = host_set->ports[i];
if (ap &&
- !(ap->flags & (ATA_FLAG_PORT_DISABLED | ATA_FLAG_NOINTR))) {
+ !(ap->flags & ATA_FLAG_PORT_DISABLED)) {
struct ata_queued_cmd *qc;
qc = ata_qc_from_tag(ap, ap->active_tag);
- if (qc && (!(qc->tf.ctl & ATA_NIEN)) &&
+ if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING)) &&
(qc->flags & ATA_QCFLAG_ACTIVE))
handled |= ata_host_intr(ap, qc);
}
@@ -3767,6 +3970,7 @@ static void atapi_packet_task(void *_dat
struct ata_port *ap = _data;
struct ata_queued_cmd *qc;
u8 status;
+ unsigned long flags;
qc = ata_qc_from_tag(ap, ap->active_tag);
assert(qc != NULL);
@@ -3782,38 +3986,39 @@ static void atapi_packet_task(void *_dat
if ((status & (ATA_BUSY | ATA_DRQ)) != ATA_DRQ)
goto err_out;
- /* send SCSI cdb */
- DPRINTK("send cdb\n");
- assert(ap->cdb_len >= 12);
+ /* Send the CDB (atapi) or the first data block (ata pio out).
+ * During the state transition, interrupt handler shouldn't
+ * be invoked before the data transfer is complete and
+ * pio_task_state is changed. Hence, the following locking.
+ */
+ spin_lock_irqsave(&ap->host_set->lock, flags);
- if (qc->tf.protocol == ATA_PROT_ATAPI_DMA ||
- qc->tf.protocol == ATA_PROT_ATAPI_NODATA) {
- unsigned long flags;
-
- /* Once we're done issuing command and kicking bmdma,
- * irq handler takes over. To not lose irq, we need
- * to clear NOINTR flag before sending cdb, but
- * interrupt handler shouldn't be invoked before we're
- * finished. Hence, the following locking.
- */
- spin_lock_irqsave(&ap->host_set->lock, flags);
- ap->flags &= ~ATA_FLAG_NOINTR;
- ata_data_xfer(ap, qc->cdb, ap->cdb_len, 1);
- if (qc->tf.protocol == ATA_PROT_ATAPI_DMA)
- ap->ops->bmdma_start(qc); /* initiate bmdma */
- spin_unlock_irqrestore(&ap->host_set->lock, flags);
+ if (is_atapi_taskfile(&qc->tf)) {
+ /* send CDB */
+ atapi_send_cdb(ap, qc);
+
+ if (qc->tf.flags & ATA_TFLAG_POLLING)
+ queue_work(ata_wq, &ap->pio_task);
} else {
- ata_data_xfer(ap, qc->cdb, ap->cdb_len, 1);
+ /* PIO data out protocol.
+ * send first data block.
+ */
- /* PIO commands are handled by polling */
+ /* ata_pio_sector() might change the state to PIO_ST_LAST.
+ * so, the state is changed here before ata_pio_sector().
+ */
ap->pio_task_state = PIO_ST;
- queue_work(ata_wq, &ap->pio_task);
+ ata_pio_sector(qc);
+
+ /* interrupt handler takes over from here */
}
+ spin_unlock_irqrestore(&ap->host_set->lock, flags);
+
return;
err_out:
- ata_poll_qc_complete(qc, ATA_ERR);
+ ata_pio_error(ap);
}
^ permalink raw reply [flat|nested] 77+ messages in thread
* Re: [PATCH/RFC 2/3] libata: rename task states/variables
2005-09-22 4:11 ` [PATCH/RFC 2/3] libata: rename task states/variables Albert Lee
@ 2005-09-23 9:34 ` Albert Lee
0 siblings, 0 replies; 77+ messages in thread
From: Albert Lee @ 2005-09-23 9:34 UTC (permalink / raw)
To: Jeff Garzik
Cc: Linux IDE, Bartlomiej Zolnierkiewicz, Doug Maxey, Tejun Heo,
Mark Lord, Brett Russ
[-- Attachment #1: Type: text/plain, Size: 478 bytes --]
Albert Lee wrote:
> Patch 2/3: rename task states/variables
>
> Changes:
> s/PIO_ST_/HSM_ST_/ and s/pio_task_state/hsm_task_state/.
>
>
patch 2/3 is also updated to sync with the revised patch 1/3:
"ap->pio_task_state = PIO_ST;" should be before "ata_pio_sector(qc);"
because ata_pio_sector() might change the state to PIO_ST_LAST.
(http://marc.theaimsgroup.com/?l=linux-ide&m=112746756929455&w=2)
Attached please find the revised patch 2/3 for your review, thanks.
Albert
[-- Attachment #2: idpio2.diff --]
[-- Type: text/plain, Size: 14551 bytes --]
--- id1/include/linux/libata.h 2005-09-21 15:49:14.000000000 +0800
+++ id2/include/linux/libata.h 2005-09-21 16:25:26.000000000 +0800
@@ -155,16 +155,16 @@ enum {
ATA_SHIFT_PIO = 11,
};
-enum pio_task_states {
- PIO_ST_UNKNOWN,
- PIO_ST_IDLE,
- PIO_ST_POLL,
- PIO_ST_TMOUT,
- PIO_ST,
- PIO_ST_LAST,
- PIO_ST_LAST_POLL,
- PIO_ST_ERR,
- PIO_ST_FIRST,
+enum hsm_task_states {
+ HSM_ST_UNKNOWN,
+ HSM_ST_IDLE,
+ HSM_ST_POLL,
+ HSM_ST_TMOUT,
+ HSM_ST,
+ HSM_ST_LAST,
+ HSM_ST_LAST_POLL,
+ HSM_ST_ERR,
+ HSM_ST_FIRST,
};
/* forward declarations */
@@ -319,7 +319,7 @@ struct ata_port {
struct work_struct packet_task;
struct work_struct pio_task;
- unsigned int pio_task_state;
+ unsigned int hsm_task_state;
unsigned long pio_task_timeout;
void *private_data;
--- id1/drivers/scsi/libata-core.c 2005-09-23 13:47:41.000000000 +0800
+++ id2/drivers/scsi/libata-core.c 2005-09-23 13:47:54.000000000 +0800
@@ -2427,20 +2427,20 @@ void ata_poll_qc_complete(struct ata_que
static unsigned long ata_pio_poll(struct ata_port *ap)
{
u8 status;
- unsigned int poll_state = PIO_ST_UNKNOWN;
- unsigned int reg_state = PIO_ST_UNKNOWN;
- const unsigned int tmout_state = PIO_ST_TMOUT;
-
- switch (ap->pio_task_state) {
- case PIO_ST:
- case PIO_ST_POLL:
- poll_state = PIO_ST_POLL;
- reg_state = PIO_ST;
- break;
- case PIO_ST_LAST:
- case PIO_ST_LAST_POLL:
- poll_state = PIO_ST_LAST_POLL;
- reg_state = PIO_ST_LAST;
+ unsigned int poll_state = HSM_ST_UNKNOWN;
+ unsigned int reg_state = HSM_ST_UNKNOWN;
+ const unsigned int tmout_state = HSM_ST_TMOUT;
+
+ switch (ap->hsm_task_state) {
+ case HSM_ST:
+ case HSM_ST_POLL:
+ poll_state = HSM_ST_POLL;
+ reg_state = HSM_ST;
+ break;
+ case HSM_ST_LAST:
+ case HSM_ST_LAST_POLL:
+ poll_state = HSM_ST_LAST_POLL;
+ reg_state = HSM_ST_LAST;
break;
default:
BUG();
@@ -2450,14 +2450,14 @@ static unsigned long ata_pio_poll(struct
status = ata_chk_status(ap);
if (status & ATA_BUSY) {
if (time_after(jiffies, ap->pio_task_timeout)) {
- ap->pio_task_state = tmout_state;
+ ap->hsm_task_state = tmout_state;
return 0;
}
- ap->pio_task_state = poll_state;
+ ap->hsm_task_state = poll_state;
return ATA_SHORT_PAUSE;
}
- ap->pio_task_state = reg_state;
+ ap->hsm_task_state = reg_state;
return 0;
}
@@ -2482,14 +2482,14 @@ static int ata_pio_complete (struct ata_
* we enter, BSY will be cleared in a chk-status or two. If not,
* the drive is probably seeking or something. Snooze for a couple
* msecs, then chk-status again. If still busy, fall back to
- * PIO_ST_POLL state.
+ * HSM_ST_POLL state.
*/
drv_stat = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 10);
if (drv_stat & (ATA_BUSY | ATA_DRQ)) {
msleep(2);
drv_stat = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 10);
if (drv_stat & (ATA_BUSY | ATA_DRQ)) {
- ap->pio_task_state = PIO_ST_LAST_POLL;
+ ap->hsm_task_state = HSM_ST_LAST_POLL;
ap->pio_task_timeout = jiffies + ATA_TMOUT_PIO;
return 0;
}
@@ -2497,14 +2497,14 @@ static int ata_pio_complete (struct ata_
drv_stat = ata_wait_idle(ap);
if (!ata_ok(drv_stat)) {
- ap->pio_task_state = PIO_ST_ERR;
+ ap->hsm_task_state = HSM_ST_ERR;
return 0;
}
qc = ata_qc_from_tag(ap, ap->active_tag);
assert(qc != NULL);
- ap->pio_task_state = PIO_ST_IDLE;
+ ap->hsm_task_state = HSM_ST_IDLE;
ata_poll_qc_complete(qc, drv_stat);
@@ -2667,7 +2667,7 @@ static void ata_pio_sector(struct ata_qu
#endif
if (qc->cursect == (qc->nsect - 1))
- ap->pio_task_state = PIO_ST_LAST;
+ ap->hsm_task_state = HSM_ST_LAST;
page = sg[qc->cursg].page;
offset = sg[qc->cursg].offset + qc->cursg_ofs * ATA_SECT_SIZE;
@@ -2726,7 +2726,7 @@ static void __atapi_pio_bytes(struct ata
#endif
if (qc->curbytes + bytes >= qc->nbytes)
- ap->pio_task_state = PIO_ST_LAST;
+ ap->hsm_task_state = HSM_ST_LAST;
next_sg:
if (unlikely(qc->cursg >= qc->n_elem)) {
@@ -2748,7 +2748,7 @@ next_sg:
for (i = 0; i < words; i++)
ata_data_xfer(ap, (unsigned char*)pad_buf, 2, do_write);
- ap->pio_task_state = PIO_ST_LAST;
+ ap->hsm_task_state = HSM_ST_LAST;
return;
}
@@ -2836,7 +2836,7 @@ static void atapi_pio_bytes(struct ata_q
err_out:
printk(KERN_INFO "ata%u: dev %u: ATAPI check failed\n",
ap->id, dev->devno);
- ap->pio_task_state = PIO_ST_ERR;
+ ap->hsm_task_state = HSM_ST_ERR;
}
/**
@@ -2858,14 +2858,14 @@ static void ata_pio_block(struct ata_por
* a chk-status or two. If not, the drive is probably seeking
* or something. Snooze for a couple msecs, then
* chk-status again. If still busy, fall back to
- * PIO_ST_POLL state.
+ * HSM_ST_POLL state.
*/
status = ata_busy_wait(ap, ATA_BUSY, 5);
if (status & ATA_BUSY) {
msleep(2);
status = ata_busy_wait(ap, ATA_BUSY, 10);
if (status & ATA_BUSY) {
- ap->pio_task_state = PIO_ST_POLL;
+ ap->hsm_task_state = HSM_ST_POLL;
ap->pio_task_timeout = jiffies + ATA_TMOUT_PIO;
return;
}
@@ -2877,7 +2877,7 @@ static void ata_pio_block(struct ata_por
if (is_atapi_taskfile(&qc->tf)) {
/* no more data to transfer or unsupported ATAPI command */
if ((status & ATA_DRQ) == 0) {
- ap->pio_task_state = PIO_ST_LAST;
+ ap->hsm_task_state = HSM_ST_LAST;
return;
}
@@ -2885,7 +2885,7 @@ static void ata_pio_block(struct ata_por
} else {
/* handle BSY=0, DRQ=0 as error */
if ((status & ATA_DRQ) == 0) {
- ap->pio_task_state = PIO_ST_ERR;
+ ap->hsm_task_state = HSM_ST_ERR;
return;
}
@@ -2905,7 +2905,7 @@ static void ata_pio_error(struct ata_por
printk(KERN_WARNING "ata%u: PIO error, drv_stat 0x%x\n",
ap->id, drv_stat);
- ap->pio_task_state = PIO_ST_IDLE;
+ ap->hsm_task_state = HSM_ST_IDLE;
ata_poll_qc_complete(qc, drv_stat | ATA_ERR);
}
@@ -2920,25 +2920,25 @@ fsm_start:
timeout = 0;
qc_completed = 0;
- switch (ap->pio_task_state) {
- case PIO_ST_IDLE:
+ switch (ap->hsm_task_state) {
+ case HSM_ST_IDLE:
return;
- case PIO_ST:
+ case HSM_ST:
ata_pio_block(ap);
break;
- case PIO_ST_LAST:
+ case HSM_ST_LAST:
qc_completed = ata_pio_complete(ap);
break;
- case PIO_ST_POLL:
- case PIO_ST_LAST_POLL:
+ case HSM_ST_POLL:
+ case HSM_ST_LAST_POLL:
timeout = ata_pio_poll(ap);
break;
- case PIO_ST_TMOUT:
- case PIO_ST_ERR:
+ case HSM_ST_TMOUT:
+ case HSM_ST_ERR:
ata_pio_error(ap);
return;
}
@@ -3075,7 +3075,7 @@ static void ata_qc_timeout(struct ata_qu
printk(KERN_ERR "ata%u: command 0x%x timeout, stat 0x%x host_stat 0x%x\n",
ap->id, qc->tf.command, drv_stat, host_stat);
- ap->pio_task_state = PIO_ST_IDLE;
+ ap->hsm_task_state = HSM_ST_IDLE;
/* complete taskfile transaction */
ata_qc_complete(qc, drv_stat);
@@ -3375,7 +3375,7 @@ int ata_qc_issue_prot(struct ata_queued_
ata_qc_set_polling(qc);
ata_tf_to_host_nolock(ap, &qc->tf);
- ap->pio_task_state = PIO_ST_LAST;
+ ap->hsm_task_state = HSM_ST_LAST;
if (qc->tf.flags & ATA_TFLAG_POLLING)
queue_work(ata_wq, &ap->pio_task);
@@ -3388,7 +3388,7 @@ int ata_qc_issue_prot(struct ata_queued_
ap->ops->tf_load(ap, &qc->tf); /* load tf registers */
ap->ops->bmdma_setup(qc); /* set up bmdma */
ap->ops->bmdma_start(qc); /* initiate bmdma */
- ap->pio_task_state = PIO_ST_LAST;
+ ap->hsm_task_state = HSM_ST_LAST;
break;
case ATA_PROT_PIO:
@@ -3399,19 +3399,19 @@ int ata_qc_issue_prot(struct ata_queued_
if (qc->tf.flags & ATA_TFLAG_POLLING) {
/* polling PIO */
- ap->pio_task_state = PIO_ST;
+ ap->hsm_task_state = HSM_ST;
queue_work(ata_wq, &ap->pio_task);
} else {
/* interrupt driven PIO */
if (qc->tf.flags & ATA_TFLAG_WRITE) {
/* PIO data out protocol */
- ap->pio_task_state = PIO_ST_FIRST;
+ ap->hsm_task_state = HSM_ST_FIRST;
queue_work(ata_wq, &ap->packet_task);
/* send first data block by polling */
} else {
/* PIO data in protocol */
- ap->pio_task_state = PIO_ST;
+ ap->hsm_task_state = HSM_ST;
/* interrupt handler takes over from here */
}
@@ -3424,7 +3424,7 @@ int ata_qc_issue_prot(struct ata_queued_
ata_qc_set_polling(qc);
ata_tf_to_host_nolock(ap, &qc->tf);
- ap->pio_task_state = PIO_ST_FIRST;
+ ap->hsm_task_state = HSM_ST_FIRST;
/* send cdb by polling if no cdb interrupt */
if ((!(qc->dev->flags & ATA_DFLAG_CDB_INTR)) ||
@@ -3437,7 +3437,7 @@ int ata_qc_issue_prot(struct ata_queued_
ata_qc_set_polling(qc);
ata_tf_to_host_nolock(ap, &qc->tf);
- ap->pio_task_state = PIO_ST_FIRST;
+ ap->hsm_task_state = HSM_ST_FIRST;
/* send cdb by polling if no cdb interrupt */
if ((!(qc->dev->flags & ATA_DFLAG_CDB_INTR)) ||
@@ -3450,7 +3450,7 @@ int ata_qc_issue_prot(struct ata_queued_
ap->ops->tf_load(ap, &qc->tf); /* load tf registers */
ap->ops->bmdma_setup(qc); /* set up bmdma */
- ap->pio_task_state = PIO_ST_FIRST;
+ ap->hsm_task_state = HSM_ST_FIRST;
/* send cdb by polling if no cdb interrupt */
if (!(qc->dev->flags & ATA_DFLAG_CDB_INTR))
@@ -3660,7 +3660,7 @@ u8 ata_bmdma_status(struct ata_port *ap)
void __iomem *mmio = (void __iomem *) ap->ioaddr.bmdma_addr;
host_stat = readb(mmio + ATA_DMA_STATUS);
} else
- host_stat = inb(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS);
+ host_stat = inb(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS);
return host_stat;
}
@@ -3718,13 +3718,13 @@ static void atapi_send_cdb(struct ata_po
switch (qc->tf.protocol) {
case ATA_PROT_ATAPI:
- ap->pio_task_state = PIO_ST;
+ ap->hsm_task_state = HSM_ST;
break;
case ATA_PROT_ATAPI_NODATA:
- ap->pio_task_state = PIO_ST_LAST;
+ ap->hsm_task_state = HSM_ST_LAST;
break;
case ATA_PROT_ATAPI_DMA:
- ap->pio_task_state = PIO_ST_LAST;
+ ap->hsm_task_state = HSM_ST_LAST;
/* initiate bmdma */
ap->ops->bmdma_start(qc);
break;
@@ -3753,11 +3753,11 @@ inline unsigned int ata_host_intr (struc
u8 status, host_stat = 0;
VPRINTK("ata%u: protocol %d task_state %d\n",
- ap->id, qc->tf.protocol, ap->pio_task_state);
+ ap->id, qc->tf.protocol, ap->hsm_task_state);
/* Check whether we are expecting interrupt in this state */
- switch (ap->pio_task_state) {
- case PIO_ST_FIRST:
+ switch (ap->hsm_task_state) {
+ case HSM_ST_FIRST:
/* Check the ATA_DFLAG_CDB_INTR flag is enough here.
* The flag was turned on only for atapi devices,
* no need to check is_atapi_taskfile(&qc->tf) again.
@@ -3765,7 +3765,7 @@ inline unsigned int ata_host_intr (struc
if (!(qc->dev->flags & ATA_DFLAG_CDB_INTR))
goto idle_irq;
break;
- case PIO_ST_LAST:
+ case HSM_ST_LAST:
if (qc->tf.protocol == ATA_PROT_DMA ||
qc->tf.protocol == ATA_PROT_ATAPI_DMA) {
/* check status of DMA engine */
@@ -3780,7 +3780,7 @@ inline unsigned int ata_host_intr (struc
ap->ops->bmdma_stop(qc);
}
break;
- case PIO_ST:
+ case HSM_ST:
break;
default:
goto idle_irq;
@@ -3797,18 +3797,18 @@ inline unsigned int ata_host_intr (struc
goto idle_irq;
DPRINTK("ata%u: protocol %d task_state %d (dev_stat 0x%X)\n",
- ap->id, qc->tf.protocol, ap->pio_task_state, status);
+ ap->id, qc->tf.protocol, ap->hsm_task_state, status);
/* ack bmdma irq events */
ap->ops->irq_clear(ap);
/* check error */
if (unlikely((status & ATA_ERR) || (host_stat & ATA_DMA_ERR)))
- ap->pio_task_state = PIO_ST_ERR;
+ ap->hsm_task_state = HSM_ST_ERR;
fsm_start:
- switch (ap->pio_task_state) {
- case PIO_ST_FIRST:
+ switch (ap->hsm_task_state) {
+ case HSM_ST_FIRST:
/* Some pre-ATAPI-4 devices assert INTRQ
* at this state when ready to receive CDB.
*/
@@ -3816,7 +3816,7 @@ fsm_start:
/* check device status */
if (unlikely((status & (ATA_BUSY | ATA_DRQ)) != ATA_DRQ)) {
/* Wrong status. Let EH handle this */
- ap->pio_task_state = PIO_ST_ERR;
+ ap->hsm_task_state = HSM_ST_ERR;
goto fsm_start;
}
@@ -3824,19 +3824,19 @@ fsm_start:
break;
- case PIO_ST:
+ case HSM_ST:
/* complete command or read/write the data register */
if (qc->tf.protocol == ATA_PROT_ATAPI) {
/* ATAPI PIO protocol */
if ((status & ATA_DRQ) == 0) {
/* no more data to transfer */
- ap->pio_task_state = PIO_ST_LAST;
+ ap->hsm_task_state = HSM_ST_LAST;
goto fsm_start;
}
atapi_pio_bytes(qc);
- if (unlikely(ap->pio_task_state == PIO_ST_ERR))
+ if (unlikely(ap->hsm_task_state == HSM_ST_ERR))
/* bad ireason reported by device */
goto fsm_start;
@@ -3844,13 +3844,13 @@ fsm_start:
/* ATA PIO protocol */
if (unlikely((status & ATA_DRQ) == 0)) {
/* handle BSY=0, DRQ=0 as error */
- ap->pio_task_state = PIO_ST_ERR;
+ ap->hsm_task_state = HSM_ST_ERR;
goto fsm_start;
}
ata_pio_sector(qc);
- if (ap->pio_task_state == PIO_ST_LAST &&
+ if (ap->hsm_task_state == HSM_ST_LAST &&
(!(qc->tf.flags & ATA_TFLAG_WRITE))) {
/* all data read */
ata_altstatus(ap);
@@ -3861,10 +3861,10 @@ fsm_start:
break;
- case PIO_ST_LAST:
+ case HSM_ST_LAST:
if (unlikely(status & ATA_DRQ)) {
/* handle DRQ=1 as error */
- ap->pio_task_state = PIO_ST_ERR;
+ ap->hsm_task_state = HSM_ST_ERR;
goto fsm_start;
}
@@ -3872,17 +3872,17 @@ fsm_start:
DPRINTK("ata%u: command complete, drv_stat 0x%x\n",
ap->id, status);
- ap->pio_task_state = PIO_ST_IDLE;
+ ap->hsm_task_state = HSM_ST_IDLE;
/* complete taskfile transaction */
ata_qc_complete(qc, status);
break;
- case PIO_ST_ERR:
+ case HSM_ST_ERR:
printk(KERN_ERR "ata%u: command error, drv_stat 0x%x host_stat 0x%x\n",
ap->id, status, host_stat);
- ap->pio_task_state = PIO_ST_IDLE;
+ ap->hsm_task_state = HSM_ST_IDLE;
ata_qc_complete(qc, status | ATA_ERR);
break;
default:
@@ -3989,7 +3989,7 @@ static void atapi_packet_task(void *_dat
/* Send the CDB (atapi) or the first data block (ata pio out).
* During the state transition, interrupt handler shouldn't
* be invoked before the data transfer is complete and
- * pio_task_state is changed. Hence, the following locking.
+ * hsm_task_state is changed. Hence, the following locking.
*/
spin_lock_irqsave(&ap->host_set->lock, flags);
@@ -4004,10 +4004,10 @@ static void atapi_packet_task(void *_dat
* send first data block.
*/
- /* ata_pio_sector() might change the state to PIO_ST_LAST.
+ /* ata_pio_sector() might change the state to HSM_ST_LAST.
* so, the state is changed here before ata_pio_sector().
*/
- ap->pio_task_state = PIO_ST;
+ ap->hsm_task_state = HSM_ST;
ata_pio_sector(qc);
/* interrupt handler takes over from here */
^ permalink raw reply [flat|nested] 77+ messages in thread
* Re: [PATCH/RFC 0/3] libata: interrupt driven pio (revised)
2005-09-22 4:00 ` [PATCH/RFC 0/3] libata: interrupt driven pio (revised) Albert Lee
` (2 preceding siblings ...)
2005-09-22 4:14 ` [PATCH/RFC 3/3] libata: interrupt driven pio for LLD Albert Lee
@ 2005-09-23 9:46 ` Jeff Garzik
2005-09-27 9:31 ` [PATCH/RFC 0/4] libata: interrupt driven pio (revised 2) Albert Lee
3 siblings, 1 reply; 77+ messages in thread
From: Jeff Garzik @ 2005-09-23 9:46 UTC (permalink / raw)
To: Albert Lee; +Cc: Linux IDE, Bartlomiej Zolnierkiewicz, Doug Maxey, Tejun Heo
Comments:
1) the more trivial (read: "easier" to apply) patches should come first
in a patch series. In this case, that means that
* patch #2, s/pioxxx/hsmxxx/ should come first
* whitespace changes in patch #3 should come before patch #1
2) LLD should signal its interest in using the polling code paths using
a new ATA_FLAG_xxx added to its host_flags list of flags. This is
greatly preferred over, e.g., hand-coding this indication in
pdc_qc_issue_prot() or mv_qc_issue_prot()
3) Testing of CONFIG_HIGHMEM should be eliminated. In general, #ifdefs
are discouraged in Linux whereever possible. That may mean that
local_irq_save() must be called unconditionally, or some other solution
should be found.
^ permalink raw reply [flat|nested] 77+ messages in thread
* [PATCH/RFC 0/4] libata: interrupt driven pio (revised 2)
2005-09-23 9:46 ` [PATCH/RFC 0/3] libata: interrupt driven pio (revised) Jeff Garzik
@ 2005-09-27 9:31 ` Albert Lee
2005-09-27 9:34 ` [PATCH/RFC 1/4] libata: indent and whitespace change Albert Lee
` (3 more replies)
0 siblings, 4 replies; 77+ messages in thread
From: Albert Lee @ 2005-09-27 9:31 UTC (permalink / raw)
To: Jeff Garzik
Cc: Linux IDE, Bartlomiej Zolnierkiewicz, Doug Maxey, Tejun Heo,
Mark Lord, Brett Russ
Dear all,
The revised interrupt driven PIO patch is ready for your review.
Patch 1/4: indent and white space change
Patch 2/4: s/PIO_ST_/HSM_ST_/ and s/pio_task_state/hsm_task_state/.
Patch 3/4: interrupt driven pio patch for libata-core
Patch 4/4: interrupt driven pio patch for LLD
Patch for 2.6.14-rc1 (044a500e46742d39d22f1781cfb64ba93b463e39).
Tested ok on x86 with Promise PDC20275, Seagate ST380011A and LITEON 52x
CD-ROM drive.
Need more testing with other host adapters and devices, especially
pre-ATA4 ATAPI CD-ROM drives with CDB interrupt.
For your review and advice, thanks.
Albert
^ permalink raw reply [flat|nested] 77+ messages in thread
* [PATCH/RFC 1/4] libata: indent and whitespace change
2005-09-27 9:31 ` [PATCH/RFC 0/4] libata: interrupt driven pio (revised 2) Albert Lee
@ 2005-09-27 9:34 ` Albert Lee
2005-09-27 9:36 ` [PATCH/RFC 2/4] libata: rename host states Albert Lee
` (2 subsequent siblings)
3 siblings, 0 replies; 77+ messages in thread
From: Albert Lee @ 2005-09-27 9:34 UTC (permalink / raw)
To: Jeff Garzik
Cc: Linux IDE, Bartlomiej Zolnierkiewicz, Doug Maxey, Tejun Heo,
Mark Lord, Brett Russ
[-- Attachment #1: Type: text/plain, Size: 125 bytes --]
Patch 1/4: indent and white space change
For your review, thanks.
Albert
Signed-off-by: Albert Lee <albertcc@tw.ibm.com>
[-- Attachment #2: idpio1.diff --]
[-- Type: text/plain, Size: 915 bytes --]
--- linux/drivers/scsi/libata-core.c 2005-09-20 17:18:00.000000000 +0800
+++ id1/drivers/scsi/libata-core.c 2005-09-26 14:11:03.000000000 +0800
@@ -3586,7 +3586,7 @@ u8 ata_bmdma_status(struct ata_port *ap)
void __iomem *mmio = (void __iomem *) ap->ioaddr.bmdma_addr;
host_stat = readb(mmio + ATA_DMA_STATUS);
} else
- host_stat = inb(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS);
+ host_stat = inb(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS);
return host_stat;
}
--- linux/drivers/scsi/sata_promise.c 2005-09-20 17:18:01.000000000 +0800
+++ id1/drivers/scsi/sata_promise.c 2005-09-26 14:36:51.000000000 +0800
@@ -438,11 +438,11 @@ static inline unsigned int pdc_host_intr
break;
default:
- ap->stats.idle_irq++;
- break;
+ ap->stats.idle_irq++;
+ break;
}
- return handled;
+ return handled;
}
static void pdc_irq_clear(struct ata_port *ap)
^ permalink raw reply [flat|nested] 77+ messages in thread
* [PATCH/RFC 2/4] libata: rename host states
2005-09-27 9:31 ` [PATCH/RFC 0/4] libata: interrupt driven pio (revised 2) Albert Lee
2005-09-27 9:34 ` [PATCH/RFC 1/4] libata: indent and whitespace change Albert Lee
@ 2005-09-27 9:36 ` Albert Lee
2005-09-28 15:59 ` Jeff Garzik
2005-09-27 9:38 ` [PATCH/RFC 3/4] libata: interrupt driven pio for libata-core Albert Lee
2005-09-27 9:39 ` [PATCH/RFC 4/4] libata: interrupt driven pio for LLD Albert Lee
3 siblings, 1 reply; 77+ messages in thread
From: Albert Lee @ 2005-09-27 9:36 UTC (permalink / raw)
To: Jeff Garzik
Cc: Linux IDE, Bartlomiej Zolnierkiewicz, Doug Maxey, Tejun Heo,
Mark Lord, Brett Russ
[-- Attachment #1: Type: text/plain, Size: 191 bytes --]
Patch 2/4: rename host states/variables
Changes:
s/PIO_ST_/HSM_ST_/ and s/pio_task_state/hsm_task_state/.
For your review, thanks.
Albert
Signed-off-by: Albert Lee <albertcc@tw.ibm.com>
[-- Attachment #2: idpio2.diff --]
[-- Type: text/plain, Size: 6929 bytes --]
--- id1/include/linux/libata.h 2005-09-26 14:08:20.000000000 +0800
+++ id2/include/linux/libata.h 2005-09-26 14:23:20.000000000 +0800
@@ -156,15 +156,15 @@ enum {
ATA_SHIFT_PIO = 11,
};
-enum pio_task_states {
- PIO_ST_UNKNOWN,
- PIO_ST_IDLE,
- PIO_ST_POLL,
- PIO_ST_TMOUT,
- PIO_ST,
- PIO_ST_LAST,
- PIO_ST_LAST_POLL,
- PIO_ST_ERR,
+enum hsm_task_states {
+ HSM_ST_UNKNOWN,
+ HSM_ST_IDLE,
+ HSM_ST_POLL,
+ HSM_ST_TMOUT,
+ HSM_ST,
+ HSM_ST_LAST,
+ HSM_ST_LAST_POLL,
+ HSM_ST_ERR,
};
/* forward declarations */
@@ -319,7 +319,7 @@ struct ata_port {
struct work_struct packet_task;
struct work_struct pio_task;
- unsigned int pio_task_state;
+ unsigned int hsm_task_state;
unsigned long pio_task_timeout;
void *private_data;
--- id1/drivers/scsi/libata-core.c 2005-09-26 14:11:03.000000000 +0800
+++ id2/drivers/scsi/libata-core.c 2005-09-26 14:25:15.000000000 +0800
@@ -2425,20 +2425,20 @@ void ata_poll_qc_complete(struct ata_que
static unsigned long ata_pio_poll(struct ata_port *ap)
{
u8 status;
- unsigned int poll_state = PIO_ST_UNKNOWN;
- unsigned int reg_state = PIO_ST_UNKNOWN;
- const unsigned int tmout_state = PIO_ST_TMOUT;
-
- switch (ap->pio_task_state) {
- case PIO_ST:
- case PIO_ST_POLL:
- poll_state = PIO_ST_POLL;
- reg_state = PIO_ST;
+ unsigned int poll_state = HSM_ST_UNKNOWN;
+ unsigned int reg_state = HSM_ST_UNKNOWN;
+ const unsigned int tmout_state = HSM_ST_TMOUT;
+
+ switch (ap->hsm_task_state) {
+ case HSM_ST:
+ case HSM_ST_POLL:
+ poll_state = HSM_ST_POLL;
+ reg_state = HSM_ST;
break;
- case PIO_ST_LAST:
- case PIO_ST_LAST_POLL:
- poll_state = PIO_ST_LAST_POLL;
- reg_state = PIO_ST_LAST;
+ case HSM_ST_LAST:
+ case HSM_ST_LAST_POLL:
+ poll_state = HSM_ST_LAST_POLL;
+ reg_state = HSM_ST_LAST;
break;
default:
BUG();
@@ -2448,14 +2448,14 @@ static unsigned long ata_pio_poll(struct
status = ata_chk_status(ap);
if (status & ATA_BUSY) {
if (time_after(jiffies, ap->pio_task_timeout)) {
- ap->pio_task_state = tmout_state;
+ ap->hsm_task_state = tmout_state;
return 0;
}
- ap->pio_task_state = poll_state;
+ ap->hsm_task_state = poll_state;
return ATA_SHORT_PAUSE;
}
- ap->pio_task_state = reg_state;
+ ap->hsm_task_state = reg_state;
return 0;
}
@@ -2480,14 +2480,14 @@ static int ata_pio_complete (struct ata_
* we enter, BSY will be cleared in a chk-status or two. If not,
* the drive is probably seeking or something. Snooze for a couple
* msecs, then chk-status again. If still busy, fall back to
- * PIO_ST_POLL state.
+ * HSM_ST_POLL state.
*/
drv_stat = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 10);
if (drv_stat & (ATA_BUSY | ATA_DRQ)) {
msleep(2);
drv_stat = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 10);
if (drv_stat & (ATA_BUSY | ATA_DRQ)) {
- ap->pio_task_state = PIO_ST_LAST_POLL;
+ ap->hsm_task_state = HSM_ST_LAST_POLL;
ap->pio_task_timeout = jiffies + ATA_TMOUT_PIO;
return 0;
}
@@ -2495,14 +2495,14 @@ static int ata_pio_complete (struct ata_
drv_stat = ata_wait_idle(ap);
if (!ata_ok(drv_stat)) {
- ap->pio_task_state = PIO_ST_ERR;
+ ap->hsm_task_state = HSM_ST_ERR;
return 0;
}
qc = ata_qc_from_tag(ap, ap->active_tag);
assert(qc != NULL);
- ap->pio_task_state = PIO_ST_IDLE;
+ ap->hsm_task_state = HSM_ST_IDLE;
ata_poll_qc_complete(qc, drv_stat);
@@ -2662,7 +2662,7 @@ static void ata_pio_sector(struct ata_qu
unsigned char *buf;
if (qc->cursect == (qc->nsect - 1))
- ap->pio_task_state = PIO_ST_LAST;
+ ap->hsm_task_state = HSM_ST_LAST;
page = sg[qc->cursg].page;
offset = sg[qc->cursg].offset + qc->cursg_ofs * ATA_SECT_SIZE;
@@ -2712,7 +2712,7 @@ static void __atapi_pio_bytes(struct ata
unsigned int offset, count;
if (qc->curbytes + bytes >= qc->nbytes)
- ap->pio_task_state = PIO_ST_LAST;
+ ap->hsm_task_state = HSM_ST_LAST;
next_sg:
if (unlikely(qc->cursg >= qc->n_elem)) {
@@ -2734,7 +2734,7 @@ next_sg:
for (i = 0; i < words; i++)
ata_data_xfer(ap, (unsigned char*)pad_buf, 2, do_write);
- ap->pio_task_state = PIO_ST_LAST;
+ ap->hsm_task_state = HSM_ST_LAST;
return;
}
@@ -2815,7 +2815,7 @@ static void atapi_pio_bytes(struct ata_q
err_out:
printk(KERN_INFO "ata%u: dev %u: ATAPI check failed\n",
ap->id, dev->devno);
- ap->pio_task_state = PIO_ST_ERR;
+ ap->hsm_task_state = HSM_ST_ERR;
}
/**
@@ -2837,14 +2837,14 @@ static void ata_pio_block(struct ata_por
* a chk-status or two. If not, the drive is probably seeking
* or something. Snooze for a couple msecs, then
* chk-status again. If still busy, fall back to
- * PIO_ST_POLL state.
+ * HSM_ST_POLL state.
*/
status = ata_busy_wait(ap, ATA_BUSY, 5);
if (status & ATA_BUSY) {
msleep(2);
status = ata_busy_wait(ap, ATA_BUSY, 10);
if (status & ATA_BUSY) {
- ap->pio_task_state = PIO_ST_POLL;
+ ap->hsm_task_state = HSM_ST_POLL;
ap->pio_task_timeout = jiffies + ATA_TMOUT_PIO;
return;
}
@@ -2856,7 +2856,7 @@ static void ata_pio_block(struct ata_por
if (is_atapi_taskfile(&qc->tf)) {
/* no more data to transfer or unsupported ATAPI command */
if ((status & ATA_DRQ) == 0) {
- ap->pio_task_state = PIO_ST_LAST;
+ ap->hsm_task_state = HSM_ST_LAST;
return;
}
@@ -2864,7 +2864,7 @@ static void ata_pio_block(struct ata_por
} else {
/* handle BSY=0, DRQ=0 as error */
if ((status & ATA_DRQ) == 0) {
- ap->pio_task_state = PIO_ST_ERR;
+ ap->hsm_task_state = HSM_ST_ERR;
return;
}
@@ -2884,7 +2884,7 @@ static void ata_pio_error(struct ata_por
printk(KERN_WARNING "ata%u: PIO error, drv_stat 0x%x\n",
ap->id, drv_stat);
- ap->pio_task_state = PIO_ST_IDLE;
+ ap->hsm_task_state = HSM_ST_IDLE;
ata_poll_qc_complete(qc, drv_stat | ATA_ERR);
}
@@ -2899,25 +2899,25 @@ fsm_start:
timeout = 0;
qc_completed = 0;
- switch (ap->pio_task_state) {
- case PIO_ST_IDLE:
+ switch (ap->hsm_task_state) {
+ case HSM_ST_IDLE:
return;
- case PIO_ST:
+ case HSM_ST:
ata_pio_block(ap);
break;
- case PIO_ST_LAST:
+ case HSM_ST_LAST:
qc_completed = ata_pio_complete(ap);
break;
- case PIO_ST_POLL:
- case PIO_ST_LAST_POLL:
+ case HSM_ST_POLL:
+ case HSM_ST_LAST_POLL:
timeout = ata_pio_poll(ap);
break;
- case PIO_ST_TMOUT:
- case PIO_ST_ERR:
+ case HSM_ST_TMOUT:
+ case HSM_ST_ERR:
ata_pio_error(ap);
return;
}
@@ -3360,7 +3360,7 @@ int ata_qc_issue_prot(struct ata_queued_
case ATA_PROT_PIO: /* load tf registers, initiate polling pio */
ata_qc_set_polling(qc);
ata_tf_to_host_nolock(ap, &qc->tf);
- ap->pio_task_state = PIO_ST;
+ ap->hsm_task_state = HSM_ST;
queue_work(ata_wq, &ap->pio_task);
break;
@@ -3806,7 +3806,7 @@ static void atapi_packet_task(void *_dat
ata_data_xfer(ap, qc->cdb, ap->cdb_len, 1);
/* PIO commands are handled by polling */
- ap->pio_task_state = PIO_ST;
+ ap->hsm_task_state = HSM_ST;
queue_work(ata_wq, &ap->pio_task);
}
^ permalink raw reply [flat|nested] 77+ messages in thread
* [PATCH/RFC 3/4] libata: interrupt driven pio for libata-core
2005-09-27 9:31 ` [PATCH/RFC 0/4] libata: interrupt driven pio (revised 2) Albert Lee
2005-09-27 9:34 ` [PATCH/RFC 1/4] libata: indent and whitespace change Albert Lee
2005-09-27 9:36 ` [PATCH/RFC 2/4] libata: rename host states Albert Lee
@ 2005-09-27 9:38 ` Albert Lee
2005-09-28 16:09 ` Jeff Garzik
2005-09-29 10:08 ` Bartlomiej Zolnierkiewicz
2005-09-27 9:39 ` [PATCH/RFC 4/4] libata: interrupt driven pio for LLD Albert Lee
3 siblings, 2 replies; 77+ messages in thread
From: Albert Lee @ 2005-09-27 9:38 UTC (permalink / raw)
To: Jeff Garzik
Cc: Linux IDE, Bartlomiej Zolnierkiewicz, Doug Maxey, Tejun Heo,
Mark Lord, Brett Russ
[-- Attachment #1: Type: text/plain, Size: 739 bytes --]
Patch 3/4: interrupt driven pio for libata-core
Changes:
- add PIO_ST_FIRST for the state before sending ATAPI CDB or sending
"ATA PIO data out" first data block.
- add ATA_TFLAG_POLLING and ATA_DFLAG_CDB_INTR flags
- remove the ATA_FLAG_NOINTR flag since the interrupt handler is now
aware of the states
- modify ata_pio_sector() and atapi_pio_bytes() to work in the interrupt
context
- modify the ata_host_intr() to handle PIO interrupts
- modify ata_qc_issue_prot() to initialize states
- atapi_packet_task() changed to handle "ATA PIO data out" first data block
- support the pre-ATA4 ATAPI device which raise interrupt when ready to
receive CDB
For your review, thanks.
Albert
Signed-off-by: Albert Lee <albertcc@tw.ibm.com>
[-- Attachment #2: idpio3.diff --]
[-- Type: text/plain, Size: 15758 bytes --]
--- id2/include/linux/ata.h 2005-09-26 14:08:23.000000000 +0800
+++ id3/include/linux/ata.h 2005-09-19 16:18:45.000000000 +0800
@@ -181,6 +181,7 @@ enum {
ATA_TFLAG_ISADDR = (1 << 1), /* enable r/w to nsect/lba regs */
ATA_TFLAG_DEVICE = (1 << 2), /* enable r/w to device reg */
ATA_TFLAG_WRITE = (1 << 3), /* data dir: host->dev==1 (write) */
+ ATA_TFLAG_POLLING = (1 << 4), /* set nIEN to 1 and use polling */
};
enum ata_tf_protocols {
@@ -250,6 +251,8 @@ struct ata_taskfile {
((u64) (id)[(n) + 1] << 16) | \
((u64) (id)[(n) + 0]) )
+#define ata_id_cdb_intr(id) (((id)[0] & 0x60) == 0x20)
+
static inline int atapi_cdb_len(u16 *dev_id)
{
u16 tmp = dev_id[0] & 0x3;
--- id2/include/linux/libata.h 2005-09-26 14:23:20.000000000 +0800
+++ id3/include/linux/libata.h 2005-09-21 16:25:26.000000000 +0800
@@ -97,6 +97,7 @@ enum {
ATA_DFLAG_LBA48 = (1 << 0), /* device supports LBA48 */
ATA_DFLAG_PIO = (1 << 1), /* device currently in PIO mode */
ATA_DFLAG_LOCK_SECTORS = (1 << 2), /* don't adjust max_sectors */
+ ATA_DFLAG_CDB_INTR = (1 << 3), /* device asserts INTRQ when ready for CDB */
ATA_DEV_UNKNOWN = 0, /* unknown device */
ATA_DEV_ATA = 1, /* ATA device */
@@ -115,8 +116,6 @@ enum {
ATA_FLAG_MMIO = (1 << 6), /* use MMIO, not PIO */
ATA_FLAG_SATA_RESET = (1 << 7), /* use COMRESET */
ATA_FLAG_PIO_DMA = (1 << 8), /* PIO cmds via DMA */
- ATA_FLAG_NOINTR = (1 << 9), /* FIXME: Remove this once
- * proper HSM is in place. */
ATA_QCFLAG_ACTIVE = (1 << 1), /* cmd not yet ack'd to scsi lyer */
ATA_QCFLAG_SG = (1 << 3), /* have s/g table? */
@@ -165,6 +164,7 @@ enum hsm_task_states {
HSM_ST_LAST,
HSM_ST_LAST_POLL,
HSM_ST_ERR,
+ HSM_ST_FIRST,
};
/* forward declarations */
--- id2/drivers/scsi/libata-core.c 2005-09-26 14:25:15.000000000 +0800
+++ id3/drivers/scsi/libata-core.c 2005-09-27 13:22:14.000000000 +0800
@@ -1292,6 +1292,9 @@ retry:
ap->cdb_len = (unsigned int) rc;
ap->host->max_cmd_len = (unsigned char) ap->cdb_len;
+ if (ata_id_cdb_intr(dev->id))
+ dev->flags |= ATA_DFLAG_CDB_INTR;
+
/* print device info to dmesg */
printk(KERN_INFO "ata%u: dev %u ATAPI, max %s\n",
ap->id, device,
@@ -2405,7 +2408,6 @@ void ata_poll_qc_complete(struct ata_que
unsigned long flags;
spin_lock_irqsave(&ap->host_set->lock, flags);
- ap->flags &= ~ATA_FLAG_NOINTR;
ata_irq_on(ap);
ata_qc_complete(qc, drv_stat);
spin_unlock_irqrestore(&ap->host_set->lock, flags);
@@ -2660,6 +2662,7 @@ static void ata_pio_sector(struct ata_qu
struct page *page;
unsigned int offset;
unsigned char *buf;
+ unsigned long flags;
if (qc->cursect == (qc->nsect - 1))
ap->hsm_task_state = HSM_ST_LAST;
@@ -2671,7 +2674,8 @@ static void ata_pio_sector(struct ata_qu
page = nth_page(page, (offset >> PAGE_SHIFT));
offset %= PAGE_SIZE;
- buf = kmap(page) + offset;
+ local_irq_save(flags);
+ buf = kmap_atomic(page, KM_IRQ0) + offset;
qc->cursect++;
qc->cursg_ofs++;
@@ -2687,7 +2691,8 @@ static void ata_pio_sector(struct ata_qu
do_write = (qc->tf.flags & ATA_TFLAG_WRITE);
ata_data_xfer(ap, buf, ATA_SECT_SIZE, do_write);
- kunmap(page);
+ kunmap_atomic(buf - offset, KM_IRQ0);
+ local_irq_restore(flags);
}
/**
@@ -2710,6 +2715,7 @@ static void __atapi_pio_bytes(struct ata
struct page *page;
unsigned char *buf;
unsigned int offset, count;
+ unsigned long flags;
if (qc->curbytes + bytes >= qc->nbytes)
ap->hsm_task_state = HSM_ST_LAST;
@@ -2753,7 +2759,8 @@ next_sg:
/* don't cross page boundaries */
count = min(count, (unsigned int)PAGE_SIZE - offset);
- buf = kmap(page) + offset;
+ local_irq_save(flags);
+ buf = kmap_atomic(page, KM_IRQ0) + offset;
bytes -= count;
qc->curbytes += count;
@@ -2769,7 +2776,8 @@ next_sg:
/* do the actual data transfer */
ata_data_xfer(ap, buf, count, do_write);
- kunmap(page);
+ kunmap_atomic(buf - offset, KM_IRQ0);
+ local_irq_restore(flags);
if (bytes)
goto next_sg;
@@ -2808,6 +2816,8 @@ static void atapi_pio_bytes(struct ata_q
if (do_write != i_write)
goto err_out;
+ VPRINTK("ata%u: xfering %d bytes\n", ap->id, bytes);
+
__atapi_pio_bytes(qc, bytes);
return;
@@ -3054,6 +3064,8 @@ static void ata_qc_timeout(struct ata_qu
printk(KERN_ERR "ata%u: command 0x%x timeout, stat 0x%x host_stat 0x%x\n",
ap->id, qc->tf.command, drv_stat, host_stat);
+ ap->hsm_task_state = HSM_ST_IDLE;
+
/* complete taskfile transaction */
ata_qc_complete(qc, drv_stat);
break;
@@ -3344,43 +3356,96 @@ int ata_qc_issue_prot(struct ata_queued_
{
struct ata_port *ap = qc->ap;
+ /* select the device */
ata_dev_select(ap, qc->dev->devno, 1, 0);
+ /* start the command */
switch (qc->tf.protocol) {
case ATA_PROT_NODATA:
+ if (qc->tf.flags & ATA_TFLAG_POLLING)
+ ata_qc_set_polling(qc);
+
ata_tf_to_host_nolock(ap, &qc->tf);
+ ap->hsm_task_state = HSM_ST_LAST;
+
+ if (qc->tf.flags & ATA_TFLAG_POLLING)
+ queue_work(ata_wq, &ap->pio_task);
+
break;
case ATA_PROT_DMA:
+ assert(!(qc->tf.flags & ATA_TFLAG_POLLING));
+
ap->ops->tf_load(ap, &qc->tf); /* load tf registers */
ap->ops->bmdma_setup(qc); /* set up bmdma */
ap->ops->bmdma_start(qc); /* initiate bmdma */
+ ap->hsm_task_state = HSM_ST_LAST;
break;
- case ATA_PROT_PIO: /* load tf registers, initiate polling pio */
- ata_qc_set_polling(qc);
+ case ATA_PROT_PIO:
+ if (qc->tf.flags & ATA_TFLAG_POLLING)
+ ata_qc_set_polling(qc);
+
ata_tf_to_host_nolock(ap, &qc->tf);
- ap->hsm_task_state = HSM_ST;
- queue_work(ata_wq, &ap->pio_task);
+
+ if (qc->tf.flags & ATA_TFLAG_POLLING) {
+ /* polling PIO */
+ ap->hsm_task_state = HSM_ST;
+ queue_work(ata_wq, &ap->pio_task);
+ } else {
+ /* interrupt driven PIO */
+ if (qc->tf.flags & ATA_TFLAG_WRITE) {
+ /* PIO data out protocol */
+ ap->hsm_task_state = HSM_ST_FIRST;
+ queue_work(ata_wq, &ap->packet_task);
+
+ /* send first data block by polling */
+ } else {
+ /* PIO data in protocol */
+ ap->hsm_task_state = HSM_ST;
+
+ /* interrupt handler takes over from here */
+ }
+ }
+
break;
case ATA_PROT_ATAPI:
- ata_qc_set_polling(qc);
+ if (qc->tf.flags & ATA_TFLAG_POLLING)
+ ata_qc_set_polling(qc);
+
ata_tf_to_host_nolock(ap, &qc->tf);
- queue_work(ata_wq, &ap->packet_task);
+ ap->hsm_task_state = HSM_ST_FIRST;
+
+ /* send cdb by polling if no cdb interrupt */
+ if ((!(qc->dev->flags & ATA_DFLAG_CDB_INTR)) ||
+ (qc->tf.flags & ATA_TFLAG_POLLING))
+ queue_work(ata_wq, &ap->packet_task);
break;
case ATA_PROT_ATAPI_NODATA:
- ap->flags |= ATA_FLAG_NOINTR;
+ if (qc->tf.flags & ATA_TFLAG_POLLING)
+ ata_qc_set_polling(qc);
+
ata_tf_to_host_nolock(ap, &qc->tf);
- queue_work(ata_wq, &ap->packet_task);
+ ap->hsm_task_state = HSM_ST_FIRST;
+
+ /* send cdb by polling if no cdb interrupt */
+ if ((!(qc->dev->flags & ATA_DFLAG_CDB_INTR)) ||
+ (qc->tf.flags & ATA_TFLAG_POLLING))
+ queue_work(ata_wq, &ap->packet_task);
break;
case ATA_PROT_ATAPI_DMA:
- ap->flags |= ATA_FLAG_NOINTR;
+ assert(!(qc->tf.flags & ATA_TFLAG_POLLING));
+
ap->ops->tf_load(ap, &qc->tf); /* load tf registers */
ap->ops->bmdma_setup(qc); /* set up bmdma */
- queue_work(ata_wq, &ap->packet_task);
+ ap->hsm_task_state = HSM_ST_FIRST;
+
+ /* send cdb by polling if no cdb interrupt */
+ if (!(qc->dev->flags & ATA_DFLAG_CDB_INTR))
+ queue_work(ata_wq, &ap->packet_task);
break;
default:
@@ -3623,6 +3688,42 @@ void ata_bmdma_stop(struct ata_queued_cm
}
/**
+ * atapi_send_cdb - Write CDB bytes to hardware
+ * @ap: Port to which ATAPI device is attached.
+ * @qc: Taskfile currently active
+ *
+ * When device has indicated its readiness to accept
+ * a CDB, this function is called. Send the CDB.
+ *
+ * LOCKING:
+ * caller.
+ */
+
+static void atapi_send_cdb(struct ata_port *ap, struct ata_queued_cmd *qc)
+{
+ /* send SCSI cdb */
+ DPRINTK("send cdb\n");
+ assert(ap->cdb_len >= 12);
+
+ ata_data_xfer(ap, qc->cdb, ap->cdb_len, 1);
+ ata_altstatus(ap); /* flush */
+
+ switch (qc->tf.protocol) {
+ case ATA_PROT_ATAPI:
+ ap->hsm_task_state = HSM_ST;
+ break;
+ case ATA_PROT_ATAPI_NODATA:
+ ap->hsm_task_state = HSM_ST_LAST;
+ break;
+ case ATA_PROT_ATAPI_DMA:
+ ap->hsm_task_state = HSM_ST_LAST;
+ /* initiate bmdma */
+ ap->ops->bmdma_start(qc);
+ break;
+ }
+}
+
+/**
* ata_host_intr - Handle host interrupt for given (port, task)
* @ap: Port on which interrupt arrived (possibly...)
* @qc: Taskfile currently active in engine
@@ -3641,47 +3742,142 @@ void ata_bmdma_stop(struct ata_queued_cm
inline unsigned int ata_host_intr (struct ata_port *ap,
struct ata_queued_cmd *qc)
{
- u8 status, host_stat;
-
- switch (qc->tf.protocol) {
+ u8 status, host_stat = 0;
- case ATA_PROT_DMA:
- case ATA_PROT_ATAPI_DMA:
- case ATA_PROT_ATAPI:
- /* check status of DMA engine */
- host_stat = ap->ops->bmdma_status(ap);
- VPRINTK("ata%u: host_stat 0x%X\n", ap->id, host_stat);
+ VPRINTK("ata%u: protocol %d task_state %d\n",
+ ap->id, qc->tf.protocol, ap->hsm_task_state);
- /* if it's not our irq... */
- if (!(host_stat & ATA_DMA_INTR))
+ /* Check whether we are expecting interrupt in this state */
+ switch (ap->hsm_task_state) {
+ case HSM_ST_FIRST:
+ /* Check the ATA_DFLAG_CDB_INTR flag is enough here.
+ * The flag was turned on only for atapi devices.
+ * No need to check is_atapi_taskfile(&qc->tf) again.
+ */
+ if (!(qc->dev->flags & ATA_DFLAG_CDB_INTR))
goto idle_irq;
+ break;
+ case HSM_ST_LAST:
+ if (qc->tf.protocol == ATA_PROT_DMA ||
+ qc->tf.protocol == ATA_PROT_ATAPI_DMA) {
+ /* check status of DMA engine */
+ host_stat = ap->ops->bmdma_status(ap);
+ VPRINTK("ata%u: host_stat 0x%X\n", ap->id, host_stat);
+
+ /* if it's not our irq... */
+ if (!(host_stat & ATA_DMA_INTR))
+ goto idle_irq;
- /* before we do anything else, clear DMA-Start bit */
- ap->ops->bmdma_stop(qc);
+ /* before we do anything else, clear DMA-Start bit */
+ ap->ops->bmdma_stop(qc);
+ }
+ break;
+ case HSM_ST:
+ break;
+ default:
+ goto idle_irq;
+ }
- /* fall through */
+ /* check altstatus */
+ status = ata_altstatus(ap);
+ if (status & ATA_BUSY)
+ goto idle_irq;
- case ATA_PROT_ATAPI_NODATA:
- case ATA_PROT_NODATA:
- /* check altstatus */
- status = ata_altstatus(ap);
- if (status & ATA_BUSY)
- goto idle_irq;
+ /* check main status, clearing INTRQ */
+ status = ata_chk_status(ap);
+ if (unlikely(status & ATA_BUSY))
+ goto idle_irq;
- /* check main status, clearing INTRQ */
- status = ata_chk_status(ap);
- if (unlikely(status & ATA_BUSY))
- goto idle_irq;
- DPRINTK("ata%u: protocol %d (dev_stat 0x%X)\n",
- ap->id, qc->tf.protocol, status);
+ DPRINTK("ata%u: protocol %d task_state %d (dev_stat 0x%X)\n",
+ ap->id, qc->tf.protocol, ap->hsm_task_state, status);
- /* ack bmdma irq events */
- ap->ops->irq_clear(ap);
+ /* ack bmdma irq events */
+ ap->ops->irq_clear(ap);
+
+ /* check error */
+ if (unlikely((status & ATA_ERR) || (host_stat & ATA_DMA_ERR)))
+ ap->hsm_task_state = HSM_ST_ERR;
+
+fsm_start:
+ switch (ap->hsm_task_state) {
+ case HSM_ST_FIRST:
+ /* Some pre-ATAPI-4 devices assert INTRQ
+ * at this state when ready to receive CDB.
+ */
+
+ /* check device status */
+ if (unlikely((status & (ATA_BUSY | ATA_DRQ)) != ATA_DRQ)) {
+ /* Wrong status. Let EH handle this */
+ ap->hsm_task_state = HSM_ST_ERR;
+ goto fsm_start;
+ }
+
+ atapi_send_cdb(ap, qc);
+
+ break;
+
+ case HSM_ST:
+ /* complete command or read/write the data register */
+ if (qc->tf.protocol == ATA_PROT_ATAPI) {
+ /* ATAPI PIO protocol */
+ if ((status & ATA_DRQ) == 0) {
+ /* no more data to transfer */
+ ap->hsm_task_state = HSM_ST_LAST;
+ goto fsm_start;
+ }
+
+ atapi_pio_bytes(qc);
+
+ if (unlikely(ap->hsm_task_state == HSM_ST_ERR))
+ /* bad ireason reported by device */
+ goto fsm_start;
+
+ } else {
+ /* ATA PIO protocol */
+ if (unlikely((status & ATA_DRQ) == 0)) {
+ /* handle BSY=0, DRQ=0 as error */
+ ap->hsm_task_state = HSM_ST_ERR;
+ goto fsm_start;
+ }
+
+ ata_pio_sector(qc);
+
+ if (ap->hsm_task_state == HSM_ST_LAST &&
+ (!(qc->tf.flags & ATA_TFLAG_WRITE))) {
+ /* all data read */
+ ata_altstatus(ap);
+ status = ata_chk_status(ap);
+ goto fsm_start;
+ }
+ }
+
+ ata_altstatus(ap); /* flush */
+ break;
+
+ case HSM_ST_LAST:
+ if (unlikely(status & ATA_DRQ)) {
+ /* handle DRQ=1 as error */
+ ap->hsm_task_state = HSM_ST_ERR;
+ goto fsm_start;
+ }
+
+ /* no more data to transfer */
+ DPRINTK("ata%u: command complete, drv_stat 0x%x\n",
+ ap->id, status);
+
+ ap->hsm_task_state = HSM_ST_IDLE;
/* complete taskfile transaction */
ata_qc_complete(qc, status);
break;
+ case HSM_ST_ERR:
+ printk(KERN_ERR "ata%u: command error, drv_stat 0x%x host_stat 0x%x\n",
+ ap->id, status, host_stat);
+
+ ap->hsm_task_state = HSM_ST_IDLE;
+ ata_qc_complete(qc, status | ATA_ERR);
+ break;
default:
goto idle_irq;
}
@@ -3733,11 +3929,11 @@ irqreturn_t ata_interrupt (int irq, void
ap = host_set->ports[i];
if (ap &&
- !(ap->flags & (ATA_FLAG_PORT_DISABLED | ATA_FLAG_NOINTR))) {
+ !(ap->flags & ATA_FLAG_PORT_DISABLED)) {
struct ata_queued_cmd *qc;
qc = ata_qc_from_tag(ap, ap->active_tag);
- if (qc && (!(qc->tf.ctl & ATA_NIEN)) &&
+ if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING)) &&
(qc->flags & ATA_QCFLAG_ACTIVE))
handled |= ata_host_intr(ap, qc);
}
@@ -3767,6 +3963,7 @@ static void atapi_packet_task(void *_dat
struct ata_port *ap = _data;
struct ata_queued_cmd *qc;
u8 status;
+ unsigned long flags;
qc = ata_qc_from_tag(ap, ap->active_tag);
assert(qc != NULL);
@@ -3782,38 +3979,40 @@ static void atapi_packet_task(void *_dat
if ((status & (ATA_BUSY | ATA_DRQ)) != ATA_DRQ)
goto err_out;
- /* send SCSI cdb */
- DPRINTK("send cdb\n");
- assert(ap->cdb_len >= 12);
+ /* Send the CDB (atapi) or the first data block (ata pio out).
+ * During the state transition, interrupt handler shouldn't
+ * be invoked before the data transfer is complete and
+ * hsm_task_state is changed. Hence, the following locking.
+ */
+ spin_lock_irqsave(&ap->host_set->lock, flags);
- if (qc->tf.protocol == ATA_PROT_ATAPI_DMA ||
- qc->tf.protocol == ATA_PROT_ATAPI_NODATA) {
- unsigned long flags;
-
- /* Once we're done issuing command and kicking bmdma,
- * irq handler takes over. To not lose irq, we need
- * to clear NOINTR flag before sending cdb, but
- * interrupt handler shouldn't be invoked before we're
- * finished. Hence, the following locking.
- */
- spin_lock_irqsave(&ap->host_set->lock, flags);
- ap->flags &= ~ATA_FLAG_NOINTR;
- ata_data_xfer(ap, qc->cdb, ap->cdb_len, 1);
- if (qc->tf.protocol == ATA_PROT_ATAPI_DMA)
- ap->ops->bmdma_start(qc); /* initiate bmdma */
- spin_unlock_irqrestore(&ap->host_set->lock, flags);
+ if (is_atapi_taskfile(&qc->tf)) {
+ /* send CDB */
+ atapi_send_cdb(ap, qc);
+
+ if (qc->tf.flags & ATA_TFLAG_POLLING)
+ queue_work(ata_wq, &ap->pio_task);
} else {
- ata_data_xfer(ap, qc->cdb, ap->cdb_len, 1);
+ /* PIO data out protocol.
+ * send first data block.
+ */
- /* PIO commands are handled by polling */
+ /* ata_pio_sector() might change the state to HSM_ST_LAST.
+ * so, the state is changed here before ata_pio_sector().
+ */
ap->hsm_task_state = HSM_ST;
- queue_work(ata_wq, &ap->pio_task);
+ ata_pio_sector(qc);
+ ata_altstatus(ap); /* flush */
+
+ /* interrupt handler takes over from here */
}
+ spin_unlock_irqrestore(&ap->host_set->lock, flags);
+
return;
err_out:
- ata_poll_qc_complete(qc, ATA_ERR);
+ ata_pio_error(ap);
}
^ permalink raw reply [flat|nested] 77+ messages in thread
* [PATCH/RFC 4/4] libata: interrupt driven pio for LLD
2005-09-27 9:31 ` [PATCH/RFC 0/4] libata: interrupt driven pio (revised 2) Albert Lee
` (2 preceding siblings ...)
2005-09-27 9:38 ` [PATCH/RFC 3/4] libata: interrupt driven pio for libata-core Albert Lee
@ 2005-09-27 9:39 ` Albert Lee
3 siblings, 0 replies; 77+ messages in thread
From: Albert Lee @ 2005-09-27 9:39 UTC (permalink / raw)
To: Jeff Garzik
Cc: Linux IDE, Bartlomiej Zolnierkiewicz, Doug Maxey, Tejun Heo,
Mark Lord, Brett Russ
[-- Attachment #1: Type: text/plain, Size: 494 bytes --]
Patch 4/4: interrupt driven pio patch for LLD
Changes:
libata.h:
libata-core:
Add ATA_FLAG_PIO_POLLING flag for LLDs that expect interrupt for
command completion only.
sata_nv.c:
sata_vsc.c:
irq handler is wrapper around ata_host_intr(), can handle PIO interrupts.
sata_promise.c:
sata_sx4.c:
sata_qstor.c:
sata_mv.c:
Private irq handler.
Polling mode ATA_FLAG_PIO_POLLING used for compatibility.
For your review, thanks.
Albert
Signed-off-by: Albert Lee <albertcc@tw.ibm.com>
[-- Attachment #2: idpio4.diff --]
[-- Type: text/plain, Size: 8663 bytes --]
--- id3/include/linux/libata.h 2005-09-21 16:25:26.000000000 +0800
+++ id4/include/linux/libata.h 2005-09-27 14:14:41.000000000 +0800
@@ -116,6 +116,8 @@ enum {
ATA_FLAG_MMIO = (1 << 6), /* use MMIO, not PIO */
ATA_FLAG_SATA_RESET = (1 << 7), /* use COMRESET */
ATA_FLAG_PIO_DMA = (1 << 8), /* PIO cmds via DMA */
+ ATA_FLAG_PIO_POLLING = (1 << 9), /* use polling PIO if LLD
+ * doesn't handle PIO interrupts */
ATA_QCFLAG_ACTIVE = (1 << 1), /* cmd not yet ack'd to scsi lyer */
ATA_QCFLAG_SG = (1 << 3), /* have s/g table? */
--- id3/drivers/scsi/libata-core.c 2005-09-27 13:22:14.000000000 +0800
+++ id4/drivers/scsi/libata-core.c 2005-09-27 13:23:20.000000000 +0800
@@ -3356,6 +3356,25 @@ int ata_qc_issue_prot(struct ata_queued_
{
struct ata_port *ap = qc->ap;
+ /* Use polling pio if the LLD doesn't handle
+ * interrupt driven pio and atapi CDB interrupt.
+ */
+ if (ap->flags & ATA_FLAG_PIO_POLLING) {
+ switch (qc->tf.protocol) {
+ case ATA_PROT_PIO:
+ case ATA_PROT_ATAPI:
+ case ATA_PROT_ATAPI_NODATA:
+ qc->tf.flags |= ATA_TFLAG_POLLING;
+ break;
+ case ATA_PROT_ATAPI_DMA:
+ if (qc->dev->flags & ATA_DFLAG_CDB_INTR)
+ BUG();
+ break;
+ default:
+ break;
+ }
+ }
+
/* select the device */
ata_dev_select(ap, qc->dev->devno, 1, 0);
--- linux/drivers/scsi/sata_nv.c 2005-09-20 17:18:01.000000000 +0800
+++ id4/drivers/scsi/sata_nv.c 2005-09-21 17:21:02.000000000 +0800
@@ -302,11 +302,11 @@ static irqreturn_t nv_interrupt (int irq
ap = host_set->ports[i];
if (ap &&
- !(ap->flags & (ATA_FLAG_PORT_DISABLED | ATA_FLAG_NOINTR))) {
+ !(ap->flags & ATA_FLAG_PORT_DISABLED)) {
struct ata_queued_cmd *qc;
qc = ata_qc_from_tag(ap, ap->active_tag);
- if (qc && (!(qc->tf.ctl & ATA_NIEN)))
+ if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING)))
handled += ata_host_intr(ap, qc);
}
--- linux/drivers/scsi/sata_vsc.c 2005-09-20 17:18:01.000000000 +0800
+++ id4/drivers/scsi/sata_vsc.c 2005-09-21 17:21:17.000000000 +0800
@@ -193,12 +193,12 @@ static irqreturn_t vsc_sata_interrupt (i
struct ata_port *ap;
ap = host_set->ports[i];
- if (ap && !(ap->flags &
- (ATA_FLAG_PORT_DISABLED|ATA_FLAG_NOINTR))) {
+ if (ap &&
+ !(ap->flags & ATA_FLAG_PORT_DISABLED)) {
struct ata_queued_cmd *qc;
qc = ata_qc_from_tag(ap, ap->active_tag);
- if (qc && (!(qc->tf.ctl & ATA_NIEN)))
+ if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING)))
handled += ata_host_intr(ap, qc);
}
}
--- id1/drivers/scsi/sata_promise.c 2005-09-26 14:36:51.000000000 +0800
+++ id4/drivers/scsi/sata_promise.c 2005-09-27 10:33:55.000000000 +0800
@@ -162,7 +162,8 @@ static struct ata_port_info pdc_port_inf
{
.sht = &pdc_ata_sht,
.host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
- ATA_FLAG_SRST | ATA_FLAG_MMIO,
+ ATA_FLAG_SRST | ATA_FLAG_MMIO |
+ ATA_FLAG_PIO_POLLING,
.pio_mask = 0x1f, /* pio0-4 */
.mwdma_mask = 0x07, /* mwdma0-2 */
.udma_mask = 0x7f, /* udma0-6 ; FIXME */
@@ -173,7 +174,8 @@ static struct ata_port_info pdc_port_inf
{
.sht = &pdc_ata_sht,
.host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
- ATA_FLAG_SRST | ATA_FLAG_MMIO,
+ ATA_FLAG_SRST | ATA_FLAG_MMIO |
+ ATA_FLAG_PIO_POLLING,
.pio_mask = 0x1f, /* pio0-4 */
.mwdma_mask = 0x07, /* mwdma0-2 */
.udma_mask = 0x7f, /* udma0-6 ; FIXME */
@@ -184,7 +186,8 @@ static struct ata_port_info pdc_port_inf
{
.sht = &pdc_ata_sht,
.host_flags = ATA_FLAG_NO_LEGACY | ATA_FLAG_SRST |
- ATA_FLAG_MMIO | ATA_FLAG_SLAVE_POSS,
+ ATA_FLAG_MMIO | ATA_FLAG_SLAVE_POSS |
+ ATA_FLAG_PIO_POLLING,
.pio_mask = 0x1f, /* pio0-4 */
.mwdma_mask = 0x07, /* mwdma0-2 */
.udma_mask = 0x7f, /* udma0-6 ; FIXME */
@@ -493,11 +496,11 @@ static irqreturn_t pdc_interrupt (int ir
ap = host_set->ports[i];
tmp = mask & (1 << (i + 1));
if (tmp && ap &&
- !(ap->flags & (ATA_FLAG_PORT_DISABLED | ATA_FLAG_NOINTR))) {
+ !(ap->flags & ATA_FLAG_PORT_DISABLED)) {
struct ata_queued_cmd *qc;
qc = ata_qc_from_tag(ap, ap->active_tag);
- if (qc && (!(qc->tf.ctl & ATA_NIEN)))
+ if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING)))
handled += pdc_host_intr(ap, qc);
}
}
--- linux/drivers/scsi/sata_sx4.c 2005-09-20 17:18:01.000000000 +0800
+++ id4/drivers/scsi/sata_sx4.c 2005-09-27 10:34:52.000000000 +0800
@@ -219,7 +219,8 @@ static struct ata_port_info pdc_port_inf
{
.sht = &pdc_sata_sht,
.host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
- ATA_FLAG_SRST | ATA_FLAG_MMIO,
+ ATA_FLAG_SRST | ATA_FLAG_MMIO |
+ ATA_FLAG_PIO_POLLING,
.pio_mask = 0x1f, /* pio0-4 */
.mwdma_mask = 0x07, /* mwdma0-2 */
.udma_mask = 0x7f, /* udma0-6 ; FIXME */
@@ -832,11 +833,11 @@ static irqreturn_t pdc20621_interrupt (i
tmp = mask & (1 << i);
VPRINTK("seq %u, port_no %u, ap %p, tmp %x\n", i, port_no, ap, tmp);
if (tmp && ap &&
- !(ap->flags & (ATA_FLAG_PORT_DISABLED | ATA_FLAG_NOINTR))) {
+ !(ap->flags & ATA_FLAG_PORT_DISABLED)) {
struct ata_queued_cmd *qc;
qc = ata_qc_from_tag(ap, ap->active_tag);
- if (qc && (!(qc->tf.ctl & ATA_NIEN)))
+ if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING)))
handled += pdc20621_host_intr(ap, qc, (i > 4),
mmio_base);
}
--- linux/drivers/scsi/sata_qstor.c 2005-09-20 17:18:01.000000000 +0800
+++ id4/drivers/scsi/sata_qstor.c 2005-09-26 17:35:08.000000000 +0800
@@ -175,7 +175,7 @@ static struct ata_port_info qs_port_info
.host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
ATA_FLAG_SATA_RESET |
//FIXME ATA_FLAG_SRST |
- ATA_FLAG_MMIO,
+ ATA_FLAG_MMIO | ATA_FLAG_PIO_POLLING,
.pio_mask = 0x10, /* pio4 */
.udma_mask = 0x7f, /* udma0-6 */
.port_ops = &qs_ata_ops,
@@ -389,14 +389,13 @@ static inline unsigned int qs_intr_pkt(s
DPRINTK("SFF=%08x%08x: sCHAN=%u sHST=%d sDST=%02x\n",
sff1, sff0, port_no, sHST, sDST);
handled = 1;
- if (ap && !(ap->flags &
- (ATA_FLAG_PORT_DISABLED|ATA_FLAG_NOINTR))) {
+ if (ap && !(ap->flags & ATA_FLAG_PORT_DISABLED)) {
struct ata_queued_cmd *qc;
struct qs_port_priv *pp = ap->private_data;
if (!pp || pp->state != qs_state_pkt)
continue;
qc = ata_qc_from_tag(ap, ap->active_tag);
- if (qc && (!(qc->tf.ctl & ATA_NIEN))) {
+ if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING))) {
switch (sHST) {
case 0: /* sucessful CPB */
case 3: /* device error */
@@ -422,13 +421,13 @@ static inline unsigned int qs_intr_mmio(
struct ata_port *ap;
ap = host_set->ports[port_no];
if (ap &&
- !(ap->flags & (ATA_FLAG_PORT_DISABLED | ATA_FLAG_NOINTR))) {
+ !(ap->flags & ATA_FLAG_PORT_DISABLED)) {
struct ata_queued_cmd *qc;
struct qs_port_priv *pp = ap->private_data;
if (!pp || pp->state != qs_state_mmio)
continue;
qc = ata_qc_from_tag(ap, ap->active_tag);
- if (qc && (!(qc->tf.ctl & ATA_NIEN))) {
+ if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING))) {
/* check main status, clearing INTRQ */
u8 status = ata_chk_status(ap);
--- linux/drivers/scsi/sata_mv.c 2005-09-20 17:18:01.000000000 +0800
+++ id4/drivers/scsi/sata_mv.c 2005-09-26 17:36:09.000000000 +0800
@@ -241,7 +241,8 @@ static struct ata_port_info mv_port_info
{ /* chip_504x */
.sht = &mv_sht,
.host_flags = (ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
- ATA_FLAG_SATA_RESET | ATA_FLAG_MMIO),
+ ATA_FLAG_SATA_RESET | ATA_FLAG_MMIO |
+ ATA_FLAG_PIO_POLLING),
.pio_mask = 0x1f, /* pio4-0 */
.udma_mask = 0, /* 0x7f (udma6-0 disabled for now) */
.port_ops = &mv_ops,
@@ -250,7 +251,7 @@ static struct ata_port_info mv_port_info
.sht = &mv_sht,
.host_flags = (ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
ATA_FLAG_SATA_RESET | ATA_FLAG_MMIO |
- MV_FLAG_DUAL_HC),
+ ATA_FLAG_PIO_POLLING | MV_FLAG_DUAL_HC),
.pio_mask = 0x1f, /* pio4-0 */
.udma_mask = 0, /* 0x7f (udma6-0 disabled for now) */
.port_ops = &mv_ops,
@@ -259,6 +260,7 @@ static struct ata_port_info mv_port_info
.sht = &mv_sht,
.host_flags = (ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
ATA_FLAG_SATA_RESET | ATA_FLAG_MMIO |
+ ATA_FLAG_PIO_POLLING |
MV_FLAG_IRQ_COALESCE | MV_FLAG_BDMA),
.pio_mask = 0x1f, /* pio4-0 */
.udma_mask = 0, /* 0x7f (udma6-0 disabled for now) */
@@ -268,6 +270,7 @@ static struct ata_port_info mv_port_info
.sht = &mv_sht,
.host_flags = (ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
ATA_FLAG_SATA_RESET | ATA_FLAG_MMIO |
+ ATA_FLAG_PIO_POLLING |
MV_FLAG_IRQ_COALESCE | MV_FLAG_DUAL_HC |
MV_FLAG_BDMA),
.pio_mask = 0x1f, /* pio4-0 */
^ permalink raw reply [flat|nested] 77+ messages in thread
* Re: [PATCH/RFC 2/4] libata: rename host states
2005-09-27 9:36 ` [PATCH/RFC 2/4] libata: rename host states Albert Lee
@ 2005-09-28 15:59 ` Jeff Garzik
0 siblings, 0 replies; 77+ messages in thread
From: Jeff Garzik @ 2005-09-28 15:59 UTC (permalink / raw)
To: Albert Lee
Cc: Linux IDE, Bartlomiej Zolnierkiewicz, Doug Maxey, Tejun Heo,
Mark Lord, Brett Russ
merged patches 1-2 into upstream branch of libata-dev.git
^ permalink raw reply [flat|nested] 77+ messages in thread
* Re: [PATCH/RFC 3/4] libata: interrupt driven pio for libata-core
2005-09-27 9:38 ` [PATCH/RFC 3/4] libata: interrupt driven pio for libata-core Albert Lee
@ 2005-09-28 16:09 ` Jeff Garzik
2005-09-29 10:08 ` Bartlomiej Zolnierkiewicz
1 sibling, 0 replies; 77+ messages in thread
From: Jeff Garzik @ 2005-09-28 16:09 UTC (permalink / raw)
To: Albert Lee
Cc: Linux IDE, Bartlomiej Zolnierkiewicz, Doug Maxey, Tejun Heo,
Mark Lord, Brett Russ
applied patches 3-4 to 'irq-pio' branch of libata-dev.git.
After verifying that EVERY driver continues to work, we can merge this
upstream. This change will need a lot of testing.
Also, note that adding support for READ/WRITE MULTIPLE SECTORS would be
nice. This will involve slight changes to the PIO code, and a SET
MULTIPLE MODE command during probe time.
Thanks for working on this!
^ permalink raw reply [flat|nested] 77+ messages in thread
* Re: [PATCH/RFC 3/4] libata: interrupt driven pio for libata-core
2005-09-27 9:38 ` [PATCH/RFC 3/4] libata: interrupt driven pio for libata-core Albert Lee
2005-09-28 16:09 ` Jeff Garzik
@ 2005-09-29 10:08 ` Bartlomiej Zolnierkiewicz
2005-09-30 8:02 ` Albert Lee
2005-09-30 11:04 ` [PATCH/RFC 0/4] libata: irq driven pio follow-up patches Albert Lee
1 sibling, 2 replies; 77+ messages in thread
From: Bartlomiej Zolnierkiewicz @ 2005-09-29 10:08 UTC (permalink / raw)
To: Albert Lee
Cc: Jeff Garzik, Linux IDE, Doug Maxey, Tejun Heo, Mark Lord,
Brett Russ
Hi,
On 9/27/05, Albert Lee <albertcc@tw.ibm.com> wrote:
> Patch 3/4: interrupt driven pio for libata-core
>
> Changes:
> - add PIO_ST_FIRST for the state before sending ATAPI CDB or sending
HSM_ST_FIRST
Could you add some brief comments about HSM_* states
(one line per state should be OK)?
> @@ -3344,43 +3356,96 @@ int ata_qc_issue_prot(struct ata_queued_
> {
> struct ata_port *ap = qc->ap;
>
> + /* select the device */
> ata_dev_select(ap, qc->dev->devno, 1, 0);
>
> + /* start the command */
> switch (qc->tf.protocol) {
> case ATA_PROT_NODATA:
> + if (qc->tf.flags & ATA_TFLAG_POLLING)
> + ata_qc_set_polling(qc);
> +
> ata_tf_to_host_nolock(ap, &qc->tf);
> + ap->hsm_task_state = HSM_ST_LAST;
> +
> + if (qc->tf.flags & ATA_TFLAG_POLLING)
> + queue_work(ata_wq, &ap->pio_task);
> +
> break;
>
> case ATA_PROT_DMA:
> + assert(!(qc->tf.flags & ATA_TFLAG_POLLING));
> +
> ap->ops->tf_load(ap, &qc->tf); /* load tf registers */
> ap->ops->bmdma_setup(qc); /* set up bmdma */
> ap->ops->bmdma_start(qc); /* initiate bmdma */
> + ap->hsm_task_state = HSM_ST_LAST;
> break;
>
> - case ATA_PROT_PIO: /* load tf registers, initiate polling pio */
> - ata_qc_set_polling(qc);
> + case ATA_PROT_PIO:
> + if (qc->tf.flags & ATA_TFLAG_POLLING)
> + ata_qc_set_polling(qc);
> +
> ata_tf_to_host_nolock(ap, &qc->tf);
> - ap->hsm_task_state = HSM_ST;
> - queue_work(ata_wq, &ap->pio_task);
> +
> + if (qc->tf.flags & ATA_TFLAG_POLLING) {
> + /* polling PIO */
> + ap->hsm_task_state = HSM_ST;
> + queue_work(ata_wq, &ap->pio_task);
> + } else {
> + /* interrupt driven PIO */
> + if (qc->tf.flags & ATA_TFLAG_WRITE) {
> + /* PIO data out protocol */
> + ap->hsm_task_state = HSM_ST_FIRST;
> + queue_work(ata_wq, &ap->packet_task);
atapi_packet_task() is now abused to do ATA PIO out which is
very confusing given that name of the function (and all the comments)
remains unchanged. Please correct it (I think it would be good idea to
separate HSM_ST_CDB from HSM_ST_FIRST).
> case ATA_PROT_ATAPI:
> - ata_qc_set_polling(qc);
> + if (qc->tf.flags & ATA_TFLAG_POLLING)
> + ata_qc_set_polling(qc);
> +
> ata_tf_to_host_nolock(ap, &qc->tf);
> - queue_work(ata_wq, &ap->packet_task);
> + ap->hsm_task_state = HSM_ST_FIRST;
> +
> + /* send cdb by polling if no cdb interrupt */
> + if ((!(qc->dev->flags & ATA_DFLAG_CDB_INTR)) ||
> + (qc->tf.flags & ATA_TFLAG_POLLING))
> + queue_work(ata_wq, &ap->packet_task);
> break;
>
> case ATA_PROT_ATAPI_NODATA:
> - ap->flags |= ATA_FLAG_NOINTR;
> + if (qc->tf.flags & ATA_TFLAG_POLLING)
> + ata_qc_set_polling(qc);
> +
> ata_tf_to_host_nolock(ap, &qc->tf);
> - queue_work(ata_wq, &ap->packet_task);
> + ap->hsm_task_state = HSM_ST_FIRST;
> +
> + /* send cdb by polling if no cdb interrupt */
> + if ((!(qc->dev->flags & ATA_DFLAG_CDB_INTR)) ||
> + (qc->tf.flags & ATA_TFLAG_POLLING))
> + queue_work(ata_wq, &ap->packet_task);
> break;
ATA_PROT_ATAPI_NODATA case is now identical
to ATA_PROT_ATAPI one - no need to duplicate code.
It may be also worth to split ata_qc_issue_prot() on IRQ
and polling versions because it is really hard to read now.
> +/**
> * ata_host_intr - Handle host interrupt for given (port, task)
> * @ap: Port on which interrupt arrived (possibly...)
> * @qc: Taskfile currently active in engine
> @@ -3641,47 +3742,142 @@ void ata_bmdma_stop(struct ata_queued_cm
> inline unsigned int ata_host_intr (struct ata_port *ap,
> struct ata_queued_cmd *qc)
> {
We should check first if we are polling and if so we shouldn't touch hardware
et all as we can interface with ata_pio_task or atapi_packet_task. Just think
about HSM_ST case when hardware is ready for the next transfer and IRQ
happens (from some other device).
Please note that this bug is present in original libata code.
> - u8 status, host_stat;
> -
> - switch (qc->tf.protocol) {
> + u8 status, host_stat = 0;
>
> - case ATA_PROT_DMA:
> - case ATA_PROT_ATAPI_DMA:
> - case ATA_PROT_ATAPI:
Your patch changes behavior for ATA_PROT_ATAPI case - now DMA
engine won't be checked. We had discussion about fixing it before
but I don't remember what was the conclusion - in any case it is worth
to at least mention this change in the patch description.
> - /* check status of DMA engine */
> - host_stat = ap->ops->bmdma_status(ap);
> - VPRINTK("ata%u: host_stat 0x%X\n", ap->id, host_stat);
> + VPRINTK("ata%u: protocol %d task_state %d\n",
> + ap->id, qc->tf.protocol, ap->hsm_task_state);
>
> - /* if it's not our irq... */
> - if (!(host_stat & ATA_DMA_INTR))
> + /* Check whether we are expecting interrupt in this state */
> + switch (ap->hsm_task_state) {
> + case HSM_ST_FIRST:
> + /* Check the ATA_DFLAG_CDB_INTR flag is enough here.
> + * The flag was turned on only for atapi devices.
> + * No need to check is_atapi_taskfile(&qc->tf) again.
> + */
> + if (!(qc->dev->flags & ATA_DFLAG_CDB_INTR))
> goto idle_irq;
> + break;
> + case HSM_ST_LAST:
> + if (qc->tf.protocol == ATA_PROT_DMA ||
> + qc->tf.protocol == ATA_PROT_ATAPI_DMA) {
> + /* check status of DMA engine */
> + host_stat = ap->ops->bmdma_status(ap);
> + VPRINTK("ata%u: host_stat 0x%X\n", ap->id, host_stat);
> +
> + /* if it's not our irq... */
> + if (!(host_stat & ATA_DMA_INTR))
> + goto idle_irq;
>
> - /* before we do anything else, clear DMA-Start bit */
> - ap->ops->bmdma_stop(qc);
> + /* before we do anything else, clear DMA-Start bit */
> + ap->ops->bmdma_stop(qc);
> + }
> + break;
> + case HSM_ST:
> + break;
> + default:
> + goto idle_irq;
> + }
>
> - /* fall through */
> + /* check altstatus */
> + status = ata_altstatus(ap);
> + if (status & ATA_BUSY)
> + goto idle_irq;
>
> - case ATA_PROT_ATAPI_NODATA:
> - case ATA_PROT_NODATA:
> - /* check altstatus */
> - status = ata_altstatus(ap);
> - if (status & ATA_BUSY)
> - goto idle_irq;
> + /* check main status, clearing INTRQ */
> + status = ata_chk_status(ap);
> + if (unlikely(status & ATA_BUSY))
> + goto idle_irq;
>
> - /* check main status, clearing INTRQ */
> - status = ata_chk_status(ap);
> - if (unlikely(status & ATA_BUSY))
> - goto idle_irq;
> - DPRINTK("ata%u: protocol %d (dev_stat 0x%X)\n",
> - ap->id, qc->tf.protocol, status);
> + DPRINTK("ata%u: protocol %d task_state %d (dev_stat 0x%X)\n",
> + ap->id, qc->tf.protocol, ap->hsm_task_state, status);
>
> - /* ack bmdma irq events */
> - ap->ops->irq_clear(ap);
> + /* ack bmdma irq events */
> + ap->ops->irq_clear(ap);
> +
> + /* check error */
> + if (unlikely((status & ATA_ERR) || (host_stat & ATA_DMA_ERR)))
> + ap->hsm_task_state = HSM_ST_ERR;
> +
> +fsm_start:
> + switch (ap->hsm_task_state) {
> + case HSM_ST_FIRST:
> + /* Some pre-ATAPI-4 devices assert INTRQ
> + * at this state when ready to receive CDB.
> + */
> +
> + /* check device status */
> + if (unlikely((status & (ATA_BUSY | ATA_DRQ)) != ATA_DRQ)) {
> + /* Wrong status. Let EH handle this */
> + ap->hsm_task_state = HSM_ST_ERR;
> + goto fsm_start;
> + }
> +
> + atapi_send_cdb(ap, qc);
This case can happen also for ATA PIO out:
ata_qc_issue_prot() -> IRQ happens -> ata_host_intr().
Sending CDB unconditionally is wrong.
The rest of the patch looks fine but it is was quite difficult to review
because you've combined two major logical changes into one patch:
* switching libata to use host state information
* adding support for IRQ driven PIO
Thanks,
Bartlomiej
^ permalink raw reply [flat|nested] 77+ messages in thread
* Re: [PATCH/RFC 3/4] libata: interrupt driven pio for libata-core
2005-09-29 10:08 ` Bartlomiej Zolnierkiewicz
@ 2005-09-30 8:02 ` Albert Lee
2005-09-30 9:28 ` Bartlomiej Zolnierkiewicz
2005-09-30 11:04 ` [PATCH/RFC 0/4] libata: irq driven pio follow-up patches Albert Lee
1 sibling, 1 reply; 77+ messages in thread
From: Albert Lee @ 2005-09-30 8:02 UTC (permalink / raw)
To: Bartlomiej Zolnierkiewicz
Cc: Jeff Garzik, Linux IDE, Doug Maxey, Tejun Heo, Mark Lord,
Brett Russ
Hi Bart:
>Hi,
>
>On 9/27/05, Albert Lee <albertcc@tw.ibm.com> wrote:
>
>
>>Patch 3/4: interrupt driven pio for libata-core
>>
>>Changes:
>>- add PIO_ST_FIRST for the state before sending ATAPI CDB or sending
>>
>>
>
>HSM_ST_FIRST
>
>Could you add some brief comments about HSM_* states
>(one line per state should be OK)?
>
>
Hmm, will add the comments in the follow up patch.
>
>
>>@@ -3344,43 +3356,96 @@ int ata_qc_issue_prot(struct ata_queued_
>> {
>> struct ata_port *ap = qc->ap;
>>
>>+ } else {
>>+ /* interrupt driven PIO */
>>+ if (qc->tf.flags & ATA_TFLAG_WRITE) {
>>+ /* PIO data out protocol */
>>+ ap->hsm_task_state = HSM_ST_FIRST;
>>+ queue_work(ata_wq, &ap->packet_task);
>>
>>
>
>atapi_packet_task() is now abused to do ATA PIO out which is
>very confusing given that name of the function (and all the comments)
>remains unchanged. Please correct it (I think it would be good idea to
>separate HSM_ST_CDB from HSM_ST_FIRST).
>
>
You're right, will rename the atapi_packet_task() and revise the related
variable and comments.
HSM_ST_CDB and HSM_ST_FIRST are almost the same except the content of
the data being sent.
Could we keep them as one state?
>
>
>> case ATA_PROT_ATAPI:
>>- ata_qc_set_polling(qc);
>>+ if (qc->tf.flags & ATA_TFLAG_POLLING)
>>+ ata_qc_set_polling(qc);
>>+
>> ata_tf_to_host_nolock(ap, &qc->tf);
>>- queue_work(ata_wq, &ap->packet_task);
>>+ ap->hsm_task_state = HSM_ST_FIRST;
>>+
>>+ /* send cdb by polling if no cdb interrupt */
>>+ if ((!(qc->dev->flags & ATA_DFLAG_CDB_INTR)) ||
>>+ (qc->tf.flags & ATA_TFLAG_POLLING))
>>+ queue_work(ata_wq, &ap->packet_task);
>> break;
>>
>> case ATA_PROT_ATAPI_NODATA:
>>- ap->flags |= ATA_FLAG_NOINTR;
>>+ if (qc->tf.flags & ATA_TFLAG_POLLING)
>>+ ata_qc_set_polling(qc);
>>+
>> ata_tf_to_host_nolock(ap, &qc->tf);
>>- queue_work(ata_wq, &ap->packet_task);
>>+ ap->hsm_task_state = HSM_ST_FIRST;
>>+
>>+ /* send cdb by polling if no cdb interrupt */
>>+ if ((!(qc->dev->flags & ATA_DFLAG_CDB_INTR)) ||
>>+ (qc->tf.flags & ATA_TFLAG_POLLING))
>>+ queue_work(ata_wq, &ap->packet_task);
>> break;
>>
>>
>
>ATA_PROT_ATAPI_NODATA case is now identical
>to ATA_PROT_ATAPI one - no need to duplicate code.
>
>It may be also worth to split ata_qc_issue_prot() on IRQ
>and polling versions because it is really hard to read now.
>
>
Nice catch, will remove the redundant code.
will also cleanup the ata_qc_issue_prot() code to simplify the PIO data
out codepath.
(Hopefully the simplified ata_qc_issue_prot() is easier to read and we
could have one version for both polling and IRQ version.)
>
>
>>+/**
>> * ata_host_intr - Handle host interrupt for given (port, task)
>> * @ap: Port on which interrupt arrived (possibly...)
>> * @qc: Taskfile currently active in engine
>>@@ -3641,47 +3742,142 @@ void ata_bmdma_stop(struct ata_queued_cm
>> inline unsigned int ata_host_intr (struct ata_port *ap,
>> struct ata_queued_cmd *qc)
>> {
>>
>>
>
>We should check first if we are polling and if so we shouldn't touch hardware
>et all as we can interface with ata_pio_task or atapi_packet_task. Just think
>about HSM_ST case when hardware is ready for the next transfer and IRQ
>happens (from some other device).
>
>Please note that this bug is present in original libata code.
>
>
>
The (qc->tf.flags & ATA_TFLAG_POLLING) flag is checked in ata_interrupt().
So, the race between the irq handler and ata_pio_task() is avoided.
When the state is HSM_ST_FIRST, ata_host_intr() checks the
(qc->dev->flags & ATA_DFLAG_CDB_INTR) flag.
Also in atapi_packet_task(), the host lock is aquired during the state
transition from HSM_ST_FIRST to next state.
So, the race between the irq handler and atapi_packet_task() is avoided.
>>- u8 status, host_stat;
>>-
>>- switch (qc->tf.protocol) {
>>+ u8 status, host_stat = 0;
>>
>>- case ATA_PROT_DMA:
>>- case ATA_PROT_ATAPI_DMA:
>>- case ATA_PROT_ATAPI:
>>
>>
>
>Your patch changes behavior for ATA_PROT_ATAPI case - now DMA
>engine won't be checked. We had discussion about fixing it before
>but I don't remember what was the conclusion - in any case it is worth
>to at least mention this change in the patch description.
>
>
>
Sorry I forgot to mention it in the description of previous patch
For the ATA_PROT_ATAPI case, the behavior is changed in the irq handler:
- The DMA status register is no longer checked.
- HSM state and device busy flag are used together to see whether it
is our irq or not.
This new behavior seems to be working ok on my test machine.
However, not sure whether this 100% works on all hardware.
Need more test and comment.
>>- /* check status of DMA engine */
>>- host_stat = ap->ops->bmdma_status(ap);
>>- VPRINTK("ata%u: host_stat 0x%X\n", ap->id, host_stat);
>>+ VPRINTK("ata%u: protocol %d task_state %d\n",
>>+ ap->id, qc->tf.protocol, ap->hsm_task_state);
>>
>>- /* if it's not our irq... */
>>- if (!(host_stat & ATA_DMA_INTR))
>>+ /* Check whether we are expecting interrupt in this state */
>>+ switch (ap->hsm_task_state) {
>>+ case HSM_ST_FIRST:
>>+ /* Check the ATA_DFLAG_CDB_INTR flag is enough here.
>>+ * The flag was turned on only for atapi devices.
>>+ * No need to check is_atapi_taskfile(&qc->tf) again.
>>+ */
>>+ if (!(qc->dev->flags & ATA_DFLAG_CDB_INTR))
>> goto idle_irq;
>>+ break;
>>... (snip) ...
>>+
>>+
>>+fsm_start:
>>+ switch (ap->hsm_task_state) {
>>+ case HSM_ST_FIRST:
>>+ /* Some pre-ATAPI-4 devices assert INTRQ
>>+ * at this state when ready to receive CDB.
>>+ */
>>+
>>+ /* check device status */
>>+ if (unlikely((status & (ATA_BUSY | ATA_DRQ)) != ATA_DRQ)) {
>>+ /* Wrong status. Let EH handle this */
>>+ ap->hsm_task_state = HSM_ST_ERR;
>>+ goto fsm_start;
>>+ }
>>+
>>+ atapi_send_cdb(ap, qc);
>>
>>
>
>This case can happen also for ATA PIO out:
>ata_qc_issue_prot() -> IRQ happens -> ata_host_intr().
>
>Sending CDB unconditionally is wrong.
>
>
>
>
The (qc->dev->flags & ATA_DFLAG_CDB_INTR) flag is only turned on for
atapi devices.
So, when we are in the HSM_ST_FIRST state, ATA devices are filtered out
and won't enter the irq handler.
Thanks for the review and advice, will revise and send follow up patch
later.
(Will also have look at the READ/WRITE MULTIPLE mentioned by Jeff.)
Albert
^ permalink raw reply [flat|nested] 77+ messages in thread
* Re: [PATCH/RFC 3/4] libata: interrupt driven pio for libata-core
2005-09-30 8:02 ` Albert Lee
@ 2005-09-30 9:28 ` Bartlomiej Zolnierkiewicz
2005-09-30 11:28 ` Albert Lee
0 siblings, 1 reply; 77+ messages in thread
From: Bartlomiej Zolnierkiewicz @ 2005-09-30 9:28 UTC (permalink / raw)
To: Albert Lee
Cc: Jeff Garzik, Linux IDE, Doug Maxey, Tejun Heo, Mark Lord,
Brett Russ
Hi,
On 9/30/05, Albert Lee <albertcc@tw.ibm.com> wrote:
> >>+/**
> >> * ata_host_intr - Handle host interrupt for given (port, task)
> >> * @ap: Port on which interrupt arrived (possibly...)
> >> * @qc: Taskfile currently active in engine
> >>@@ -3641,47 +3742,142 @@ void ata_bmdma_stop(struct ata_queued_cm
> >> inline unsigned int ata_host_intr (struct ata_port *ap,
> >> struct ata_queued_cmd *qc)
> >> {
> >>
> >>
> >
> >We should check first if we are polling and if so we shouldn't touch hardware
> >et all as we can interface with ata_pio_task or atapi_packet_task. Just think
> >about HSM_ST case when hardware is ready for the next transfer and IRQ
> >happens (from some other device).
> >
> >Please note that this bug is present in original libata code.
> >
> >
> >
> The (qc->tf.flags & ATA_TFLAG_POLLING) flag is checked in ata_interrupt().
> So, the race between the irq handler and ata_pio_task() is avoided.
You are right, I completely forgot about ata_interrupt(). :-)
> When the state is HSM_ST_FIRST, ata_host_intr() checks the
> (qc->dev->flags & ATA_DFLAG_CDB_INTR) flag.
> Also in atapi_packet_task(), the host lock is aquired during the state
> transition from HSM_ST_FIRST to next state.
> So, the race between the irq handler and atapi_packet_task() is avoided.
What about ATAPI device with !dev->flags & ATA_DFLAG_CDB_INTR)?
Shouldn't we do spin_lock_irqsave() in atapi_packet_task() before
actually touching hardware?
> >>+fsm_start:
> >>+ switch (ap->hsm_task_state) {
> >>+ case HSM_ST_FIRST:
> >>+ /* Some pre-ATAPI-4 devices assert INTRQ
> >>+ * at this state when ready to receive CDB.
> >>+ */
> >>+
> >>+ /* check device status */
> >>+ if (unlikely((status & (ATA_BUSY | ATA_DRQ)) != ATA_DRQ)) {
> >>+ /* Wrong status. Let EH handle this */
> >>+ ap->hsm_task_state = HSM_ST_ERR;
> >>+ goto fsm_start;
> >>+ }
> >>+
> >>+ atapi_send_cdb(ap, qc);
> >>
> >>
> >
> >This case can happen also for ATA PIO out:
> >ata_qc_issue_prot() -> IRQ happens -> ata_host_intr().
> >
> >Sending CDB unconditionally is wrong.
> >
> >
> >
> >
> The (qc->dev->flags & ATA_DFLAG_CDB_INTR) flag is only turned on for
> atapi devices.
> So, when we are in the HSM_ST_FIRST state, ATA devices are filtered out
> and won't enter the irq handler.
Yep, you are right, so we can keep one state (HSM_ST_FIRST)
for ATA and ATAPI.
> Thanks for the review and advice, will revise and send follow up patch
> later.
> (Will also have look at the READ/WRITE MULTIPLE mentioned by Jeff.)
Thanks for working on this.
Bartlomiej
^ permalink raw reply [flat|nested] 77+ messages in thread
* [PATCH/RFC 0/4] libata: irq driven pio follow-up patches
2005-09-29 10:08 ` Bartlomiej Zolnierkiewicz
2005-09-30 8:02 ` Albert Lee
@ 2005-09-30 11:04 ` Albert Lee
2005-09-30 11:07 ` [PATCH/RFC 1/4] irq-pio: add comments and cleanup Albert Lee
` (4 more replies)
1 sibling, 5 replies; 77+ messages in thread
From: Albert Lee @ 2005-09-30 11:04 UTC (permalink / raw)
To: Bartlomiej Zolnierkiewicz, Jeff Garzik
Cc: Linux IDE, Doug Maxey, Tejun Heo, Mark Lord, Brett Russ
Dear all,
The irq driven PIO follow up patches per Bart's advice.
patch 1/4:
- add comments for HSM_ST_*
ata_qc_issue_prot():
- remove the redundant code for the ATA_PROT_ATAPI case.
patch 2/4:
- rename atapi_packet_task() to ata_dataout_task() and change comments
patch 3/4:
- simplify if condition in ata_dataout_task():
Use if (qc->tf.protocol == ATA_PROT_PIO) instead of
is_atapi_taskfile()
patch 4/4:
ata_qc_issue_prot():
- let the PIO data out case always go through the ata_dataout_task()
codepath.
ata_dataout_task():
- handle the PIO data out + polling case.
Patch against libata-dev irq-pio tree
(e50362eccd8809a224cda5f71714a088ba37b2ab).
For your review and advice, thanks.
Albert
^ permalink raw reply [flat|nested] 77+ messages in thread
* [PATCH/RFC 1/4] irq-pio: add comments and cleanup
2005-09-30 11:04 ` [PATCH/RFC 0/4] libata: irq driven pio follow-up patches Albert Lee
@ 2005-09-30 11:07 ` Albert Lee
2005-09-30 11:09 ` [PATCH/RFC 2/4] irq-pio: rename atapi_packet_task() and comments Albert Lee
` (3 subsequent siblings)
4 siblings, 0 replies; 77+ messages in thread
From: Albert Lee @ 2005-09-30 11:07 UTC (permalink / raw)
To: Bartlomiej Zolnierkiewicz, Jeff Garzik
Cc: Linux IDE, Doug Maxey, Tejun Heo, Mark Lord, Brett Russ
[-- Attachment #1: Type: text/plain, Size: 134 bytes --]
Patch 1/4: add comments and remove redundant code
For your review, thanks.
Albert
Signed-off-by: Albert Lee <albertcc@tw.ibm.com>
[-- Attachment #2: idpio1.diff --]
[-- Type: text/plain, Size: 1515 bytes --]
--- irq-pio/include/linux/libata.h 2005-09-30 10:00:31.000000000 +0800
+++ id1/include/linux/libata.h 2005-09-30 17:49:24.000000000 +0800
@@ -158,15 +158,16 @@ enum {
};
enum hsm_task_states {
- HSM_ST_UNKNOWN,
- HSM_ST_IDLE,
- HSM_ST_POLL,
- HSM_ST_TMOUT,
- HSM_ST,
- HSM_ST_LAST,
- HSM_ST_LAST_POLL,
- HSM_ST_ERR,
- HSM_ST_FIRST,
+ HSM_ST_UNKNOWN, /* state unknown */
+ HSM_ST_IDLE, /* no command on going */
+ HSM_ST_POLL, /* same as HSM_ST, waits longer */
+ HSM_ST_TMOUT, /* timeout */
+ HSM_ST, /* (waiting the device to) transfer data */
+ HSM_ST_LAST, /* (waiting the device to) complete command */
+ HSM_ST_LAST_POLL, /* same as HSM_ST_LAST, waits longer */
+ HSM_ST_ERR, /* error */
+ HSM_ST_FIRST, /* (waiting the device to)
+ write CDB or first data block */
};
/* forward declarations */
--- irq-pio/drivers/scsi/libata-core.c 2005-09-30 10:00:04.000000000 +0800
+++ id1/drivers/scsi/libata-core.c 2005-09-30 14:31:28.000000000 +0800
@@ -3430,18 +3430,6 @@ int ata_qc_issue_prot(struct ata_queued_
break;
case ATA_PROT_ATAPI:
- if (qc->tf.flags & ATA_TFLAG_POLLING)
- ata_qc_set_polling(qc);
-
- ata_tf_to_host_nolock(ap, &qc->tf);
- ap->hsm_task_state = HSM_ST_FIRST;
-
- /* send cdb by polling if no cdb interrupt */
- if ((!(qc->dev->flags & ATA_DFLAG_CDB_INTR)) ||
- (qc->tf.flags & ATA_TFLAG_POLLING))
- queue_work(ata_wq, &ap->packet_task);
- break;
-
case ATA_PROT_ATAPI_NODATA:
if (qc->tf.flags & ATA_TFLAG_POLLING)
ata_qc_set_polling(qc);
^ permalink raw reply [flat|nested] 77+ messages in thread
* [PATCH/RFC 2/4] irq-pio: rename atapi_packet_task() and comments
2005-09-30 11:04 ` [PATCH/RFC 0/4] libata: irq driven pio follow-up patches Albert Lee
2005-09-30 11:07 ` [PATCH/RFC 1/4] irq-pio: add comments and cleanup Albert Lee
@ 2005-09-30 11:09 ` Albert Lee
2005-09-30 11:11 ` [PATCH/RFC 3/4] irq-pio: simplify if condition in ata_dataout_task() Albert Lee
` (2 subsequent siblings)
4 siblings, 0 replies; 77+ messages in thread
From: Albert Lee @ 2005-09-30 11:09 UTC (permalink / raw)
To: Bartlomiej Zolnierkiewicz, Jeff Garzik
Cc: Linux IDE, Doug Maxey, Tejun Heo, Mark Lord, Brett Russ
[-- Attachment #1: Type: text/plain, Size: 141 bytes --]
Patch 2/4: rename atapi_packet_task() and change comments
For your review, thanks.
Albert
Signed-off-by: Albert Lee <albertcc@tw.ibm.com>
[-- Attachment #2: idpio2.diff --]
[-- Type: text/plain, Size: 3342 bytes --]
--- id1/include/linux/libata.h 2005-09-30 17:49:24.000000000 +0800
+++ id2/include/linux/libata.h 2005-09-30 17:48:55.000000000 +0800
@@ -129,8 +129,8 @@ enum {
ATA_TMOUT_PIO = 30 * HZ,
ATA_TMOUT_BOOT = 30 * HZ, /* hueristic */
ATA_TMOUT_BOOT_QUICK = 7 * HZ, /* hueristic */
- ATA_TMOUT_CDB = 30 * HZ,
- ATA_TMOUT_CDB_QUICK = 5 * HZ,
+ ATA_TMOUT_DATAOUT = 30 * HZ,
+ ATA_TMOUT_DATAOUT_QUICK = 5 * HZ,
/* ATA bus states */
BUS_UNKNOWN = 0,
@@ -319,7 +319,7 @@ struct ata_port {
struct ata_host_stats stats;
struct ata_host_set *host_set;
- struct work_struct packet_task;
+ struct work_struct dataout_task;
struct work_struct pio_task;
unsigned int hsm_task_state;
--- id1/drivers/scsi/libata-core.c 2005-09-30 14:31:28.000000000 +0800
+++ id2/drivers/scsi/libata-core.c 2005-09-30 18:04:29.000000000 +0800
@@ -3416,7 +3416,7 @@ int ata_qc_issue_prot(struct ata_queued_
if (qc->tf.flags & ATA_TFLAG_WRITE) {
/* PIO data out protocol */
ap->hsm_task_state = HSM_ST_FIRST;
- queue_work(ata_wq, &ap->packet_task);
+ queue_work(ata_wq, &ap->dataout_task);
/* send first data block by polling */
} else {
@@ -3440,7 +3440,7 @@ int ata_qc_issue_prot(struct ata_queued_
/* send cdb by polling if no cdb interrupt */
if ((!(qc->dev->flags & ATA_DFLAG_CDB_INTR)) ||
(qc->tf.flags & ATA_TFLAG_POLLING))
- queue_work(ata_wq, &ap->packet_task);
+ queue_work(ata_wq, &ap->dataout_task);
break;
case ATA_PROT_ATAPI_DMA:
@@ -3452,7 +3452,7 @@ int ata_qc_issue_prot(struct ata_queued_
/* send cdb by polling if no cdb interrupt */
if (!(qc->dev->flags & ATA_DFLAG_CDB_INTR))
- queue_work(ata_wq, &ap->packet_task);
+ queue_work(ata_wq, &ap->dataout_task);
break;
default:
@@ -3952,20 +3952,21 @@ irqreturn_t ata_interrupt (int irq, void
}
/**
- * atapi_packet_task - Write CDB bytes to hardware
- * @_data: Port to which ATAPI device is attached.
+ * ata_dataout_task - Write first data block to hardware
+ * @_data: Port to which ATA/ATAPI device is attached.
*
* When device has indicated its readiness to accept
- * a CDB, this function is called. Send the CDB.
- * If DMA is to be performed, exit immediately.
- * Otherwise, we are in polling mode, so poll
- * status under operation succeeds or fails.
+ * the data, this function sends out the CDB or
+ * the first data block by PIO.
+ * After this,
+ * - If polling, ata_pio_task() handles the rest.
+ * - Otherwise, interrupt handler takes over.
*
* LOCKING:
* Kernel thread context (may sleep)
*/
-static void atapi_packet_task(void *_data)
+static void ata_dataout_task(void *_data)
{
struct ata_port *ap = _data;
struct ata_queued_cmd *qc;
@@ -3978,7 +3979,7 @@ static void atapi_packet_task(void *_dat
/* sleep-wait for BSY to clear */
DPRINTK("busy wait\n");
- if (ata_busy_sleep(ap, ATA_TMOUT_CDB_QUICK, ATA_TMOUT_CDB))
+ if (ata_busy_sleep(ap, ATA_TMOUT_DATAOUT_QUICK, ATA_TMOUT_DATAOUT))
goto err_out;
/* make sure DRQ is set */
@@ -4141,7 +4142,7 @@ static void ata_host_init(struct ata_por
ap->active_tag = ATA_TAG_POISON;
ap->last_ctl = 0xFF;
- INIT_WORK(&ap->packet_task, atapi_packet_task, ap);
+ INIT_WORK(&ap->dataout_task, ata_dataout_task, ap);
INIT_WORK(&ap->pio_task, ata_pio_task, ap);
for (i = 0; i < ATA_MAX_DEVICES; i++)
^ permalink raw reply [flat|nested] 77+ messages in thread
* [PATCH/RFC 3/4] irq-pio: simplify if condition in ata_dataout_task()
2005-09-30 11:04 ` [PATCH/RFC 0/4] libata: irq driven pio follow-up patches Albert Lee
2005-09-30 11:07 ` [PATCH/RFC 1/4] irq-pio: add comments and cleanup Albert Lee
2005-09-30 11:09 ` [PATCH/RFC 2/4] irq-pio: rename atapi_packet_task() and comments Albert Lee
@ 2005-09-30 11:11 ` Albert Lee
2005-09-30 11:14 ` [PATCH/RFC 4/4] irq-pio: cleanup ata_qc_issue_prot() Albert Lee
2005-09-30 11:21 ` [PATCH/RFC 0/4] libata: irq driven pio follow-up patches Jeff Garzik
4 siblings, 0 replies; 77+ messages in thread
From: Albert Lee @ 2005-09-30 11:11 UTC (permalink / raw)
To: Bartlomiej Zolnierkiewicz, Jeff Garzik
Cc: Linux IDE, Doug Maxey, Tejun Heo, Mark Lord, Brett Russ
[-- Attachment #1: Type: text/plain, Size: 250 bytes --]
Patch 3/4: simplify if condition in ata_dataout_task()
Changes:
- Use if (qc->tf.protocol == ATA_PROT_PIO) instead of
if(is_atapi_taskfile()) in ata_dataout_task()
For your review, thanks.
Albert
Signed-off-by: Albert Lee <albertcc@tw.ibm.com>
[-- Attachment #2: idpio3.diff --]
[-- Type: text/plain, Size: 889 bytes --]
--- id2/drivers/scsi/libata-core.c 2005-09-30 18:04:29.000000000 +0800
+++ id3/drivers/scsi/libata-core.c 2005-09-30 18:04:42.000000000 +0800
@@ -3994,13 +3994,7 @@ static void ata_dataout_task(void *_data
*/
spin_lock_irqsave(&ap->host_set->lock, flags);
- if (is_atapi_taskfile(&qc->tf)) {
- /* send CDB */
- atapi_send_cdb(ap, qc);
-
- if (qc->tf.flags & ATA_TFLAG_POLLING)
- queue_work(ata_wq, &ap->pio_task);
- } else {
+ if (qc->tf.protocol == ATA_PROT_PIO) {
/* PIO data out protocol.
* send first data block.
*/
@@ -4013,6 +4007,12 @@ static void ata_dataout_task(void *_data
ata_altstatus(ap); /* flush */
/* interrupt handler takes over from here */
+ } else {
+ /* send CDB */
+ atapi_send_cdb(ap, qc);
+
+ if (qc->tf.flags & ATA_TFLAG_POLLING)
+ queue_work(ata_wq, &ap->pio_task);
}
spin_unlock_irqrestore(&ap->host_set->lock, flags);
^ permalink raw reply [flat|nested] 77+ messages in thread
* [PATCH/RFC 4/4] irq-pio: cleanup ata_qc_issue_prot()
2005-09-30 11:04 ` [PATCH/RFC 0/4] libata: irq driven pio follow-up patches Albert Lee
` (2 preceding siblings ...)
2005-09-30 11:11 ` [PATCH/RFC 3/4] irq-pio: simplify if condition in ata_dataout_task() Albert Lee
@ 2005-09-30 11:14 ` Albert Lee
2005-09-30 11:21 ` [PATCH/RFC 0/4] libata: irq driven pio follow-up patches Jeff Garzik
4 siblings, 0 replies; 77+ messages in thread
From: Albert Lee @ 2005-09-30 11:14 UTC (permalink / raw)
To: Bartlomiej Zolnierkiewicz, Jeff Garzik
Cc: Linux IDE, Doug Maxey, Tejun Heo, Mark Lord, Brett Russ
[-- Attachment #1: Type: text/plain, Size: 590 bytes --]
Patch 4/4: cleanup ata_qc_issue_prot()
Changes:
ata_qc_issue_prot():
- cleanup and let the PIO data out case always go through the
ata_dataout_task() codepath.
(Previously for PIO data out case, 2 code pathes were used
- irq case goes through ata_data_out_task() codepath.
- polling case jumps over the HSM_ST_FIRST state and goes to
HSM_ST and ata_pio_task() directly.)
ata_dataout_task():
- rearrange the queue_work() code to handle the PIO data out +
polling case.
For your review, thanks.
Albert
Signed-off-by: Albert Lee <albertcc@tw.ibm.com>
[-- Attachment #2: idpio4.diff --]
[-- Type: text/plain, Size: 1905 bytes --]
--- id3/drivers/scsi/libata-core.c 2005-09-30 18:04:42.000000000 +0800
+++ id4/drivers/scsi/libata-core.c 2005-09-30 18:04:33.000000000 +0800
@@ -3407,24 +3407,24 @@ int ata_qc_issue_prot(struct ata_queued_
ata_tf_to_host_nolock(ap, &qc->tf);
- if (qc->tf.flags & ATA_TFLAG_POLLING) {
- /* polling PIO */
- ap->hsm_task_state = HSM_ST;
- queue_work(ata_wq, &ap->pio_task);
+ if (qc->tf.flags & ATA_TFLAG_WRITE) {
+ /* PIO data out protocol */
+ ap->hsm_task_state = HSM_ST_FIRST;
+ queue_work(ata_wq, &ap->dataout_task);
+
+ /* always send first data block using
+ * the ata_dataout_task() codepath.
+ */
} else {
- /* interrupt driven PIO */
- if (qc->tf.flags & ATA_TFLAG_WRITE) {
- /* PIO data out protocol */
- ap->hsm_task_state = HSM_ST_FIRST;
- queue_work(ata_wq, &ap->dataout_task);
-
- /* send first data block by polling */
- } else {
- /* PIO data in protocol */
- ap->hsm_task_state = HSM_ST;
+ /* PIO data in protocol */
+ ap->hsm_task_state = HSM_ST;
- /* interrupt handler takes over from here */
- }
+ if (qc->tf.flags & ATA_TFLAG_POLLING)
+ queue_work(ata_wq, &ap->pio_task);
+
+ /* if polling, ata_pio_task() handles the rest.
+ * otherwise, interrupt handler takes over from here.
+ */
}
break;
@@ -4005,15 +4005,15 @@ static void ata_dataout_task(void *_data
ap->hsm_task_state = HSM_ST;
ata_pio_sector(qc);
ata_altstatus(ap); /* flush */
-
- /* interrupt handler takes over from here */
- } else {
+ } else
/* send CDB */
atapi_send_cdb(ap, qc);
- if (qc->tf.flags & ATA_TFLAG_POLLING)
- queue_work(ata_wq, &ap->pio_task);
- }
+ /* if polling, ata_pio_task() handles the rest.
+ * otherwise, interrupt handler takes over from here.
+ */
+ if (qc->tf.flags & ATA_TFLAG_POLLING)
+ queue_work(ata_wq, &ap->pio_task);
spin_unlock_irqrestore(&ap->host_set->lock, flags);
^ permalink raw reply [flat|nested] 77+ messages in thread
* Re: [PATCH/RFC 0/4] libata: irq driven pio follow-up patches
2005-09-30 11:04 ` [PATCH/RFC 0/4] libata: irq driven pio follow-up patches Albert Lee
` (3 preceding siblings ...)
2005-09-30 11:14 ` [PATCH/RFC 4/4] irq-pio: cleanup ata_qc_issue_prot() Albert Lee
@ 2005-09-30 11:21 ` Jeff Garzik
2005-10-03 11:46 ` [PATCH/RFC 0/4] libata: more " Albert Lee
4 siblings, 1 reply; 77+ messages in thread
From: Jeff Garzik @ 2005-09-30 11:21 UTC (permalink / raw)
To: Albert Lee
Cc: Bartlomiej Zolnierkiewicz, Linux IDE, Doug Maxey, Tejun Heo,
Mark Lord, Brett Russ
Applied patches 1-4 to irq-pio branch.
I wonder if dataout_task and pio_task can be merged?
Jeff
^ permalink raw reply [flat|nested] 77+ messages in thread
* Re: [PATCH/RFC 3/4] libata: interrupt driven pio for libata-core
2005-09-30 9:28 ` Bartlomiej Zolnierkiewicz
@ 2005-09-30 11:28 ` Albert Lee
2005-09-30 12:00 ` Bartlomiej Zolnierkiewicz
0 siblings, 1 reply; 77+ messages in thread
From: Albert Lee @ 2005-09-30 11:28 UTC (permalink / raw)
To: Bartlomiej Zolnierkiewicz
Cc: Jeff Garzik, Linux IDE, Doug Maxey, Tejun Heo, Mark Lord,
Brett Russ
Hi Bart,:
>
>>When the state is HSM_ST_FIRST, ata_host_intr() checks the
>>(qc->dev->flags & ATA_DFLAG_CDB_INTR) flag.
>>Also in atapi_packet_task(), the host lock is aquired during the state
>>transition from HSM_ST_FIRST to next state.
>>So, the race between the irq handler and atapi_packet_task() is avoided.
>>
>>
>
>What about ATAPI device with !dev->flags & ATA_DFLAG_CDB_INTR)?
>
>Shouldn't we do spin_lock_irqsave() in atapi_packet_task() before
>actually touching hardware?
>
>
>
For the ATAPI devices that don't raise CDB interrupes,
when atapi_packet_task() is entered, the state is HSM_ST_FIRST.
In this state, the irq handler will check the ATA_DFLAG_CDB_INTR flag
and skip touching the hardware.
atapi_packet_task() is safe to read the device status register at this
state.
atapi_packet_task() does spin_lock_irqsave() when changing the states
from HSM_ST_FIRST to say, HSM_ST and sending out the data.
For the ATAPI devices that raise CDB interrupes,
ata_qc_issue_prot() won't queue an new atapi_packet_task().
The irq handler takes over after ata_qc_issue_prot() and can touch the
hardware.
Thanks for the comments,
Albert
^ permalink raw reply [flat|nested] 77+ messages in thread
* Re: [PATCH/RFC 3/4] libata: interrupt driven pio for libata-core
2005-09-30 11:28 ` Albert Lee
@ 2005-09-30 12:00 ` Bartlomiej Zolnierkiewicz
0 siblings, 0 replies; 77+ messages in thread
From: Bartlomiej Zolnierkiewicz @ 2005-09-30 12:00 UTC (permalink / raw)
To: Albert Lee
Cc: Jeff Garzik, Linux IDE, Doug Maxey, Tejun Heo, Mark Lord,
Brett Russ
On 9/30/05, Albert Lee <albertcc@tw.ibm.com> wrote:
> Hi Bart,:
>
> >
> >>When the state is HSM_ST_FIRST, ata_host_intr() checks the
> >>(qc->dev->flags & ATA_DFLAG_CDB_INTR) flag.
> >>Also in atapi_packet_task(), the host lock is aquired during the state
> >>transition from HSM_ST_FIRST to next state.
> >>So, the race between the irq handler and atapi_packet_task() is avoided.
> >>
> >>
> >
> >What about ATAPI device with !dev->flags & ATA_DFLAG_CDB_INTR)?
> >
> >Shouldn't we do spin_lock_irqsave() in atapi_packet_task() before
> >actually touching hardware?
> >
> >
> >
> For the ATAPI devices that don't raise CDB interrupes,
> when atapi_packet_task() is entered, the state is HSM_ST_FIRST.
> In this state, the irq handler will check the ATA_DFLAG_CDB_INTR flag
> and skip touching the hardware.
> atapi_packet_task() is safe to read the device status register at this
> state.
> atapi_packet_task() does spin_lock_irqsave() when changing the states
> from HSM_ST_FIRST to say, HSM_ST and sending out the data.
>
> For the ATAPI devices that raise CDB interrupes,
> ata_qc_issue_prot() won't queue an new atapi_packet_task().
> The irq handler takes over after ata_qc_issue_prot() and can touch the
> hardware.
Yes, this is correct - thanks for detailed explanation.
Bartlomiej
^ permalink raw reply [flat|nested] 77+ messages in thread
* [PATCH/RFC 0/4] libata: more irq driven pio follow-up patches
2005-09-30 11:21 ` [PATCH/RFC 0/4] libata: irq driven pio follow-up patches Jeff Garzik
@ 2005-10-03 11:46 ` Albert Lee
2005-10-03 13:00 ` [PATCH/RFC 1/4] irq-pio: move functions Albert Lee
` (3 more replies)
0 siblings, 4 replies; 77+ messages in thread
From: Albert Lee @ 2005-10-03 11:46 UTC (permalink / raw)
To: Jeff Garzik
Cc: Bartlomiej Zolnierkiewicz, Linux IDE, Doug Maxey, Tejun Heo,
Mark Lord, Brett Russ
Dear all,
More irq driven PIO follow-up patches per Jeff's advice:
1. merge ata_dataout_task and ata_pio_task
2. add read/write multiple support
patch 1/4: move functions
- move atapi_send_cdb() and ata_dataout_task() to be near
ata_pio_*() functions
patch 2/4: remove ap->dataout_task
- remove ap->dataout_task
- let ata_pio_task() handle the HSM_ST_FIRST state.
- rename ata_dataout_task() to ata_pio_first_block()
patch 3/4: integrate ata_pio_first_block() with ata_pio_task()
- change the return value of ata_pio_complete()
- add return value for ata_pio_first_block()
- rename variable "qc_completed" to "has_next" in ata_pio_task()
patch 4/4: add read/write multiple support
- add ATA_CMD_READ_MULTI, etc. to ata.h
- add multi_count to ata_device and initialize it with device
identify data
- merge ata_prot_to_cmd() with ata_dev_set_protocol()
- ata_pio_complete(): change the wait condition from (ATA_BUSY |
ATA_DRQ) to ATA_BUSY
- add ata_pio_sectors() to support r/w multiple commands
- ata_pio_block(): add ata_altstatus(ap) to prevent reading device
status before it is valid
Patch against libata-dev irq-pio branch
(54f00389563c80fa1de250a21256313ba01ca07d).
For your review and advice, thanks.
Albert
^ permalink raw reply [flat|nested] 77+ messages in thread
* [PATCH/RFC 1/4] irq-pio: move functions
2005-10-03 11:46 ` [PATCH/RFC 0/4] libata: more " Albert Lee
@ 2005-10-03 13:00 ` Albert Lee
2005-10-03 13:02 ` [PATCH/RFC 2/4] irq-pio: remove ap->dataout_task Albert Lee
` (2 subsequent siblings)
3 siblings, 0 replies; 77+ messages in thread
From: Albert Lee @ 2005-10-03 13:00 UTC (permalink / raw)
To: Jeff Garzik
Cc: Bartlomiej Zolnierkiewicz, Linux IDE, Doug Maxey, Tejun Heo,
Mark Lord, Brett Russ
[-- Attachment #1: Type: text/plain, Size: 177 bytes --]
Patch 1/4:
move atapi_send_cdb() and ata_dataout_task() to be near ata_pio_*()
functions
For your review, thanks.
Albert
Signed-off-by: Albert Lee <albertcc@tw.ibm.com>
[-- Attachment #2: idpio1.diff --]
[-- Type: text/plain, Size: 6292 bytes --]
--- id4/drivers/scsi/libata-core.c 2005-09-30 18:04:33.000000000 +0800
+++ id5/drivers/scsi/libata-core.c 2005-10-03 10:25:01.000000000 +0800
@@ -2696,6 +2696,114 @@ static void ata_pio_sector(struct ata_qu
}
/**
+ * atapi_send_cdb - Write CDB bytes to hardware
+ * @ap: Port to which ATAPI device is attached.
+ * @qc: Taskfile currently active
+ *
+ * When device has indicated its readiness to accept
+ * a CDB, this function is called. Send the CDB.
+ *
+ * LOCKING:
+ * caller.
+ */
+
+static void atapi_send_cdb(struct ata_port *ap, struct ata_queued_cmd *qc)
+{
+ /* send SCSI cdb */
+ DPRINTK("send cdb\n");
+ assert(ap->cdb_len >= 12);
+
+ ata_data_xfer(ap, qc->cdb, ap->cdb_len, 1);
+ ata_altstatus(ap); /* flush */
+
+ switch (qc->tf.protocol) {
+ case ATA_PROT_ATAPI:
+ ap->hsm_task_state = HSM_ST;
+ break;
+ case ATA_PROT_ATAPI_NODATA:
+ ap->hsm_task_state = HSM_ST_LAST;
+ break;
+ case ATA_PROT_ATAPI_DMA:
+ ap->hsm_task_state = HSM_ST_LAST;
+ /* initiate bmdma */
+ ap->ops->bmdma_start(qc);
+ break;
+ }
+}
+
+/**
+ * ata_dataout_task - Write first data block to hardware
+ * @_data: Port to which ATA/ATAPI device is attached.
+ *
+ * When device has indicated its readiness to accept
+ * the data, this function sends out the CDB or
+ * the first data block by PIO.
+ * After this,
+ * - If polling, ata_pio_task() handles the rest.
+ * - Otherwise, interrupt handler takes over.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep)
+ */
+
+static void ata_dataout_task(void *_data)
+{
+ struct ata_port *ap = _data;
+ struct ata_queued_cmd *qc;
+ u8 status;
+ unsigned long flags;
+
+ qc = ata_qc_from_tag(ap, ap->active_tag);
+ assert(qc != NULL);
+ assert(qc->flags & ATA_QCFLAG_ACTIVE);
+
+ /* sleep-wait for BSY to clear */
+ DPRINTK("busy wait\n");
+ if (ata_busy_sleep(ap, ATA_TMOUT_DATAOUT_QUICK, ATA_TMOUT_DATAOUT))
+ goto err_out;
+
+ /* make sure DRQ is set */
+ status = ata_chk_status(ap);
+ if ((status & (ATA_BUSY | ATA_DRQ)) != ATA_DRQ)
+ goto err_out;
+
+ /* Send the CDB (atapi) or the first data block (ata pio out).
+ * During the state transition, interrupt handler shouldn't
+ * be invoked before the data transfer is complete and
+ * hsm_task_state is changed. Hence, the following locking.
+ */
+ spin_lock_irqsave(&ap->host_set->lock, flags);
+
+ if (qc->tf.protocol == ATA_PROT_PIO) {
+ /* PIO data out protocol.
+ * send first data block.
+ */
+
+ /* ata_pio_sector() might change the state to HSM_ST_LAST.
+ * so, the state is changed here before ata_pio_sector().
+ */
+ ap->hsm_task_state = HSM_ST;
+ ata_pio_sector(qc);
+ ata_altstatus(ap); /* flush */
+ } else
+ /* send CDB */
+ atapi_send_cdb(ap, qc);
+
+ /* if polling, ata_pio_task() handles the rest.
+ * otherwise, interrupt handler takes over from here.
+ */
+ if (qc->tf.flags & ATA_TFLAG_POLLING)
+ queue_work(ata_wq, &ap->pio_task);
+
+ spin_unlock_irqrestore(&ap->host_set->lock, flags);
+
+ return;
+
+err_out:
+ ata_pio_error(ap);
+}
+
+/**
* __atapi_pio_bytes - Transfer data from/to the ATAPI device.
* @qc: Command on going
* @bytes: number of bytes
@@ -3695,42 +3803,6 @@ void ata_bmdma_stop(struct ata_queued_cm
}
/**
- * atapi_send_cdb - Write CDB bytes to hardware
- * @ap: Port to which ATAPI device is attached.
- * @qc: Taskfile currently active
- *
- * When device has indicated its readiness to accept
- * a CDB, this function is called. Send the CDB.
- *
- * LOCKING:
- * caller.
- */
-
-static void atapi_send_cdb(struct ata_port *ap, struct ata_queued_cmd *qc)
-{
- /* send SCSI cdb */
- DPRINTK("send cdb\n");
- assert(ap->cdb_len >= 12);
-
- ata_data_xfer(ap, qc->cdb, ap->cdb_len, 1);
- ata_altstatus(ap); /* flush */
-
- switch (qc->tf.protocol) {
- case ATA_PROT_ATAPI:
- ap->hsm_task_state = HSM_ST;
- break;
- case ATA_PROT_ATAPI_NODATA:
- ap->hsm_task_state = HSM_ST_LAST;
- break;
- case ATA_PROT_ATAPI_DMA:
- ap->hsm_task_state = HSM_ST_LAST;
- /* initiate bmdma */
- ap->ops->bmdma_start(qc);
- break;
- }
-}
-
-/**
* ata_host_intr - Handle host interrupt for given (port, task)
* @ap: Port on which interrupt arrived (possibly...)
* @qc: Taskfile currently active in engine
@@ -3952,79 +4024,6 @@ irqreturn_t ata_interrupt (int irq, void
}
/**
- * ata_dataout_task - Write first data block to hardware
- * @_data: Port to which ATA/ATAPI device is attached.
- *
- * When device has indicated its readiness to accept
- * the data, this function sends out the CDB or
- * the first data block by PIO.
- * After this,
- * - If polling, ata_pio_task() handles the rest.
- * - Otherwise, interrupt handler takes over.
- *
- * LOCKING:
- * Kernel thread context (may sleep)
- */
-
-static void ata_dataout_task(void *_data)
-{
- struct ata_port *ap = _data;
- struct ata_queued_cmd *qc;
- u8 status;
- unsigned long flags;
-
- qc = ata_qc_from_tag(ap, ap->active_tag);
- assert(qc != NULL);
- assert(qc->flags & ATA_QCFLAG_ACTIVE);
-
- /* sleep-wait for BSY to clear */
- DPRINTK("busy wait\n");
- if (ata_busy_sleep(ap, ATA_TMOUT_DATAOUT_QUICK, ATA_TMOUT_DATAOUT))
- goto err_out;
-
- /* make sure DRQ is set */
- status = ata_chk_status(ap);
- if ((status & (ATA_BUSY | ATA_DRQ)) != ATA_DRQ)
- goto err_out;
-
- /* Send the CDB (atapi) or the first data block (ata pio out).
- * During the state transition, interrupt handler shouldn't
- * be invoked before the data transfer is complete and
- * hsm_task_state is changed. Hence, the following locking.
- */
- spin_lock_irqsave(&ap->host_set->lock, flags);
-
- if (qc->tf.protocol == ATA_PROT_PIO) {
- /* PIO data out protocol.
- * send first data block.
- */
-
- /* ata_pio_sector() might change the state to HSM_ST_LAST.
- * so, the state is changed here before ata_pio_sector().
- */
- ap->hsm_task_state = HSM_ST;
- ata_pio_sector(qc);
- ata_altstatus(ap); /* flush */
- } else
- /* send CDB */
- atapi_send_cdb(ap, qc);
-
- /* if polling, ata_pio_task() handles the rest.
- * otherwise, interrupt handler takes over from here.
- */
- if (qc->tf.flags & ATA_TFLAG_POLLING)
- queue_work(ata_wq, &ap->pio_task);
-
- spin_unlock_irqrestore(&ap->host_set->lock, flags);
-
- return;
-
-err_out:
- ata_pio_error(ap);
-}
-
-
-/**
* ata_port_start - Set port up for dma.
* @ap: Port to initialize
*
^ permalink raw reply [flat|nested] 77+ messages in thread
* [PATCH/RFC 2/4] irq-pio: remove ap->dataout_task
2005-10-03 11:46 ` [PATCH/RFC 0/4] libata: more " Albert Lee
2005-10-03 13:00 ` [PATCH/RFC 1/4] irq-pio: move functions Albert Lee
@ 2005-10-03 13:02 ` Albert Lee
2005-10-04 10:09 ` Jeff Garzik
2005-10-03 13:18 ` [PATCH/RFC 3/4] irq-pio: integrate ata_pio_first_block() with ata_pio_task() Albert Lee
2005-10-03 13:19 ` [PATCH/RFC 4/4] irq-pio: add read/write multiple support Albert Lee
3 siblings, 1 reply; 77+ messages in thread
From: Albert Lee @ 2005-10-03 13:02 UTC (permalink / raw)
To: Jeff Garzik
Cc: Bartlomiej Zolnierkiewicz, Linux IDE, Doug Maxey, Tejun Heo,
Mark Lord, Brett Russ
[-- Attachment #1: Type: text/plain, Size: 272 bytes --]
Patch 2/4: remove ap->dataout_task
changes:
- remove ap->dataout_task
- let ata_pio_task() handle the HSM_ST_FIRST state.
- rename ata_dataout_task() to ata_pio_first_block()
For your review, thanks.
Albert
Signed-off-by: Albert Lee <albertcc@tw.ibm.com>
[-- Attachment #2: idpio2.diff --]
[-- Type: text/plain, Size: 2838 bytes --]
--- id2/include/linux/libata.h 2005-09-30 17:48:55.000000000 +0800
+++ id6/include/linux/libata.h 2005-10-03 10:18:29.000000000 +0800
@@ -319,8 +319,6 @@ struct ata_port {
struct ata_host_stats stats;
struct ata_host_set *host_set;
- struct work_struct dataout_task;
-
struct work_struct pio_task;
unsigned int hsm_task_state;
unsigned long pio_task_timeout;
--- id5/drivers/scsi/libata-core.c 2005-10-03 10:25:01.000000000 +0800
+++ id6/drivers/scsi/libata-core.c 2005-10-03 11:07:01.000000000 +0800
@@ -2732,8 +2732,8 @@ static void atapi_send_cdb(struct ata_po
}
/**
- * ata_dataout_task - Write first data block to hardware
- * @_data: Port to which ATA/ATAPI device is attached.
+ * ata_pio_first_block - Write first data block to hardware
+ * @ap: Port to which ATA/ATAPI device is attached.
*
* When device has indicated its readiness to accept
* the data, this function sends out the CDB or
@@ -2746,9 +2746,8 @@ static void atapi_send_cdb(struct ata_po
* Kernel thread context (may sleep)
*/
-static void ata_dataout_task(void *_data)
+static void ata_pio_first_block(struct ata_port *ap)
{
- struct ata_port *ap = _data;
struct ata_queued_cmd *qc;
u8 status;
unsigned long flags;
@@ -3018,7 +3017,8 @@ fsm_start:
qc_completed = 0;
switch (ap->hsm_task_state) {
- case HSM_ST_IDLE:
+ case HSM_ST_FIRST:
+ ata_pio_first_block(ap);
return;
case HSM_ST:
@@ -3038,6 +3038,9 @@ fsm_start:
case HSM_ST_ERR:
ata_pio_error(ap);
return;
+ default:
+ BUG();
+ return;
}
if (timeout)
@@ -3518,10 +3521,10 @@ int ata_qc_issue_prot(struct ata_queued_
if (qc->tf.flags & ATA_TFLAG_WRITE) {
/* PIO data out protocol */
ap->hsm_task_state = HSM_ST_FIRST;
- queue_work(ata_wq, &ap->dataout_task);
+ queue_work(ata_wq, &ap->pio_task);
/* always send first data block using
- * the ata_dataout_task() codepath.
+ * the ata_pio_task() codepath.
*/
} else {
/* PIO data in protocol */
@@ -3548,7 +3551,7 @@ int ata_qc_issue_prot(struct ata_queued_
/* send cdb by polling if no cdb interrupt */
if ((!(qc->dev->flags & ATA_DFLAG_CDB_INTR)) ||
(qc->tf.flags & ATA_TFLAG_POLLING))
- queue_work(ata_wq, &ap->dataout_task);
+ queue_work(ata_wq, &ap->pio_task);
break;
case ATA_PROT_ATAPI_DMA:
@@ -3560,7 +3563,7 @@ int ata_qc_issue_prot(struct ata_queued_
/* send cdb by polling if no cdb interrupt */
if (!(qc->dev->flags & ATA_DFLAG_CDB_INTR))
- queue_work(ata_wq, &ap->dataout_task);
+ queue_work(ata_wq, &ap->pio_task);
break;
default:
@@ -4141,7 +4144,6 @@ static void ata_host_init(struct ata_por
ap->active_tag = ATA_TAG_POISON;
ap->last_ctl = 0xFF;
- INIT_WORK(&ap->dataout_task, ata_dataout_task, ap);
INIT_WORK(&ap->pio_task, ata_pio_task, ap);
for (i = 0; i < ATA_MAX_DEVICES; i++)
^ permalink raw reply [flat|nested] 77+ messages in thread
* [PATCH/RFC 3/4] irq-pio: integrate ata_pio_first_block() with ata_pio_task()
2005-10-03 11:46 ` [PATCH/RFC 0/4] libata: more " Albert Lee
2005-10-03 13:00 ` [PATCH/RFC 1/4] irq-pio: move functions Albert Lee
2005-10-03 13:02 ` [PATCH/RFC 2/4] irq-pio: remove ap->dataout_task Albert Lee
@ 2005-10-03 13:18 ` Albert Lee
2005-10-04 10:10 ` Jeff Garzik
2005-10-03 13:19 ` [PATCH/RFC 4/4] irq-pio: add read/write multiple support Albert Lee
3 siblings, 1 reply; 77+ messages in thread
From: Albert Lee @ 2005-10-03 13:18 UTC (permalink / raw)
To: Jeff Garzik
Cc: Bartlomiej Zolnierkiewicz, Linux IDE, Doug Maxey, Tejun Heo,
Mark Lord, Brett Russ
[-- Attachment #1: Type: text/plain, Size: 368 bytes --]
Patch 3/4: integrate ata_pio_first_block() with ata_pio_task()
Changes:
- change the return value of ata_pio_complete()
- add return value for ata_pio_first_block() to avoid queuing
another ata_pio_task()
- rename variable "qc_completed" to "has_next" in ata_pio_task()
For your review, thanks.
Albert
Signed-off-by: Albert Lee <albertcc@tw.ibm.com>
[-- Attachment #2: idpio3.diff --]
[-- Type: text/plain, Size: 3414 bytes --]
--- id6/drivers/scsi/libata-core.c 2005-10-03 11:07:01.000000000 +0800
+++ id7/drivers/scsi/libata-core.c 2005-10-03 12:39:03.000000000 +0800
@@ -2469,7 +2469,8 @@ static unsigned long ata_pio_poll(struct
* None. (executing in kernel thread context)
*
* RETURNS:
- * Non-zero if qc completed, zero otherwise.
+ * Zero if qc completed.
+ * Non-zero if has next.
*/
static int ata_pio_complete (struct ata_port *ap)
@@ -2491,14 +2492,14 @@ static int ata_pio_complete (struct ata_
if (drv_stat & (ATA_BUSY | ATA_DRQ)) {
ap->hsm_task_state = HSM_ST_LAST_POLL;
ap->pio_task_timeout = jiffies + ATA_TMOUT_PIO;
- return 0;
+ return 1;
}
}
drv_stat = ata_wait_idle(ap);
if (!ata_ok(drv_stat)) {
ap->hsm_task_state = HSM_ST_ERR;
- return 0;
+ return 1;
}
qc = ata_qc_from_tag(ap, ap->active_tag);
@@ -2510,7 +2511,7 @@ static int ata_pio_complete (struct ata_
/* another command may start at this point */
- return 1;
+ return 0;
}
@@ -2744,27 +2745,39 @@ static void atapi_send_cdb(struct ata_po
*
* LOCKING:
* Kernel thread context (may sleep)
+ *
+ * RETURNS:
+ * Zero if irq handler takes over
+ * Non-zero if has next (polling).
*/
-static void ata_pio_first_block(struct ata_port *ap)
+static int ata_pio_first_block(struct ata_port *ap)
{
struct ata_queued_cmd *qc;
u8 status;
unsigned long flags;
+ int has_next;
qc = ata_qc_from_tag(ap, ap->active_tag);
assert(qc != NULL);
assert(qc->flags & ATA_QCFLAG_ACTIVE);
+ has_next = (qc->tf.flags & ATA_TFLAG_POLLING);
+
/* sleep-wait for BSY to clear */
DPRINTK("busy wait\n");
- if (ata_busy_sleep(ap, ATA_TMOUT_DATAOUT_QUICK, ATA_TMOUT_DATAOUT))
+ if (ata_busy_sleep(ap, ATA_TMOUT_DATAOUT_QUICK, ATA_TMOUT_DATAOUT)) {
+ ap->hsm_task_state = HSM_ST_TMOUT;
goto err_out;
+ }
/* make sure DRQ is set */
status = ata_chk_status(ap);
- if ((status & (ATA_BUSY | ATA_DRQ)) != ATA_DRQ)
+ if ((status & (ATA_BUSY | ATA_DRQ)) != ATA_DRQ) {
+ /* device status error */
+ ap->hsm_task_state = HSM_ST_ERR;
goto err_out;
+ }
/* Send the CDB (atapi) or the first data block (ata pio out).
* During the state transition, interrupt handler shouldn't
@@ -2788,18 +2801,15 @@ static void ata_pio_first_block(struct a
/* send CDB */
atapi_send_cdb(ap, qc);
+ spin_unlock_irqrestore(&ap->host_set->lock, flags);
+
/* if polling, ata_pio_task() handles the rest.
* otherwise, interrupt handler takes over from here.
*/
- if (qc->tf.flags & ATA_TFLAG_POLLING)
- queue_work(ata_wq, &ap->pio_task);
-
- spin_unlock_irqrestore(&ap->host_set->lock, flags);
-
- return;
+ return has_next;
err_out:
- ata_pio_error(ap);
+ return 1;
}
/**
@@ -3010,23 +3020,23 @@ static void ata_pio_task(void *_data)
{
struct ata_port *ap = _data;
unsigned long timeout;
- int qc_completed;
+ int has_next;
fsm_start:
timeout = 0;
- qc_completed = 0;
+ has_next = 1;
switch (ap->hsm_task_state) {
case HSM_ST_FIRST:
- ata_pio_first_block(ap);
- return;
+ has_next = ata_pio_first_block(ap);
+ break;
case HSM_ST:
ata_pio_block(ap);
break;
case HSM_ST_LAST:
- qc_completed = ata_pio_complete(ap);
+ has_next = ata_pio_complete(ap);
break;
case HSM_ST_POLL:
@@ -3045,7 +3055,7 @@ fsm_start:
if (timeout)
queue_delayed_work(ata_wq, &ap->pio_task, timeout);
- else if (!qc_completed)
+ else if (has_next)
goto fsm_start;
}
^ permalink raw reply [flat|nested] 77+ messages in thread
* [PATCH/RFC 4/4] irq-pio: add read/write multiple support
2005-10-03 11:46 ` [PATCH/RFC 0/4] libata: more " Albert Lee
` (2 preceding siblings ...)
2005-10-03 13:18 ` [PATCH/RFC 3/4] irq-pio: integrate ata_pio_first_block() with ata_pio_task() Albert Lee
@ 2005-10-03 13:19 ` Albert Lee
2005-10-03 13:35 ` Mark Lord
2005-10-04 10:19 ` [PATCH/RFC 4/4] irq-pio: add read/write multiple support Jeff Garzik
3 siblings, 2 replies; 77+ messages in thread
From: Albert Lee @ 2005-10-03 13:19 UTC (permalink / raw)
To: Jeff Garzik
Cc: Bartlomiej Zolnierkiewicz, Linux IDE, Doug Maxey, Tejun Heo,
Mark Lord, Brett Russ
[-- Attachment #1: Type: text/plain, Size: 570 bytes --]
Patch 4/4: add read/write multiple support
Changes:
- add ATA_CMD_READ_MULTI, etc. to ata.h
- add multi_count to ata_device and initialize it with device
identify data
- merge ata_prot_to_cmd() with ata_dev_set_protocol()
- ata_pio_complete(): change the wait condition from (ATA_BUSY |
ATA_DRQ) to ATA_BUSY
- add ata_pio_sectors() to support r/w multiple commands
- ata_pio_block(): add ata_altstatus(ap) to prevent reading device
status before it is valid
For your review, thanks.
Albert
Signed-off-by: Albert Lee <albertcc@tw.ibm.com>
[-- Attachment #2: idpio4.diff --]
[-- Type: text/plain, Size: 6509 bytes --]
--- irq-pio/include/linux/ata.h 2005-09-30 10:00:30.000000000 +0800
+++ id8/include/linux/ata.h 2005-10-03 13:54:52.000000000 +0800
@@ -128,6 +128,10 @@ enum {
ATA_CMD_PIO_READ_EXT = 0x24,
ATA_CMD_PIO_WRITE = 0x30,
ATA_CMD_PIO_WRITE_EXT = 0x34,
+ ATA_CMD_READ_MULTI = 0xC4,
+ ATA_CMD_READ_MULTI_EXT = 0x29,
+ ATA_CMD_WRITE_MULTI = 0xC5,
+ ATA_CMD_WRITE_MULTI_EXT = 0x39,
ATA_CMD_SET_FEATURES = 0xEF,
ATA_CMD_PACKET = 0xA0,
ATA_CMD_VERIFY = 0x40,
@@ -270,6 +274,14 @@ static inline int is_atapi_taskfile(stru
(tf->protocol == ATA_PROT_ATAPI_DMA);
}
+static inline int is_multi_taskfile(struct ata_taskfile *tf)
+{
+ return (tf->command == ATA_CMD_READ_MULTI) ||
+ (tf->command == ATA_CMD_WRITE_MULTI) ||
+ (tf->command == ATA_CMD_READ_MULTI_EXT) ||
+ (tf->command == ATA_CMD_WRITE_MULTI_EXT);
+}
+
static inline int ata_ok(u8 status)
{
return ((status & (ATA_BUSY | ATA_DRDY | ATA_DF | ATA_DRQ | ATA_ERR))
--- id6/include/linux/libata.h 2005-10-03 10:18:29.000000000 +0800
+++ id8/include/linux/libata.h 2005-10-03 13:56:29.000000000 +0800
@@ -285,6 +285,8 @@ struct ata_device {
u8 xfer_protocol; /* taskfile xfer protocol */
u8 read_cmd; /* opcode to use on read */
u8 write_cmd; /* opcode to use on write */
+ unsigned int multi_count; /* sectors count for
+ READ/WRITE MULTIPLE */
};
struct ata_port {
--- id7/drivers/scsi/libata-core.c 2005-10-03 12:39:03.000000000 +0800
+++ id8/drivers/scsi/libata-core.c 2005-10-03 18:33:26.000000000 +0800
@@ -616,49 +616,6 @@ void ata_tf_from_fis(u8 *fis, struct ata
}
/**
- * ata_prot_to_cmd - determine which read/write opcodes to use
- * @protocol: ATA_PROT_xxx taskfile protocol
- * @lba48: true is lba48 is present
- *
- * Given necessary input, determine which read/write commands
- * to use to transfer data.
- *
- * LOCKING:
- * None.
- */
-static int ata_prot_to_cmd(int protocol, int lba48)
-{
- int rcmd = 0, wcmd = 0;
-
- switch (protocol) {
- case ATA_PROT_PIO:
- if (lba48) {
- rcmd = ATA_CMD_PIO_READ_EXT;
- wcmd = ATA_CMD_PIO_WRITE_EXT;
- } else {
- rcmd = ATA_CMD_PIO_READ;
- wcmd = ATA_CMD_PIO_WRITE;
- }
- break;
-
- case ATA_PROT_DMA:
- if (lba48) {
- rcmd = ATA_CMD_READ_EXT;
- wcmd = ATA_CMD_WRITE_EXT;
- } else {
- rcmd = ATA_CMD_READ;
- wcmd = ATA_CMD_WRITE;
- }
- break;
-
- default:
- return -1;
- }
-
- return rcmd | (wcmd << 8);
-}
-
-/**
* ata_dev_set_protocol - set taskfile protocol and r/w commands
* @dev: device to examine and configure
*
@@ -675,19 +632,42 @@ static void ata_dev_set_protocol(struct
{
int pio = (dev->flags & ATA_DFLAG_PIO);
int lba48 = (dev->flags & ATA_DFLAG_LBA48);
- int proto, cmd;
+ int rcmd, wcmd;
- if (pio)
- proto = dev->xfer_protocol = ATA_PROT_PIO;
- else
- proto = dev->xfer_protocol = ATA_PROT_DMA;
+ if (pio) {
+ dev->xfer_protocol = ATA_PROT_PIO;
- cmd = ata_prot_to_cmd(proto, lba48);
- if (cmd < 0)
- BUG();
+ if (dev->multi_count) {
+ if (lba48) {
+ rcmd = ATA_CMD_READ_MULTI_EXT;
+ wcmd = ATA_CMD_WRITE_MULTI_EXT;
+ } else {
+ rcmd = ATA_CMD_READ_MULTI;
+ wcmd = ATA_CMD_WRITE_MULTI;
+ }
+ } else {
+ if (lba48) {
+ rcmd = ATA_CMD_PIO_READ_EXT;
+ wcmd = ATA_CMD_PIO_WRITE_EXT;
+ } else {
+ rcmd = ATA_CMD_PIO_READ;
+ wcmd = ATA_CMD_PIO_WRITE;
+ }
+ }
+ } else {
+ dev->xfer_protocol = ATA_PROT_DMA;
+
+ if (lba48) {
+ rcmd = ATA_CMD_READ_EXT;
+ wcmd = ATA_CMD_WRITE_EXT;
+ } else {
+ rcmd = ATA_CMD_READ;
+ wcmd = ATA_CMD_WRITE;
+ }
+ }
- dev->read_cmd = cmd & 0xff;
- dev->write_cmd = (cmd >> 8) & 0xff;
+ dev->read_cmd = rcmd;
+ dev->write_cmd = wcmd;
}
static const char * xfer_mode_str[] = {
@@ -1269,6 +1249,12 @@ retry:
dev->n_sectors = ata_id_u32(dev->id, 60);
}
+ if (dev->id[59] & 0x100) {
+ dev->multi_count = dev->id[59] & 0xff;
+ DPRINTK("ata%u: dev %u multi count %u\n",
+ ap->id, device, dev->multi_count);
+ }
+
ap->host->max_cmd_len = 16;
/* print device info to dmesg */
@@ -2483,13 +2469,13 @@ static int ata_pio_complete (struct ata_
* we enter, BSY will be cleared in a chk-status or two. If not,
* the drive is probably seeking or something. Snooze for a couple
* msecs, then chk-status again. If still busy, fall back to
- * HSM_ST_POLL state.
+ * HSM_ST_LAST_POLL state.
*/
- drv_stat = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 10);
- if (drv_stat & (ATA_BUSY | ATA_DRQ)) {
+ drv_stat = ata_busy_wait(ap, ATA_BUSY, 10);
+ if (drv_stat & ATA_BUSY) {
msleep(2);
- drv_stat = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 10);
- if (drv_stat & (ATA_BUSY | ATA_DRQ)) {
+ drv_stat = ata_busy_wait(ap, ATA_BUSY, 10);
+ if (drv_stat & ATA_BUSY) {
ap->hsm_task_state = HSM_ST_LAST_POLL;
ap->pio_task_timeout = jiffies + ATA_TMOUT_PIO;
return 1;
@@ -2697,6 +2683,32 @@ static void ata_pio_sector(struct ata_qu
}
/**
+ * ata_pio_sectors - Transfer one or many 512-byte sectors.
+ * @qc: Command on going
+ *
+ * Transfer one or many ATA_SECT_SIZE of data from/to the
+ * ATA device for the DRQ request.
+ *
+ * LOCKING:
+ * Inherited from caller.
+ */
+
+static void ata_pio_sectors(struct ata_queued_cmd *qc)
+{
+ if (is_multi_taskfile(&qc->tf)) {
+ /* READ/WRITE MULTIPLE */
+ unsigned int nsect;
+
+ assert(qc->dev->multi_count);
+
+ nsect = min(qc->nsect - qc->cursect, qc->dev->multi_count);
+ while (nsect--)
+ ata_pio_sector(qc);
+ } else
+ ata_pio_sector(qc);
+}
+
+/**
* atapi_send_cdb - Write CDB bytes to hardware
* @ap: Port to which ATAPI device is attached.
* @qc: Taskfile currently active
@@ -2791,11 +2803,11 @@ static int ata_pio_first_block(struct at
* send first data block.
*/
- /* ata_pio_sector() might change the state to HSM_ST_LAST.
- * so, the state is changed here before ata_pio_sector().
+ /* ata_pio_sectors() might change the state to HSM_ST_LAST.
+ * so, the state is changed here before ata_pio_sectors().
*/
ap->hsm_task_state = HSM_ST;
- ata_pio_sector(qc);
+ ata_pio_sectors(qc);
ata_altstatus(ap); /* flush */
} else
/* send CDB */
@@ -2995,8 +3007,10 @@ static void ata_pio_block(struct ata_por
return;
}
- ata_pio_sector(qc);
+ ata_pio_sectors(qc);
}
+
+ ata_altstatus(ap); /* flush */
}
static void ata_pio_error(struct ata_port *ap)
@@ -3932,7 +3946,7 @@ fsm_start:
goto fsm_start;
}
- ata_pio_sector(qc);
+ ata_pio_sectors(qc);
if (ap->hsm_task_state == HSM_ST_LAST &&
(!(qc->tf.flags & ATA_TFLAG_WRITE))) {
^ permalink raw reply [flat|nested] 77+ messages in thread
* Re: [PATCH/RFC 4/4] irq-pio: add read/write multiple support
2005-10-03 13:19 ` [PATCH/RFC 4/4] irq-pio: add read/write multiple support Albert Lee
@ 2005-10-03 13:35 ` Mark Lord
2005-10-04 9:43 ` Jeff Garzik
2005-10-04 10:19 ` [PATCH/RFC 4/4] irq-pio: add read/write multiple support Jeff Garzik
1 sibling, 1 reply; 77+ messages in thread
From: Mark Lord @ 2005-10-03 13:35 UTC (permalink / raw)
To: Albert Lee
Cc: Jeff Garzik, Bartlomiej Zolnierkiewicz, Linux IDE, Doug Maxey,
Tejun Heo, Brett Russ
Albert Lee wrote:
> Patch 4/4: add read/write multiple support
>
One "fine point" when programming the R/W MULT commands
is to remember that each register access is very costly
in terms of processor time.
So whenever an access can be done with 28-bit LBA,
it should not use the EXT versions of the instructions,
even though the device may be LBA48 capable.
The various drivers I have written for Linux and other OSs
that deal with this always logic equivalen to this somewhere:
if (lba_sector < (1<<28) && sector_count <= 256) {
use LBA28
} else if (device is lba48 capable) {
use LBA48
} else {
error
}
For SATA drives, this is unlikely to make any difference,
but for PATA it can reduce the CPU overhead of issuing
a command by 40% or so --> saves three PCI bus transactions,
which amounts to about 1-4us real-time, depending on the
exact hardware in question.
I'm really looking forward to having PIO in libata,
so that we can support compactflash cards and the like.
My Delkin 32-bit Cardbus Adapter driver (currently in 2.4.x IDE)
will be one of the first new pure PIO drivers in libata..
Cheers
--
Mark Lord
Real-Time Remedies Inc.
mlord@pobox.com
^ permalink raw reply [flat|nested] 77+ messages in thread
* Re: [PATCH/RFC 4/4] irq-pio: add read/write multiple support
2005-10-03 13:35 ` Mark Lord
@ 2005-10-04 9:43 ` Jeff Garzik
2005-10-04 12:00 ` Albert Lee
0 siblings, 1 reply; 77+ messages in thread
From: Jeff Garzik @ 2005-10-04 9:43 UTC (permalink / raw)
To: Mark Lord
Cc: Albert Lee, Bartlomiej Zolnierkiewicz, Linux IDE, Doug Maxey,
Tejun Heo, Brett Russ, Alan Cox
Mark Lord wrote:
> Albert Lee wrote:
>
>> Patch 4/4: add read/write multiple support
>>
>
> One "fine point" when programming the R/W MULT commands
> is to remember that each register access is very costly
> in terms of processor time.
>
> So whenever an access can be done with 28-bit LBA,
> it should not use the EXT versions of the instructions,
> even though the device may be LBA48 capable.
>
> The various drivers I have written for Linux and other OSs
> that deal with this always logic equivalen to this somewhere:
>
> if (lba_sector < (1<<28) && sector_count <= 256) {
> use LBA28
> } else if (device is lba48 capable) {
> use LBA48
> } else {
> error
> }
Alan lists this on his PATA should-do list, too.
Since this is legacy hardware, I am a bit skeptical about doing this --
and also 32-bit PIO, which is in the same category -- because this
increases the amount of code we have to deal with, for the same basic
function. For rarely-hit situations, I don't mind paying some
performance penalty if it reduces long term maintenance. I am willing
to push some ancient platforms in the "slow but working" category, to
keep the code small and easier to review/debug/maintain.
That said, it should be simple enough to push the logic into
libata-scsi.c, where it translates a SCSI READ/WRITE command into an ATA
read/write command. Patches welcome...
> For SATA drives, this is unlikely to make any difference,
> but for PATA it can reduce the CPU overhead of issuing
> a command by 40% or so --> saves three PCI bus transactions,
> which amounts to about 1-4us real-time, depending on the
> exact hardware in question.
When running devices in PIO-only mode, the PCI bus transactions are very
noticeable even with SATA.
Also, though this may be stating the obvious, all this discussion is
irrelevant for FIS-based chips, since the control flow is entirely
different there.
> I'm really looking forward to having PIO in libata,
> so that we can support compactflash cards and the like.
> My Delkin 32-bit Cardbus Adapter driver (currently in 2.4.x IDE)
> will be one of the first new pure PIO drivers in libata..
Cool :)
Jeff
^ permalink raw reply [flat|nested] 77+ messages in thread
* Re: [PATCH/RFC 2/4] irq-pio: remove ap->dataout_task
2005-10-03 13:02 ` [PATCH/RFC 2/4] irq-pio: remove ap->dataout_task Albert Lee
@ 2005-10-04 10:09 ` Jeff Garzik
2005-10-04 11:54 ` Albert Lee
0 siblings, 1 reply; 77+ messages in thread
From: Jeff Garzik @ 2005-10-04 10:09 UTC (permalink / raw)
To: Albert Lee
Cc: Bartlomiej Zolnierkiewicz, Linux IDE, Doug Maxey, Tejun Heo,
Mark Lord, Brett Russ
Albert Lee wrote:
> @@ -3018,7 +3017,8 @@ fsm_start:
> qc_completed = 0;
>
> switch (ap->hsm_task_state) {
> - case HSM_ST_IDLE:
> + case HSM_ST_FIRST:
> + ata_pio_first_block(ap);
> return;
>
> case HSM_ST:
Am I missing something? You're removing the handling of HSM_ST_IDLE,
which looks very wrong.
AFAICS, even after your patch is applied, the completion of a qc still
transitions the state to HSM_ST_IDLE. Perhaps your patch is missing
some transitions -from- HSM_ST_IDLE to HSM_ST_FIRST?
Jeff
^ permalink raw reply [flat|nested] 77+ messages in thread
* Re: [PATCH/RFC 3/4] irq-pio: integrate ata_pio_first_block() with ata_pio_task()
2005-10-03 13:18 ` [PATCH/RFC 3/4] irq-pio: integrate ata_pio_first_block() with ata_pio_task() Albert Lee
@ 2005-10-04 10:10 ` Jeff Garzik
0 siblings, 0 replies; 77+ messages in thread
From: Jeff Garzik @ 2005-10-04 10:10 UTC (permalink / raw)
To: Albert Lee
Cc: Bartlomiej Zolnierkiewicz, Linux IDE, Doug Maxey, Tejun Heo,
Mark Lord, Brett Russ
Albert Lee wrote:
> Patch 3/4: integrate ata_pio_first_block() with ata_pio_task()
>
> Changes:
> - change the return value of ata_pio_complete()
> - add return value for ata_pio_first_block() to avoid queuing another
> ata_pio_task()
> - rename variable "qc_completed" to "has_next" in ata_pio_task()
seems OK.
not applied since patch #2 was not applied.
^ permalink raw reply [flat|nested] 77+ messages in thread
* Re: [PATCH/RFC 4/4] irq-pio: add read/write multiple support
2005-10-03 13:19 ` [PATCH/RFC 4/4] irq-pio: add read/write multiple support Albert Lee
2005-10-03 13:35 ` Mark Lord
@ 2005-10-04 10:19 ` Jeff Garzik
1 sibling, 0 replies; 77+ messages in thread
From: Jeff Garzik @ 2005-10-04 10:19 UTC (permalink / raw)
To: Albert Lee
Cc: Bartlomiej Zolnierkiewicz, Linux IDE, Doug Maxey, Tejun Heo,
Mark Lord, Brett Russ
Albert Lee wrote:
> Patch 4/4: add read/write multiple support
>
> Changes:
> - add ATA_CMD_READ_MULTI, etc. to ata.h
> - add multi_count to ata_device and initialize it with device
> identify data
> - merge ata_prot_to_cmd() with ata_dev_set_protocol()
> - ata_pio_complete(): change the wait condition from (ATA_BUSY |
> ATA_DRQ) to ATA_BUSY
> - add ata_pio_sectors() to support r/w multiple commands
> - ata_pio_block(): add ata_altstatus(ap) to prevent reading device
> status before it is valid
>
>
> For your review, thanks.
>
> Albert
> Signed-off-by: Albert Lee <albertcc@tw.ibm.com>
>
>
> ------------------------------------------------------------------------
>
> --- id7/drivers/scsi/libata-core.c 2005-10-03 12:39:03.000000000 +0800
> +++ id8/drivers/scsi/libata-core.c 2005-10-03 18:33:26.000000000 +0800
> @@ -616,49 +616,6 @@ void ata_tf_from_fis(u8 *fis, struct ata
> }
>
> /**
> - * ata_prot_to_cmd - determine which read/write opcodes to use
> - * @protocol: ATA_PROT_xxx taskfile protocol
> - * @lba48: true is lba48 is present
> - *
> - * Given necessary input, determine which read/write commands
> - * to use to transfer data.
> - *
> - * LOCKING:
> - * None.
> - */
> -static int ata_prot_to_cmd(int protocol, int lba48)
> -{
> - int rcmd = 0, wcmd = 0;
> -
> - switch (protocol) {
> - case ATA_PROT_PIO:
> - if (lba48) {
> - rcmd = ATA_CMD_PIO_READ_EXT;
> - wcmd = ATA_CMD_PIO_WRITE_EXT;
> - } else {
> - rcmd = ATA_CMD_PIO_READ;
> - wcmd = ATA_CMD_PIO_WRITE;
> - }
> - break;
> -
> - case ATA_PROT_DMA:
> - if (lba48) {
> - rcmd = ATA_CMD_READ_EXT;
> - wcmd = ATA_CMD_WRITE_EXT;
> - } else {
> - rcmd = ATA_CMD_READ;
> - wcmd = ATA_CMD_WRITE;
> - }
> - break;
> -
> - default:
> - return -1;
> - }
> -
> - return rcmd | (wcmd << 8);
> -}
> -
> -/**
> * ata_dev_set_protocol - set taskfile protocol and r/w commands
> * @dev: device to examine and configure
> *
> @@ -675,19 +632,42 @@ static void ata_dev_set_protocol(struct
> {
> int pio = (dev->flags & ATA_DFLAG_PIO);
> int lba48 = (dev->flags & ATA_DFLAG_LBA48);
> - int proto, cmd;
> + int rcmd, wcmd;
>
> - if (pio)
> - proto = dev->xfer_protocol = ATA_PROT_PIO;
> - else
> - proto = dev->xfer_protocol = ATA_PROT_DMA;
> + if (pio) {
> + dev->xfer_protocol = ATA_PROT_PIO;
>
> - cmd = ata_prot_to_cmd(proto, lba48);
> - if (cmd < 0)
> - BUG();
> + if (dev->multi_count) {
> + if (lba48) {
> + rcmd = ATA_CMD_READ_MULTI_EXT;
> + wcmd = ATA_CMD_WRITE_MULTI_EXT;
> + } else {
> + rcmd = ATA_CMD_READ_MULTI;
> + wcmd = ATA_CMD_WRITE_MULTI;
> + }
> + } else {
> + if (lba48) {
> + rcmd = ATA_CMD_PIO_READ_EXT;
> + wcmd = ATA_CMD_PIO_WRITE_EXT;
> + } else {
> + rcmd = ATA_CMD_PIO_READ;
> + wcmd = ATA_CMD_PIO_WRITE;
> + }
> + }
> + } else {
> + dev->xfer_protocol = ATA_PROT_DMA;
> +
> + if (lba48) {
> + rcmd = ATA_CMD_READ_EXT;
> + wcmd = ATA_CMD_WRITE_EXT;
> + } else {
> + rcmd = ATA_CMD_READ;
> + wcmd = ATA_CMD_WRITE;
> + }
> + }
>
> - dev->read_cmd = cmd & 0xff;
> - dev->write_cmd = (cmd >> 8) & 0xff;
> + dev->read_cmd = rcmd;
> + dev->write_cmd = wcmd;
> }
>
> static const char * xfer_mode_str[] = {
I rather liked having ata_prot_to_cmd() separate, but your version is
OK. No objection, just a twitch :)
> @@ -2483,13 +2469,13 @@ static int ata_pio_complete (struct ata_
> * we enter, BSY will be cleared in a chk-status or two. If not,
> * the drive is probably seeking or something. Snooze for a couple
> * msecs, then chk-status again. If still busy, fall back to
> - * HSM_ST_POLL state.
> + * HSM_ST_LAST_POLL state.
> */
> - drv_stat = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 10);
> - if (drv_stat & (ATA_BUSY | ATA_DRQ)) {
> + drv_stat = ata_busy_wait(ap, ATA_BUSY, 10);
> + if (drv_stat & ATA_BUSY) {
> msleep(2);
> - drv_stat = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 10);
> - if (drv_stat & (ATA_BUSY | ATA_DRQ)) {
> + drv_stat = ata_busy_wait(ap, ATA_BUSY, 10);
> + if (drv_stat & ATA_BUSY) {
> ap->hsm_task_state = HSM_ST_LAST_POLL;
> ap->pio_task_timeout = jiffies + ATA_TMOUT_PIO;
> return 1;
Eventually we should make sure that DRQ is cleared, at the end of the
transfer. Does other code make this check?
Ideally, in _all_ cases where look at the status register, we should
check the DRDY and DF bits as well. That's why in drivers/ide/ you find
check_bits = ATA_BSY | ATA_DRQ | ATA_DF | ATA_DRDY
ok_bits = ATA_DRDY
if ((Status & check_bits) == ok_bits) # BUS IDLE
OK
else
error
Patch is otherwise OK.
Not applied, since patches #2 and #3 were not applied.
^ permalink raw reply [flat|nested] 77+ messages in thread
* Re: [PATCH/RFC 2/4] irq-pio: remove ap->dataout_task
2005-10-04 10:09 ` Jeff Garzik
@ 2005-10-04 11:54 ` Albert Lee
0 siblings, 0 replies; 77+ messages in thread
From: Albert Lee @ 2005-10-04 11:54 UTC (permalink / raw)
To: Jeff Garzik
Cc: Bartlomiej Zolnierkiewicz, Linux IDE, Doug Maxey, Tejun Heo,
Mark Lord, Brett Russ
Jeff Garzik wrote:
> Albert Lee wrote:
>
>> @@ -3018,7 +3017,8 @@ fsm_start:
>> qc_completed = 0;
>>
>> switch (ap->hsm_task_state) {
>> - case HSM_ST_IDLE:
>> + case HSM_ST_FIRST:
>> + ata_pio_first_block(ap);
>> return;
>>
>> case HSM_ST:
>
>
> Am I missing something? You're removing the handling of HSM_ST_IDLE,
> which looks very wrong.
The qc_completed flag is introduced to replace the volatile HSM_ST_IDLE
state.
If we access the port when ap->hsm_task_state is HSM_ST_IDLE, the
command is completed, next qc might be running on the same port and
changing ap->hsm_task_state. So, we cannot rely on ap->hsm_task_state
when it is HSM_ST_IDLE.
>
> AFAICS, even after your patch is applied, the completion of a qc still
> transitions the state to HSM_ST_IDLE. Perhaps your patch is missing
> some transitions -from- HSM_ST_IDLE to HSM_ST_FIRST?
>
Yes, the completion of a qc still transitions the state to HSM_ST_IDLE.
But we need another way - the qc_completed flag to finish the polling loop.
Albert
^ permalink raw reply [flat|nested] 77+ messages in thread
* Re: [PATCH/RFC 4/4] irq-pio: add read/write multiple support
2005-10-04 9:43 ` Jeff Garzik
@ 2005-10-04 12:00 ` Albert Lee
2005-10-04 12:07 ` Jeff Garzik
0 siblings, 1 reply; 77+ messages in thread
From: Albert Lee @ 2005-10-04 12:00 UTC (permalink / raw)
To: Jeff Garzik
Cc: Mark Lord, Bartlomiej Zolnierkiewicz, Linux IDE, Doug Maxey,
Tejun Heo, Brett Russ, Alan Cox
Jeff,
> Mark Lord wrote:
>
>> Albert Lee wrote:
>>
>>> Patch 4/4: add read/write multiple support
>>>
>>
>> One "fine point" when programming the R/W MULT commands
>> is to remember that each register access is very costly
>> in terms of processor time.
>>
>> So whenever an access can be done with 28-bit LBA,
>> it should not use the EXT versions of the instructions,
>> even though the device may be LBA48 capable.
>>
>> The various drivers I have written for Linux and other OSs
>> that deal with this always logic equivalen to this somewhere:
>>
>> if (lba_sector < (1<<28) && sector_count <= 256) {
>> use LBA28
>> } else if (device is lba48 capable) {
>> use LBA48
>> } else {
>> error
>> }
>
>
> Alan lists this on his PATA should-do list, too.
>
> Since this is legacy hardware, I am a bit skeptical about doing this
> -- and also 32-bit PIO, which is in the same category -- because this
> increases the amount of code we have to deal with, for the same basic
> function. For rarely-hit situations, I don't mind paying some
> performance penalty if it reduces long term maintenance. I am willing
> to push some ancient platforms in the "slow but working" category, to
> keep the code small and easier to review/debug/maintain.
>
> That said, it should be simple enough to push the logic into
> libata-scsi.c, where it translates a SCSI READ/WRITE command into an
> ATA read/write command. Patches welcome...
>
I would like to work on the LBA28/LBA48 translation. Please withdraw the
r/w multiple patch 4/4 for the moment since it might conflict with it.
Thanks.
Albert
^ permalink raw reply [flat|nested] 77+ messages in thread
* Re: [PATCH/RFC 4/4] irq-pio: add read/write multiple support
2005-10-04 12:00 ` Albert Lee
@ 2005-10-04 12:07 ` Jeff Garzik
2005-10-04 12:22 ` [PATCH/RFC 0/4] libata: CHS follow-up patches Albert Lee
0 siblings, 1 reply; 77+ messages in thread
From: Jeff Garzik @ 2005-10-04 12:07 UTC (permalink / raw)
To: Albert Lee
Cc: Mark Lord, Bartlomiej Zolnierkiewicz, Linux IDE, Doug Maxey,
Tejun Heo, Brett Russ, Alan Cox
Albert Lee wrote:
> I would like to work on the LBA28/LBA48 translation. Please withdraw the
> r/w multiple patch 4/4 for the moment since it might conflict with it.
> Thanks.
Now that your C/H/S support work is merged into the 'upstream' branch
(queued for 2.6.15), the LBA28/LBA48 translation work is probably
easier. Your C/H/S patches really did a good job of cleaning up
ata_scsi_rw_xlat().
Jeff
^ permalink raw reply [flat|nested] 77+ messages in thread
* [PATCH/RFC 0/4] libata: CHS follow-up patches
2005-10-04 12:07 ` Jeff Garzik
@ 2005-10-04 12:22 ` Albert Lee
2005-10-04 12:27 ` [PATCH/RFC 1/4] CHS: white space beautification Albert Lee
` (3 more replies)
0 siblings, 4 replies; 77+ messages in thread
From: Albert Lee @ 2005-10-04 12:22 UTC (permalink / raw)
To: Jeff Garzik
Cc: Mark Lord, Bartlomiej Zolnierkiewicz, Linux IDE, Doug Maxey,
Tejun Heo, Brett Russ, Alan Cox
Dear all,
CHS follow-up patches:
patch 1/4: white space, comments and debug message beautification
patch 2/4: tidy up SCSI lba and transfer length calculation
patch 3/4: add CHS support to ata_scsi_start_stop_xlat()
patch 4/4: calculate LBA28/LBA48 commands and protocol on the fly
Patch against libata-dev upstream branch
(a1213499b0ef75d8c627b461047805a235c9dd00).
For your review and advice, thanks.
Albert
^ permalink raw reply [flat|nested] 77+ messages in thread
* [PATCH/RFC 1/4] CHS: white space beautification
2005-10-04 12:22 ` [PATCH/RFC 0/4] libata: CHS follow-up patches Albert Lee
@ 2005-10-04 12:27 ` Albert Lee
2005-10-04 12:49 ` Jeff Garzik
2005-10-04 12:29 ` [PATCH/RFC 2/4] CHS: tidy up SCSI lba and transfer length calculation Albert Lee
` (2 subsequent siblings)
3 siblings, 1 reply; 77+ messages in thread
From: Albert Lee @ 2005-10-04 12:27 UTC (permalink / raw)
To: Jeff Garzik
Cc: Mark Lord, Bartlomiej Zolnierkiewicz, Linux IDE, Doug Maxey,
Tejun Heo, Brett Russ, Alan Cox
[-- Attachment #1: Type: text/plain, Size: 152 bytes --]
Patch 1/4:
white space, comments and debug message beautification
For your review, thanks.
Albert
Signed-off-by: Albert Lee <albertcc@tw.ibm.com>
[-- Attachment #2: chs1.diff --]
[-- Type: text/plain, Size: 2337 bytes --]
--- upstream/drivers/scsi/libata-scsi.c 2005-09-29 15:32:03.000000000 +0800
+++ chs0/drivers/scsi/libata-scsi.c 2005-10-04 17:50:13.000000000 +0800
@@ -589,7 +589,8 @@ static unsigned int ata_scsi_verify_xlat
head = track % dev->heads;
sect = (u32)block % dev->sectors + 1;
- DPRINTK("block[%u] track[%u] cyl[%u] head[%u] sect[%u] \n", (u32)block, track, cyl, head, sect);
+ DPRINTK("block %u track %u cyl %u head %u sect %u\n",
+ (u32)block, track, cyl, head, sect);
/* Check whether the converted CHS can fit.
Cylinder: 0-65535
@@ -665,6 +666,10 @@ static unsigned int ata_scsi_rw_xlat(str
block |= ((u64)scsicmd[3]);
n_block |= ((u32)scsicmd[4]);
+
+ /* for 6-byte r/w commands, transfer length 0
+ * means 256 blocks of data, not 0 block.
+ */
if (!n_block)
n_block = 256;
@@ -692,7 +697,11 @@ static unsigned int ata_scsi_rw_xlat(str
/* Check and compose ATA command */
if (!n_block)
- /* In ATA, sector count 0 means 256 or 65536 sectors, not 0 sectors. */
+ /* For 10-byte and 16-byte SCSI R/W commands, transfer
+ * length 0 means transfer 0 block of data.
+ * However, for ATA R/W commands, sector count 0 means
+ * 256 or 65536 sectors, not 0 sectors as in SCSI.
+ */
return 1;
if (lba) {
@@ -715,7 +724,7 @@ static unsigned int ata_scsi_rw_xlat(str
tf->device |= (block >> 24) & 0xf;
}
-
+
qc->nsect = n_block;
tf->nsect = n_block & 0xff;
@@ -731,23 +740,23 @@ static unsigned int ata_scsi_rw_xlat(str
/* The request -may- be too large for CHS addressing. */
if ((block >> 28) || (n_block > 256))
return 1;
-
+
/* Convert LBA to CHS */
track = (u32)block / dev->sectors;
cyl = track / dev->heads;
head = track % dev->heads;
sect = (u32)block % dev->sectors + 1;
- DPRINTK("block[%u] track[%u] cyl[%u] head[%u] sect[%u] \n",
+ DPRINTK("block %u track %u cyl %u head %u sect %u\n",
(u32)block, track, cyl, head, sect);
-
+
/* Check whether the converted CHS can fit.
Cylinder: 0-65535
Head: 0-15
Sector: 1-255*/
- if ((cyl >> 16) || (head >> 4) || (sect >> 8) || (!sect))
+ if ((cyl >> 16) || (head >> 4) || (sect >> 8) || (!sect))
return 1;
-
+
qc->nsect = n_block;
tf->nsect = n_block & 0xff; /* Sector count 0 means 256 sectors */
tf->lbal = sect;
^ permalink raw reply [flat|nested] 77+ messages in thread
* [PATCH/RFC 2/4] CHS: tidy up SCSI lba and transfer length calculation
2005-10-04 12:22 ` [PATCH/RFC 0/4] libata: CHS follow-up patches Albert Lee
2005-10-04 12:27 ` [PATCH/RFC 1/4] CHS: white space beautification Albert Lee
@ 2005-10-04 12:29 ` Albert Lee
2005-10-04 12:30 ` [PATCH/RFC 3/4] CHS: add CHS support to ata_scsi_start_stop_xlat() Albert Lee
2005-10-04 12:34 ` [PATCH/RFC 4/4] CHS: calculate LBA28/LBA48 commands and protocol on the fly Albert Lee
3 siblings, 0 replies; 77+ messages in thread
From: Albert Lee @ 2005-10-04 12:29 UTC (permalink / raw)
To: Jeff Garzik
Cc: Mark Lord, Bartlomiej Zolnierkiewicz, Linux IDE, Doug Maxey,
Tejun Heo, Brett Russ, Alan Cox
[-- Attachment #1: Type: text/plain, Size: 299 bytes --]
Patch 2/4: tidy up SCSI lba and transfer length calculation
changes:
- move the redundant SCSI lba and transfer length calculation code
from ata_scsi_verify_xlat() and ata_scsi_rw_xlat() to common functions.
For your review, thanks.
Albert
Signed-off-by: Albert Lee <albertcc@tw.ibm.com>
[-- Attachment #2: chs2.diff --]
[-- Type: text/plain, Size: 5584 bytes --]
--- chs0/drivers/scsi/libata-scsi.c 2005-10-04 17:50:13.000000000 +0800
+++ chs1/drivers/scsi/libata-scsi.c 2005-10-04 17:50:33.000000000 +0800
@@ -488,6 +488,99 @@ static unsigned int ata_scsi_flush_xlat(
}
/**
+ * scsi_6_lba_len - Get LBA and transfer length
+ * @scsicmd: SCSI command to translate
+ *
+ * Calculate LBA and transfer length for 6-byte commands.
+ *
+ * RETURNS:
+ * @plba: the LBA
+ * @plen: the transfer length
+ */
+
+static void scsi_6_lba_len(u8 *scsicmd, u64 *plba, u32 *plen)
+{
+ u64 lba = 0;
+ u32 len = 0;
+
+ VPRINTK("six-byte command\n");
+
+ lba |= ((u64)scsicmd[2]) << 8;
+ lba |= ((u64)scsicmd[3]);
+
+ len |= ((u32)scsicmd[4]);
+
+ *plba = lba;
+ *plen = len;
+}
+
+/**
+ * scsi_10_lba_len - Get LBA and transfer length
+ * @scsicmd: SCSI command to translate
+ *
+ * Calculate LBA and transfer length for 10-byte commands.
+ *
+ * RETURNS:
+ * @plba: the LBA
+ * @plen: the transfer length
+ */
+
+static void scsi_10_lba_len(u8 *scsicmd, u64 *plba, u32 *plen)
+{
+ u64 lba = 0;
+ u32 len = 0;
+
+ VPRINTK("ten-byte command\n");
+
+ lba |= ((u64)scsicmd[2]) << 24;
+ lba |= ((u64)scsicmd[3]) << 16;
+ lba |= ((u64)scsicmd[4]) << 8;
+ lba |= ((u64)scsicmd[5]);
+
+ len |= ((u32)scsicmd[7]) << 8;
+ len |= ((u32)scsicmd[8]);
+
+ *plba = lba;
+ *plen = len;
+}
+
+/**
+ * scsi_16_lba_len - Get LBA and transfer length
+ * @scsicmd: SCSI command to translate
+ *
+ * Calculate LBA and transfer length for 16-byte commands.
+ *
+ * RETURNS:
+ * @plba: the LBA
+ * @plen: the transfer length
+ */
+
+static void scsi_16_lba_len(u8 *scsicmd, u64 *plba, u32 *plen)
+{
+ u64 lba = 0;
+ u32 len = 0;
+
+ VPRINTK("sixteen-byte command\n");
+
+ lba |= ((u64)scsicmd[2]) << 56;
+ lba |= ((u64)scsicmd[3]) << 48;
+ lba |= ((u64)scsicmd[4]) << 40;
+ lba |= ((u64)scsicmd[5]) << 32;
+ lba |= ((u64)scsicmd[6]) << 24;
+ lba |= ((u64)scsicmd[7]) << 16;
+ lba |= ((u64)scsicmd[8]) << 8;
+ lba |= ((u64)scsicmd[9]);
+
+ len |= ((u32)scsicmd[10]) << 24;
+ len |= ((u32)scsicmd[11]) << 16;
+ len |= ((u32)scsicmd[12]) << 8;
+ len |= ((u32)scsicmd[13]);
+
+ *plba = lba;
+ *plen = len;
+}
+
+/**
* ata_scsi_verify_xlat - Translate SCSI VERIFY command into an ATA one
* @qc: Storage for translated ATA taskfile
* @scsicmd: SCSI command to translate
@@ -508,38 +601,16 @@ static unsigned int ata_scsi_verify_xlat
unsigned int lba = tf->flags & ATA_TFLAG_LBA;
unsigned int lba48 = tf->flags & ATA_TFLAG_LBA48;
u64 dev_sectors = qc->dev->n_sectors;
- u64 block = 0;
- u32 n_block = 0;
+ u64 block;
+ u32 n_block;
tf->flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
tf->protocol = ATA_PROT_NODATA;
- if (scsicmd[0] == VERIFY) {
- block |= ((u64)scsicmd[2]) << 24;
- block |= ((u64)scsicmd[3]) << 16;
- block |= ((u64)scsicmd[4]) << 8;
- block |= ((u64)scsicmd[5]);
-
- n_block |= ((u32)scsicmd[7]) << 8;
- n_block |= ((u32)scsicmd[8]);
- }
-
- else if (scsicmd[0] == VERIFY_16) {
- block |= ((u64)scsicmd[2]) << 56;
- block |= ((u64)scsicmd[3]) << 48;
- block |= ((u64)scsicmd[4]) << 40;
- block |= ((u64)scsicmd[5]) << 32;
- block |= ((u64)scsicmd[6]) << 24;
- block |= ((u64)scsicmd[7]) << 16;
- block |= ((u64)scsicmd[8]) << 8;
- block |= ((u64)scsicmd[9]);
-
- n_block |= ((u32)scsicmd[10]) << 24;
- n_block |= ((u32)scsicmd[11]) << 16;
- n_block |= ((u32)scsicmd[12]) << 8;
- n_block |= ((u32)scsicmd[13]);
- }
-
+ if (scsicmd[0] == VERIFY)
+ scsi_10_lba_len(scsicmd, &block, &n_block);
+ else if (scsicmd[0] == VERIFY_16)
+ scsi_16_lba_len(scsicmd, &block, &n_block);
else
return 1;
@@ -636,8 +707,8 @@ static unsigned int ata_scsi_rw_xlat(str
struct ata_device *dev = qc->dev;
unsigned int lba = tf->flags & ATA_TFLAG_LBA;
unsigned int lba48 = tf->flags & ATA_TFLAG_LBA48;
- u64 block = 0;
- u32 n_block = 0;
+ u64 block;
+ u32 n_block;
tf->flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
tf->protocol = qc->dev->xfer_protocol;
@@ -651,46 +722,26 @@ static unsigned int ata_scsi_rw_xlat(str
}
/* Calculate the SCSI LBA and transfer length. */
- if (scsicmd[0] == READ_10 || scsicmd[0] == WRITE_10) {
- block |= ((u64)scsicmd[2]) << 24;
- block |= ((u64)scsicmd[3]) << 16;
- block |= ((u64)scsicmd[4]) << 8;
- block |= ((u64)scsicmd[5]);
-
- n_block |= ((u32)scsicmd[7]) << 8;
- n_block |= ((u32)scsicmd[8]);
-
- VPRINTK("ten-byte command\n");
- } else if (scsicmd[0] == READ_6 || scsicmd[0] == WRITE_6) {
- block |= ((u64)scsicmd[2]) << 8;
- block |= ((u64)scsicmd[3]);
-
- n_block |= ((u32)scsicmd[4]);
+ switch (scsicmd[0]) {
+ case READ_10:
+ case WRITE_10:
+ scsi_10_lba_len(scsicmd, &block, &n_block);
+ break;
+ case READ_6:
+ case WRITE_6:
+ scsi_6_lba_len(scsicmd, &block, &n_block);
/* for 6-byte r/w commands, transfer length 0
* means 256 blocks of data, not 0 block.
*/
if (!n_block)
n_block = 256;
-
- VPRINTK("six-byte command\n");
- } else if (scsicmd[0] == READ_16 || scsicmd[0] == WRITE_16) {
- block |= ((u64)scsicmd[2]) << 56;
- block |= ((u64)scsicmd[3]) << 48;
- block |= ((u64)scsicmd[4]) << 40;
- block |= ((u64)scsicmd[5]) << 32;
- block |= ((u64)scsicmd[6]) << 24;
- block |= ((u64)scsicmd[7]) << 16;
- block |= ((u64)scsicmd[8]) << 8;
- block |= ((u64)scsicmd[9]);
-
- n_block |= ((u32)scsicmd[10]) << 24;
- n_block |= ((u32)scsicmd[11]) << 16;
- n_block |= ((u32)scsicmd[12]) << 8;
- n_block |= ((u32)scsicmd[13]);
-
- VPRINTK("sixteen-byte command\n");
- } else {
+ break;
+ case READ_16:
+ case WRITE_16:
+ scsi_16_lba_len(scsicmd, &block, &n_block);
+ break;
+ default:
DPRINTK("no-byte command\n");
return 1;
}
^ permalink raw reply [flat|nested] 77+ messages in thread
* [PATCH/RFC 3/4] CHS: add CHS support to ata_scsi_start_stop_xlat()
2005-10-04 12:22 ` [PATCH/RFC 0/4] libata: CHS follow-up patches Albert Lee
2005-10-04 12:27 ` [PATCH/RFC 1/4] CHS: white space beautification Albert Lee
2005-10-04 12:29 ` [PATCH/RFC 2/4] CHS: tidy up SCSI lba and transfer length calculation Albert Lee
@ 2005-10-04 12:30 ` Albert Lee
2005-10-04 12:34 ` [PATCH/RFC 4/4] CHS: calculate LBA28/LBA48 commands and protocol on the fly Albert Lee
3 siblings, 0 replies; 77+ messages in thread
From: Albert Lee @ 2005-10-04 12:30 UTC (permalink / raw)
To: Jeff Garzik
Cc: Mark Lord, Bartlomiej Zolnierkiewicz, Linux IDE, Doug Maxey,
Tejun Heo, Brett Russ, Alan Cox
[-- Attachment #1: Type: text/plain, Size: 140 bytes --]
Patch 3/4: add CHS support to ata_scsi_start_stop_xlat()
For your review, thanks.
Albert
Signed-off-by: Albert Lee <albertcc@tw.ibm.com>
[-- Attachment #2: chs3.diff --]
[-- Type: text/plain, Size: 826 bytes --]
--- chs1/drivers/scsi/libata-scsi.c 2005-10-04 17:50:33.000000000 +0800
+++ chs2/drivers/scsi/libata-scsi.c 2005-10-04 19:01:17.000000000 +0800
@@ -435,10 +435,21 @@ static unsigned int ata_scsi_start_stop_
return 1; /* power conditions not supported */
if (scsicmd[4] & 0x1) {
tf->nsect = 1; /* 1 sector, lba=0 */
- tf->lbah = 0x0;
- tf->lbam = 0x0;
- tf->lbal = 0x0;
- tf->device |= ATA_LBA;
+
+ if (qc->dev->flags & ATA_DFLAG_LBA) {
+ qc->tf.flags |= ATA_TFLAG_LBA;
+
+ tf->lbah = 0x0;
+ tf->lbam = 0x0;
+ tf->lbal = 0x0;
+ tf->device |= ATA_LBA;
+ } else {
+ /* CHS */
+ tf->lbal = 0x1; /* sect */
+ tf->lbam = 0x0; /* cyl low */
+ tf->lbah = 0x0; /* cyl high */
+ }
+
tf->command = ATA_CMD_VERIFY; /* READ VERIFY */
} else {
tf->nsect = 0; /* time period value (0 implies now) */
^ permalink raw reply [flat|nested] 77+ messages in thread
* [PATCH/RFC 4/4] CHS: calculate LBA28/LBA48 commands and protocol on the fly
2005-10-04 12:22 ` [PATCH/RFC 0/4] libata: CHS follow-up patches Albert Lee
` (2 preceding siblings ...)
2005-10-04 12:30 ` [PATCH/RFC 3/4] CHS: add CHS support to ata_scsi_start_stop_xlat() Albert Lee
@ 2005-10-04 12:34 ` Albert Lee
2005-10-04 12:52 ` Jeff Garzik
2005-10-04 15:48 ` [PATCH/RFC 4/4] CHS: calculate LBA28/LBA48 commands and protocol on the fly Alan Cox
3 siblings, 2 replies; 77+ messages in thread
From: Albert Lee @ 2005-10-04 12:34 UTC (permalink / raw)
To: Jeff Garzik
Cc: Mark Lord, Bartlomiej Zolnierkiewicz, Linux IDE, Doug Maxey,
Tejun Heo, Brett Russ, Alan Cox
[-- Attachment #1: Type: text/plain, Size: 524 bytes --]
Patch 4/4: calculate LBA28/LBA48 commands and protocol on the fly
Changes:
- calculate LBA28/LBA48 commands and protocol on the fly per Mark
and Jeff's advice
- add ATA_CMD_READ_MULTI, etc. to ata.h
- add multi_count to ata_device (just pave the road for r/w multiple)
- removed xfer_protocol, read_cmd and write_cmd from ata_device.
- merge ata_prot_to_cmd() and ata_dev_set_protocol() and move it to
libata-scsi.c
For your review, thanks.
Albert
Signed-off-by: Albert Lee <albertcc@tw.ibm.com>
[-- Attachment #2: chs4.diff --]
[-- Type: text/plain, Size: 9709 bytes --]
--- upstream/include/linux/ata.h 2005-09-29 15:32:12.000000000 +0800
+++ chs3/include/linux/ata.h 2005-10-04 18:37:42.000000000 +0800
@@ -128,6 +128,10 @@ enum {
ATA_CMD_PIO_READ_EXT = 0x24,
ATA_CMD_PIO_WRITE = 0x30,
ATA_CMD_PIO_WRITE_EXT = 0x34,
+ ATA_CMD_READ_MULTI = 0xC4,
+ ATA_CMD_READ_MULTI_EXT = 0x29,
+ ATA_CMD_WRITE_MULTI = 0xC5,
+ ATA_CMD_WRITE_MULTI_EXT = 0x39,
ATA_CMD_SET_FEATURES = 0xEF,
ATA_CMD_PACKET = 0xA0,
ATA_CMD_VERIFY = 0x40,
@@ -287,4 +291,14 @@ static inline int ata_ok(u8 status)
== ATA_DRDY);
}
+static inline int lba_28_ok(u64 block, u32 n_block)
+{
+ return (block < ((u64)1 << 28)) && (n_block <= 256);
+}
+
+static inline int lba_48_ok(u64 block, u32 n_block)
+{
+ return (block < ((u64)1 << 48)) && (n_block <= 65536);
+}
+
#endif /* __LINUX_ATA_H__ */
--- upstream/include/linux/libata.h 2005-09-29 15:32:12.000000000 +0800
+++ chs3/include/linux/libata.h 2005-10-04 17:16:56.000000000 +0800
@@ -279,10 +279,8 @@ struct ata_device {
u8 xfer_mode;
unsigned int xfer_shift; /* ATA_SHIFT_xxx */
- /* cache info about current transfer mode */
- u8 xfer_protocol; /* taskfile xfer protocol */
- u8 read_cmd; /* opcode to use on read */
- u8 write_cmd; /* opcode to use on write */
+ unsigned int multi_count; /* sectors count for
+ READ/WRITE MULTIPLE */
/* for CHS addressing */
u16 cylinders; /* Number of cylinders */
--- upstream/drivers/scsi/libata-core.c 2005-09-29 15:32:03.000000000 +0800
+++ chs3/drivers/scsi/libata-core.c 2005-10-04 18:36:15.000000000 +0800
@@ -616,81 +616,6 @@ void ata_tf_from_fis(u8 *fis, struct ata
tf->hob_nsect = fis[13];
}
-/**
- * ata_prot_to_cmd - determine which read/write opcodes to use
- * @protocol: ATA_PROT_xxx taskfile protocol
- * @lba48: true is lba48 is present
- *
- * Given necessary input, determine which read/write commands
- * to use to transfer data.
- *
- * LOCKING:
- * None.
- */
-static int ata_prot_to_cmd(int protocol, int lba48)
-{
- int rcmd = 0, wcmd = 0;
-
- switch (protocol) {
- case ATA_PROT_PIO:
- if (lba48) {
- rcmd = ATA_CMD_PIO_READ_EXT;
- wcmd = ATA_CMD_PIO_WRITE_EXT;
- } else {
- rcmd = ATA_CMD_PIO_READ;
- wcmd = ATA_CMD_PIO_WRITE;
- }
- break;
-
- case ATA_PROT_DMA:
- if (lba48) {
- rcmd = ATA_CMD_READ_EXT;
- wcmd = ATA_CMD_WRITE_EXT;
- } else {
- rcmd = ATA_CMD_READ;
- wcmd = ATA_CMD_WRITE;
- }
- break;
-
- default:
- return -1;
- }
-
- return rcmd | (wcmd << 8);
-}
-
-/**
- * ata_dev_set_protocol - set taskfile protocol and r/w commands
- * @dev: device to examine and configure
- *
- * Examine the device configuration, after we have
- * read the identify-device page and configured the
- * data transfer mode. Set internal state related to
- * the ATA taskfile protocol (pio, pio mult, dma, etc.)
- * and calculate the proper read/write commands to use.
- *
- * LOCKING:
- * caller.
- */
-static void ata_dev_set_protocol(struct ata_device *dev)
-{
- int pio = (dev->flags & ATA_DFLAG_PIO);
- int lba48 = (dev->flags & ATA_DFLAG_LBA48);
- int proto, cmd;
-
- if (pio)
- proto = dev->xfer_protocol = ATA_PROT_PIO;
- else
- proto = dev->xfer_protocol = ATA_PROT_DMA;
-
- cmd = ata_prot_to_cmd(proto, lba48);
- if (cmd < 0)
- BUG();
-
- dev->read_cmd = cmd & 0xff;
- dev->write_cmd = (cmd >> 8) & 0xff;
-}
-
static const char * xfer_mode_str[] = {
"UDMA/16",
"UDMA/25",
@@ -1641,7 +1566,7 @@ static void ata_host_set_dma(struct ata_
*/
static void ata_set_mode(struct ata_port *ap)
{
- unsigned int i, xfer_shift;
+ unsigned int xfer_shift;
u8 xfer_mode;
int rc;
@@ -1670,11 +1595,6 @@ static void ata_set_mode(struct ata_port
if (ap->ops->post_set_mode)
ap->ops->post_set_mode(ap);
- for (i = 0; i < 2; i++) {
- struct ata_device *dev = &ap->device[i];
- ata_dev_set_protocol(dev);
- }
-
return;
err_out:
@@ -3241,13 +3161,6 @@ struct ata_queued_cmd *ata_qc_new_init(s
qc->nbytes = qc->curbytes = 0;
ata_tf_init(ap, &qc->tf, dev->devno);
-
- if (dev->flags & ATA_DFLAG_LBA) {
- qc->tf.flags |= ATA_TFLAG_LBA;
-
- if (dev->flags & ATA_DFLAG_LBA48)
- qc->tf.flags |= ATA_TFLAG_LBA48;
- }
}
return qc;
--- chs2/drivers/scsi/libata-scsi.c 2005-10-04 19:01:17.000000000 +0800
+++ chs3/drivers/scsi/libata-scsi.c 2005-10-04 18:36:48.000000000 +0800
@@ -489,7 +489,7 @@ static unsigned int ata_scsi_flush_xlat(
tf->flags |= ATA_TFLAG_DEVICE;
tf->protocol = ATA_PROT_NODATA;
- if ((tf->flags & ATA_TFLAG_LBA48) &&
+ if ((qc->dev->flags & ATA_DFLAG_LBA48) &&
(ata_id_has_flush_ext(qc->dev->id)))
tf->command = ATA_CMD_FLUSH_EXT;
else
@@ -609,8 +609,6 @@ static unsigned int ata_scsi_verify_xlat
{
struct ata_taskfile *tf = &qc->tf;
struct ata_device *dev = qc->dev;
- unsigned int lba = tf->flags & ATA_TFLAG_LBA;
- unsigned int lba48 = tf->flags & ATA_TFLAG_LBA48;
u64 dev_sectors = qc->dev->n_sectors;
u64 block;
u32 n_block;
@@ -631,16 +629,21 @@ static unsigned int ata_scsi_verify_xlat
return 1;
if ((block + n_block) > dev_sectors)
return 1;
- if (lba48) {
- if (n_block > (64 * 1024))
- return 1;
- } else {
- if (n_block > 256)
- return 1;
- }
- if (lba) {
- if (lba48) {
+ if (dev->flags & ATA_DFLAG_LBA) {
+ qc->tf.flags |= ATA_TFLAG_LBA;
+
+ if (lba_28_ok(block, n_block)) {
+ /* use LBA28 */
+ tf->command = ATA_CMD_VERIFY;
+
+ tf->device |= (block >> 24) & 0xf;
+ } else if (lba_48_ok(block, n_block)) {
+ if (!(dev->flags & ATA_DFLAG_LBA48))
+ return 1;
+
+ /* use LBA48 */
+ qc->tf.flags |= ATA_TFLAG_LBA48;
tf->command = ATA_CMD_VERIFY_EXT;
tf->hob_nsect = (n_block >> 8) & 0xff;
@@ -648,11 +651,9 @@ static unsigned int ata_scsi_verify_xlat
tf->hob_lbah = (block >> 40) & 0xff;
tf->hob_lbam = (block >> 32) & 0xff;
tf->hob_lbal = (block >> 24) & 0xff;
- } else {
- tf->command = ATA_CMD_VERIFY;
-
- tf->device |= (block >> 24) & 0xf;
- }
+ } else
+ /* request too large even for LBA48 */
+ return 1;
tf->nsect = n_block & 0xff;
@@ -665,6 +666,9 @@ static unsigned int ata_scsi_verify_xlat
/* CHS */
u32 sect, head, cyl, track;
+ if (!lba_28_ok(block, n_block))
+ return 1;
+
/* Convert LBA to CHS */
track = (u32)block / dev->sectors;
cyl = track / dev->heads;
@@ -692,6 +696,55 @@ static unsigned int ata_scsi_verify_xlat
return 0;
}
+static const u8 ata_rw_cmds[] = {
+ /* pio multi */
+ ATA_CMD_READ_MULTI,
+ ATA_CMD_WRITE_MULTI,
+ ATA_CMD_READ_MULTI_EXT,
+ ATA_CMD_WRITE_MULTI_EXT,
+ /* pio */
+ ATA_CMD_PIO_READ,
+ ATA_CMD_PIO_WRITE,
+ ATA_CMD_PIO_READ_EXT,
+ ATA_CMD_PIO_WRITE_EXT,
+ /* dma */
+ ATA_CMD_READ,
+ ATA_CMD_WRITE,
+ ATA_CMD_READ_EXT,
+ ATA_CMD_WRITE_EXT
+};
+
+/**
+ * ata_rw_cmd_protocol - set taskfile r/w commands and protocol
+ * @qc: command to examine and configure
+ *
+ * Examine the device configuration and tf->flags to calculate
+ * the proper read/write commands and protocol to use.
+ *
+ * LOCKING:
+ * caller.
+ */
+static void ata_rw_cmd_protocol(struct ata_queued_cmd *qc)
+{
+ struct ata_taskfile *tf = &qc->tf;
+ struct ata_device *dev = qc->dev;
+
+ int index, lba48, write;
+
+ lba48 = (tf->flags & ATA_TFLAG_LBA48) ? 2 : 0;
+ write = (tf->flags & ATA_TFLAG_WRITE) ? 1 : 0;
+
+ if (dev->flags & ATA_DFLAG_PIO) {
+ tf->protocol = ATA_PROT_PIO;
+ index = dev->multi_count ? 0 : 4;
+ } else {
+ tf->protocol = ATA_PROT_DMA;
+ index = 8;
+ }
+
+ tf->command = ata_rw_cmds[index + lba48 + write];
+}
+
/**
* ata_scsi_rw_xlat - Translate SCSI r/w command into an ATA one
* @qc: Storage for translated ATA taskfile
@@ -716,21 +769,14 @@ static unsigned int ata_scsi_rw_xlat(str
{
struct ata_taskfile *tf = &qc->tf;
struct ata_device *dev = qc->dev;
- unsigned int lba = tf->flags & ATA_TFLAG_LBA;
- unsigned int lba48 = tf->flags & ATA_TFLAG_LBA48;
u64 block;
u32 n_block;
tf->flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
- tf->protocol = qc->dev->xfer_protocol;
- if (scsicmd[0] == READ_10 || scsicmd[0] == READ_6 ||
- scsicmd[0] == READ_16) {
- tf->command = qc->dev->read_cmd;
- } else {
- tf->command = qc->dev->write_cmd;
+ if (scsicmd[0] == WRITE_10 || scsicmd[0] == WRITE_6 ||
+ scsicmd[0] == WRITE_16)
tf->flags |= ATA_TFLAG_WRITE;
- }
/* Calculate the SCSI LBA and transfer length. */
switch (scsicmd[0]) {
@@ -766,26 +812,30 @@ static unsigned int ata_scsi_rw_xlat(str
*/
return 1;
- if (lba) {
- if (lba48) {
- /* The request -may- be too large for LBA48. */
- if ((block >> 48) || (n_block > 65536))
+ if (dev->flags & ATA_DFLAG_LBA) {
+ qc->tf.flags |= ATA_TFLAG_LBA;
+
+ if (lba_28_ok(block, n_block)) {
+ /* use LBA28 */
+ tf->device |= (block >> 24) & 0xf;
+
+ } else if (lba_48_ok(block, n_block)) {
+ if (!(dev->flags & ATA_DFLAG_LBA48))
return 1;
+ /* use LBA48 */
+ qc->tf.flags |= ATA_TFLAG_LBA48;
+
tf->hob_nsect = (n_block >> 8) & 0xff;
tf->hob_lbah = (block >> 40) & 0xff;
tf->hob_lbam = (block >> 32) & 0xff;
tf->hob_lbal = (block >> 24) & 0xff;
- } else {
- /* LBA28 */
-
- /* The request -may- be too large for LBA28. */
- if ((block >> 28) || (n_block > 256))
- return 1;
+ } else
+ /* request too large even for LBA48 */
+ return 1;
- tf->device |= (block >> 24) & 0xf;
- }
+ ata_rw_cmd_protocol(qc);
qc->nsect = n_block;
tf->nsect = n_block & 0xff;
@@ -800,9 +850,11 @@ static unsigned int ata_scsi_rw_xlat(str
u32 sect, head, cyl, track;
/* The request -may- be too large for CHS addressing. */
- if ((block >> 28) || (n_block > 256))
+ if (!lba_28_ok(block, n_block))
return 1;
+ ata_rw_cmd_protocol(qc);
+
/* Convert LBA to CHS */
track = (u32)block / dev->sectors;
cyl = track / dev->heads;
^ permalink raw reply [flat|nested] 77+ messages in thread
* Re: [PATCH/RFC 1/4] CHS: white space beautification
2005-10-04 12:27 ` [PATCH/RFC 1/4] CHS: white space beautification Albert Lee
@ 2005-10-04 12:49 ` Jeff Garzik
0 siblings, 0 replies; 77+ messages in thread
From: Jeff Garzik @ 2005-10-04 12:49 UTC (permalink / raw)
To: Albert Lee
Cc: Mark Lord, Bartlomiej Zolnierkiewicz, Linux IDE, Doug Maxey,
Tejun Heo, Brett Russ, Alan Cox
applied patches 1-3.
Can you please work out an email solution that doesn't involve attaching
patches? I have to manually each patch, rather than running the
git-applymbox script.
^ permalink raw reply [flat|nested] 77+ messages in thread
* Re: [PATCH/RFC 4/4] CHS: calculate LBA28/LBA48 commands and protocol on the fly
2005-10-04 12:34 ` [PATCH/RFC 4/4] CHS: calculate LBA28/LBA48 commands and protocol on the fly Albert Lee
@ 2005-10-04 12:52 ` Jeff Garzik
2005-10-05 11:16 ` [PATCH/RFC 0/4] libata: more CHS follow-up patches Albert Lee
2005-10-04 15:48 ` [PATCH/RFC 4/4] CHS: calculate LBA28/LBA48 commands and protocol on the fly Alan Cox
1 sibling, 1 reply; 77+ messages in thread
From: Jeff Garzik @ 2005-10-04 12:52 UTC (permalink / raw)
To: Albert Lee
Cc: Mark Lord, Bartlomiej Zolnierkiewicz, Linux IDE, Doug Maxey,
Tejun Heo, Brett Russ, Alan Cox
Albert Lee wrote:
> Patch 4/4: calculate LBA28/LBA48 commands and protocol on the fly
>
> Changes:
> - calculate LBA28/LBA48 commands and protocol on the fly per Mark and
> Jeff's advice
> - add ATA_CMD_READ_MULTI, etc. to ata.h
> - add multi_count to ata_device (just pave the road for r/w multiple)
> - removed xfer_protocol, read_cmd and write_cmd from ata_device.
> - merge ata_prot_to_cmd() and ata_dev_set_protocol() and move it to
> libata-scsi.c
seems OK at first glance, but please move the LBA28/LBA48 optimization
change into a separate patch from the rest of these cleanups.
not applied.
^ permalink raw reply [flat|nested] 77+ messages in thread
* Re: [PATCH/RFC 4/4] CHS: calculate LBA28/LBA48 commands and protocol on the fly
2005-10-04 12:34 ` [PATCH/RFC 4/4] CHS: calculate LBA28/LBA48 commands and protocol on the fly Albert Lee
2005-10-04 12:52 ` Jeff Garzik
@ 2005-10-04 15:48 ` Alan Cox
1 sibling, 0 replies; 77+ messages in thread
From: Alan Cox @ 2005-10-04 15:48 UTC (permalink / raw)
To: Albert Lee
Cc: Jeff Garzik, Mark Lord, Bartlomiej Zolnierkiewicz, Linux IDE,
Doug Maxey, Tejun Heo, Brett Russ
> + if (dev->flags & ATA_DFLAG_LBA) {
> + qc->tf.flags |= ATA_TFLAG_LBA;
> +
> + if (lba_28_ok(block, n_block)) {
> + /* use LBA28 */
> + tf->command = ATA_CMD_VERIFY;
> +
> + tf->device |= (block >> 24) & 0xf;
> + } else if (lba_48_ok(block, n_block)) {
> + if (!(dev->flags & ATA_DFLAG_LBA48))
> + return 1;
> +
> + /* use LBA48 */
> + qc->tf.flags |= ATA_TFLAG_LBA48;
Can you make this decision a function because older ALi controllers at
least will need to replace it (they do LBA48 PIO, LBA28 DMA)
^ permalink raw reply [flat|nested] 77+ messages in thread
* [PATCH/RFC 0/4] libata: more CHS follow-up patches
2005-10-04 12:52 ` Jeff Garzik
@ 2005-10-05 11:16 ` Albert Lee
2005-10-05 11:20 ` [PATCH/RFC 1/4] CHS: move the initialization of taskfile LBA flags Albert Lee
` (8 more replies)
0 siblings, 9 replies; 77+ messages in thread
From: Albert Lee @ 2005-10-05 11:16 UTC (permalink / raw)
To: Jeff Garzik
Cc: Mark Lord, Bartlomiej Zolnierkiewicz, Linux IDE, Doug Maxey,
Tejun Heo, Brett Russ, Alan Cox
Dear all,
More CHS follow-up patches:
patch 1/4: move the initialization of ATA_TFLAG_LBA and ATA_TFLAG_LBA48
flags to the SCSI translation functions
patch 2/4: calculate read/write commands and protocols on the fly
patch 3/4: support overriding the ata_rwcmd_protocol() function
patch 4/4: optimize LBA28/LBA48 usage
Patch against libata-dev upstream branch
(643736a58d2668af94aee05670c5e9ae76e7b85f).
For your review and advice, thanks.
Albert
^ permalink raw reply [flat|nested] 77+ messages in thread
* [PATCH/RFC 1/4] CHS: move the initialization of taskfile LBA flags
2005-10-05 11:16 ` [PATCH/RFC 0/4] libata: more CHS follow-up patches Albert Lee
@ 2005-10-05 11:20 ` Albert Lee
2005-10-05 11:23 ` [PATCH/RFC 2/4] CHS: calculate read/write commands and protocol on the fly Albert Lee
` (7 subsequent siblings)
8 siblings, 0 replies; 77+ messages in thread
From: Albert Lee @ 2005-10-05 11:20 UTC (permalink / raw)
To: Jeff Garzik
Cc: Mark Lord, Bartlomiej Zolnierkiewicz, Linux IDE, Doug Maxey,
Tejun Heo, Brett Russ, Alan Cox
Patch 1/4:
move the initialization of taskfile LBA flags:
ATA_TFLAG_LBA and ATA_TFLAG_LBA48 flags
to the SCSI translation functions
For your review, thanks.
Albert
Signed-off-by: Albert Lee <albertcc@tw.ibm.com>
=============
--- upstream/drivers/scsi/libata-core.c 2005-10-05 18:04:07.000000000
+0800
+++ ch1/drivers/scsi/libata-core.c 2005-10-05 18:10:28.000000000 +0800
@@ -3241,13 +3241,6 @@ struct ata_queued_cmd *ata_qc_new_init(s
qc->nbytes = qc->curbytes = 0;
ata_tf_init(ap, &qc->tf, dev->devno);
-
- if (dev->flags & ATA_DFLAG_LBA) {
- qc->tf.flags |= ATA_TFLAG_LBA;
-
- if (dev->flags & ATA_DFLAG_LBA48)
- qc->tf.flags |= ATA_TFLAG_LBA48;
- }
}
return qc;
--- upstream/drivers/scsi/libata-scsi.c 2005-10-05 18:04:07.000000000
+0800
+++ ch1/drivers/scsi/libata-scsi.c 2005-10-05 18:10:28.000000000 +0800
@@ -489,7 +489,7 @@ static unsigned int ata_scsi_flush_xlat(
tf->flags |= ATA_TFLAG_DEVICE;
tf->protocol = ATA_PROT_NODATA;
- if ((tf->flags & ATA_TFLAG_LBA48) &&
+ if ((qc->dev->flags & ATA_DFLAG_LBA48) &&
(ata_id_has_flush_ext(qc->dev->id)))
tf->command = ATA_CMD_FLUSH_EXT;
else
@@ -609,8 +609,6 @@ static unsigned int ata_scsi_verify_xlat
{
struct ata_taskfile *tf = &qc->tf;
struct ata_device *dev = qc->dev;
- unsigned int lba = tf->flags & ATA_TFLAG_LBA;
- unsigned int lba48 = tf->flags & ATA_TFLAG_LBA48;
u64 dev_sectors = qc->dev->n_sectors;
u64 block;
u32 n_block;
@@ -631,16 +629,16 @@ static unsigned int ata_scsi_verify_xlat
return 1;
if ((block + n_block) > dev_sectors)
return 1;
- if (lba48) {
- if (n_block > (64 * 1024))
- return 1;
- } else {
- if (n_block > 256)
- return 1;
- }
- if (lba) {
- if (lba48) {
+ if (dev->flags & ATA_DFLAG_LBA) {
+ tf->flags |= ATA_TFLAG_LBA;
+
+ if (dev->flags & ATA_DFLAG_LBA48) {
+ if (n_block > (64 * 1024))
+ return 1;
+
+ /* use LBA48 */
+ tf->flags |= ATA_TFLAG_LBA48;
tf->command = ATA_CMD_VERIFY_EXT;
tf->hob_nsect = (n_block >> 8) & 0xff;
@@ -649,8 +647,11 @@ static unsigned int ata_scsi_verify_xlat
tf->hob_lbam = (block >> 32) & 0xff;
tf->hob_lbal = (block >> 24) & 0xff;
} else {
- tf->command = ATA_CMD_VERIFY;
+ if (n_block > 256)
+ return 1;
+ /* use LBA28 */
+ tf->command = ATA_CMD_VERIFY;
tf->device |= (block >> 24) & 0xf;
}
@@ -665,6 +666,9 @@ static unsigned int ata_scsi_verify_xlat
/* CHS */
u32 sect, head, cyl, track;
+ if (n_block > 256)
+ return 1;
+
/* Convert LBA to CHS */
track = (u32)block / dev->sectors;
cyl = track / dev->heads;
@@ -716,8 +720,6 @@ static unsigned int ata_scsi_rw_xlat(str
{
struct ata_taskfile *tf = &qc->tf;
struct ata_device *dev = qc->dev;
- unsigned int lba = tf->flags & ATA_TFLAG_LBA;
- unsigned int lba48 = tf->flags & ATA_TFLAG_LBA48;
u64 block;
u32 n_block;
@@ -766,19 +768,24 @@ static unsigned int ata_scsi_rw_xlat(str
*/
return 1;
- if (lba) {
- if (lba48) {
+ if (dev->flags & ATA_DFLAG_LBA) {
+ tf->flags |= ATA_TFLAG_LBA;
+
+ if (dev->flags & ATA_DFLAG_LBA48) {
/* The request -may- be too large for LBA48. */
if ((block >> 48) || (n_block > 65536))
return 1;
+ /* use LBA48 */
+ tf->flags |= ATA_TFLAG_LBA48;
+
tf->hob_nsect = (n_block >> 8) & 0xff;
tf->hob_lbah = (block >> 40) & 0xff;
tf->hob_lbam = (block >> 32) & 0xff;
tf->hob_lbal = (block >> 24) & 0xff;
} else {
- /* LBA28 */
+ /* use LBA28 */
/* The request -may- be too large for LBA28. */
if ((block >> 28) || (n_block > 256))
^ permalink raw reply [flat|nested] 77+ messages in thread
* [PATCH/RFC 2/4] CHS: calculate read/write commands and protocol on the fly
2005-10-05 11:16 ` [PATCH/RFC 0/4] libata: more CHS follow-up patches Albert Lee
2005-10-05 11:20 ` [PATCH/RFC 1/4] CHS: move the initialization of taskfile LBA flags Albert Lee
@ 2005-10-05 11:23 ` Albert Lee
2005-10-05 11:25 ` [PATCH/RFC 3/4] CHS: support overriding the ata_rwcmd_protocol() function Albert Lee
` (6 subsequent siblings)
8 siblings, 0 replies; 77+ messages in thread
From: Albert Lee @ 2005-10-05 11:23 UTC (permalink / raw)
To: Jeff Garzik
Cc: Mark Lord, Bartlomiej Zolnierkiewicz, Linux IDE, Doug Maxey,
Tejun Heo, Brett Russ, Alan Cox
Patch 2/4: calculate read/write commands and protocols on the fly
changes:
- merge ata_prot_to_cmd() and ata_dev_set_protocol() as
ata_rwcmd_protocol()
- pave road for read/write multiple support
- remove usage of pre-cached command and protocol values and call
ata_rwcmd_protocol() instead
For your review, thanks.
Albert
Signed-off-by: Albert Lee <albertcc@tw.ibm.com>
==============
--- upstream/include/linux/ata.h 2005-10-05 18:04:16.000000000 +0800
+++ ch2/include/linux/ata.h 2005-10-05 18:11:12.000000000 +0800
@@ -128,6 +128,10 @@ enum {
ATA_CMD_PIO_READ_EXT = 0x24,
ATA_CMD_PIO_WRITE = 0x30,
ATA_CMD_PIO_WRITE_EXT = 0x34,
+ ATA_CMD_READ_MULTI = 0xC4,
+ ATA_CMD_READ_MULTI_EXT = 0x29,
+ ATA_CMD_WRITE_MULTI = 0xC5,
+ ATA_CMD_WRITE_MULTI_EXT = 0x39,
ATA_CMD_SET_FEATURES = 0xEF,
ATA_CMD_PACKET = 0xA0,
ATA_CMD_VERIFY = 0x40,
--- upstream/include/linux/libata.h 2005-10-05 18:04:16.000000000 +0800
+++ ch2/include/linux/libata.h 2005-10-05 18:11:12.000000000 +0800
@@ -283,10 +283,8 @@ struct ata_device {
u8 xfer_mode;
unsigned int xfer_shift; /* ATA_SHIFT_xxx */
- /* cache info about current transfer mode */
- u8 xfer_protocol; /* taskfile xfer protocol */
- u8 read_cmd; /* opcode to use on read */
- u8 write_cmd; /* opcode to use on write */
+ unsigned int multi_count; /* sectors count for
+ READ/WRITE MULTIPLE */
/* for CHS addressing */
u16 cylinders; /* Number of cylinders */
--- upstream/drivers/scsi/libata.h 2005-10-05 18:04:07.000000000 +0800
+++ ch2/drivers/scsi/libata.h 2005-10-05 18:11:12.000000000 +0800
@@ -41,6 +41,7 @@ struct ata_scsi_args {
extern int atapi_enabled;
extern struct ata_queued_cmd *ata_qc_new_init(struct ata_port *ap,
struct ata_device *dev);
+extern void ata_rwcmd_protocol(struct ata_queued_cmd *qc);
extern void ata_qc_free(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);
--- ch1/drivers/scsi/libata-core.c 2005-10-05 18:10:28.000000000 +0800
+++ ch2/drivers/scsi/libata-core.c 2005-10-05 18:11:12.000000000 +0800
@@ -616,79 +616,68 @@ void ata_tf_from_fis(u8 *fis, struct ata
tf->hob_nsect = fis[13];
}
+static const u8 ata_rw_cmds[] = {
+ /* pio multi */
+ ATA_CMD_READ_MULTI,
+ ATA_CMD_WRITE_MULTI,
+ ATA_CMD_READ_MULTI_EXT,
+ ATA_CMD_WRITE_MULTI_EXT,
+ /* pio */
+ ATA_CMD_PIO_READ,
+ ATA_CMD_PIO_WRITE,
+ ATA_CMD_PIO_READ_EXT,
+ ATA_CMD_PIO_WRITE_EXT,
+ /* dma */
+ ATA_CMD_READ,
+ ATA_CMD_WRITE,
+ ATA_CMD_READ_EXT,
+ ATA_CMD_WRITE_EXT
+};
+
/**
- * ata_prot_to_cmd - determine which read/write opcodes to use
- * @protocol: ATA_PROT_xxx taskfile protocol
- * @lba48: true is lba48 is present
+ * ata_qc_rwcmd_protocol - set taskfile r/w commands and protocol
+ * @qc: command to examine and configure
*
- * Given necessary input, determine which read/write commands
- * to use to transfer data.
+ * Examine the device configuration and tf->flags to calculate
+ * the proper read/write commands and protocol to use.
*
* LOCKING:
- * None.
+ * caller.
*/
-static int ata_prot_to_cmd(int protocol, int lba48)
+static void ata_qc_rwcmd_protocol(struct ata_queued_cmd *qc)
{
- int rcmd = 0, wcmd = 0;
-
- switch (protocol) {
- case ATA_PROT_PIO:
- if (lba48) {
- rcmd = ATA_CMD_PIO_READ_EXT;
- wcmd = ATA_CMD_PIO_WRITE_EXT;
- } else {
- rcmd = ATA_CMD_PIO_READ;
- wcmd = ATA_CMD_PIO_WRITE;
- }
- break;
-
- case ATA_PROT_DMA:
- if (lba48) {
- rcmd = ATA_CMD_READ_EXT;
- wcmd = ATA_CMD_WRITE_EXT;
- } else {
- rcmd = ATA_CMD_READ;
- wcmd = ATA_CMD_WRITE;
- }
- break;
+ struct ata_taskfile *tf = &qc->tf;
+ struct ata_device *dev = qc->dev;
- default:
- return -1;
+ int index, lba48, write;
+
+ lba48 = (tf->flags & ATA_TFLAG_LBA48) ? 2 : 0;
+ write = (tf->flags & ATA_TFLAG_WRITE) ? 1 : 0;
+
+ if (dev->flags & ATA_DFLAG_PIO) {
+ tf->protocol = ATA_PROT_PIO;
+ index = dev->multi_count ? 0 : 4;
+ } else {
+ tf->protocol = ATA_PROT_DMA;
+ index = 8;
}
- return rcmd | (wcmd << 8);
+ tf->command = ata_rw_cmds[index + lba48 + write];
}
/**
- * ata_dev_set_protocol - set taskfile protocol and r/w commands
- * @dev: device to examine and configure
+ * ata_rwcmd_protocol - set taskfile r/w commands and protocol
+ * @qc: command to examine and configure
*
- * Examine the device configuration, after we have
- * read the identify-device page and configured the
- * data transfer mode. Set internal state related to
- * the ATA taskfile protocol (pio, pio mult, dma, etc.)
- * and calculate the proper read/write commands to use.
+ * Examine the device configuration and tf->flags to calculate
+ * the proper read/write commands and protocol to use.
*
* LOCKING:
* caller.
*/
-static void ata_dev_set_protocol(struct ata_device *dev)
+void ata_rwcmd_protocol(struct ata_queued_cmd *qc)
{
- int pio = (dev->flags & ATA_DFLAG_PIO);
- int lba48 = (dev->flags & ATA_DFLAG_LBA48);
- int proto, cmd;
-
- if (pio)
- proto = dev->xfer_protocol = ATA_PROT_PIO;
- else
- proto = dev->xfer_protocol = ATA_PROT_DMA;
-
- cmd = ata_prot_to_cmd(proto, lba48);
- if (cmd < 0)
- BUG();
-
- dev->read_cmd = cmd & 0xff;
- dev->write_cmd = (cmd >> 8) & 0xff;
+ ata_qc_rwcmd_protocol(qc);
}
static const char * xfer_mode_str[] = {
@@ -1641,7 +1630,7 @@ static void ata_host_set_dma(struct ata_
*/
static void ata_set_mode(struct ata_port *ap)
{
- unsigned int i, xfer_shift;
+ unsigned int xfer_shift;
u8 xfer_mode;
int rc;
@@ -1670,11 +1659,6 @@ static void ata_set_mode(struct ata_port
if (ap->ops->post_set_mode)
ap->ops->post_set_mode(ap);
- for (i = 0; i < 2; i++) {
- struct ata_device *dev = &ap->device[i];
- ata_dev_set_protocol(dev);
- }
-
return;
err_out:
--- ch1/drivers/scsi/libata-scsi.c 2005-10-05 18:10:28.000000000 +0800
+++ ch2/drivers/scsi/libata-scsi.c 2005-10-05 18:11:12.000000000 +0800
@@ -724,15 +724,10 @@ static unsigned int ata_scsi_rw_xlat(str
u32 n_block;
tf->flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
- tf->protocol = qc->dev->xfer_protocol;
- if (scsicmd[0] == READ_10 || scsicmd[0] == READ_6 ||
- scsicmd[0] == READ_16) {
- tf->command = qc->dev->read_cmd;
- } else {
- tf->command = qc->dev->write_cmd;
+ if (scsicmd[0] == WRITE_10 || scsicmd[0] == WRITE_6 ||
+ scsicmd[0] == WRITE_16)
tf->flags |= ATA_TFLAG_WRITE;
- }
/* Calculate the SCSI LBA and transfer length. */
switch (scsicmd[0]) {
@@ -794,6 +789,8 @@ static unsigned int ata_scsi_rw_xlat(str
tf->device |= (block >> 24) & 0xf;
}
+ ata_rwcmd_protocol(qc);
+
qc->nsect = n_block;
tf->nsect = n_block & 0xff;
@@ -810,6 +807,8 @@ static unsigned int ata_scsi_rw_xlat(str
if ((block >> 28) || (n_block > 256))
return 1;
+ ata_rwcmd_protocol(qc);
+
/* Convert LBA to CHS */
track = (u32)block / dev->sectors;
cyl = track / dev->heads;
^ permalink raw reply [flat|nested] 77+ messages in thread
* [PATCH/RFC 3/4] CHS: support overriding the ata_rwcmd_protocol() function
2005-10-05 11:16 ` [PATCH/RFC 0/4] libata: more CHS follow-up patches Albert Lee
2005-10-05 11:20 ` [PATCH/RFC 1/4] CHS: move the initialization of taskfile LBA flags Albert Lee
2005-10-05 11:23 ` [PATCH/RFC 2/4] CHS: calculate read/write commands and protocol on the fly Albert Lee
@ 2005-10-05 11:25 ` Albert Lee
2005-10-05 11:27 ` [PATCH/RFC 4/4] CHS: optimize LBA28/LBA48 usage Albert Lee
` (5 subsequent siblings)
8 siblings, 0 replies; 77+ messages in thread
From: Albert Lee @ 2005-10-05 11:25 UTC (permalink / raw)
To: Jeff Garzik
Cc: Mark Lord, Bartlomiej Zolnierkiewicz, Linux IDE, Doug Maxey,
Tejun Heo, Brett Russ, Alan Cox
Patch 3/4:
support overriding the ata_rwcmd_protocol() function for some VIA
adapters per Alan's advice.
For your review, thanks.
Albert
Signed-off-by: Albert Lee <albertcc@tw.ibm.com>
=======
--- ch2/include/linux/libata.h 2005-10-05 18:11:12.000000000 +0800
+++ ch3/include/linux/libata.h 2005-10-05 18:11:51.000000000 +0800
@@ -353,6 +353,8 @@ struct ata_port_operations {
void (*phy_reset) (struct ata_port *ap);
void (*post_set_mode) (struct ata_port *ap);
+ /* workaround host adapter limitations */
+ void (*rwcmd_protocol) (struct ata_queued_cmd *qc);
int (*check_atapi_dma) (struct ata_queued_cmd *qc);
void (*bmdma_setup) (struct ata_queued_cmd *qc);
--- ch2/drivers/scsi/libata-core.c 2005-10-05 18:11:12.000000000 +0800
+++ ch3/drivers/scsi/libata-core.c 2005-10-05 18:11:51.000000000 +0800
@@ -677,7 +677,14 @@ static void ata_qc_rwcmd_protocol(struct
*/
void ata_rwcmd_protocol(struct ata_queued_cmd *qc)
{
- ata_qc_rwcmd_protocol(qc);
+ /* give LLD a chance to override
+ * ex. for some VIA adapters, LLD have to use
+ * PIO commands if LBA48 + DMA is seen.
+ */
+ if (qc->ap->ops->rwcmd_protocol)
+ qc->ap->ops->rwcmd_protocol(qc);
+ else
+ ata_qc_rwcmd_protocol(qc);
}
static const char * xfer_mode_str[] = {
^ permalink raw reply [flat|nested] 77+ messages in thread
* [PATCH/RFC 4/4] CHS: optimize LBA28/LBA48 usage
2005-10-05 11:16 ` [PATCH/RFC 0/4] libata: more CHS follow-up patches Albert Lee
` (2 preceding siblings ...)
2005-10-05 11:25 ` [PATCH/RFC 3/4] CHS: support overriding the ata_rwcmd_protocol() function Albert Lee
@ 2005-10-05 11:27 ` Albert Lee
2005-10-05 11:59 ` [PATCH/RFC 1/4] CHS: move the initialization of taskfile LBA flags (resend) Albert Lee
` (4 subsequent siblings)
8 siblings, 0 replies; 77+ messages in thread
From: Albert Lee @ 2005-10-05 11:27 UTC (permalink / raw)
To: Jeff Garzik
Cc: Mark Lord, Bartlomiej Zolnierkiewicz, Linux IDE, Doug Maxey,
Tejun Heo, Brett Russ, Alan Cox
Patch 4/4: optimize LBA28/LBA48 per Mark's advice.
Changes:
- add lba_28_ok() and lba_48_ok() to ata.h
- use lba_28_ok() for CHS range check
- LBA28/LBA48 optimization
For your review, thanks.
Albert
Signed-off-by: Albert Lee <albertcc@tw.ibm.com>
=====
--- ch2/include/linux/ata.h 2005-10-05 18:11:12.000000000 +0800
+++ ch4/include/linux/ata.h 2005-10-05 18:12:09.000000000 +0800
@@ -291,4 +291,14 @@ static inline int ata_ok(u8 status)
== ATA_DRDY);
}
+static inline int lba_28_ok(u64 block, u32 n_block)
+{
+ return (block < ((u64)1 << 28)) && (n_block <= 256);
+}
+
+static inline int lba_48_ok(u64 block, u32 n_block)
+{
+ return (block < ((u64)1 << 48)) && (n_block <= 65536);
+}
+
#endif /* __LINUX_ATA_H__ */
--- ch3/drivers/scsi/libata-scsi.c 2005-10-05 18:11:12.000000000 +0800
+++ ch4/drivers/scsi/libata-scsi.c 2005-10-05 18:12:09.000000000 +0800
@@ -633,8 +633,12 @@ static unsigned int ata_scsi_verify_xlat
if (dev->flags & ATA_DFLAG_LBA) {
tf->flags |= ATA_TFLAG_LBA;
- if (dev->flags & ATA_DFLAG_LBA48) {
- if (n_block > (64 * 1024))
+ if (lba_28_ok(block, n_block)) {
+ /* use LBA28 */
+ tf->command = ATA_CMD_VERIFY;
+ tf->device |= (block >> 24) & 0xf;
+ } else if (lba_48_ok(block, n_block)) {
+ if (!(dev->flags & ATA_DFLAG_LBA48))
return 1;
/* use LBA48 */
@@ -646,14 +650,9 @@ static unsigned int ata_scsi_verify_xlat
tf->hob_lbah = (block >> 40) & 0xff;
tf->hob_lbam = (block >> 32) & 0xff;
tf->hob_lbal = (block >> 24) & 0xff;
- } else {
- if (n_block > 256)
- return 1;
-
- /* use LBA28 */
- tf->command = ATA_CMD_VERIFY;
- tf->device |= (block >> 24) & 0xf;
- }
+ } else
+ /* request too large even for LBA48 */
+ return 1;
tf->nsect = n_block & 0xff;
@@ -666,7 +665,7 @@ static unsigned int ata_scsi_verify_xlat
/* CHS */
u32 sect, head, cyl, track;
- if (n_block > 256)
+ if (!lba_28_ok(block, n_block))
return 1;
/* Convert LBA to CHS */
@@ -766,9 +765,11 @@ static unsigned int ata_scsi_rw_xlat(str
if (dev->flags & ATA_DFLAG_LBA) {
tf->flags |= ATA_TFLAG_LBA;
- if (dev->flags & ATA_DFLAG_LBA48) {
- /* The request -may- be too large for LBA48. */
- if ((block >> 48) || (n_block > 65536))
+ if (lba_28_ok(block, n_block)) {
+ /* use LBA28 */
+ tf->device |= (block >> 24) & 0xf;
+ } else if (lba_48_ok(block, n_block)) {
+ if (!(dev->flags & ATA_DFLAG_LBA48))
return 1;
/* use LBA48 */
@@ -779,15 +780,9 @@ static unsigned int ata_scsi_rw_xlat(str
tf->hob_lbah = (block >> 40) & 0xff;
tf->hob_lbam = (block >> 32) & 0xff;
tf->hob_lbal = (block >> 24) & 0xff;
- } else {
- /* use LBA28 */
-
- /* The request -may- be too large for LBA28. */
- if ((block >> 28) || (n_block > 256))
- return 1;
-
- tf->device |= (block >> 24) & 0xf;
- }
+ } else
+ /* request too large even for LBA48 */
+ return 1;
ata_rwcmd_protocol(qc);
@@ -804,7 +799,7 @@ static unsigned int ata_scsi_rw_xlat(str
u32 sect, head, cyl, track;
/* The request -may- be too large for CHS addressing. */
- if ((block >> 28) || (n_block > 256))
+ if (!lba_28_ok(block, n_block))
return 1;
ata_rwcmd_protocol(qc);
^ permalink raw reply [flat|nested] 77+ messages in thread
* [PATCH/RFC 1/4] CHS: move the initialization of taskfile LBA flags (resend)
2005-10-05 11:16 ` [PATCH/RFC 0/4] libata: more CHS follow-up patches Albert Lee
` (3 preceding siblings ...)
2005-10-05 11:27 ` [PATCH/RFC 4/4] CHS: optimize LBA28/LBA48 usage Albert Lee
@ 2005-10-05 11:59 ` Albert Lee
2005-10-05 12:02 ` [PATCH/RFC 2/4] CHS: calculate read/write commands and protocol on the fly (resend) Albert Lee
` (3 subsequent siblings)
8 siblings, 0 replies; 77+ messages in thread
From: Albert Lee @ 2005-10-05 11:59 UTC (permalink / raw)
To: Jeff Garzik
Cc: Mark Lord, Bartlomiej Zolnierkiewicz, Linux IDE, Doug Maxey,
Tejun Heo, Brett Russ, Alan Cox
The tab was expanded to spaces in the previous mail. :(
Hope this time it is correct.
Patch 1/4:
move the initialization of taskfile LBA flags:
ATA_TFLAG_LBA and ATA_TFLAG_LBA48 flags
to the SCSI translation functions
For your review, thanks.
Albert
Signed-off-by: Albert Lee <albertcc@tw.ibm.com>
=============
--- upstream/drivers/scsi/libata-core.c 2005-10-05 18:04:07.000000000 +0800
+++ ch1/drivers/scsi/libata-core.c 2005-10-05 18:10:28.000000000 +0800
@@ -3241,13 +3241,6 @@ struct ata_queued_cmd *ata_qc_new_init(s
qc->nbytes = qc->curbytes = 0;
ata_tf_init(ap, &qc->tf, dev->devno);
-
- if (dev->flags & ATA_DFLAG_LBA) {
- qc->tf.flags |= ATA_TFLAG_LBA;
-
- if (dev->flags & ATA_DFLAG_LBA48)
- qc->tf.flags |= ATA_TFLAG_LBA48;
- }
}
return qc;
--- upstream/drivers/scsi/libata-scsi.c 2005-10-05 18:04:07.000000000 +0800
+++ ch1/drivers/scsi/libata-scsi.c 2005-10-05 18:10:28.000000000 +0800
@@ -489,7 +489,7 @@ static unsigned int ata_scsi_flush_xlat(
tf->flags |= ATA_TFLAG_DEVICE;
tf->protocol = ATA_PROT_NODATA;
- if ((tf->flags & ATA_TFLAG_LBA48) &&
+ if ((qc->dev->flags & ATA_DFLAG_LBA48) &&
(ata_id_has_flush_ext(qc->dev->id)))
tf->command = ATA_CMD_FLUSH_EXT;
else
@@ -609,8 +609,6 @@ static unsigned int ata_scsi_verify_xlat
{
struct ata_taskfile *tf = &qc->tf;
struct ata_device *dev = qc->dev;
- unsigned int lba = tf->flags & ATA_TFLAG_LBA;
- unsigned int lba48 = tf->flags & ATA_TFLAG_LBA48;
u64 dev_sectors = qc->dev->n_sectors;
u64 block;
u32 n_block;
@@ -631,16 +629,16 @@ static unsigned int ata_scsi_verify_xlat
return 1;
if ((block + n_block) > dev_sectors)
return 1;
- if (lba48) {
- if (n_block > (64 * 1024))
- return 1;
- } else {
- if (n_block > 256)
- return 1;
- }
- if (lba) {
- if (lba48) {
+ if (dev->flags & ATA_DFLAG_LBA) {
+ tf->flags |= ATA_TFLAG_LBA;
+
+ if (dev->flags & ATA_DFLAG_LBA48) {
+ if (n_block > (64 * 1024))
+ return 1;
+
+ /* use LBA48 */
+ tf->flags |= ATA_TFLAG_LBA48;
tf->command = ATA_CMD_VERIFY_EXT;
tf->hob_nsect = (n_block >> 8) & 0xff;
@@ -649,8 +647,11 @@ static unsigned int ata_scsi_verify_xlat
tf->hob_lbam = (block >> 32) & 0xff;
tf->hob_lbal = (block >> 24) & 0xff;
} else {
- tf->command = ATA_CMD_VERIFY;
+ if (n_block > 256)
+ return 1;
+ /* use LBA28 */
+ tf->command = ATA_CMD_VERIFY;
tf->device |= (block >> 24) & 0xf;
}
@@ -665,6 +666,9 @@ static unsigned int ata_scsi_verify_xlat
/* CHS */
u32 sect, head, cyl, track;
+ if (n_block > 256)
+ return 1;
+
/* Convert LBA to CHS */
track = (u32)block / dev->sectors;
cyl = track / dev->heads;
@@ -716,8 +720,6 @@ static unsigned int ata_scsi_rw_xlat(str
{
struct ata_taskfile *tf = &qc->tf;
struct ata_device *dev = qc->dev;
- unsigned int lba = tf->flags & ATA_TFLAG_LBA;
- unsigned int lba48 = tf->flags & ATA_TFLAG_LBA48;
u64 block;
u32 n_block;
@@ -766,19 +768,24 @@ static unsigned int ata_scsi_rw_xlat(str
*/
return 1;
- if (lba) {
- if (lba48) {
+ if (dev->flags & ATA_DFLAG_LBA) {
+ tf->flags |= ATA_TFLAG_LBA;
+
+ if (dev->flags & ATA_DFLAG_LBA48) {
/* The request -may- be too large for LBA48. */
if ((block >> 48) || (n_block > 65536))
return 1;
+ /* use LBA48 */
+ tf->flags |= ATA_TFLAG_LBA48;
+
tf->hob_nsect = (n_block >> 8) & 0xff;
tf->hob_lbah = (block >> 40) & 0xff;
tf->hob_lbam = (block >> 32) & 0xff;
tf->hob_lbal = (block >> 24) & 0xff;
} else {
- /* LBA28 */
+ /* use LBA28 */
/* The request -may- be too large for LBA28. */
if ((block >> 28) || (n_block > 256))
^ permalink raw reply [flat|nested] 77+ messages in thread
* [PATCH/RFC 2/4] CHS: calculate read/write commands and protocol on the fly (resend)
2005-10-05 11:16 ` [PATCH/RFC 0/4] libata: more CHS follow-up patches Albert Lee
` (4 preceding siblings ...)
2005-10-05 11:59 ` [PATCH/RFC 1/4] CHS: move the initialization of taskfile LBA flags (resend) Albert Lee
@ 2005-10-05 12:02 ` Albert Lee
2005-10-05 12:03 ` [PATCH/RFC 3/4] CHS: support overriding the ata_rwcmd_protocol() function (resend) Albert Lee
` (2 subsequent siblings)
8 siblings, 0 replies; 77+ messages in thread
From: Albert Lee @ 2005-10-05 12:02 UTC (permalink / raw)
To: Jeff Garzik
Cc: Mark Lord, Bartlomiej Zolnierkiewicz, Linux IDE, Doug Maxey,
Tejun Heo, Brett Russ, Alan Cox
(Resend for the tab problem)
Patch 2/4: calculate read/write commands and protocols on the fly
changes:
- merge ata_prot_to_cmd() and ata_dev_set_protocol() as
ata_rwcmd_protocol()
- pave road for read/write multiple support
- remove usage of pre-cached command and protocol values and call
ata_rwcmd_protocol() instead
For your review, thanks.
Albert
Signed-off-by: Albert Lee <albertcc@tw.ibm.com>
==============
--- upstream/include/linux/ata.h 2005-10-05 18:04:16.000000000 +0800
+++ ch2/include/linux/ata.h 2005-10-05 18:11:12.000000000 +0800
@@ -128,6 +128,10 @@ enum {
ATA_CMD_PIO_READ_EXT = 0x24,
ATA_CMD_PIO_WRITE = 0x30,
ATA_CMD_PIO_WRITE_EXT = 0x34,
+ ATA_CMD_READ_MULTI = 0xC4,
+ ATA_CMD_READ_MULTI_EXT = 0x29,
+ ATA_CMD_WRITE_MULTI = 0xC5,
+ ATA_CMD_WRITE_MULTI_EXT = 0x39,
ATA_CMD_SET_FEATURES = 0xEF,
ATA_CMD_PACKET = 0xA0,
ATA_CMD_VERIFY = 0x40,
--- upstream/include/linux/libata.h 2005-10-05 18:04:16.000000000 +0800
+++ ch2/include/linux/libata.h 2005-10-05 18:11:12.000000000 +0800
@@ -283,10 +283,8 @@ struct ata_device {
u8 xfer_mode;
unsigned int xfer_shift; /* ATA_SHIFT_xxx */
- /* cache info about current transfer mode */
- u8 xfer_protocol; /* taskfile xfer protocol */
- u8 read_cmd; /* opcode to use on read */
- u8 write_cmd; /* opcode to use on write */
+ unsigned int multi_count; /* sectors count for
+ READ/WRITE MULTIPLE */
/* for CHS addressing */
u16 cylinders; /* Number of cylinders */
--- upstream/drivers/scsi/libata.h 2005-10-05 18:04:07.000000000 +0800
+++ ch2/drivers/scsi/libata.h 2005-10-05 18:11:12.000000000 +0800
@@ -41,6 +41,7 @@ struct ata_scsi_args {
extern int atapi_enabled;
extern struct ata_queued_cmd *ata_qc_new_init(struct ata_port *ap,
struct ata_device *dev);
+extern void ata_rwcmd_protocol(struct ata_queued_cmd *qc);
extern void ata_qc_free(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);
--- ch1/drivers/scsi/libata-core.c 2005-10-05 18:10:28.000000000 +0800
+++ ch2/drivers/scsi/libata-core.c 2005-10-05 18:11:12.000000000 +0800
@@ -616,79 +616,68 @@ void ata_tf_from_fis(u8 *fis, struct ata
tf->hob_nsect = fis[13];
}
+static const u8 ata_rw_cmds[] = {
+ /* pio multi */
+ ATA_CMD_READ_MULTI,
+ ATA_CMD_WRITE_MULTI,
+ ATA_CMD_READ_MULTI_EXT,
+ ATA_CMD_WRITE_MULTI_EXT,
+ /* pio */
+ ATA_CMD_PIO_READ,
+ ATA_CMD_PIO_WRITE,
+ ATA_CMD_PIO_READ_EXT,
+ ATA_CMD_PIO_WRITE_EXT,
+ /* dma */
+ ATA_CMD_READ,
+ ATA_CMD_WRITE,
+ ATA_CMD_READ_EXT,
+ ATA_CMD_WRITE_EXT
+};
+
/**
- * ata_prot_to_cmd - determine which read/write opcodes to use
- * @protocol: ATA_PROT_xxx taskfile protocol
- * @lba48: true is lba48 is present
+ * ata_qc_rwcmd_protocol - set taskfile r/w commands and protocol
+ * @qc: command to examine and configure
*
- * Given necessary input, determine which read/write commands
- * to use to transfer data.
+ * Examine the device configuration and tf->flags to calculate
+ * the proper read/write commands and protocol to use.
*
* LOCKING:
- * None.
+ * caller.
*/
-static int ata_prot_to_cmd(int protocol, int lba48)
+static void ata_qc_rwcmd_protocol(struct ata_queued_cmd *qc)
{
- int rcmd = 0, wcmd = 0;
-
- switch (protocol) {
- case ATA_PROT_PIO:
- if (lba48) {
- rcmd = ATA_CMD_PIO_READ_EXT;
- wcmd = ATA_CMD_PIO_WRITE_EXT;
- } else {
- rcmd = ATA_CMD_PIO_READ;
- wcmd = ATA_CMD_PIO_WRITE;
- }
- break;
-
- case ATA_PROT_DMA:
- if (lba48) {
- rcmd = ATA_CMD_READ_EXT;
- wcmd = ATA_CMD_WRITE_EXT;
- } else {
- rcmd = ATA_CMD_READ;
- wcmd = ATA_CMD_WRITE;
- }
- break;
+ struct ata_taskfile *tf = &qc->tf;
+ struct ata_device *dev = qc->dev;
- default:
- return -1;
+ int index, lba48, write;
+
+ lba48 = (tf->flags & ATA_TFLAG_LBA48) ? 2 : 0;
+ write = (tf->flags & ATA_TFLAG_WRITE) ? 1 : 0;
+
+ if (dev->flags & ATA_DFLAG_PIO) {
+ tf->protocol = ATA_PROT_PIO;
+ index = dev->multi_count ? 0 : 4;
+ } else {
+ tf->protocol = ATA_PROT_DMA;
+ index = 8;
}
- return rcmd | (wcmd << 8);
+ tf->command = ata_rw_cmds[index + lba48 + write];
}
/**
- * ata_dev_set_protocol - set taskfile protocol and r/w commands
- * @dev: device to examine and configure
+ * ata_rwcmd_protocol - set taskfile r/w commands and protocol
+ * @qc: command to examine and configure
*
- * Examine the device configuration, after we have
- * read the identify-device page and configured the
- * data transfer mode. Set internal state related to
- * the ATA taskfile protocol (pio, pio mult, dma, etc.)
- * and calculate the proper read/write commands to use.
+ * Examine the device configuration and tf->flags to calculate
+ * the proper read/write commands and protocol to use.
*
* LOCKING:
* caller.
*/
-static void ata_dev_set_protocol(struct ata_device *dev)
+void ata_rwcmd_protocol(struct ata_queued_cmd *qc)
{
- int pio = (dev->flags & ATA_DFLAG_PIO);
- int lba48 = (dev->flags & ATA_DFLAG_LBA48);
- int proto, cmd;
-
- if (pio)
- proto = dev->xfer_protocol = ATA_PROT_PIO;
- else
- proto = dev->xfer_protocol = ATA_PROT_DMA;
-
- cmd = ata_prot_to_cmd(proto, lba48);
- if (cmd < 0)
- BUG();
-
- dev->read_cmd = cmd & 0xff;
- dev->write_cmd = (cmd >> 8) & 0xff;
+ ata_qc_rwcmd_protocol(qc);
}
static const char * xfer_mode_str[] = {
@@ -1641,7 +1630,7 @@ static void ata_host_set_dma(struct ata_
*/
static void ata_set_mode(struct ata_port *ap)
{
- unsigned int i, xfer_shift;
+ unsigned int xfer_shift;
u8 xfer_mode;
int rc;
@@ -1670,11 +1659,6 @@ static void ata_set_mode(struct ata_port
if (ap->ops->post_set_mode)
ap->ops->post_set_mode(ap);
- for (i = 0; i < 2; i++) {
- struct ata_device *dev = &ap->device[i];
- ata_dev_set_protocol(dev);
- }
-
return;
err_out:
--- ch1/drivers/scsi/libata-scsi.c 2005-10-05 18:10:28.000000000 +0800
+++ ch2/drivers/scsi/libata-scsi.c 2005-10-05 18:11:12.000000000 +0800
@@ -724,15 +724,10 @@ static unsigned int ata_scsi_rw_xlat(str
u32 n_block;
tf->flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
- tf->protocol = qc->dev->xfer_protocol;
- if (scsicmd[0] == READ_10 || scsicmd[0] == READ_6 ||
- scsicmd[0] == READ_16) {
- tf->command = qc->dev->read_cmd;
- } else {
- tf->command = qc->dev->write_cmd;
+ if (scsicmd[0] == WRITE_10 || scsicmd[0] == WRITE_6 ||
+ scsicmd[0] == WRITE_16)
tf->flags |= ATA_TFLAG_WRITE;
- }
/* Calculate the SCSI LBA and transfer length. */
switch (scsicmd[0]) {
@@ -794,6 +789,8 @@ static unsigned int ata_scsi_rw_xlat(str
tf->device |= (block >> 24) & 0xf;
}
+ ata_rwcmd_protocol(qc);
+
qc->nsect = n_block;
tf->nsect = n_block & 0xff;
@@ -810,6 +807,8 @@ static unsigned int ata_scsi_rw_xlat(str
if ((block >> 28) || (n_block > 256))
return 1;
+ ata_rwcmd_protocol(qc);
+
/* Convert LBA to CHS */
track = (u32)block / dev->sectors;
cyl = track / dev->heads;
^ permalink raw reply [flat|nested] 77+ messages in thread
* [PATCH/RFC 3/4] CHS: support overriding the ata_rwcmd_protocol() function (resend)
2005-10-05 11:16 ` [PATCH/RFC 0/4] libata: more CHS follow-up patches Albert Lee
` (5 preceding siblings ...)
2005-10-05 12:02 ` [PATCH/RFC 2/4] CHS: calculate read/write commands and protocol on the fly (resend) Albert Lee
@ 2005-10-05 12:03 ` Albert Lee
2005-10-05 12:04 ` [PATCH/RFC 4/4] CHS: optimize LBA28/LBA48 usage (resend) Albert Lee
2005-10-06 11:26 ` [PATCH/RFC 0/4] libata: more CHS follow-up patches Jeff Garzik
8 siblings, 0 replies; 77+ messages in thread
From: Albert Lee @ 2005-10-05 12:03 UTC (permalink / raw)
To: Jeff Garzik
Cc: Mark Lord, Bartlomiej Zolnierkiewicz, Linux IDE, Doug Maxey,
Tejun Heo, Brett Russ, Alan Cox
(Resend for the tab problem)
Patch 3/4:
support overriding the ata_rwcmd_protocol() function for some VIA
adapters per Alan's advice.
For your review, thanks.
Albert
Signed-off-by: Albert Lee <albertcc@tw.ibm.com>
=======
--- ch2/include/linux/libata.h 2005-10-05 18:11:12.000000000 +0800
+++ ch3/include/linux/libata.h 2005-10-05 18:11:51.000000000 +0800
@@ -353,6 +353,8 @@ struct ata_port_operations {
void (*phy_reset) (struct ata_port *ap);
void (*post_set_mode) (struct ata_port *ap);
+ /* workaround host adapter limitations */
+ void (*rwcmd_protocol) (struct ata_queued_cmd *qc);
int (*check_atapi_dma) (struct ata_queued_cmd *qc);
void (*bmdma_setup) (struct ata_queued_cmd *qc);
--- ch2/drivers/scsi/libata-core.c 2005-10-05 18:11:12.000000000 +0800
+++ ch3/drivers/scsi/libata-core.c 2005-10-05 18:11:51.000000000 +0800
@@ -677,7 +677,14 @@ static void ata_qc_rwcmd_protocol(struct
*/
void ata_rwcmd_protocol(struct ata_queued_cmd *qc)
{
- ata_qc_rwcmd_protocol(qc);
+ /* give LLD a chance to override
+ * ex. for some VIA adapters, LLD have to use
+ * PIO commands if LBA48 + DMA is seen.
+ */
+ if (qc->ap->ops->rwcmd_protocol)
+ qc->ap->ops->rwcmd_protocol(qc);
+ else
+ ata_qc_rwcmd_protocol(qc);
}
static const char * xfer_mode_str[] = {
^ permalink raw reply [flat|nested] 77+ messages in thread
* [PATCH/RFC 4/4] CHS: optimize LBA28/LBA48 usage (resend)
2005-10-05 11:16 ` [PATCH/RFC 0/4] libata: more CHS follow-up patches Albert Lee
` (6 preceding siblings ...)
2005-10-05 12:03 ` [PATCH/RFC 3/4] CHS: support overriding the ata_rwcmd_protocol() function (resend) Albert Lee
@ 2005-10-05 12:04 ` Albert Lee
2005-10-06 11:26 ` [PATCH/RFC 0/4] libata: more CHS follow-up patches Jeff Garzik
8 siblings, 0 replies; 77+ messages in thread
From: Albert Lee @ 2005-10-05 12:04 UTC (permalink / raw)
To: Albert Lee
Cc: Jeff Garzik, Mark Lord, Bartlomiej Zolnierkiewicz, Linux IDE,
Doug Maxey, Tejun Heo, Brett Russ, Alan Cox
(Resend for the tab problem)
Patch 4/4: optimize LBA28/LBA48 per Mark's advice.
Changes:
- add lba_28_ok() and lba_48_ok() to ata.h
- use lba_28_ok() for CHS range check
- LBA28/LBA48 optimization
For your review, thanks.
Albert
Signed-off-by: Albert Lee <albertcc@tw.ibm.com>
=====
--- ch2/include/linux/ata.h 2005-10-05 18:11:12.000000000 +0800
+++ ch4/include/linux/ata.h 2005-10-05 18:12:09.000000000 +0800
@@ -291,4 +291,14 @@ static inline int ata_ok(u8 status)
== ATA_DRDY);
}
+static inline int lba_28_ok(u64 block, u32 n_block)
+{
+ return (block < ((u64)1 << 28)) && (n_block <= 256);
+}
+
+static inline int lba_48_ok(u64 block, u32 n_block)
+{
+ return (block < ((u64)1 << 48)) && (n_block <= 65536);
+}
+
#endif /* __LINUX_ATA_H__ */
--- ch3/drivers/scsi/libata-scsi.c 2005-10-05 18:11:12.000000000 +0800
+++ ch4/drivers/scsi/libata-scsi.c 2005-10-05 18:12:09.000000000 +0800
@@ -633,8 +633,12 @@ static unsigned int ata_scsi_verify_xlat
if (dev->flags & ATA_DFLAG_LBA) {
tf->flags |= ATA_TFLAG_LBA;
- if (dev->flags & ATA_DFLAG_LBA48) {
- if (n_block > (64 * 1024))
+ if (lba_28_ok(block, n_block)) {
+ /* use LBA28 */
+ tf->command = ATA_CMD_VERIFY;
+ tf->device |= (block >> 24) & 0xf;
+ } else if (lba_48_ok(block, n_block)) {
+ if (!(dev->flags & ATA_DFLAG_LBA48))
return 1;
/* use LBA48 */
@@ -646,14 +650,9 @@ static unsigned int ata_scsi_verify_xlat
tf->hob_lbah = (block >> 40) & 0xff;
tf->hob_lbam = (block >> 32) & 0xff;
tf->hob_lbal = (block >> 24) & 0xff;
- } else {
- if (n_block > 256)
- return 1;
-
- /* use LBA28 */
- tf->command = ATA_CMD_VERIFY;
- tf->device |= (block >> 24) & 0xf;
- }
+ } else
+ /* request too large even for LBA48 */
+ return 1;
tf->nsect = n_block & 0xff;
@@ -666,7 +665,7 @@ static unsigned int ata_scsi_verify_xlat
/* CHS */
u32 sect, head, cyl, track;
- if (n_block > 256)
+ if (!lba_28_ok(block, n_block))
return 1;
/* Convert LBA to CHS */
@@ -766,9 +765,11 @@ static unsigned int ata_scsi_rw_xlat(str
if (dev->flags & ATA_DFLAG_LBA) {
tf->flags |= ATA_TFLAG_LBA;
- if (dev->flags & ATA_DFLAG_LBA48) {
- /* The request -may- be too large for LBA48. */
- if ((block >> 48) || (n_block > 65536))
+ if (lba_28_ok(block, n_block)) {
+ /* use LBA28 */
+ tf->device |= (block >> 24) & 0xf;
+ } else if (lba_48_ok(block, n_block)) {
+ if (!(dev->flags & ATA_DFLAG_LBA48))
return 1;
/* use LBA48 */
@@ -779,15 +780,9 @@ static unsigned int ata_scsi_rw_xlat(str
tf->hob_lbah = (block >> 40) & 0xff;
tf->hob_lbam = (block >> 32) & 0xff;
tf->hob_lbal = (block >> 24) & 0xff;
- } else {
- /* use LBA28 */
-
- /* The request -may- be too large for LBA28. */
- if ((block >> 28) || (n_block > 256))
- return 1;
-
- tf->device |= (block >> 24) & 0xf;
- }
+ } else
+ /* request too large even for LBA48 */
+ return 1;
ata_rwcmd_protocol(qc);
@@ -804,7 +799,7 @@ static unsigned int ata_scsi_rw_xlat(str
u32 sect, head, cyl, track;
/* The request -may- be too large for CHS addressing. */
- if ((block >> 28) || (n_block > 256))
+ if (!lba_28_ok(block, n_block))
return 1;
ata_rwcmd_protocol(qc);
^ permalink raw reply [flat|nested] 77+ messages in thread
* Re: [PATCH/RFC 0/4] libata: more CHS follow-up patches
2005-10-05 11:16 ` [PATCH/RFC 0/4] libata: more CHS follow-up patches Albert Lee
` (7 preceding siblings ...)
2005-10-05 12:04 ` [PATCH/RFC 4/4] CHS: optimize LBA28/LBA48 usage (resend) Albert Lee
@ 2005-10-06 11:26 ` Jeff Garzik
2005-10-07 6:53 ` [PATCH 0/3] libata: CHS follow-up patches (resend #2) Albert Lee
8 siblings, 1 reply; 77+ messages in thread
From: Jeff Garzik @ 2005-10-06 11:26 UTC (permalink / raw)
To: Albert Lee
Cc: Mark Lord, Bartlomiej Zolnierkiewicz, Linux IDE, Doug Maxey,
Tejun Heo, Brett Russ, Alan Cox
Albert Lee wrote:
> Dear all,
>
> More CHS follow-up patches:
>
> patch 1/4: move the initialization of ATA_TFLAG_LBA and ATA_TFLAG_LBA48
> flags to the SCSI translation functions
>
> patch 2/4: calculate read/write commands and protocols on the fly
These two patches are OK, but failed to apply, probably due to mailer
issues.
> [jgarzik@pretzel libata-dev]$ patch -sp1 < /g/tmp/mbox
> 1 out of 1 hunk FAILED -- saving rejects to file drivers/scsi/libata-core.c.rej
> 7 out of 7 hunks FAILED -- saving rejects to file drivers/scsi/libata-scsi.c.rej
> patch 3/4: support overriding the ata_rwcmd_protocol() function
Your above patches make it easy enough to add this patch at any time. I
would rather wait until Alan is actually using the hook in his code.
> patch 4/4: optimize LBA28/LBA48 usage
seems OK, but I would like this to see a lot of testing before getting
merged. Once they are mailer-unmunged, I will apply patches #1 and #2
to 'upstream' branch. Then I will clone a branch from upstream called
optimize-lba48, and apply patch #4.
I'm worried, for example, that some hardware may not have been tested
much in the field with rapid switching between LBA28 and LBA48.
Jeff
^ permalink raw reply [flat|nested] 77+ messages in thread
* [PATCH 0/3] libata: CHS follow-up patches (resend #2)
2005-10-06 11:26 ` [PATCH/RFC 0/4] libata: more CHS follow-up patches Jeff Garzik
@ 2005-10-07 6:53 ` Albert Lee
2005-10-07 6:58 ` [PATCH 1/3] CHS: move the initialization of taskfile LBA flags Albert Lee
` (3 more replies)
0 siblings, 4 replies; 77+ messages in thread
From: Albert Lee @ 2005-10-07 6:53 UTC (permalink / raw)
To: Jeff Garzik
Cc: Mark Lord, Bartlomiej Zolnierkiewicz, Linux IDE, Doug Maxey,
Tejun Heo, Brett Russ, Alan Cox
Dear all,
CHS follow-up patches - resend #2 due to whitespace problem in the previous patches.
patch 1/3: move the initialization of ATA_TFLAG_LBA and ATA_TFLAG_LBA48
flags to the SCSI translation functions
patch 2/3: calculate read/write commands and protocols on the fly
patch 3/3: LBA28/LBA48 optimization
Patch against libata-dev upstream branch
(643736a58d2668af94aee05670c5e9ae76e7b85f).
Thanks.
Albert
^ permalink raw reply [flat|nested] 77+ messages in thread
* [PATCH 1/3] CHS: move the initialization of taskfile LBA flags
2005-10-07 6:53 ` [PATCH 0/3] libata: CHS follow-up patches (resend #2) Albert Lee
@ 2005-10-07 6:58 ` Albert Lee
2005-10-07 7:01 ` [PATCH 2/3] CHS: calculate read/write commands and protocol on the fly Albert Lee
` (2 subsequent siblings)
3 siblings, 0 replies; 77+ messages in thread
From: Albert Lee @ 2005-10-07 6:58 UTC (permalink / raw)
To: Jeff Garzik
Cc: Mark Lord, Bartlomiej Zolnierkiewicz, Linux IDE, Doug Maxey,
Tejun Heo, Brett Russ, Alan Cox
Patch 1/3:
move the initialization of taskfile LBA flags
"ATA_TFLAG_LBA" and "ATA_TFLAG_LBA48 flags"
to the SCSI translation functions
Signed-off-by: Albert Lee <albertcc@tw.ibm.com>
=============
--- upstream/drivers/scsi/libata-core.c 2005-10-05 18:04:07.000000000 +0800
+++ ch1/drivers/scsi/libata-core.c 2005-10-05 18:10:28.000000000 +0800
@@ -3241,13 +3241,6 @@ struct ata_queued_cmd *ata_qc_new_init(s
qc->nbytes = qc->curbytes = 0;
ata_tf_init(ap, &qc->tf, dev->devno);
-
- if (dev->flags & ATA_DFLAG_LBA) {
- qc->tf.flags |= ATA_TFLAG_LBA;
-
- if (dev->flags & ATA_DFLAG_LBA48)
- qc->tf.flags |= ATA_TFLAG_LBA48;
- }
}
return qc;
--- upstream/drivers/scsi/libata-scsi.c 2005-10-05 18:04:07.000000000 +0800
+++ ch1/drivers/scsi/libata-scsi.c 2005-10-05 18:10:28.000000000 +0800
@@ -489,7 +489,7 @@ static unsigned int ata_scsi_flush_xlat(
tf->flags |= ATA_TFLAG_DEVICE;
tf->protocol = ATA_PROT_NODATA;
- if ((tf->flags & ATA_TFLAG_LBA48) &&
+ if ((qc->dev->flags & ATA_DFLAG_LBA48) &&
(ata_id_has_flush_ext(qc->dev->id)))
tf->command = ATA_CMD_FLUSH_EXT;
else
@@ -609,8 +609,6 @@ static unsigned int ata_scsi_verify_xlat
{
struct ata_taskfile *tf = &qc->tf;
struct ata_device *dev = qc->dev;
- unsigned int lba = tf->flags & ATA_TFLAG_LBA;
- unsigned int lba48 = tf->flags & ATA_TFLAG_LBA48;
u64 dev_sectors = qc->dev->n_sectors;
u64 block;
u32 n_block;
@@ -631,16 +629,16 @@ static unsigned int ata_scsi_verify_xlat
return 1;
if ((block + n_block) > dev_sectors)
return 1;
- if (lba48) {
- if (n_block > (64 * 1024))
- return 1;
- } else {
- if (n_block > 256)
- return 1;
- }
- if (lba) {
- if (lba48) {
+ if (dev->flags & ATA_DFLAG_LBA) {
+ tf->flags |= ATA_TFLAG_LBA;
+
+ if (dev->flags & ATA_DFLAG_LBA48) {
+ if (n_block > (64 * 1024))
+ return 1;
+
+ /* use LBA48 */
+ tf->flags |= ATA_TFLAG_LBA48;
tf->command = ATA_CMD_VERIFY_EXT;
tf->hob_nsect = (n_block >> 8) & 0xff;
@@ -649,8 +647,11 @@ static unsigned int ata_scsi_verify_xlat
tf->hob_lbam = (block >> 32) & 0xff;
tf->hob_lbal = (block >> 24) & 0xff;
} else {
- tf->command = ATA_CMD_VERIFY;
+ if (n_block > 256)
+ return 1;
+ /* use LBA28 */
+ tf->command = ATA_CMD_VERIFY;
tf->device |= (block >> 24) & 0xf;
}
@@ -665,6 +666,9 @@ static unsigned int ata_scsi_verify_xlat
/* CHS */
u32 sect, head, cyl, track;
+ if (n_block > 256)
+ return 1;
+
/* Convert LBA to CHS */
track = (u32)block / dev->sectors;
cyl = track / dev->heads;
@@ -716,8 +720,6 @@ static unsigned int ata_scsi_rw_xlat(str
{
struct ata_taskfile *tf = &qc->tf;
struct ata_device *dev = qc->dev;
- unsigned int lba = tf->flags & ATA_TFLAG_LBA;
- unsigned int lba48 = tf->flags & ATA_TFLAG_LBA48;
u64 block;
u32 n_block;
@@ -766,19 +768,24 @@ static unsigned int ata_scsi_rw_xlat(str
*/
return 1;
- if (lba) {
- if (lba48) {
+ if (dev->flags & ATA_DFLAG_LBA) {
+ tf->flags |= ATA_TFLAG_LBA;
+
+ if (dev->flags & ATA_DFLAG_LBA48) {
/* The request -may- be too large for LBA48. */
if ((block >> 48) || (n_block > 65536))
return 1;
+ /* use LBA48 */
+ tf->flags |= ATA_TFLAG_LBA48;
+
tf->hob_nsect = (n_block >> 8) & 0xff;
tf->hob_lbah = (block >> 40) & 0xff;
tf->hob_lbam = (block >> 32) & 0xff;
tf->hob_lbal = (block >> 24) & 0xff;
} else {
- /* LBA28 */
+ /* use LBA28 */
/* The request -may- be too large for LBA28. */
if ((block >> 28) || (n_block > 256))
^ permalink raw reply [flat|nested] 77+ messages in thread
* [PATCH 2/3] CHS: calculate read/write commands and protocol on the fly
2005-10-07 6:53 ` [PATCH 0/3] libata: CHS follow-up patches (resend #2) Albert Lee
2005-10-07 6:58 ` [PATCH 1/3] CHS: move the initialization of taskfile LBA flags Albert Lee
@ 2005-10-07 7:01 ` Albert Lee
2005-10-07 7:04 ` [PATCH 3/3] CHS: LBA28/LBA48 optimization Albert Lee
2005-10-07 8:32 ` [PATCH 0/3] libata: CHS follow-up patches (resend #4) Albert Lee
3 siblings, 0 replies; 77+ messages in thread
From: Albert Lee @ 2005-10-07 7:01 UTC (permalink / raw)
To: Jeff Garzik
Cc: Mark Lord, Bartlomiej Zolnierkiewicz, Linux IDE, Doug Maxey,
Tejun Heo, Brett Russ, Alan Cox
(Resend #2)
Patch 2/3: calculate read/write commands and protocols on the fly
changes:
- merge ata_prot_to_cmd() and ata_dev_set_protocol() as ata_rwcmd_protocol()
- pave road for read/write multiple support
- remove usage of pre-cached command and protocol values and call ata_rwcmd_protocol() instead
Signed-off-by: Albert Lee <albertcc@tw.ibm.com>
==============
--- upstream/include/linux/ata.h 2005-10-05 18:04:16.000000000 +0800
+++ ch2/include/linux/ata.h 2005-10-05 18:11:12.000000000 +0800
@@ -128,6 +128,10 @@ enum {
ATA_CMD_PIO_READ_EXT = 0x24,
ATA_CMD_PIO_WRITE = 0x30,
ATA_CMD_PIO_WRITE_EXT = 0x34,
+ ATA_CMD_READ_MULTI = 0xC4,
+ ATA_CMD_READ_MULTI_EXT = 0x29,
+ ATA_CMD_WRITE_MULTI = 0xC5,
+ ATA_CMD_WRITE_MULTI_EXT = 0x39,
ATA_CMD_SET_FEATURES = 0xEF,
ATA_CMD_PACKET = 0xA0,
ATA_CMD_VERIFY = 0x40,
--- upstream/include/linux/libata.h 2005-10-05 18:04:16.000000000 +0800
+++ ch2/include/linux/libata.h 2005-10-05 18:11:12.000000000 +0800
@@ -283,10 +283,8 @@ struct ata_device {
u8 xfer_mode;
unsigned int xfer_shift; /* ATA_SHIFT_xxx */
- /* cache info about current transfer mode */
- u8 xfer_protocol; /* taskfile xfer protocol */
- u8 read_cmd; /* opcode to use on read */
- u8 write_cmd; /* opcode to use on write */
+ unsigned int multi_count; /* sectors count for
+ READ/WRITE MULTIPLE */
/* for CHS addressing */
u16 cylinders; /* Number of cylinders */
--- upstream/drivers/scsi/libata.h 2005-10-05 18:04:07.000000000 +0800
+++ ch2/drivers/scsi/libata.h 2005-10-05 18:11:12.000000000 +0800
@@ -41,6 +41,7 @@ struct ata_scsi_args {
extern int atapi_enabled;
extern struct ata_queued_cmd *ata_qc_new_init(struct ata_port *ap,
struct ata_device *dev);
+extern void ata_rwcmd_protocol(struct ata_queued_cmd *qc);
extern void ata_qc_free(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);
--- ch1/drivers/scsi/libata-core.c 2005-10-05 18:10:28.000000000 +0800
+++ ch2/drivers/scsi/libata-core.c 2005-10-07 14:27:38.000000000 +0800
@@ -616,79 +616,53 @@ void ata_tf_from_fis(u8 *fis, struct ata
tf->hob_nsect = fis[13];
}
-/**
- * ata_prot_to_cmd - determine which read/write opcodes to use
- * @protocol: ATA_PROT_xxx taskfile protocol
- * @lba48: true is lba48 is present
- *
- * Given necessary input, determine which read/write commands
- * to use to transfer data.
- *
- * LOCKING:
- * None.
- */
-static int ata_prot_to_cmd(int protocol, int lba48)
-{
- int rcmd = 0, wcmd = 0;
-
- switch (protocol) {
- case ATA_PROT_PIO:
- if (lba48) {
- rcmd = ATA_CMD_PIO_READ_EXT;
- wcmd = ATA_CMD_PIO_WRITE_EXT;
- } else {
- rcmd = ATA_CMD_PIO_READ;
- wcmd = ATA_CMD_PIO_WRITE;
- }
- break;
-
- case ATA_PROT_DMA:
- if (lba48) {
- rcmd = ATA_CMD_READ_EXT;
- wcmd = ATA_CMD_WRITE_EXT;
- } else {
- rcmd = ATA_CMD_READ;
- wcmd = ATA_CMD_WRITE;
- }
- break;
-
- default:
- return -1;
- }
-
- return rcmd | (wcmd << 8);
-}
+static const u8 ata_rw_cmds[] = {
+ /* pio multi */
+ ATA_CMD_READ_MULTI,
+ ATA_CMD_WRITE_MULTI,
+ ATA_CMD_READ_MULTI_EXT,
+ ATA_CMD_WRITE_MULTI_EXT,
+ /* pio */
+ ATA_CMD_PIO_READ,
+ ATA_CMD_PIO_WRITE,
+ ATA_CMD_PIO_READ_EXT,
+ ATA_CMD_PIO_WRITE_EXT,
+ /* dma */
+ ATA_CMD_READ,
+ ATA_CMD_WRITE,
+ ATA_CMD_READ_EXT,
+ ATA_CMD_WRITE_EXT
+};
/**
- * ata_dev_set_protocol - set taskfile protocol and r/w commands
- * @dev: device to examine and configure
+ * ata_rwcmd_protocol - set taskfile r/w commands and protocol
+ * @qc: command to examine and configure
*
- * Examine the device configuration, after we have
- * read the identify-device page and configured the
- * data transfer mode. Set internal state related to
- * the ATA taskfile protocol (pio, pio mult, dma, etc.)
- * and calculate the proper read/write commands to use.
+ * Examine the device configuration and tf->flags to calculate
+ * the proper read/write commands and protocol to use.
*
* LOCKING:
* caller.
*/
-static void ata_dev_set_protocol(struct ata_device *dev)
+void ata_rwcmd_protocol(struct ata_queued_cmd *qc)
{
- int pio = (dev->flags & ATA_DFLAG_PIO);
- int lba48 = (dev->flags & ATA_DFLAG_LBA48);
- int proto, cmd;
-
- if (pio)
- proto = dev->xfer_protocol = ATA_PROT_PIO;
- else
- proto = dev->xfer_protocol = ATA_PROT_DMA;
+ struct ata_taskfile *tf = &qc->tf;
+ struct ata_device *dev = qc->dev;
- cmd = ata_prot_to_cmd(proto, lba48);
- if (cmd < 0)
- BUG();
+ int index, lba48, write;
+
+ lba48 = (tf->flags & ATA_TFLAG_LBA48) ? 2 : 0;
+ write = (tf->flags & ATA_TFLAG_WRITE) ? 1 : 0;
+
+ if (dev->flags & ATA_DFLAG_PIO) {
+ tf->protocol = ATA_PROT_PIO;
+ index = dev->multi_count ? 0 : 4;
+ } else {
+ tf->protocol = ATA_PROT_DMA;
+ index = 8;
+ }
- dev->read_cmd = cmd & 0xff;
- dev->write_cmd = (cmd >> 8) & 0xff;
+ tf->command = ata_rw_cmds[index + lba48 + write];
}
static const char * xfer_mode_str[] = {
@@ -1641,7 +1615,7 @@ static void ata_host_set_dma(struct ata_
*/
static void ata_set_mode(struct ata_port *ap)
{
- unsigned int i, xfer_shift;
+ unsigned int xfer_shift;
u8 xfer_mode;
int rc;
@@ -1670,11 +1644,6 @@ static void ata_set_mode(struct ata_port
if (ap->ops->post_set_mode)
ap->ops->post_set_mode(ap);
- for (i = 0; i < 2; i++) {
- struct ata_device *dev = &ap->device[i];
- ata_dev_set_protocol(dev);
- }
-
return;
err_out:
--- ch1/drivers/scsi/libata-scsi.c 2005-10-05 18:10:28.000000000 +0800
+++ ch2/drivers/scsi/libata-scsi.c 2005-10-05 18:11:12.000000000 +0800
@@ -724,15 +724,10 @@ static unsigned int ata_scsi_rw_xlat(str
u32 n_block;
tf->flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
- tf->protocol = qc->dev->xfer_protocol;
- if (scsicmd[0] == READ_10 || scsicmd[0] == READ_6 ||
- scsicmd[0] == READ_16) {
- tf->command = qc->dev->read_cmd;
- } else {
- tf->command = qc->dev->write_cmd;
+ if (scsicmd[0] == WRITE_10 || scsicmd[0] == WRITE_6 ||
+ scsicmd[0] == WRITE_16)
tf->flags |= ATA_TFLAG_WRITE;
- }
/* Calculate the SCSI LBA and transfer length. */
switch (scsicmd[0]) {
@@ -794,6 +789,8 @@ static unsigned int ata_scsi_rw_xlat(str
tf->device |= (block >> 24) & 0xf;
}
+ ata_rwcmd_protocol(qc);
+
qc->nsect = n_block;
tf->nsect = n_block & 0xff;
@@ -810,6 +807,8 @@ static unsigned int ata_scsi_rw_xlat(str
if ((block >> 28) || (n_block > 256))
return 1;
+ ata_rwcmd_protocol(qc);
+
/* Convert LBA to CHS */
track = (u32)block / dev->sectors;
cyl = track / dev->heads;
^ permalink raw reply [flat|nested] 77+ messages in thread
* [PATCH 3/3] CHS: LBA28/LBA48 optimization
2005-10-07 6:53 ` [PATCH 0/3] libata: CHS follow-up patches (resend #2) Albert Lee
2005-10-07 6:58 ` [PATCH 1/3] CHS: move the initialization of taskfile LBA flags Albert Lee
2005-10-07 7:01 ` [PATCH 2/3] CHS: calculate read/write commands and protocol on the fly Albert Lee
@ 2005-10-07 7:04 ` Albert Lee
2005-10-07 8:32 ` [PATCH 0/3] libata: CHS follow-up patches (resend #4) Albert Lee
3 siblings, 0 replies; 77+ messages in thread
From: Albert Lee @ 2005-10-07 7:04 UTC (permalink / raw)
To: Jeff Garzik
Cc: Mark Lord, Bartlomiej Zolnierkiewicz, Linux IDE, Doug Maxey,
Tejun Heo, Brett Russ, Alan Cox
(resend #2)
Patch 3/3: LBA28/LBA48 optimization per Mark's advice.
Changes:
- add lba_28_ok() and lba_48_ok() to ata.h
- use lba_28_ok() for CHS range check
- LBA28/LBA48 optimization
Signed-off-by: Albert Lee <albertcc@tw.ibm.com>
=====
--- ch2/include/linux/ata.h 2005-10-05 18:11:12.000000000 +0800
+++ ch4/include/linux/ata.h 2005-10-05 18:47:29.000000000 +0800
@@ -291,4 +291,14 @@ static inline int ata_ok(u8 status)
== ATA_DRDY);
}
+static inline int lba_28_ok(u64 block, u32 n_block)
+{
+ return (block < ((u64)1 << 28)) && (n_block <= 256);
+}
+
+static inline int lba_48_ok(u64 block, u32 n_block)
+{
+ return (block < ((u64)1 << 48)) && (n_block <= 65536);
+}
+
#endif /* __LINUX_ATA_H__ */
--- ch3/drivers/scsi/libata-scsi.c 2005-10-05 18:11:12.000000000 +0800
+++ ch4/drivers/scsi/libata-scsi.c 2005-10-05 18:12:09.000000000 +0800
@@ -633,8 +633,12 @@ static unsigned int ata_scsi_verify_xlat
if (dev->flags & ATA_DFLAG_LBA) {
tf->flags |= ATA_TFLAG_LBA;
- if (dev->flags & ATA_DFLAG_LBA48) {
- if (n_block > (64 * 1024))
+ if (lba_28_ok(block, n_block)) {
+ /* use LBA28 */
+ tf->command = ATA_CMD_VERIFY;
+ tf->device |= (block >> 24) & 0xf;
+ } else if (lba_48_ok(block, n_block)) {
+ if (!(dev->flags & ATA_DFLAG_LBA48))
return 1;
/* use LBA48 */
@@ -646,14 +650,9 @@ static unsigned int ata_scsi_verify_xlat
tf->hob_lbah = (block >> 40) & 0xff;
tf->hob_lbam = (block >> 32) & 0xff;
tf->hob_lbal = (block >> 24) & 0xff;
- } else {
- if (n_block > 256)
- return 1;
-
- /* use LBA28 */
- tf->command = ATA_CMD_VERIFY;
- tf->device |= (block >> 24) & 0xf;
- }
+ } else
+ /* request too large even for LBA48 */
+ return 1;
tf->nsect = n_block & 0xff;
@@ -666,7 +665,7 @@ static unsigned int ata_scsi_verify_xlat
/* CHS */
u32 sect, head, cyl, track;
- if (n_block > 256)
+ if (!lba_28_ok(block, n_block))
return 1;
/* Convert LBA to CHS */
@@ -766,9 +765,11 @@ static unsigned int ata_scsi_rw_xlat(str
if (dev->flags & ATA_DFLAG_LBA) {
tf->flags |= ATA_TFLAG_LBA;
- if (dev->flags & ATA_DFLAG_LBA48) {
- /* The request -may- be too large for LBA48. */
- if ((block >> 48) || (n_block > 65536))
+ if (lba_28_ok(block, n_block)) {
+ /* use LBA28 */
+ tf->device |= (block >> 24) & 0xf;
+ } else if (lba_48_ok(block, n_block)) {
+ if (!(dev->flags & ATA_DFLAG_LBA48))
return 1;
/* use LBA48 */
@@ -779,15 +780,9 @@ static unsigned int ata_scsi_rw_xlat(str
tf->hob_lbah = (block >> 40) & 0xff;
tf->hob_lbam = (block >> 32) & 0xff;
tf->hob_lbal = (block >> 24) & 0xff;
- } else {
- /* use LBA28 */
-
- /* The request -may- be too large for LBA28. */
- if ((block >> 28) || (n_block > 256))
- return 1;
-
- tf->device |= (block >> 24) & 0xf;
- }
+ } else
+ /* request too large even for LBA48 */
+ return 1;
ata_rwcmd_protocol(qc);
@@ -804,7 +799,7 @@ static unsigned int ata_scsi_rw_xlat(str
u32 sect, head, cyl, track;
/* The request -may- be too large for CHS addressing. */
- if ((block >> 28) || (n_block > 256))
+ if (!lba_28_ok(block, n_block))
return 1;
ata_rwcmd_protocol(qc);
^ permalink raw reply [flat|nested] 77+ messages in thread
* [PATCH 0/3] libata: CHS follow-up patches (resend #4)
2005-10-07 6:53 ` [PATCH 0/3] libata: CHS follow-up patches (resend #2) Albert Lee
` (2 preceding siblings ...)
2005-10-07 7:04 ` [PATCH 3/3] CHS: LBA28/LBA48 optimization Albert Lee
@ 2005-10-07 8:32 ` Albert Lee
2005-10-07 8:34 ` [PATCH 1/3] CHS: move the initialization of taskfile LBA flags " Albert Lee
` (3 more replies)
3 siblings, 4 replies; 77+ messages in thread
From: Albert Lee @ 2005-10-07 8:32 UTC (permalink / raw)
To: Jeff Garzik
Cc: Mark Lord, Bartlomiej Zolnierkiewicz, Linux IDE, Doug Maxey,
Tejun Heo, Brett Russ, Alan Cox
(Resend #4, mailnews.wraplength set to 0 to keep Thunderbird from trimming trailing whitespaces.
Sorry for all the noises.)
CHS follow-up patches.
patch 1/3: move the initialization of ATA_TFLAG_LBA and ATA_TFLAG_LBA48
flags to the SCSI translation functions
patch 2/3: calculate read/write commands and protocols on the fly
patch 3/3: LBA28/LBA48 optimization
Patch against libata-dev upstream branch
(643736a58d2668af94aee05670c5e9ae76e7b85f).
Thanks.
Albert
^ permalink raw reply [flat|nested] 77+ messages in thread
* [PATCH 1/3] CHS: move the initialization of taskfile LBA flags (resend #4)
2005-10-07 8:32 ` [PATCH 0/3] libata: CHS follow-up patches (resend #4) Albert Lee
@ 2005-10-07 8:34 ` Albert Lee
2005-10-07 8:36 ` [PATCH 2/3] CHS: calculate read/write commands and protocol on the fly " Albert Lee
` (2 subsequent siblings)
3 siblings, 0 replies; 77+ messages in thread
From: Albert Lee @ 2005-10-07 8:34 UTC (permalink / raw)
To: Jeff Garzik
Cc: Mark Lord, Bartlomiej Zolnierkiewicz, Linux IDE, Doug Maxey,
Tejun Heo, Brett Russ, Alan Cox
(resend #4)
Patch 1/3:
move the initialization of taskfile LBA flags
"ATA_TFLAG_LBA" and "ATA_TFLAG_LBA48 flags"
to the SCSI translation functions
Signed-off-by: Albert Lee <albertcc@tw.ibm.com>
=============
--- upstream/drivers/scsi/libata-core.c 2005-10-05 18:04:07.000000000 +0800
+++ ch1/drivers/scsi/libata-core.c 2005-10-05 18:10:28.000000000 +0800
@@ -3241,13 +3241,6 @@ struct ata_queued_cmd *ata_qc_new_init(s
qc->nbytes = qc->curbytes = 0;
ata_tf_init(ap, &qc->tf, dev->devno);
-
- if (dev->flags & ATA_DFLAG_LBA) {
- qc->tf.flags |= ATA_TFLAG_LBA;
-
- if (dev->flags & ATA_DFLAG_LBA48)
- qc->tf.flags |= ATA_TFLAG_LBA48;
- }
}
return qc;
--- upstream/drivers/scsi/libata-scsi.c 2005-10-05 18:04:07.000000000 +0800
+++ ch1/drivers/scsi/libata-scsi.c 2005-10-05 18:10:28.000000000 +0800
@@ -489,7 +489,7 @@ static unsigned int ata_scsi_flush_xlat(
tf->flags |= ATA_TFLAG_DEVICE;
tf->protocol = ATA_PROT_NODATA;
- if ((tf->flags & ATA_TFLAG_LBA48) &&
+ if ((qc->dev->flags & ATA_DFLAG_LBA48) &&
(ata_id_has_flush_ext(qc->dev->id)))
tf->command = ATA_CMD_FLUSH_EXT;
else
@@ -609,8 +609,6 @@ static unsigned int ata_scsi_verify_xlat
{
struct ata_taskfile *tf = &qc->tf;
struct ata_device *dev = qc->dev;
- unsigned int lba = tf->flags & ATA_TFLAG_LBA;
- unsigned int lba48 = tf->flags & ATA_TFLAG_LBA48;
u64 dev_sectors = qc->dev->n_sectors;
u64 block;
u32 n_block;
@@ -631,16 +629,16 @@ static unsigned int ata_scsi_verify_xlat
return 1;
if ((block + n_block) > dev_sectors)
return 1;
- if (lba48) {
- if (n_block > (64 * 1024))
- return 1;
- } else {
- if (n_block > 256)
- return 1;
- }
- if (lba) {
- if (lba48) {
+ if (dev->flags & ATA_DFLAG_LBA) {
+ tf->flags |= ATA_TFLAG_LBA;
+
+ if (dev->flags & ATA_DFLAG_LBA48) {
+ if (n_block > (64 * 1024))
+ return 1;
+
+ /* use LBA48 */
+ tf->flags |= ATA_TFLAG_LBA48;
tf->command = ATA_CMD_VERIFY_EXT;
tf->hob_nsect = (n_block >> 8) & 0xff;
@@ -649,8 +647,11 @@ static unsigned int ata_scsi_verify_xlat
tf->hob_lbam = (block >> 32) & 0xff;
tf->hob_lbal = (block >> 24) & 0xff;
} else {
- tf->command = ATA_CMD_VERIFY;
+ if (n_block > 256)
+ return 1;
+ /* use LBA28 */
+ tf->command = ATA_CMD_VERIFY;
tf->device |= (block >> 24) & 0xf;
}
@@ -665,6 +666,9 @@ static unsigned int ata_scsi_verify_xlat
/* CHS */
u32 sect, head, cyl, track;
+ if (n_block > 256)
+ return 1;
+
/* Convert LBA to CHS */
track = (u32)block / dev->sectors;
cyl = track / dev->heads;
@@ -716,8 +720,6 @@ static unsigned int ata_scsi_rw_xlat(str
{
struct ata_taskfile *tf = &qc->tf;
struct ata_device *dev = qc->dev;
- unsigned int lba = tf->flags & ATA_TFLAG_LBA;
- unsigned int lba48 = tf->flags & ATA_TFLAG_LBA48;
u64 block;
u32 n_block;
@@ -766,19 +768,24 @@ static unsigned int ata_scsi_rw_xlat(str
*/
return 1;
- if (lba) {
- if (lba48) {
+ if (dev->flags & ATA_DFLAG_LBA) {
+ tf->flags |= ATA_TFLAG_LBA;
+
+ if (dev->flags & ATA_DFLAG_LBA48) {
/* The request -may- be too large for LBA48. */
if ((block >> 48) || (n_block > 65536))
return 1;
+ /* use LBA48 */
+ tf->flags |= ATA_TFLAG_LBA48;
+
tf->hob_nsect = (n_block >> 8) & 0xff;
tf->hob_lbah = (block >> 40) & 0xff;
tf->hob_lbam = (block >> 32) & 0xff;
tf->hob_lbal = (block >> 24) & 0xff;
} else {
- /* LBA28 */
+ /* use LBA28 */
/* The request -may- be too large for LBA28. */
if ((block >> 28) || (n_block > 256))
^ permalink raw reply [flat|nested] 77+ messages in thread
* [PATCH 2/3] CHS: calculate read/write commands and protocol on the fly (resend #4)
2005-10-07 8:32 ` [PATCH 0/3] libata: CHS follow-up patches (resend #4) Albert Lee
2005-10-07 8:34 ` [PATCH 1/3] CHS: move the initialization of taskfile LBA flags " Albert Lee
@ 2005-10-07 8:36 ` Albert Lee
2005-10-07 8:37 ` [PATCH 3/3] CHS: LBA28/LBA48 optimization " Albert Lee
2005-10-09 13:41 ` [PATCH 0/3] libata: CHS follow-up patches " Jeff Garzik
3 siblings, 0 replies; 77+ messages in thread
From: Albert Lee @ 2005-10-07 8:36 UTC (permalink / raw)
To: Jeff Garzik
Cc: Mark Lord, Bartlomiej Zolnierkiewicz, Linux IDE, Doug Maxey,
Tejun Heo, Brett Russ, Alan Cox
(Resend #4)
Patch 2/3: calculate read/write commands and protocols on the fly
changes:
- merge ata_prot_to_cmd() and ata_dev_set_protocol() as
ata_rwcmd_protocol()
- pave road for read/write multiple support
- remove usage of pre-cached command and protocol values and call
ata_rwcmd_protocol() instead
Signed-off-by: Albert Lee <albertcc@tw.ibm.com>
==============
--- upstream/include/linux/ata.h 2005-10-05 18:04:16.000000000 +0800
+++ ch2/include/linux/ata.h 2005-10-05 18:11:12.000000000 +0800
@@ -128,6 +128,10 @@ enum {
ATA_CMD_PIO_READ_EXT = 0x24,
ATA_CMD_PIO_WRITE = 0x30,
ATA_CMD_PIO_WRITE_EXT = 0x34,
+ ATA_CMD_READ_MULTI = 0xC4,
+ ATA_CMD_READ_MULTI_EXT = 0x29,
+ ATA_CMD_WRITE_MULTI = 0xC5,
+ ATA_CMD_WRITE_MULTI_EXT = 0x39,
ATA_CMD_SET_FEATURES = 0xEF,
ATA_CMD_PACKET = 0xA0,
ATA_CMD_VERIFY = 0x40,
--- upstream/include/linux/libata.h 2005-10-05 18:04:16.000000000 +0800
+++ ch2/include/linux/libata.h 2005-10-05 18:11:12.000000000 +0800
@@ -283,10 +283,8 @@ struct ata_device {
u8 xfer_mode;
unsigned int xfer_shift; /* ATA_SHIFT_xxx */
- /* cache info about current transfer mode */
- u8 xfer_protocol; /* taskfile xfer protocol */
- u8 read_cmd; /* opcode to use on read */
- u8 write_cmd; /* opcode to use on write */
+ unsigned int multi_count; /* sectors count for
+ READ/WRITE MULTIPLE */
/* for CHS addressing */
u16 cylinders; /* Number of cylinders */
--- upstream/drivers/scsi/libata.h 2005-10-05 18:04:07.000000000 +0800
+++ ch2/drivers/scsi/libata.h 2005-10-05 18:11:12.000000000 +0800
@@ -41,6 +41,7 @@ struct ata_scsi_args {
extern int atapi_enabled;
extern struct ata_queued_cmd *ata_qc_new_init(struct ata_port *ap,
struct ata_device *dev);
+extern void ata_rwcmd_protocol(struct ata_queued_cmd *qc);
extern void ata_qc_free(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);
--- ch1/drivers/scsi/libata-core.c 2005-10-05 18:10:28.000000000 +0800
+++ ch2/drivers/scsi/libata-core.c 2005-10-07 14:27:38.000000000 +0800
@@ -616,79 +616,53 @@ void ata_tf_from_fis(u8 *fis, struct ata
tf->hob_nsect = fis[13];
}
-/**
- * ata_prot_to_cmd - determine which read/write opcodes to use
- * @protocol: ATA_PROT_xxx taskfile protocol
- * @lba48: true is lba48 is present
- *
- * Given necessary input, determine which read/write commands
- * to use to transfer data.
- *
- * LOCKING:
- * None.
- */
-static int ata_prot_to_cmd(int protocol, int lba48)
-{
- int rcmd = 0, wcmd = 0;
-
- switch (protocol) {
- case ATA_PROT_PIO:
- if (lba48) {
- rcmd = ATA_CMD_PIO_READ_EXT;
- wcmd = ATA_CMD_PIO_WRITE_EXT;
- } else {
- rcmd = ATA_CMD_PIO_READ;
- wcmd = ATA_CMD_PIO_WRITE;
- }
- break;
-
- case ATA_PROT_DMA:
- if (lba48) {
- rcmd = ATA_CMD_READ_EXT;
- wcmd = ATA_CMD_WRITE_EXT;
- } else {
- rcmd = ATA_CMD_READ;
- wcmd = ATA_CMD_WRITE;
- }
- break;
-
- default:
- return -1;
- }
-
- return rcmd | (wcmd << 8);
-}
+static const u8 ata_rw_cmds[] = {
+ /* pio multi */
+ ATA_CMD_READ_MULTI,
+ ATA_CMD_WRITE_MULTI,
+ ATA_CMD_READ_MULTI_EXT,
+ ATA_CMD_WRITE_MULTI_EXT,
+ /* pio */
+ ATA_CMD_PIO_READ,
+ ATA_CMD_PIO_WRITE,
+ ATA_CMD_PIO_READ_EXT,
+ ATA_CMD_PIO_WRITE_EXT,
+ /* dma */
+ ATA_CMD_READ,
+ ATA_CMD_WRITE,
+ ATA_CMD_READ_EXT,
+ ATA_CMD_WRITE_EXT
+};
/**
- * ata_dev_set_protocol - set taskfile protocol and r/w commands
- * @dev: device to examine and configure
+ * ata_rwcmd_protocol - set taskfile r/w commands and protocol
+ * @qc: command to examine and configure
*
- * Examine the device configuration, after we have
- * read the identify-device page and configured the
- * data transfer mode. Set internal state related to
- * the ATA taskfile protocol (pio, pio mult, dma, etc.)
- * and calculate the proper read/write commands to use.
+ * Examine the device configuration and tf->flags to calculate
+ * the proper read/write commands and protocol to use.
*
* LOCKING:
* caller.
*/
-static void ata_dev_set_protocol(struct ata_device *dev)
+void ata_rwcmd_protocol(struct ata_queued_cmd *qc)
{
- int pio = (dev->flags & ATA_DFLAG_PIO);
- int lba48 = (dev->flags & ATA_DFLAG_LBA48);
- int proto, cmd;
-
- if (pio)
- proto = dev->xfer_protocol = ATA_PROT_PIO;
- else
- proto = dev->xfer_protocol = ATA_PROT_DMA;
+ struct ata_taskfile *tf = &qc->tf;
+ struct ata_device *dev = qc->dev;
- cmd = ata_prot_to_cmd(proto, lba48);
- if (cmd < 0)
- BUG();
+ int index, lba48, write;
+
+ lba48 = (tf->flags & ATA_TFLAG_LBA48) ? 2 : 0;
+ write = (tf->flags & ATA_TFLAG_WRITE) ? 1 : 0;
+
+ if (dev->flags & ATA_DFLAG_PIO) {
+ tf->protocol = ATA_PROT_PIO;
+ index = dev->multi_count ? 0 : 4;
+ } else {
+ tf->protocol = ATA_PROT_DMA;
+ index = 8;
+ }
- dev->read_cmd = cmd & 0xff;
- dev->write_cmd = (cmd >> 8) & 0xff;
+ tf->command = ata_rw_cmds[index + lba48 + write];
}
static const char * xfer_mode_str[] = {
@@ -1641,7 +1615,7 @@ static void ata_host_set_dma(struct ata_
*/
static void ata_set_mode(struct ata_port *ap)
{
- unsigned int i, xfer_shift;
+ unsigned int xfer_shift;
u8 xfer_mode;
int rc;
@@ -1670,11 +1644,6 @@ static void ata_set_mode(struct ata_port
if (ap->ops->post_set_mode)
ap->ops->post_set_mode(ap);
- for (i = 0; i < 2; i++) {
- struct ata_device *dev = &ap->device[i];
- ata_dev_set_protocol(dev);
- }
-
return;
err_out:
--- ch1/drivers/scsi/libata-scsi.c 2005-10-05 18:10:28.000000000 +0800
+++ ch2/drivers/scsi/libata-scsi.c 2005-10-05 18:11:12.000000000 +0800
@@ -724,15 +724,10 @@ static unsigned int ata_scsi_rw_xlat(str
u32 n_block;
tf->flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
- tf->protocol = qc->dev->xfer_protocol;
- if (scsicmd[0] == READ_10 || scsicmd[0] == READ_6 ||
- scsicmd[0] == READ_16) {
- tf->command = qc->dev->read_cmd;
- } else {
- tf->command = qc->dev->write_cmd;
+ if (scsicmd[0] == WRITE_10 || scsicmd[0] == WRITE_6 ||
+ scsicmd[0] == WRITE_16)
tf->flags |= ATA_TFLAG_WRITE;
- }
/* Calculate the SCSI LBA and transfer length. */
switch (scsicmd[0]) {
@@ -794,6 +789,8 @@ static unsigned int ata_scsi_rw_xlat(str
tf->device |= (block >> 24) & 0xf;
}
+ ata_rwcmd_protocol(qc);
+
qc->nsect = n_block;
tf->nsect = n_block & 0xff;
@@ -810,6 +807,8 @@ static unsigned int ata_scsi_rw_xlat(str
if ((block >> 28) || (n_block > 256))
return 1;
+ ata_rwcmd_protocol(qc);
+
/* Convert LBA to CHS */
track = (u32)block / dev->sectors;
cyl = track / dev->heads;
^ permalink raw reply [flat|nested] 77+ messages in thread
* [PATCH 3/3] CHS: LBA28/LBA48 optimization (resend #4)
2005-10-07 8:32 ` [PATCH 0/3] libata: CHS follow-up patches (resend #4) Albert Lee
2005-10-07 8:34 ` [PATCH 1/3] CHS: move the initialization of taskfile LBA flags " Albert Lee
2005-10-07 8:36 ` [PATCH 2/3] CHS: calculate read/write commands and protocol on the fly " Albert Lee
@ 2005-10-07 8:37 ` Albert Lee
2005-10-09 13:41 ` [PATCH 0/3] libata: CHS follow-up patches " Jeff Garzik
3 siblings, 0 replies; 77+ messages in thread
From: Albert Lee @ 2005-10-07 8:37 UTC (permalink / raw)
To: Jeff Garzik
Cc: Mark Lord, Bartlomiej Zolnierkiewicz, Linux IDE, Doug Maxey,
Tejun Heo, Brett Russ, Alan Cox
(resend #4)
Patch 3/3: LBA28/LBA48 optimization per Mark's advice.
Changes:
- add lba_28_ok() and lba_48_ok() to ata.h
- use lba_28_ok() for CHS range check
- LBA28/LBA48 optimization
Signed-off-by: Albert Lee <albertcc@tw.ibm.com>
=====
--- ch2/include/linux/ata.h 2005-10-05 18:11:12.000000000 +0800
+++ ch4/include/linux/ata.h 2005-10-05 18:47:29.000000000 +0800
@@ -291,4 +291,14 @@ static inline int ata_ok(u8 status)
== ATA_DRDY);
}
+static inline int lba_28_ok(u64 block, u32 n_block)
+{
+ return (block < ((u64)1 << 28)) && (n_block <= 256);
+}
+
+static inline int lba_48_ok(u64 block, u32 n_block)
+{
+ return (block < ((u64)1 << 48)) && (n_block <= 65536);
+}
+
#endif /* __LINUX_ATA_H__ */
--- ch3/drivers/scsi/libata-scsi.c 2005-10-05 18:11:12.000000000 +0800
+++ ch4/drivers/scsi/libata-scsi.c 2005-10-05 18:12:09.000000000 +0800
@@ -633,8 +633,12 @@ static unsigned int ata_scsi_verify_xlat
if (dev->flags & ATA_DFLAG_LBA) {
tf->flags |= ATA_TFLAG_LBA;
- if (dev->flags & ATA_DFLAG_LBA48) {
- if (n_block > (64 * 1024))
+ if (lba_28_ok(block, n_block)) {
+ /* use LBA28 */
+ tf->command = ATA_CMD_VERIFY;
+ tf->device |= (block >> 24) & 0xf;
+ } else if (lba_48_ok(block, n_block)) {
+ if (!(dev->flags & ATA_DFLAG_LBA48))
return 1;
/* use LBA48 */
@@ -646,14 +650,9 @@ static unsigned int ata_scsi_verify_xlat
tf->hob_lbah = (block >> 40) & 0xff;
tf->hob_lbam = (block >> 32) & 0xff;
tf->hob_lbal = (block >> 24) & 0xff;
- } else {
- if (n_block > 256)
- return 1;
-
- /* use LBA28 */
- tf->command = ATA_CMD_VERIFY;
- tf->device |= (block >> 24) & 0xf;
- }
+ } else
+ /* request too large even for LBA48 */
+ return 1;
tf->nsect = n_block & 0xff;
@@ -666,7 +665,7 @@ static unsigned int ata_scsi_verify_xlat
/* CHS */
u32 sect, head, cyl, track;
- if (n_block > 256)
+ if (!lba_28_ok(block, n_block))
return 1;
/* Convert LBA to CHS */
@@ -766,9 +765,11 @@ static unsigned int ata_scsi_rw_xlat(str
if (dev->flags & ATA_DFLAG_LBA) {
tf->flags |= ATA_TFLAG_LBA;
- if (dev->flags & ATA_DFLAG_LBA48) {
- /* The request -may- be too large for LBA48. */
- if ((block >> 48) || (n_block > 65536))
+ if (lba_28_ok(block, n_block)) {
+ /* use LBA28 */
+ tf->device |= (block >> 24) & 0xf;
+ } else if (lba_48_ok(block, n_block)) {
+ if (!(dev->flags & ATA_DFLAG_LBA48))
return 1;
/* use LBA48 */
@@ -779,15 +780,9 @@ static unsigned int ata_scsi_rw_xlat(str
tf->hob_lbah = (block >> 40) & 0xff;
tf->hob_lbam = (block >> 32) & 0xff;
tf->hob_lbal = (block >> 24) & 0xff;
- } else {
- /* use LBA28 */
-
- /* The request -may- be too large for LBA28. */
- if ((block >> 28) || (n_block > 256))
- return 1;
-
- tf->device |= (block >> 24) & 0xf;
- }
+ } else
+ /* request too large even for LBA48 */
+ return 1;
ata_rwcmd_protocol(qc);
@@ -804,7 +799,7 @@ static unsigned int ata_scsi_rw_xlat(str
u32 sect, head, cyl, track;
/* The request -may- be too large for CHS addressing. */
- if ((block >> 28) || (n_block > 256))
+ if (!lba_28_ok(block, n_block))
return 1;
ata_rwcmd_protocol(qc);
^ permalink raw reply [flat|nested] 77+ messages in thread
* Re: [PATCH 0/3] libata: CHS follow-up patches (resend #4)
2005-10-07 8:32 ` [PATCH 0/3] libata: CHS follow-up patches (resend #4) Albert Lee
` (2 preceding siblings ...)
2005-10-07 8:37 ` [PATCH 3/3] CHS: LBA28/LBA48 optimization " Albert Lee
@ 2005-10-09 13:41 ` Jeff Garzik
2005-10-11 11:05 ` [PATCH 0/4] libata: CHS follow-up patches (resend #5) Albert Lee
3 siblings, 1 reply; 77+ messages in thread
From: Jeff Garzik @ 2005-10-09 13:41 UTC (permalink / raw)
To: Albert Lee
Cc: Mark Lord, Bartlomiej Zolnierkiewicz, Linux IDE, Doug Maxey,
Tejun Heo, Brett Russ, Alan Cox
Albert Lee wrote:
> (Resend #4, mailnews.wraplength set to 0 to keep Thunderbird from trimming trailing whitespaces.
> Sorry for all the noises.)
>
>
> CHS follow-up patches.
>
> patch 1/3: move the initialization of ATA_TFLAG_LBA and ATA_TFLAG_LBA48
> flags to the SCSI translation functions
>
> patch 2/3: calculate read/write commands and protocols on the fly
>
> patch 3/3: LBA28/LBA48 optimization
You've been very patient in resending, thanks :)
I wanted to go ahead and merge Doug Gilbert's error handling updates,
which in turn caused some conflicts with your patches. Would you please
rediff and resend the same three patches, against the latest 'upstream'
branch?
Jeff
^ permalink raw reply [flat|nested] 77+ messages in thread
* [PATCH 0/4] libata: CHS follow-up patches (resend #5)
2005-10-09 13:41 ` [PATCH 0/3] libata: CHS follow-up patches " Jeff Garzik
@ 2005-10-11 11:05 ` Albert Lee
2005-10-11 11:09 ` [PATCH 1/4] CHS: move the initialization of taskfile LBA flags " Albert Lee
` (2 more replies)
0 siblings, 3 replies; 77+ messages in thread
From: Albert Lee @ 2005-10-11 11:05 UTC (permalink / raw)
To: Jeff Garzik; +Cc: Linux IDE
Jeff,
CHS follow-up patches. (Keep sync with the scsi error handling patch. Also added patch 3/4.)
patch 1/4: move the initialization of ATA_TFLAG_LBA and ATA_TFLAG_LBA48 flags to the SCSI translation functions
patch 2/4: calculate read/write commands and protocols on the fly
patch 3/4: reread device identify info after initializing device CHS settings
patch 4/4: LBA28/LBA48 optimization
Patch against libata-dev upstream branch
(edea3ab58f8edd5f72d31f891ab4f34382e97e3a).
For your review, thanks.
Albert
^ permalink raw reply [flat|nested] 77+ messages in thread
* [PATCH 1/4] CHS: move the initialization of taskfile LBA flags (resend #5)
2005-10-11 11:05 ` [PATCH 0/4] libata: CHS follow-up patches (resend #5) Albert Lee
@ 2005-10-11 11:09 ` Albert Lee
2005-10-11 11:11 ` [PATCH 2/4] CHS: calculate read/write commands and protocol on the fly " Albert Lee
2005-10-11 11:21 ` [PATCH 4/4] CHS: LBA28/LBA48 optimization " Albert Lee
2 siblings, 0 replies; 77+ messages in thread
From: Albert Lee @ 2005-10-11 11:09 UTC (permalink / raw)
To: Jeff Garzik; +Cc: Linux IDE
Patch 1/4:
move the initialization of taskfile LBA flags
"ATA_TFLAG_LBA" and "ATA_TFLAG_LBA48 flags"
to the SCSI translation functions
Signed-off-by: Albert Lee <albertcc@tw.ibm.com>
=============
--- upstream/drivers/scsi/libata-core.c 2005-10-11 11:40:03.000000000 +0800
+++ ch1/drivers/scsi/libata-core.c 2005-10-11 12:44:53.000000000 +0800
@@ -3195,13 +3195,6 @@ struct ata_queued_cmd *ata_qc_new_init(s
qc->nbytes = qc->curbytes = 0;
ata_tf_init(ap, &qc->tf, dev->devno);
-
- if (dev->flags & ATA_DFLAG_LBA) {
- qc->tf.flags |= ATA_TFLAG_LBA;
-
- if (dev->flags & ATA_DFLAG_LBA48)
- qc->tf.flags |= ATA_TFLAG_LBA48;
- }
}
return qc;
--- upstream/drivers/scsi/libata-scsi.c 2005-10-11 11:40:03.000000000 +0800
+++ ch1/drivers/scsi/libata-scsi.c 2005-10-11 12:53:36.000000000 +0800
@@ -492,7 +492,7 @@ static unsigned int ata_scsi_flush_xlat(
tf->flags |= ATA_TFLAG_DEVICE;
tf->protocol = ATA_PROT_NODATA;
- if ((tf->flags & ATA_TFLAG_LBA48) &&
+ if ((qc->dev->flags & ATA_DFLAG_LBA48) &&
(ata_id_has_flush_ext(qc->dev->id)))
tf->command = ATA_CMD_FLUSH_EXT;
else
@@ -612,8 +612,6 @@ static unsigned int ata_scsi_verify_xlat
{
struct ata_taskfile *tf = &qc->tf;
struct ata_device *dev = qc->dev;
- unsigned int lba = tf->flags & ATA_TFLAG_LBA;
- unsigned int lba48 = tf->flags & ATA_TFLAG_LBA48;
u64 dev_sectors = qc->dev->n_sectors;
u64 block;
u32 n_block;
@@ -634,16 +632,16 @@ static unsigned int ata_scsi_verify_xlat
goto out_of_range;
if ((block + n_block) > dev_sectors)
goto out_of_range;
- if (lba48) {
- if (n_block > (64 * 1024))
- goto invalid_fld;
- } else {
- if (n_block > 256)
- goto invalid_fld;
- }
- if (lba) {
- if (lba48) {
+ if (dev->flags & ATA_DFLAG_LBA) {
+ tf->flags |= ATA_TFLAG_LBA;
+
+ if (dev->flags & ATA_DFLAG_LBA48) {
+ if (n_block > (64 * 1024))
+ goto invalid_fld;
+
+ /* use LBA48 */
+ tf->flags |= ATA_TFLAG_LBA48;
tf->command = ATA_CMD_VERIFY_EXT;
tf->hob_nsect = (n_block >> 8) & 0xff;
@@ -652,6 +650,10 @@ static unsigned int ata_scsi_verify_xlat
tf->hob_lbam = (block >> 32) & 0xff;
tf->hob_lbal = (block >> 24) & 0xff;
} else {
+ if (n_block > 256)
+ goto invalid_fld;
+
+ /* use LBA28 */
tf->command = ATA_CMD_VERIFY;
tf->device |= (block >> 24) & 0xf;
@@ -668,6 +670,9 @@ static unsigned int ata_scsi_verify_xlat
/* CHS */
u32 sect, head, cyl, track;
+ if (n_block > 256)
+ goto invalid_fld;
+
/* Convert LBA to CHS */
track = (u32)block / dev->sectors;
cyl = track / dev->heads;
@@ -733,8 +738,6 @@ static unsigned int ata_scsi_rw_xlat(str
{
struct ata_taskfile *tf = &qc->tf;
struct ata_device *dev = qc->dev;
- unsigned int lba = tf->flags & ATA_TFLAG_LBA;
- unsigned int lba48 = tf->flags & ATA_TFLAG_LBA48;
u64 block;
u32 n_block;
@@ -783,19 +786,24 @@ static unsigned int ata_scsi_rw_xlat(str
*/
goto nothing_to_do;
- if (lba) {
- if (lba48) {
+ if (dev->flags & ATA_DFLAG_LBA) {
+ tf->flags |= ATA_TFLAG_LBA;
+
+ if (dev->flags & ATA_DFLAG_LBA48) {
/* The request -may- be too large for LBA48. */
if ((block >> 48) || (n_block > 65536))
goto out_of_range;
+ /* use LBA48 */
+ tf->flags |= ATA_TFLAG_LBA48;
+
tf->hob_nsect = (n_block >> 8) & 0xff;
tf->hob_lbah = (block >> 40) & 0xff;
tf->hob_lbam = (block >> 32) & 0xff;
tf->hob_lbal = (block >> 24) & 0xff;
} else {
- /* LBA28 */
+ /* use LBA28 */
/* The request -may- be too large for LBA28. */
if ((block >> 28) || (n_block > 256))
^ permalink raw reply [flat|nested] 77+ messages in thread
* [PATCH 2/4] CHS: calculate read/write commands and protocol on the fly (resend #5)
2005-10-11 11:05 ` [PATCH 0/4] libata: CHS follow-up patches (resend #5) Albert Lee
2005-10-11 11:09 ` [PATCH 1/4] CHS: move the initialization of taskfile LBA flags " Albert Lee
@ 2005-10-11 11:11 ` Albert Lee
2005-10-11 11:21 ` [PATCH 4/4] CHS: LBA28/LBA48 optimization " Albert Lee
2 siblings, 0 replies; 77+ messages in thread
From: Albert Lee @ 2005-10-11 11:11 UTC (permalink / raw)
To: Jeff Garzik; +Cc: Linux IDE
Patch 2/4: calculate read/write commands and protocols on the fly
changes:
- merge ata_prot_to_cmd() and ata_dev_set_protocol() as
ata_rwcmd_protocol()
- pave road for read/write multiple support
- remove usage of pre-cached command and protocol values and call
ata_rwcmd_protocol() instead
Signed-off-by: Albert Lee <albertcc@tw.ibm.com>
==============
--- upstream/include/linux/ata.h 2005-10-11 11:40:08.000000000 +0800
+++ ch2/include/linux/ata.h 2005-10-11 12:56:56.000000000 +0800
@@ -128,6 +128,10 @@ enum {
ATA_CMD_PIO_READ_EXT = 0x24,
ATA_CMD_PIO_WRITE = 0x30,
ATA_CMD_PIO_WRITE_EXT = 0x34,
+ ATA_CMD_READ_MULTI = 0xC4,
+ ATA_CMD_READ_MULTI_EXT = 0x29,
+ ATA_CMD_WRITE_MULTI = 0xC5,
+ ATA_CMD_WRITE_MULTI_EXT = 0x39,
ATA_CMD_SET_FEATURES = 0xEF,
ATA_CMD_PACKET = 0xA0,
ATA_CMD_VERIFY = 0x40,
--- upstream/include/linux/libata.h 2005-10-11 11:40:09.000000000 +0800
+++ ch2/include/linux/libata.h 2005-10-11 12:58:12.000000000 +0800
@@ -283,10 +283,8 @@ struct ata_device {
u8 xfer_mode;
unsigned int xfer_shift; /* ATA_SHIFT_xxx */
- /* cache info about current transfer mode */
- u8 xfer_protocol; /* taskfile xfer protocol */
- u8 read_cmd; /* opcode to use on read */
- u8 write_cmd; /* opcode to use on write */
+ unsigned int multi_count; /* sectors count for
+ READ/WRITE MULTIPLE */
/* for CHS addressing */
u16 cylinders; /* Number of cylinders */
--- upstream/drivers/scsi/libata.h 2005-10-11 11:40:03.000000000 +0800
+++ ch2/drivers/scsi/libata.h 2005-10-11 12:59:09.000000000 +0800
@@ -42,6 +42,7 @@ extern int atapi_enabled;
extern int ata_qc_complete_noop(struct ata_queued_cmd *qc, u8 drv_stat);
extern struct ata_queued_cmd *ata_qc_new_init(struct ata_port *ap,
struct ata_device *dev);
+extern void ata_rwcmd_protocol(struct ata_queued_cmd *qc);
extern void ata_qc_free(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);
--- ch1/drivers/scsi/libata-core.c 2005-10-11 12:44:53.000000000 +0800
+++ ch2/drivers/scsi/libata-core.c 2005-10-11 13:01:05.000000000 +0800
@@ -616,79 +616,53 @@ void ata_tf_from_fis(u8 *fis, struct ata
tf->hob_nsect = fis[13];
}
-/**
- * ata_prot_to_cmd - determine which read/write opcodes to use
- * @protocol: ATA_PROT_xxx taskfile protocol
- * @lba48: true is lba48 is present
- *
- * Given necessary input, determine which read/write commands
- * to use to transfer data.
- *
- * LOCKING:
- * None.
- */
-static int ata_prot_to_cmd(int protocol, int lba48)
-{
- int rcmd = 0, wcmd = 0;
-
- switch (protocol) {
- case ATA_PROT_PIO:
- if (lba48) {
- rcmd = ATA_CMD_PIO_READ_EXT;
- wcmd = ATA_CMD_PIO_WRITE_EXT;
- } else {
- rcmd = ATA_CMD_PIO_READ;
- wcmd = ATA_CMD_PIO_WRITE;
- }
- break;
-
- case ATA_PROT_DMA:
- if (lba48) {
- rcmd = ATA_CMD_READ_EXT;
- wcmd = ATA_CMD_WRITE_EXT;
- } else {
- rcmd = ATA_CMD_READ;
- wcmd = ATA_CMD_WRITE;
- }
- break;
-
- default:
- return -1;
- }
-
- return rcmd | (wcmd << 8);
-}
+static const u8 ata_rw_cmds[] = {
+ /* pio multi */
+ ATA_CMD_READ_MULTI,
+ ATA_CMD_WRITE_MULTI,
+ ATA_CMD_READ_MULTI_EXT,
+ ATA_CMD_WRITE_MULTI_EXT,
+ /* pio */
+ ATA_CMD_PIO_READ,
+ ATA_CMD_PIO_WRITE,
+ ATA_CMD_PIO_READ_EXT,
+ ATA_CMD_PIO_WRITE_EXT,
+ /* dma */
+ ATA_CMD_READ,
+ ATA_CMD_WRITE,
+ ATA_CMD_READ_EXT,
+ ATA_CMD_WRITE_EXT
+};
/**
- * ata_dev_set_protocol - set taskfile protocol and r/w commands
- * @dev: device to examine and configure
+ * ata_rwcmd_protocol - set taskfile r/w commands and protocol
+ * @qc: command to examine and configure
*
- * Examine the device configuration, after we have
- * read the identify-device page and configured the
- * data transfer mode. Set internal state related to
- * the ATA taskfile protocol (pio, pio mult, dma, etc.)
- * and calculate the proper read/write commands to use.
+ * Examine the device configuration and tf->flags to calculate
+ * the proper read/write commands and protocol to use.
*
* LOCKING:
* caller.
*/
-static void ata_dev_set_protocol(struct ata_device *dev)
+void ata_rwcmd_protocol(struct ata_queued_cmd *qc)
{
- int pio = (dev->flags & ATA_DFLAG_PIO);
- int lba48 = (dev->flags & ATA_DFLAG_LBA48);
- int proto, cmd;
-
- if (pio)
- proto = dev->xfer_protocol = ATA_PROT_PIO;
- else
- proto = dev->xfer_protocol = ATA_PROT_DMA;
+ struct ata_taskfile *tf = &qc->tf;
+ struct ata_device *dev = qc->dev;
- cmd = ata_prot_to_cmd(proto, lba48);
- if (cmd < 0)
- BUG();
+ int index, lba48, write;
+
+ lba48 = (tf->flags & ATA_TFLAG_LBA48) ? 2 : 0;
+ write = (tf->flags & ATA_TFLAG_WRITE) ? 1 : 0;
+
+ if (dev->flags & ATA_DFLAG_PIO) {
+ tf->protocol = ATA_PROT_PIO;
+ index = dev->multi_count ? 0 : 4;
+ } else {
+ tf->protocol = ATA_PROT_DMA;
+ index = 8;
+ }
- dev->read_cmd = cmd & 0xff;
- dev->write_cmd = (cmd >> 8) & 0xff;
+ tf->command = ata_rw_cmds[index + lba48 + write];
}
static const char * xfer_mode_str[] = {
@@ -1641,7 +1615,7 @@ static void ata_host_set_dma(struct ata_
*/
static void ata_set_mode(struct ata_port *ap)
{
- unsigned int i, xfer_shift;
+ unsigned int xfer_shift;
u8 xfer_mode;
int rc;
@@ -1670,11 +1644,6 @@ static void ata_set_mode(struct ata_port
if (ap->ops->post_set_mode)
ap->ops->post_set_mode(ap);
- for (i = 0; i < 2; i++) {
- struct ata_device *dev = &ap->device[i];
- ata_dev_set_protocol(dev);
- }
-
return;
err_out:
--- ch1/drivers/scsi/libata-scsi.c 2005-10-11 12:53:36.000000000 +0800
+++ ch2/drivers/scsi/libata-scsi.c 2005-10-11 13:03:10.000000000 +0800
@@ -742,15 +742,10 @@ static unsigned int ata_scsi_rw_xlat(str
u32 n_block;
tf->flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
- tf->protocol = qc->dev->xfer_protocol;
- if (scsicmd[0] == READ_10 || scsicmd[0] == READ_6 ||
- scsicmd[0] == READ_16) {
- tf->command = qc->dev->read_cmd;
- } else {
- tf->command = qc->dev->write_cmd;
+ if (scsicmd[0] == WRITE_10 || scsicmd[0] == WRITE_6 ||
+ scsicmd[0] == WRITE_16)
tf->flags |= ATA_TFLAG_WRITE;
- }
/* Calculate the SCSI LBA and transfer length. */
switch (scsicmd[0]) {
@@ -812,6 +807,8 @@ static unsigned int ata_scsi_rw_xlat(str
tf->device |= (block >> 24) & 0xf;
}
+ ata_rwcmd_protocol(qc);
+
qc->nsect = n_block;
tf->nsect = n_block & 0xff;
@@ -828,6 +825,8 @@ static unsigned int ata_scsi_rw_xlat(str
if ((block >> 28) || (n_block > 256))
goto out_of_range;
+ ata_rwcmd_protocol(qc);
+
/* Convert LBA to CHS */
track = (u32)block / dev->sectors;
cyl = track / dev->heads;
^ permalink raw reply [flat|nested] 77+ messages in thread
* [PATCH 4/4] CHS: LBA28/LBA48 optimization (resend #5)
2005-10-11 11:05 ` [PATCH 0/4] libata: CHS follow-up patches (resend #5) Albert Lee
2005-10-11 11:09 ` [PATCH 1/4] CHS: move the initialization of taskfile LBA flags " Albert Lee
2005-10-11 11:11 ` [PATCH 2/4] CHS: calculate read/write commands and protocol on the fly " Albert Lee
@ 2005-10-11 11:21 ` Albert Lee
2005-10-11 13:09 ` Mark Lord
2005-10-11 13:12 ` Mark Lord
2 siblings, 2 replies; 77+ messages in thread
From: Albert Lee @ 2005-10-11 11:21 UTC (permalink / raw)
To: Jeff Garzik; +Cc: Linux IDE
Patch 4/4: LBA28/LBA48 optimization per Mark's advice.
Changes:
- add lba_28_ok() and lba_48_ok() to ata.h
- use lba_28_ok() for CHS range check
- LBA28/LBA48 optimization
Signed-off-by: Albert Lee <albertcc@tw.ibm.com>
=====
--- ch2/include/linux/ata.h 2005-10-11 12:56:56.000000000 +0800
+++ ch4/include/linux/ata.h 2005-10-11 13:04:18.000000000 +0800
@@ -291,4 +291,14 @@ static inline int ata_ok(u8 status)
== ATA_DRDY);
}
+static inline int lba_28_ok(u64 block, u32 n_block)
+{
+ return (block < ((u64)1 << 28)) && (n_block <= 256);
+}
+
+static inline int lba_48_ok(u64 block, u32 n_block)
+{
+ return (block < ((u64)1 << 48)) && (n_block <= 65536);
+}
+
#endif /* __LINUX_ATA_H__ */
--- ch2/drivers/scsi/libata-scsi.c 2005-10-11 13:03:10.000000000 +0800
+++ ch4/drivers/scsi/libata-scsi.c 2005-10-11 13:13:19.000000000 +0800
@@ -636,9 +636,13 @@ static unsigned int ata_scsi_verify_xlat
if (dev->flags & ATA_DFLAG_LBA) {
tf->flags |= ATA_TFLAG_LBA;
- if (dev->flags & ATA_DFLAG_LBA48) {
- if (n_block > (64 * 1024))
- goto invalid_fld;
+ if (lba_28_ok(block, n_block)) {
+ /* use LBA28 */
+ tf->command = ATA_CMD_VERIFY;
+ tf->device |= (block >> 24) & 0xf;
+ } else if (lba_48_ok(block, n_block)) {
+ if (!(dev->flags & ATA_DFLAG_LBA48))
+ goto out_of_range;
/* use LBA48 */
tf->flags |= ATA_TFLAG_LBA48;
@@ -649,15 +653,9 @@ static unsigned int ata_scsi_verify_xlat
tf->hob_lbah = (block >> 40) & 0xff;
tf->hob_lbam = (block >> 32) & 0xff;
tf->hob_lbal = (block >> 24) & 0xff;
- } else {
- if (n_block > 256)
- goto invalid_fld;
-
- /* use LBA28 */
- tf->command = ATA_CMD_VERIFY;
-
- tf->device |= (block >> 24) & 0xf;
- }
+ } else
+ /* request too large even for LBA48 */
+ goto out_of_range;
tf->nsect = n_block & 0xff;
@@ -670,8 +668,8 @@ static unsigned int ata_scsi_verify_xlat
/* CHS */
u32 sect, head, cyl, track;
- if (n_block > 256)
- goto invalid_fld;
+ if (!lba_28_ok(block, n_block))
+ goto out_of_range;
/* Convert LBA to CHS */
track = (u32)block / dev->sectors;
@@ -784,9 +782,11 @@ static unsigned int ata_scsi_rw_xlat(str
if (dev->flags & ATA_DFLAG_LBA) {
tf->flags |= ATA_TFLAG_LBA;
- if (dev->flags & ATA_DFLAG_LBA48) {
- /* The request -may- be too large for LBA48. */
- if ((block >> 48) || (n_block > 65536))
+ if (lba_28_ok(block, n_block)) {
+ /* use LBA28 */
+ tf->device |= (block >> 24) & 0xf;
+ } else if (lba_48_ok(block, n_block)) {
+ if (!(dev->flags & ATA_DFLAG_LBA48))
goto out_of_range;
/* use LBA48 */
@@ -797,15 +797,9 @@ static unsigned int ata_scsi_rw_xlat(str
tf->hob_lbah = (block >> 40) & 0xff;
tf->hob_lbam = (block >> 32) & 0xff;
tf->hob_lbal = (block >> 24) & 0xff;
- } else {
- /* use LBA28 */
-
- /* The request -may- be too large for LBA28. */
- if ((block >> 28) || (n_block > 256))
- goto out_of_range;
-
- tf->device |= (block >> 24) & 0xf;
- }
+ } else
+ /* request too large even for LBA48 */
+ goto out_of_range;
ata_rwcmd_protocol(qc);
@@ -822,7 +816,7 @@ static unsigned int ata_scsi_rw_xlat(str
u32 sect, head, cyl, track;
/* The request -may- be too large for CHS addressing. */
- if ((block >> 28) || (n_block > 256))
+ if (!lba_28_ok(block, n_block))
goto out_of_range;
ata_rwcmd_protocol(qc);
^ permalink raw reply [flat|nested] 77+ messages in thread
* Re: [PATCH 4/4] CHS: LBA28/LBA48 optimization (resend #5)
2005-10-11 11:21 ` [PATCH 4/4] CHS: LBA28/LBA48 optimization " Albert Lee
@ 2005-10-11 13:09 ` Mark Lord
2005-10-11 13:12 ` Mark Lord
1 sibling, 0 replies; 77+ messages in thread
From: Mark Lord @ 2005-10-11 13:09 UTC (permalink / raw)
To: Albert Lee; +Cc: Jeff Garzik, Linux IDE
Albert Lee wrote:
> Patch 4/4: LBA28/LBA48 optimization per Mark's advice.
I must confess I'm so far behind on following these patches
that I don't know the answer to this, so..
Does this patch compare the *ending* block number when
checking for 28-bit LBA, or the *starting* block number?
It's the *ending* block number that should be used,
because some drives don't deal well with boundary crossings.
Cheers
^ permalink raw reply [flat|nested] 77+ messages in thread
* Re: [PATCH 4/4] CHS: LBA28/LBA48 optimization (resend #5)
2005-10-11 11:21 ` [PATCH 4/4] CHS: LBA28/LBA48 optimization " Albert Lee
2005-10-11 13:09 ` Mark Lord
@ 2005-10-11 13:12 ` Mark Lord
2005-10-12 5:05 ` Albert Lee
1 sibling, 1 reply; 77+ messages in thread
From: Mark Lord @ 2005-10-11 13:12 UTC (permalink / raw)
To: Albert Lee; +Cc: Jeff Garzik, Linux IDE
Ah, here it is:
> +static inline int lba_28_ok(u64 block, u32 n_block)
> +{
> + return (block < ((u64)1 << 28)) && (n_block <= 256);
> +}
> +
That will need to change, so something like this:
return ((block + n_block - 1) < ((u64)1 << 28)) && (n_block <= 256);
^ permalink raw reply [flat|nested] 77+ messages in thread
* Re: [PATCH 4/4] CHS: LBA28/LBA48 optimization (resend #5)
2005-10-11 13:12 ` Mark Lord
@ 2005-10-12 5:05 ` Albert Lee
0 siblings, 0 replies; 77+ messages in thread
From: Albert Lee @ 2005-10-12 5:05 UTC (permalink / raw)
To: Mark Lord; +Cc: Jeff Garzik, Linux IDE
Mark Lord wrote:
> Ah, here it is:
>
>> +static inline int lba_28_ok(u64 block, u32 n_block)
>> +{
>> + return (block < ((u64)1 << 28)) && (n_block <= 256);
>> +}
>> +
>
>
> That will need to change, so something like this:
>
> return ((block + n_block - 1) < ((u64)1 << 28)) && (n_block <= 256);
> -
Thanks for the advice. I didn't think of it.
Will revise and resend the patch.
Albert
^ permalink raw reply [flat|nested] 77+ messages in thread
end of thread, other threads:[~2005-10-12 5:05 UTC | newest]
Thread overview: 77+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2005-09-09 16:14 [PATCH RFC] libata: interrupt driven pio Albert Lee
2005-09-09 17:35 ` Jeff Garzik
2005-09-09 18:14 ` Doug Maxey
2005-09-22 4:00 ` [PATCH/RFC 0/3] libata: interrupt driven pio (revised) Albert Lee
2005-09-22 4:09 ` [PATCH/RFC 1/3] libata: interrupt driven pio for libata-core Albert Lee
2005-09-23 9:25 ` Albert Lee
2005-09-22 4:11 ` [PATCH/RFC 2/3] libata: rename task states/variables Albert Lee
2005-09-23 9:34 ` Albert Lee
2005-09-22 4:14 ` [PATCH/RFC 3/3] libata: interrupt driven pio for LLD Albert Lee
2005-09-22 12:56 ` Mark Lord
2005-09-23 2:40 ` Albert Lee
2005-09-23 9:46 ` [PATCH/RFC 0/3] libata: interrupt driven pio (revised) Jeff Garzik
2005-09-27 9:31 ` [PATCH/RFC 0/4] libata: interrupt driven pio (revised 2) Albert Lee
2005-09-27 9:34 ` [PATCH/RFC 1/4] libata: indent and whitespace change Albert Lee
2005-09-27 9:36 ` [PATCH/RFC 2/4] libata: rename host states Albert Lee
2005-09-28 15:59 ` Jeff Garzik
2005-09-27 9:38 ` [PATCH/RFC 3/4] libata: interrupt driven pio for libata-core Albert Lee
2005-09-28 16:09 ` Jeff Garzik
2005-09-29 10:08 ` Bartlomiej Zolnierkiewicz
2005-09-30 8:02 ` Albert Lee
2005-09-30 9:28 ` Bartlomiej Zolnierkiewicz
2005-09-30 11:28 ` Albert Lee
2005-09-30 12:00 ` Bartlomiej Zolnierkiewicz
2005-09-30 11:04 ` [PATCH/RFC 0/4] libata: irq driven pio follow-up patches Albert Lee
2005-09-30 11:07 ` [PATCH/RFC 1/4] irq-pio: add comments and cleanup Albert Lee
2005-09-30 11:09 ` [PATCH/RFC 2/4] irq-pio: rename atapi_packet_task() and comments Albert Lee
2005-09-30 11:11 ` [PATCH/RFC 3/4] irq-pio: simplify if condition in ata_dataout_task() Albert Lee
2005-09-30 11:14 ` [PATCH/RFC 4/4] irq-pio: cleanup ata_qc_issue_prot() Albert Lee
2005-09-30 11:21 ` [PATCH/RFC 0/4] libata: irq driven pio follow-up patches Jeff Garzik
2005-10-03 11:46 ` [PATCH/RFC 0/4] libata: more " Albert Lee
2005-10-03 13:00 ` [PATCH/RFC 1/4] irq-pio: move functions Albert Lee
2005-10-03 13:02 ` [PATCH/RFC 2/4] irq-pio: remove ap->dataout_task Albert Lee
2005-10-04 10:09 ` Jeff Garzik
2005-10-04 11:54 ` Albert Lee
2005-10-03 13:18 ` [PATCH/RFC 3/4] irq-pio: integrate ata_pio_first_block() with ata_pio_task() Albert Lee
2005-10-04 10:10 ` Jeff Garzik
2005-10-03 13:19 ` [PATCH/RFC 4/4] irq-pio: add read/write multiple support Albert Lee
2005-10-03 13:35 ` Mark Lord
2005-10-04 9:43 ` Jeff Garzik
2005-10-04 12:00 ` Albert Lee
2005-10-04 12:07 ` Jeff Garzik
2005-10-04 12:22 ` [PATCH/RFC 0/4] libata: CHS follow-up patches Albert Lee
2005-10-04 12:27 ` [PATCH/RFC 1/4] CHS: white space beautification Albert Lee
2005-10-04 12:49 ` Jeff Garzik
2005-10-04 12:29 ` [PATCH/RFC 2/4] CHS: tidy up SCSI lba and transfer length calculation Albert Lee
2005-10-04 12:30 ` [PATCH/RFC 3/4] CHS: add CHS support to ata_scsi_start_stop_xlat() Albert Lee
2005-10-04 12:34 ` [PATCH/RFC 4/4] CHS: calculate LBA28/LBA48 commands and protocol on the fly Albert Lee
2005-10-04 12:52 ` Jeff Garzik
2005-10-05 11:16 ` [PATCH/RFC 0/4] libata: more CHS follow-up patches Albert Lee
2005-10-05 11:20 ` [PATCH/RFC 1/4] CHS: move the initialization of taskfile LBA flags Albert Lee
2005-10-05 11:23 ` [PATCH/RFC 2/4] CHS: calculate read/write commands and protocol on the fly Albert Lee
2005-10-05 11:25 ` [PATCH/RFC 3/4] CHS: support overriding the ata_rwcmd_protocol() function Albert Lee
2005-10-05 11:27 ` [PATCH/RFC 4/4] CHS: optimize LBA28/LBA48 usage Albert Lee
2005-10-05 11:59 ` [PATCH/RFC 1/4] CHS: move the initialization of taskfile LBA flags (resend) Albert Lee
2005-10-05 12:02 ` [PATCH/RFC 2/4] CHS: calculate read/write commands and protocol on the fly (resend) Albert Lee
2005-10-05 12:03 ` [PATCH/RFC 3/4] CHS: support overriding the ata_rwcmd_protocol() function (resend) Albert Lee
2005-10-05 12:04 ` [PATCH/RFC 4/4] CHS: optimize LBA28/LBA48 usage (resend) Albert Lee
2005-10-06 11:26 ` [PATCH/RFC 0/4] libata: more CHS follow-up patches Jeff Garzik
2005-10-07 6:53 ` [PATCH 0/3] libata: CHS follow-up patches (resend #2) Albert Lee
2005-10-07 6:58 ` [PATCH 1/3] CHS: move the initialization of taskfile LBA flags Albert Lee
2005-10-07 7:01 ` [PATCH 2/3] CHS: calculate read/write commands and protocol on the fly Albert Lee
2005-10-07 7:04 ` [PATCH 3/3] CHS: LBA28/LBA48 optimization Albert Lee
2005-10-07 8:32 ` [PATCH 0/3] libata: CHS follow-up patches (resend #4) Albert Lee
2005-10-07 8:34 ` [PATCH 1/3] CHS: move the initialization of taskfile LBA flags " Albert Lee
2005-10-07 8:36 ` [PATCH 2/3] CHS: calculate read/write commands and protocol on the fly " Albert Lee
2005-10-07 8:37 ` [PATCH 3/3] CHS: LBA28/LBA48 optimization " Albert Lee
2005-10-09 13:41 ` [PATCH 0/3] libata: CHS follow-up patches " Jeff Garzik
2005-10-11 11:05 ` [PATCH 0/4] libata: CHS follow-up patches (resend #5) Albert Lee
2005-10-11 11:09 ` [PATCH 1/4] CHS: move the initialization of taskfile LBA flags " Albert Lee
2005-10-11 11:11 ` [PATCH 2/4] CHS: calculate read/write commands and protocol on the fly " Albert Lee
2005-10-11 11:21 ` [PATCH 4/4] CHS: LBA28/LBA48 optimization " Albert Lee
2005-10-11 13:09 ` Mark Lord
2005-10-11 13:12 ` Mark Lord
2005-10-12 5:05 ` Albert Lee
2005-10-04 15:48 ` [PATCH/RFC 4/4] CHS: calculate LBA28/LBA48 commands and protocol on the fly Alan Cox
2005-10-04 10:19 ` [PATCH/RFC 4/4] irq-pio: add read/write multiple support Jeff Garzik
2005-09-27 9:39 ` [PATCH/RFC 4/4] libata: interrupt driven pio for LLD Albert Lee
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).