[PATCH] libata irq-pio: add read/write multiple support
authorAlbert Lee <albertcc@tw.ibm.com>
Tue, 1 Nov 2005 11:33:20 +0000 (19:33 +0800)
committerJeff Garzik <jgarzik@pobox.com>
Wed, 9 Nov 2005 06:22:19 +0000 (01:22 -0500)
   - 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

Signed-off-by: Albert Lee <albertcc@tw.ibm.com>
========
Signed-off-by: Jeff Garzik <jgarzik@pobox.com>
drivers/scsi/libata-core.c
include/linux/ata.h

index 2e0e6cca327c638b93c77a745b1bc002be9382ad..59a4a26bc13fdb495b8e138ab7c5813eeb270391 100644 (file)
@@ -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;
        }
 
@@ -2804,7 +2810,7 @@ static int ata_pio_complete (struct ata_port *ap)
         * 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)) {
@@ -3020,6 +3026,32 @@ static void ata_pio_sector(struct ata_queued_cmd *qc)
        }
 }
 
+/**
+ *     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.
@@ -3118,11 +3150,11 @@ static int ata_pio_first_block(struct ata_port *ap)
                 * 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 */
@@ -3327,7 +3359,7 @@ static void ata_pio_block(struct ata_port *ap)
                        return;
                }
 
-               ata_pio_sector(qc);
+               ata_pio_sectors(qc);
        }
 
        ata_altstatus(ap); /* flush */
@@ -4213,7 +4245,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))) {
index d54da3306d2c6fe2d614c9862dfae3019dd48e83..f512104a1a3f56c7b5694f618bfe23c0de351424 100644 (file)
@@ -293,6 +293,14 @@ static inline int is_atapi_taskfile(const struct ata_taskfile *tf)
               (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))