From 9874865a6f1ac3742f21faceb99069252637187e Mon Sep 17 00:00:00 2001 From: David van Moolenbroek Date: Wed, 23 Nov 2011 15:35:07 +0100 Subject: [PATCH] ahci: FUA (force-write) support --- drivers/ahci/ahci.c | 27 +++++++++++++++++++-------- drivers/ahci/ahci.h | 3 +++ 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/drivers/ahci/ahci.c b/drivers/ahci/ahci.c index 675d95e80..2cc2d2310 100644 --- a/drivers/ahci/ahci.c +++ b/drivers/ahci/ahci.c @@ -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); } /*===========================================================================* diff --git a/drivers/ahci/ahci.h b/drivers/ahci/ahci.h index 863da3a27..aa662d162 100644 --- a/drivers/ahci/ahci.h +++ b/drivers/ahci/ahci.h @@ -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 */ -- 2.44.0