* [PATCH/RFC 1/4] irq-pio: misc fixes
2005-11-01 11:12 [PATCH/RFC 0/4] libata: more irq driven pio follow-up patches Albert Lee
@ 2005-11-01 11:19 ` Albert Lee
2005-11-09 6:22 ` Jeff Garzik
2005-11-01 11:24 ` [PATCH/RFC 2/4] irq-pio: merge the ata_dataout_task workqueue with ata_pio_task workqueue Albert Lee
` (2 subsequent siblings)
3 siblings, 1 reply; 6+ messages in thread
From: Albert Lee @ 2005-11-01 11:19 UTC (permalink / raw)
To: Jeff Garzik; +Cc: Doug Maxey, Bartlomiej Zolnierkiewicz, Mark Lord, Linux IDE
Patch 1/4: misc fixes
Changes:
- ata_pio_block(): add ata_altstatus(ap) to prevent reading device status before it is valid
- remove the unnecessary HSM_ST_IDLE state from ata_pio_task()
- raise BUG() when unknown state is found in ata_pio_task()
For your review, thanks.
Albert
Signed-off-by: Albert Lee <albertcc@tw.ibm.com>
============
--- linux-ori/drivers/scsi/libata-core.c 2005-11-01 17:22:41.000000000 +0800
+++ id1/drivers/scsi/libata-core.c 2005-11-01 18:45:16.000000000 +0800
@@ -3224,6 +3224,8 @@ static void ata_pio_block(struct ata_por
ata_pio_sector(qc);
}
+
+ ata_altstatus(ap); /* flush */
}
static void ata_pio_error(struct ata_port *ap)
@@ -3251,9 +3253,6 @@ fsm_start:
qc_completed = 0;
switch (ap->hsm_task_state) {
- case HSM_ST_IDLE:
- return;
-
case HSM_ST:
ata_pio_block(ap);
break;
@@ -3271,6 +3270,10 @@ fsm_start:
case HSM_ST_ERR:
ata_pio_error(ap);
return;
+
+ default:
+ BUG();
+ return;
}
if (timeout)
^ permalink raw reply [flat|nested] 6+ messages in thread* [PATCH/RFC 2/4] irq-pio: merge the ata_dataout_task workqueue with ata_pio_task workqueue
2005-11-01 11:12 [PATCH/RFC 0/4] libata: more irq driven pio follow-up patches Albert Lee
2005-11-01 11:19 ` [PATCH/RFC 1/4] irq-pio: misc fixes Albert Lee
@ 2005-11-01 11:24 ` Albert Lee
2005-11-01 11:30 ` [PATCH/RFC 3/4] irq-pio: eliminate unnecessary queuing in ata_pio_first_block() Albert Lee
2005-11-01 11:33 ` [PATCH/RFC 4/4] irq-pio: add read/write multiple support Albert Lee
3 siblings, 0 replies; 6+ messages in thread
From: Albert Lee @ 2005-11-01 11:24 UTC (permalink / raw)
To: Jeff Garzik; +Cc: Doug Maxey, Bartlomiej Zolnierkiewicz, Mark Lord, Linux IDE
Patch 2/4:
merge the ata_dataout_task workqueue with ata_pio_task workqueue
Changes:
- remove ap->dataout_task from struct ata_port
- let ata_pio_task() handle the HSM_ST_FIRST state.
- rename ata_dataout_task() to ata_pio_first_block()
- replace the ata_dataout_task workqueue with ata_pio_task workqueue
For your review, thanks.
Albert
Signed-off-by: Albert Lee <albertcc@tw.ibm.com>
========
--- id1/include/linux/libata.h 2005-11-01 17:39:14.000000000 +0800
+++ id2/include/linux/libata.h 2005-11-01 17:57:00.000000000 +0800
@@ -334,8 +334,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;
--- id1/drivers/scsi/libata-core.c 2005-11-01 18:45:16.000000000 +0800
+++ id2/drivers/scsi/libata-core.c 2005-11-01 18:45:35.000000000 +0800
@@ -2963,8 +2963,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
@@ -2977,9 +2977,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;
@@ -3253,6 +3252,10 @@ fsm_start:
qc_completed = 0;
switch (ap->hsm_task_state) {
+ case HSM_ST_FIRST:
+ ata_pio_first_block(ap);
+ return;
+
case HSM_ST:
ata_pio_block(ap);
break;
@@ -3703,10 +3706,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 */
@@ -3733,7 +3736,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:
@@ -3745,7 +3748,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:
@@ -4325,7 +4328,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] 6+ messages in thread* [PATCH/RFC 3/4] irq-pio: eliminate unnecessary queuing in ata_pio_first_block()
2005-11-01 11:12 [PATCH/RFC 0/4] libata: more irq driven pio follow-up patches Albert Lee
2005-11-01 11:19 ` [PATCH/RFC 1/4] irq-pio: misc fixes Albert Lee
2005-11-01 11:24 ` [PATCH/RFC 2/4] irq-pio: merge the ata_dataout_task workqueue with ata_pio_task workqueue Albert Lee
@ 2005-11-01 11:30 ` Albert Lee
2005-11-01 11:33 ` [PATCH/RFC 4/4] irq-pio: add read/write multiple support Albert Lee
3 siblings, 0 replies; 6+ messages in thread
From: Albert Lee @ 2005-11-01 11:30 UTC (permalink / raw)
To: Jeff Garzik; +Cc: Doug Maxey, Bartlomiej Zolnierkiewicz, Mark Lord, Linux IDE
patch 3/4:
eliminate unnecessary queuing in ata_pio_first_block()
Changes:
- change the return value of ata_pio_complete() 0 <-> 1
- add return value for ata_pio_first_block()
- rename variable "qc_completed" to "has_next" in ata_pio_task()
- use has_next to eliminate unnecessary queuing in ata_pio_first_block()
For your review, thanks.
Albert
Signed-off-by: Albert Lee <albertcc@tw.ibm.com>
==========
--- id2/drivers/scsi/libata-core.c 2005-11-01 18:45:35.000000000 +0800
+++ id3/drivers/scsi/libata-core.c 2005-11-01 18:45:50.000000000 +0800
@@ -2697,7 +2697,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)
@@ -2719,14 +2720,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);
@@ -2738,7 +2739,7 @@ static int ata_pio_complete (struct ata_
/* another command may start at this point */
- return 1;
+ return 0;
}
@@ -2975,27 +2976,42 @@ 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);
+ /* if polling, we will stay in the work queue after sending the data.
+ * otherwise, interrupt handler takes over after sending the data.
+ */
+ 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
@@ -3019,18 +3035,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; /* has next */
}
/**
@@ -3245,23 +3258,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:
@@ -3281,7 +3294,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] 6+ messages in thread* [PATCH/RFC 4/4] irq-pio: add read/write multiple support
2005-11-01 11:12 [PATCH/RFC 0/4] libata: more irq driven pio follow-up patches Albert Lee
` (2 preceding siblings ...)
2005-11-01 11:30 ` [PATCH/RFC 3/4] irq-pio: eliminate unnecessary queuing in ata_pio_first_block() Albert Lee
@ 2005-11-01 11:33 ` Albert Lee
3 siblings, 0 replies; 6+ messages in thread
From: Albert Lee @ 2005-11-01 11:33 UTC (permalink / raw)
To: Jeff Garzik; +Cc: Doug Maxey, Bartlomiej Zolnierkiewicz, Mark Lord, Linux IDE
patch 4/4:
add read/write multiple support
Changes:
- add is_multi_taskfile() to ata.h
- initialize ata_device->multi_count with device identify data
- use ata_pio_sectors() to support r/w multiple commands
For your review, thanks.
Albert
Signed-off-by: Albert Lee <albertcc@tw.ibm.com>
========
--- linux-ori/include/linux/ata.h 2005-11-01 17:22:45.000000000 +0800
+++ id4/include/linux/ata.h 2005-11-01 18:27:08.000000000 +0800
@@ -293,6 +293,14 @@ static inline int is_atapi_taskfile(cons
(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))
--- id3/drivers/scsi/libata-core.c 2005-11-01 18:45:50.000000000 +0800
+++ id4/drivers/scsi/libata-core.c 2005-11-01 18:36:08.000000000 +0800
@@ -1261,6 +1261,12 @@ retry:
}
+ 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;
}
@@ -2711,7 +2717,7 @@ 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)) {
@@ -2928,6 +2934,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
@@ -3025,11 +3057,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 */
@@ -3234,7 +3266,7 @@ static void ata_pio_block(struct ata_por
return;
}
- ata_pio_sector(qc);
+ ata_pio_sectors(qc);
}
ata_altstatus(ap); /* flush */
@@ -4120,7 +4152,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] 6+ messages in thread