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;
}
* 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);
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;
* 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.
*/
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;
* 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.
*/
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);
}
/*===========================================================================*
#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 */
#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 */
#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 */