* [PATCH/RFC 4/4] irq-pio: add read/write multiple support
2005-10-03 11:46 ` [PATCH/RFC 0/4] libata: more " Albert Lee
@ 2005-10-03 13:19 ` Albert Lee
2005-10-03 13:35 ` Mark Lord
2005-10-04 10:19 ` Jeff Garzik
0 siblings, 2 replies; 12+ 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] 12+ 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 ` Jeff Garzik
1 sibling, 1 reply; 12+ 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] 12+ 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; 12+ 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] 12+ 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; 12+ 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] 12+ 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; 12+ 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] 12+ 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
0 siblings, 0 replies; 12+ 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] 12+ messages in thread
* [PATCH/RFC 0/4] libata: more irq driven pio follow-up patches
@ 2005-11-01 11:12 Albert Lee
2005-11-01 11:19 ` [PATCH/RFC 1/4] irq-pio: misc fixes Albert Lee
` (3 more replies)
0 siblings, 4 replies; 12+ messages in thread
From: Albert Lee @ 2005-11-01 11:12 UTC (permalink / raw)
To: Jeff Garzik; +Cc: Doug Maxey, Bartlomiej Zolnierkiewicz, Mark Lord, Linux IDE
Dear all,
More irq driven PIO follow-up patches (revised).
Changes:
1. merge the ata_dataout_task workqueue with the ata_pio_task workqueue
2. add read/write multiple support
patch 1/4: misc fixes
- 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()
patch 2/4: merge the ata_dataout_task workqueue with the ata_pio_task workqueue
- 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()
patch 3/4: eliminate unnecessary queuing in ata_pio_first_block()
- change the return value of ata_pio_complete()
- add return value to ata_pio_first_block()
- rename the variable "qc_completed" to "has_next" in ata_pio_task()
- use "has_next" to eliminate unnecessary queuing in ata_pio_first_block()
patch 4/4: add read/write multiple support
- 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
Patch against the libata-dev irq-pio branch (cd8200e6d4f9f05e6ea48f7c000be890337396ac).
For your review and advice, thanks.
Albert
^ permalink raw reply [flat|nested] 12+ messages in thread
* [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; 12+ 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] 12+ 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; 12+ 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] 12+ 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; 12+ 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] 12+ 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; 12+ 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] 12+ messages in thread
* Re: [PATCH/RFC 1/4] irq-pio: misc fixes
2005-11-01 11:19 ` [PATCH/RFC 1/4] irq-pio: misc fixes Albert Lee
@ 2005-11-09 6:22 ` Jeff Garzik
0 siblings, 0 replies; 12+ messages in thread
From: Jeff Garzik @ 2005-11-09 6:22 UTC (permalink / raw)
To: Albert Lee; +Cc: Doug Maxey, Bartlomiej Zolnierkiewicz, Mark Lord, Linux IDE
applied 1-4
^ permalink raw reply [flat|nested] 12+ messages in thread
end of thread, other threads:[~2005-11-09 6:22 UTC | newest]
Thread overview: 12+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
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-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
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
-- strict thread matches above, loose matches on Subject: below --
2005-09-09 16:14 [PATCH RFC] libata: interrupt driven pio Albert Lee
2005-09-09 17:35 ` Jeff Garzik
2005-09-22 4:00 ` [PATCH/RFC 0/3] libata: interrupt driven pio (revised) 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
2005-09-27 9:38 ` [PATCH/RFC 3/4] libata: interrupt driven pio for libata-core Albert Lee
2005-09-29 10:08 ` Bartlomiej Zolnierkiewicz
2005-09-30 11:04 ` [PATCH/RFC 0/4] libata: irq driven pio follow-up patches Albert Lee
2005-09-30 11:21 ` Jeff Garzik
2005-10-03 11:46 ` [PATCH/RFC 0/4] libata: more " Albert Lee
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 10:19 ` Jeff Garzik
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).