07_blk_libata-add-fua-support.patch

        Add FUA support to libata.

Signed-off-by: Tejun Heo <[EMAIL PROTECTED]>

 drivers/scsi/libata-core.c |   14 +++++++++-----
 drivers/scsi/libata-scsi.c |   26 ++++++++++++++++++++++++--
 include/linux/ata.h        |    4 +++-
 include/linux/libata.h     |    1 +
 4 files changed, 37 insertions(+), 8 deletions(-)

Index: blk-fixes/drivers/scsi/libata-core.c
===================================================================
--- blk-fixes.orig/drivers/scsi/libata-core.c   2005-07-27 00:44:48.000000000 
+0900
+++ blk-fixes/drivers/scsi/libata-core.c        2005-07-27 00:44:52.000000000 
+0900
@@ -602,19 +602,21 @@ void ata_tf_from_fis(u8 *fis, struct ata
 }
 
 /**
- *     ata_prot_to_cmd - determine which read/write opcodes to use
+ *     ata_prot_to_cmd - determine which read/write/fua-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.
+ *     Given necessary input, determine which read/write/fua-write
+ *     commands to use to transfer data.  Note that we only support
+ *     fua-writes on DMA LBA48 protocol.  In other cases, we simply
+ *     return 0 which is NOP.
  *
  *     LOCKING:
  *     None.
  */
 static int ata_prot_to_cmd(int protocol, int lba48)
 {
-       int rcmd = 0, wcmd = 0;
+       int rcmd = 0, wcmd = 0, wfua = 0;
 
        switch (protocol) {
        case ATA_PROT_PIO:
@@ -631,6 +633,7 @@ static int ata_prot_to_cmd(int protocol,
                if (lba48) {
                        rcmd = ATA_CMD_READ_EXT;
                        wcmd = ATA_CMD_WRITE_EXT;
+                       wfua = ATA_CMD_WRITE_FUA_EXT;
                } else {
                        rcmd = ATA_CMD_READ;
                        wcmd = ATA_CMD_WRITE;
@@ -641,7 +644,7 @@ static int ata_prot_to_cmd(int protocol,
                return -1;
        }
 
-       return rcmd | (wcmd << 8);
+       return rcmd | (wcmd << 8) | (wfua << 16);
 }
 
 /**
@@ -674,6 +677,7 @@ static void ata_dev_set_protocol(struct 
 
        dev->read_cmd = cmd & 0xff;
        dev->write_cmd = (cmd >> 8) & 0xff;
+       dev->write_fua_cmd = (cmd >> 16) & 0xff;
 }
 
 static const char * xfer_mode_str[] = {
Index: blk-fixes/include/linux/ata.h
===================================================================
--- blk-fixes.orig/include/linux/ata.h  2005-07-27 00:44:48.000000000 +0900
+++ blk-fixes/include/linux/ata.h       2005-07-27 00:44:52.000000000 +0900
@@ -117,6 +117,7 @@ enum {
        ATA_CMD_READ_EXT        = 0x25,
        ATA_CMD_WRITE           = 0xCA,
        ATA_CMD_WRITE_EXT       = 0x35,
+       ATA_CMD_WRITE_FUA_EXT   = 0x3D,
        ATA_CMD_PIO_READ        = 0x20,
        ATA_CMD_PIO_READ_EXT    = 0x24,
        ATA_CMD_PIO_WRITE       = 0x30,
@@ -227,7 +228,8 @@ struct ata_taskfile {
 #define ata_id_is_sata(id)     ((id)[93] == 0)
 #define ata_id_rahead_enabled(id) ((id)[85] & (1 << 6))
 #define ata_id_wcache_enabled(id) ((id)[85] & (1 << 5))
-#define ata_id_has_flush(id) ((id)[83] & (1 << 12))
+#define ata_id_has_fua(id)     ((id)[84] & (1 << 6))
+#define ata_id_has_flush(id)   ((id)[83] & (1 << 12))
 #define ata_id_has_flush_ext(id) ((id)[83] & (1 << 13))
 #define ata_id_has_lba48(id)   ((id)[83] & (1 << 10))
 #define ata_id_has_wcache(id)  ((id)[82] & (1 << 5))
Index: blk-fixes/include/linux/libata.h
===================================================================
--- blk-fixes.orig/include/linux/libata.h       2005-07-27 00:44:48.000000000 
+0900
+++ blk-fixes/include/linux/libata.h    2005-07-27 00:44:52.000000000 +0900
@@ -278,6 +278,7 @@ 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 */
+       u8                      write_fua_cmd;  /* opcode to use on FUA write */
 };
 
 struct ata_port {
Index: blk-fixes/drivers/scsi/libata-scsi.c
===================================================================
--- blk-fixes.orig/drivers/scsi/libata-scsi.c   2005-07-27 00:44:48.000000000 
+0900
+++ blk-fixes/drivers/scsi/libata-scsi.c        2005-07-27 00:44:52.000000000 
+0900
@@ -537,6 +537,7 @@ static unsigned int ata_scsi_rw_xlat(str
 {
        struct ata_taskfile *tf = &qc->tf;
        unsigned int lba48 = tf->flags & ATA_TFLAG_LBA48;
+       int fua = scsicmd[1] & (1 << 3);
 
        tf->flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
        tf->protocol = qc->dev->xfer_protocol;
@@ -544,9 +545,28 @@ static unsigned int ata_scsi_rw_xlat(str
 
        if (scsicmd[0] == READ_10 || scsicmd[0] == READ_6 ||
            scsicmd[0] == READ_16) {
-               tf->command = qc->dev->read_cmd;
+               if (!fua) {
+                       tf->command = qc->dev->read_cmd;
+               } else {
+                       printk(KERN_WARNING
+                              "ata%u(%u): WARNING: FUA READ unsupported\n",
+                              qc->ap->id, qc->dev->devno);
+                       return 1;
+               }
        } else {
-               tf->command = qc->dev->write_cmd;
+               if (!fua) {
+                       tf->command = qc->dev->write_cmd;
+               } else {
+                       if (qc->dev->write_fua_cmd == 0 || !lba48) {
+                               printk(KERN_WARNING
+                                      "ata%u(%u): WARNING: FUA WRITE "
+                                      "unsupported with the current "
+                                      "protocol/addressing\n",
+                                      qc->ap->id, qc->dev->devno);
+                               return 1;
+                       }
+                       tf->command = qc->dev->write_fua_cmd;
+               }
                tf->flags |= ATA_TFLAG_WRITE;
        }
 
@@ -1141,10 +1161,12 @@ unsigned int ata_scsiop_mode_sense(struc
        if (six_byte) {
                output_len--;
                rbuf[0] = output_len;
+               rbuf[2] |= ata_id_has_fua(args->id) ? 1 << 4 : 0;
        } else {
                output_len -= 2;
                rbuf[0] = output_len >> 8;
                rbuf[1] = output_len;
+               rbuf[3] |= ata_id_has_fua(args->id) ? 1 << 4 : 0;
        }
 
        return 0;

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to