ahci: FUA (force-write) support

This commit is contained in:
David van Moolenbroek 2011-11-23 15:35:07 +01:00
parent b4d909d415
commit 9874865a6f
2 changed files with 22 additions and 8 deletions

View 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) if (buf[ATA_ID_SUP0] & ATA_ID_SUP0_WCACHE)
ps->flags |= FLAG_HAS_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; return TRUE;
} }
@ -548,11 +553,12 @@ PRIVATE int ata_id_check(struct port_state *ps, u16_t *buf)
* ata_transfer * * ata_transfer *
*===========================================================================*/ *===========================================================================*/
PRIVATE int ata_transfer(struct port_state *ps, int cmd, u64_t start_lba, 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. /* Perform data transfer from or to an ATA device.
*/ */
cmd_fis_t fis; cmd_fis_t fis;
u8_t opcode;
assert(count <= ATA_MAX_SECTORS); 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; count = 0;
/* Fill in a transfer command. */ /* 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)); 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_lba = ex64lo(start_lba) & 0x00FFFFFFL;
fis.cf_dev = ATA_DEV_LBA; fis.cf_dev = ATA_DEV_LBA;
fis.cf_lba_exp = ex64lo(rshift64(start_lba, 24)) & 0x00FFFFFFL; 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 * * port_transfer *
*===========================================================================*/ *===========================================================================*/
PRIVATE ssize_t port_transfer(struct port_state *ps, int cmd, u64_t pos, 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. /* 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, r = atapi_transfer(ps, cmd, start_lba, count, write, prdt,
nr_prds); nr_prds);
else else
r = ata_transfer(ps, cmd, start_lba, count, write, prdt, r = ata_transfer(ps, cmd, start_lba, count, write,
nr_prds); !!(flags & BDEV_FORCEWRITE), prdt, nr_prds);
if (r != OK) return r; if (r != OK) return r;
@ -2343,8 +2355,7 @@ PRIVATE int ahci_close(dev_t minor)
* ahci_transfer * * ahci_transfer *
*===========================================================================*/ *===========================================================================*/
PRIVATE ssize_t ahci_transfer(dev_t minor, int do_write, u64_t position, PRIVATE ssize_t ahci_transfer(dev_t minor, int do_write, u64_t position,
endpoint_t endpt, iovec_t *iovec, unsigned int count, endpoint_t endpt, iovec_t *iovec, unsigned int count, int flags)
int UNUSED(flags))
{ {
/* Perform data transfer on the selected device. /* 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); eof = add64(dv->dv_base, dv->dv_size);
return port_transfer(ps, 0, pos, eof, endpt, (iovec_s_t *) iovec, return port_transfer(ps, 0, pos, eof, endpt, (iovec_s_t *) iovec,
count, do_write); count, do_write, flags);
} }
/*===========================================================================* /*===========================================================================*

View File

@ -30,6 +30,7 @@
#define ATA_H2D_CMD 2 /* Command */ #define ATA_H2D_CMD 2 /* Command */
#define ATA_CMD_READ_DMA_EXT 0x25 /* READ DMA EXT */ #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_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_PACKET 0xA0 /* PACKET */
#define ATA_CMD_IDENTIFY_PACKET 0xA1 /* IDENTIFY PACKET DEVICE */ #define ATA_CMD_IDENTIFY_PACKET 0xA1 /* IDENTIFY PACKET DEVICE */
#define ATA_CMD_FLUSH_CACHE 0xE7 /* FLUSH CACHE */ #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 87 /* Features enabled (3/3) */
#define ATA_ID_ENA2_VALID_MASK 0xC000 /* Word validity mask */ #define ATA_ID_ENA2_VALID_MASK 0xC000 /* Word validity mask */
#define ATA_ID_ENA2_VALID 0x4000 /* Word contents are valid */ #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_LBA0 100 /* Max. LBA48 address (LSW) */
#define ATA_ID_LBA1 101 /* Max. LBA48 address */ #define ATA_ID_LBA1 101 /* Max. LBA48 address */
#define ATA_ID_LBA2 102 /* 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_WCACHE 0x00000080 /* is a write cache present? */
#define FLAG_HAS_FLUSH 0x00000100 /* is FLUSH CACHE supported? */ #define FLAG_HAS_FLUSH 0x00000100 /* is FLUSH CACHE supported? */
#define FLAG_SUSPENDED 0x00000200 /* is the thread suspended? */ #define FLAG_SUSPENDED 0x00000200 /* is the thread suspended? */
#define FLAG_HAS_FUA 0x00000400 /* is WRITE DMA FUA EX sup.? */
/* Mapping between devices and ports. */ /* Mapping between devices and ports. */
#define NO_PORT -1 /* this device maps to no port */ #define NO_PORT -1 /* this device maps to no port */