]> Zhao Yanbai Git Server - minix.git/commitdiff
ahci: FUA (force-write) support
authorDavid van Moolenbroek <david@minix3.org>
Wed, 23 Nov 2011 14:35:07 +0000 (15:35 +0100)
committerDavid van Moolenbroek <david@minix3.org>
Wed, 23 Nov 2011 14:40:38 +0000 (15:40 +0100)
drivers/ahci/ahci.c
drivers/ahci/ahci.h

index 675d95e80c2ecfd68f0ed9d83f1aef4ac6b526de..2cc2d231027b2815f27b9ebeb2d68118a5b4530c 100644 (file)
@@ -541,6 +541,11 @@ PRIVATE int ata_id_check(struct port_state *ps, u16_t *buf)
        if (buf[ATA_ID_SUP0] & ATA_ID_SUP0_WCACHE)
                ps->flags |= FLAG_HAS_WCACHE;
 
+       /* Check Force Unit Access capability of the device. */
+       if ((buf[ATA_ID_ENA2] & (ATA_ID_ENA2_VALID_MASK | ATA_ID_ENA2_FUA)) ==
+               (ATA_ID_ENA2_VALID | ATA_ID_ENA2_FUA))
+               ps->flags |= FLAG_HAS_FUA;
+
        return TRUE;
 }
 
@@ -548,11 +553,12 @@ PRIVATE int ata_id_check(struct port_state *ps, u16_t *buf)
  *                             ata_transfer                                 *
  *===========================================================================*/
 PRIVATE int ata_transfer(struct port_state *ps, int cmd, u64_t start_lba,
-       unsigned int count, int write, prd_t *prdt, int nr_prds)
+       unsigned int count, int write, int force, prd_t *prdt, int nr_prds)
 {
        /* Perform data transfer from or to an ATA device.
         */
        cmd_fis_t fis;
+       u8_t opcode;
 
        assert(count <= ATA_MAX_SECTORS);
 
@@ -561,8 +567,13 @@ PRIVATE int ata_transfer(struct port_state *ps, int cmd, u64_t start_lba,
                count = 0;
 
        /* Fill in a transfer command. */
+       if (write && force && (ps->flags & FLAG_HAS_FUA))
+               opcode = ATA_CMD_WRITE_DMA_FUA_EXT;
+       else
+               opcode = write ? ATA_CMD_WRITE_DMA_EXT : ATA_CMD_READ_DMA_EXT;
+
        memset(&fis, 0, sizeof(fis));
-       fis.cf_cmd = write ? ATA_CMD_WRITE_DMA_EXT : ATA_CMD_READ_DMA_EXT;
+       fis.cf_cmd = opcode;
        fis.cf_lba = ex64lo(start_lba) & 0x00FFFFFFL;
        fis.cf_dev = ATA_DEV_LBA;
        fis.cf_lba_exp = ex64lo(rshift64(start_lba, 24)) & 0x00FFFFFFL;
@@ -945,7 +956,8 @@ PRIVATE int setup_prdt(struct port_state *ps, endpoint_t endpt,
  *                             port_transfer                                *
  *===========================================================================*/
 PRIVATE ssize_t port_transfer(struct port_state *ps, int cmd, u64_t pos,
-       u64_t eof, endpoint_t endpt, iovec_s_t *iovec, int nr_req, int write)
+       u64_t eof, endpoint_t endpt, iovec_s_t *iovec, int nr_req, int write,
+       int flags)
 {
        /* Perform an I/O transfer on a port.
         */
@@ -1012,8 +1024,8 @@ PRIVATE ssize_t port_transfer(struct port_state *ps, int cmd, u64_t pos,
                r = atapi_transfer(ps, cmd, start_lba, count, write, prdt,
                        nr_prds);
        else
-               r = ata_transfer(ps, cmd, start_lba, count, write, prdt,
-                       nr_prds);
+               r = ata_transfer(ps, cmd, start_lba, count, write,
+                       !!(flags & BDEV_FORCEWRITE), prdt, nr_prds);
 
        if (r != OK) return r;
 
@@ -2343,8 +2355,7 @@ PRIVATE int ahci_close(dev_t minor)
  *                             ahci_transfer                                *
  *===========================================================================*/
 PRIVATE ssize_t ahci_transfer(dev_t minor, int do_write, u64_t position,
-       endpoint_t endpt, iovec_t *iovec, unsigned int count,
-       int UNUSED(flags))
+       endpoint_t endpt, iovec_t *iovec, unsigned int count, int flags)
 {
        /* Perform data transfer on the selected device.
         */
@@ -2372,7 +2383,7 @@ PRIVATE ssize_t ahci_transfer(dev_t minor, int do_write, u64_t position,
        eof = add64(dv->dv_base, dv->dv_size);
 
        return port_transfer(ps, 0, pos, eof, endpt, (iovec_s_t *) iovec,
-               count, do_write);
+               count, do_write, flags);
 }
 
 /*===========================================================================*
index 863da3a2701093dc1a657f2009dcb8c590dd7b2d..aa662d1624d4a1b707f3b6fd30428293899ade0c 100644 (file)
@@ -30,6 +30,7 @@
 #define ATA_H2D_CMD                    2       /* Command */
 #define        ATA_CMD_READ_DMA_EXT    0x25    /* READ DMA EXT */
 #define        ATA_CMD_WRITE_DMA_EXT   0x35    /* WRITE DMA EXT */
+#define        ATA_CMD_WRITE_DMA_FUA_EXT       0x3D    /* WRITE DMA FUA EXT */
 #define        ATA_CMD_PACKET          0xA0    /* PACKET */
 #define        ATA_CMD_IDENTIFY_PACKET 0xA1    /* IDENTIFY PACKET DEVICE */
 #define        ATA_CMD_FLUSH_CACHE     0xE7    /* FLUSH CACHE */
@@ -84,6 +85,7 @@
 #define ATA_ID_ENA2            87              /* Features enabled (3/3) */
 #define ATA_ID_ENA2_VALID_MASK 0xC000          /* Word validity mask */
 #define ATA_ID_ENA2_VALID      0x4000          /* Word contents are valid */
+#define ATA_ID_ENA2_FUA                0x0040          /* Forced Unit Access sup. */
 #define ATA_ID_LBA0            100             /* Max. LBA48 address (LSW) */
 #define ATA_ID_LBA1            101             /* Max. LBA48 address */
 #define ATA_ID_LBA2            102             /* Max. LBA48 address */
@@ -271,6 +273,7 @@ enum {
 #define FLAG_HAS_WCACHE                0x00000080      /* is a write cache present? */
 #define FLAG_HAS_FLUSH         0x00000100      /* is FLUSH CACHE supported? */
 #define FLAG_SUSPENDED         0x00000200      /* is the thread suspended? */
+#define FLAG_HAS_FUA           0x00000400      /* is WRITE DMA FUA EX sup.? */
 
 /* Mapping between devices and ports. */
 #define NO_PORT                -1      /* this device maps to no port */