[PATCH] libata: separate out rw ATA taskfile building into ata_build_rw_tf()
authorTejun Heo <htejun@gmail.com>
Tue, 14 Nov 2006 13:47:10 +0000 (22:47 +0900)
committerTejun Heo <htejun@gmail.com>
Sun, 3 Dec 2006 08:56:24 +0000 (17:56 +0900)
Separate out rw ATA taskfile building from ata_scsi_rw_xlat() into
ata_build_rw_tf().  This will be used to improve media error handling.

Signed-off-by: Tejun Heo <htejun@gmail.com>
drivers/ata/libata-core.c
drivers/ata/libata-scsi.c
drivers/ata/libata.h

index 0a5103b707c686f33eb2f15c2fb8129a6fcdd5ff..4ac53ef0e4b0d89e3c473deff6b9300d819b37fc 100644 (file)
@@ -199,7 +199,8 @@ static const u8 ata_rw_cmds[] = {
 
 /**
  *     ata_rwcmd_protocol - set taskfile r/w commands and protocol
- *     @qc: command to examine and configure
+ *     @tf: command to examine and configure
+ *     @dev: device tf belongs to
  *
  *     Examine the device configuration and tf->flags to calculate
  *     the proper read/write commands and protocol to use.
@@ -207,10 +208,8 @@ static const u8 ata_rw_cmds[] = {
  *     LOCKING:
  *     caller.
  */
-int ata_rwcmd_protocol(struct ata_queued_cmd *qc)
+static int ata_rwcmd_protocol(struct ata_taskfile *tf, struct ata_device *dev)
 {
-       struct ata_taskfile *tf = &qc->tf;
-       struct ata_device *dev = qc->dev;
        u8 cmd;
 
        int index, fua, lba48, write;
@@ -222,7 +221,7 @@ int ata_rwcmd_protocol(struct ata_queued_cmd *qc)
        if (dev->flags & ATA_DFLAG_PIO) {
                tf->protocol = ATA_PROT_PIO;
                index = dev->multi_count ? 0 : 8;
-       } else if (lba48 && (qc->ap->flags & ATA_FLAG_PIO_LBA48)) {
+       } else if (lba48 && (dev->ap->flags & ATA_FLAG_PIO_LBA48)) {
                /* Unable to use DMA due to host limitation */
                tf->protocol = ATA_PROT_PIO;
                index = dev->multi_count ? 0 : 8;
@@ -282,6 +281,130 @@ u64 ata_tf_read_block(struct ata_taskfile *tf, struct ata_device *dev)
        return block;
 }
 
+/**
+ *     ata_build_rw_tf - Build ATA taskfile for given read/write request
+ *     @tf: Target ATA taskfile
+ *     @dev: ATA device @tf belongs to
+ *     @block: Block address
+ *     @n_block: Number of blocks
+ *     @tf_flags: RW/FUA etc...
+ *     @tag: tag
+ *
+ *     LOCKING:
+ *     None.
+ *
+ *     Build ATA taskfile @tf for read/write request described by
+ *     @block, @n_block, @tf_flags and @tag on @dev.
+ *
+ *     RETURNS:
+ *
+ *     0 on success, -ERANGE if the request is too large for @dev,
+ *     -EINVAL if the request is invalid.
+ */
+int ata_build_rw_tf(struct ata_taskfile *tf, struct ata_device *dev,
+                   u64 block, u32 n_block, unsigned int tf_flags,
+                   unsigned int tag)
+{
+       tf->flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
+       tf->flags |= tf_flags;
+
+       if ((dev->flags & (ATA_DFLAG_PIO | ATA_DFLAG_NCQ_OFF |
+                          ATA_DFLAG_NCQ)) == ATA_DFLAG_NCQ) {
+               /* yay, NCQ */
+               if (!lba_48_ok(block, n_block))
+                       return -ERANGE;
+
+               tf->protocol = ATA_PROT_NCQ;
+               tf->flags |= ATA_TFLAG_LBA | ATA_TFLAG_LBA48;
+
+               if (tf->flags & ATA_TFLAG_WRITE)
+                       tf->command = ATA_CMD_FPDMA_WRITE;
+               else
+                       tf->command = ATA_CMD_FPDMA_READ;
+
+               tf->nsect = tag << 3;
+               tf->hob_feature = (n_block >> 8) & 0xff;
+               tf->feature = n_block & 0xff;
+
+               tf->hob_lbah = (block >> 40) & 0xff;
+               tf->hob_lbam = (block >> 32) & 0xff;
+               tf->hob_lbal = (block >> 24) & 0xff;
+               tf->lbah = (block >> 16) & 0xff;
+               tf->lbam = (block >> 8) & 0xff;
+               tf->lbal = block & 0xff;
+
+               tf->device = 1 << 6;
+               if (tf->flags & ATA_TFLAG_FUA)
+                       tf->device |= 1 << 7;
+       } else if (dev->flags & ATA_DFLAG_LBA) {
+               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 -ERANGE;
+
+                       /* 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
+                       /* request too large even for LBA48 */
+                       return -ERANGE;
+
+               if (unlikely(ata_rwcmd_protocol(tf, dev) < 0))
+                       return -EINVAL;
+
+               tf->nsect = n_block & 0xff;
+
+               tf->lbah = (block >> 16) & 0xff;
+               tf->lbam = (block >> 8) & 0xff;
+               tf->lbal = block & 0xff;
+
+               tf->device |= ATA_LBA;
+       } else {
+               /* CHS */
+               u32 sect, head, cyl, track;
+
+               /* The request -may- be too large for CHS addressing. */
+               if (!lba_28_ok(block, n_block))
+                       return -ERANGE;
+
+               if (unlikely(ata_rwcmd_protocol(tf, dev) < 0))
+                       return -EINVAL;
+
+               /* 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",
+                       (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))
+                       return -ERANGE;
+
+               tf->nsect = n_block & 0xff; /* Sector count 0 means 256 sectors */
+               tf->lbal = sect;
+               tf->lbam = cyl;
+               tf->lbah = cyl >> 8;
+               tf->device |= head;
+       }
+
+       return 0;
+}
+
 /**
  *     ata_pack_xfermask - Pack pio, mwdma and udma masks into xfer_mask
  *     @pio_mask: pio_mask
index d250858d201c995ff76e5abbc15da73cfcb2560f..8eaace94d9631e9e2b64fdc3443ca26d0d41bf66 100644 (file)
@@ -1265,17 +1265,14 @@ nothing_to_do:
 
 static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc, const u8 *scsicmd)
 {
-       struct ata_taskfile *tf = &qc->tf;
-       struct ata_device *dev = qc->dev;
+       unsigned int tf_flags = 0;
        u64 block;
        u32 n_block;
-
-       qc->flags |= ATA_QCFLAG_IO;
-       tf->flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
+       int rc;
 
        if (scsicmd[0] == WRITE_10 || scsicmd[0] == WRITE_6 ||
            scsicmd[0] == WRITE_16)
-               tf->flags |= ATA_TFLAG_WRITE;
+               tf_flags |= ATA_TFLAG_WRITE;
 
        /* Calculate the SCSI LBA, transfer length and FUA. */
        switch (scsicmd[0]) {
@@ -1283,7 +1280,7 @@ static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc, const u8 *scsicm
        case WRITE_10:
                scsi_10_lba_len(scsicmd, &block, &n_block);
                if (unlikely(scsicmd[1] & (1 << 3)))
-                       tf->flags |= ATA_TFLAG_FUA;
+                       tf_flags |= ATA_TFLAG_FUA;
                break;
        case READ_6:
        case WRITE_6:
@@ -1299,7 +1296,7 @@ static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc, const u8 *scsicm
        case WRITE_16:
                scsi_16_lba_len(scsicmd, &block, &n_block);
                if (unlikely(scsicmd[1] & (1 << 3)))
-                       tf->flags |= ATA_TFLAG_FUA;
+                       tf_flags |= ATA_TFLAG_FUA;
                break;
        default:
                DPRINTK("no-byte command\n");
@@ -1317,106 +1314,17 @@ static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc, const u8 *scsicm
                 */
                goto nothing_to_do;
 
-       if ((dev->flags & (ATA_DFLAG_PIO | ATA_DFLAG_NCQ_OFF |
-                          ATA_DFLAG_NCQ)) == ATA_DFLAG_NCQ) {
-               /* yay, NCQ */
-               if (!lba_48_ok(block, n_block))
-                       goto out_of_range;
-
-               tf->protocol = ATA_PROT_NCQ;
-               tf->flags |= ATA_TFLAG_LBA | ATA_TFLAG_LBA48;
-
-               if (tf->flags & ATA_TFLAG_WRITE)
-                       tf->command = ATA_CMD_FPDMA_WRITE;
-               else
-                       tf->command = ATA_CMD_FPDMA_READ;
-
-               qc->nsect = n_block;
-
-               tf->nsect = qc->tag << 3;
-               tf->hob_feature = (n_block >> 8) & 0xff;
-               tf->feature = n_block & 0xff;
-
-               tf->hob_lbah = (block >> 40) & 0xff;
-               tf->hob_lbam = (block >> 32) & 0xff;
-               tf->hob_lbal = (block >> 24) & 0xff;
-               tf->lbah = (block >> 16) & 0xff;
-               tf->lbam = (block >> 8) & 0xff;
-               tf->lbal = block & 0xff;
-
-               tf->device = 1 << 6;
-               if (tf->flags & ATA_TFLAG_FUA)
-                       tf->device |= 1 << 7;
-       } else if (dev->flags & ATA_DFLAG_LBA) {
-               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))
-                               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
-                       /* request too large even for LBA48 */
-                       goto out_of_range;
-
-               if (unlikely(ata_rwcmd_protocol(qc) < 0))
-                       goto invalid_fld;
-
-               qc->nsect = n_block;
-               tf->nsect = n_block & 0xff;
-
-               tf->lbah = (block >> 16) & 0xff;
-               tf->lbam = (block >> 8) & 0xff;
-               tf->lbal = block & 0xff;
-
-               tf->device |= ATA_LBA;
-       } else {
-               /* CHS */
-               u32 sect, head, cyl, track;
-
-               /* The request -may- be too large for CHS addressing. */
-               if (!lba_28_ok(block, n_block))
-                       goto out_of_range;
-
-               if (unlikely(ata_rwcmd_protocol(qc) < 0))
-                       goto invalid_fld;
-
-               /* 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",
-                       (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))
-                       goto out_of_range;
-
-               qc->nsect = n_block;
-               tf->nsect = n_block & 0xff; /* Sector count 0 means 256 sectors */
-               tf->lbal = sect;
-               tf->lbam = cyl;
-               tf->lbah = cyl >> 8;
-               tf->device |= head;
-       }
+       qc->flags |= ATA_QCFLAG_IO;
+       qc->nsect = n_block;
 
-       return 0;
+       rc = ata_build_rw_tf(&qc->tf, qc->dev, block, n_block, tf_flags,
+                            qc->tag);
+       if (likely(rc == 0))
+               return 0;
 
+       if (rc == -ERANGE)
+               goto out_of_range;
+       /* treat all other errors as -EINVAL, fall through */
 invalid_fld:
        ata_scsi_set_sense(qc->scsicmd, ILLEGAL_REQUEST, 0x24, 0x0);
        /* "Invalid field in cbd" */
index ca6f36c13115e757024143668a327e00b2454d4a..60576b1237e4cbe9d6b51161e64c2161649b4116 100644 (file)
@@ -51,7 +51,9 @@ extern int atapi_enabled;
 extern int atapi_dmadir;
 extern int libata_fua;
 extern struct ata_queued_cmd *ata_qc_new_init(struct ata_device *dev);
-extern int ata_rwcmd_protocol(struct ata_queued_cmd *qc);
+extern int ata_build_rw_tf(struct ata_taskfile *tf, struct ata_device *dev,
+                          u64 block, u32 n_block, unsigned int tf_flags,
+                          unsigned int tag);
 extern u64 ata_tf_read_block(struct ata_taskfile *tf, struct ata_device *dev);
 extern void ata_dev_disable(struct ata_device *dev);
 extern void ata_port_flush_task(struct ata_port *ap);