diff options
author | John Snow <jsnow@redhat.com> | 2015-07-04 02:06:03 -0400 |
---|---|---|
committer | John Snow <jsnow@redhat.com> | 2015-07-04 02:06:03 -0400 |
commit | cb45304108ab733aaf2e4351e77cb6d07ac88fd5 (patch) | |
tree | c92694ce9acf13502ef694ee0c7c96925f902dc1 | |
parent | 40d29928caa6db154182f5314f497020f81e640e (diff) | |
download | qemu-cb45304108ab733aaf2e4351e77cb6d07ac88fd5.zip qemu-cb45304108ab733aaf2e4351e77cb6d07ac88fd5.tar.gz qemu-cb45304108ab733aaf2e4351e77cb6d07ac88fd5.tar.bz2 |
libqos/ahci: add NCQ frame support
NCQ frames are generated a little differently than
their non-NCQ cousins. Add support for them.
Signed-off-by: John Snow <jsnow@redhat.com>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Message-id: 1435016308-6150-11-git-send-email-jsnow@redhat.com
-rw-r--r-- | tests/libqos/ahci.c | 44 | ||||
-rw-r--r-- | tests/libqos/ahci.h | 29 |
2 files changed, 63 insertions, 10 deletions
diff --git a/tests/libqos/ahci.c b/tests/libqos/ahci.c index 922af8b..9a4d510 100644 --- a/tests/libqos/ahci.c +++ b/tests/libqos/ahci.c @@ -695,19 +695,34 @@ static void command_header_init(AHCICommand *cmd) static void command_table_init(AHCICommand *cmd) { RegH2DFIS *fis = &(cmd->fis); + uint16_t sect_count = (cmd->xbytes / AHCI_SECTOR_SIZE); fis->fis_type = REG_H2D_FIS; fis->flags = REG_H2D_FIS_CMD; /* "Command" bit */ fis->command = cmd->name; - cmd->fis.feature_low = 0x00; - cmd->fis.feature_high = 0x00; - if (cmd->props->lba28 || cmd->props->lba48) { - cmd->fis.device = ATA_DEVICE_LBA; + + if (cmd->props->ncq) { + NCQFIS *ncqfis = (NCQFIS *)fis; + /* NCQ is weird and re-uses FIS frames for unrelated data. + * See SATA 3.2, 13.6.4.1 READ FPDMA QUEUED for an example. */ + ncqfis->sector_low = sect_count & 0xFF; + ncqfis->sector_hi = (sect_count >> 8) & 0xFF; + ncqfis->device = NCQ_DEVICE_MAGIC; + /* Force Unit Access is bit 7 in the device register */ + ncqfis->tag = 0; /* bits 3-7 are the NCQ tag */ + ncqfis->prio = 0; /* bits 6,7 are a prio tag */ + /* RARC bit is bit 0 of TAG field */ + } else { + fis->feature_low = 0x00; + fis->feature_high = 0x00; + if (cmd->props->lba28 || cmd->props->lba48) { + fis->device = ATA_DEVICE_LBA; + } + fis->count = (cmd->xbytes / AHCI_SECTOR_SIZE); } - cmd->fis.count = (cmd->xbytes / AHCI_SECTOR_SIZE); - cmd->fis.icc = 0x00; - cmd->fis.control = 0x00; - memset(cmd->fis.aux, 0x00, ARRAY_SIZE(cmd->fis.aux)); + fis->icc = 0x00; + fis->control = 0x00; + memset(fis->aux, 0x00, ARRAY_SIZE(fis->aux)); } AHCICommand *ahci_command_create(uint8_t command_name) @@ -721,6 +736,7 @@ AHCICommand *ahci_command_create(uint8_t command_name) g_assert(!(props->lba28 && props->lba48)); g_assert(!(props->read && props->write)); g_assert(!props->size || props->data); + g_assert(!props->ncq || (props->ncq && props->lba48)); /* Defaults and book-keeping */ cmd->props = props; @@ -789,6 +805,8 @@ void ahci_command_set_buffer(AHCICommand *cmd, uint64_t buffer) void ahci_command_set_sizes(AHCICommand *cmd, uint64_t xbytes, unsigned prd_size) { + uint16_t sect_count; + /* Each PRD can describe up to 4MiB, and must not be odd. */ g_assert_cmphex(prd_size, <=, 4096 * 1024); g_assert_cmphex(prd_size & 0x01, ==, 0x00); @@ -796,7 +814,15 @@ void ahci_command_set_sizes(AHCICommand *cmd, uint64_t xbytes, cmd->prd_size = prd_size; } cmd->xbytes = xbytes; - cmd->fis.count = (cmd->xbytes / AHCI_SECTOR_SIZE); + sect_count = (cmd->xbytes / AHCI_SECTOR_SIZE); + + if (cmd->props->ncq) { + NCQFIS *nfis = (NCQFIS *)&(cmd->fis); + nfis->sector_low = sect_count & 0xFF; + nfis->sector_hi = (sect_count >> 8) & 0xFF; + } else { + cmd->fis.count = sect_count; + } cmd->header.prdtl = size_to_prdtl(cmd->xbytes, cmd->prd_size); } diff --git a/tests/libqos/ahci.h b/tests/libqos/ahci.h index ca8abee..594a1c9 100644 --- a/tests/libqos/ahci.h +++ b/tests/libqos/ahci.h @@ -291,8 +291,9 @@ enum { #define CMDH_PMP (0xF000) /* ATA device register masks */ -#define ATA_DEVICE_MAGIC 0xA0 +#define ATA_DEVICE_MAGIC 0xA0 /* used in ata1-3 */ #define ATA_DEVICE_LBA 0x40 +#define NCQ_DEVICE_MAGIC 0x40 /* for ncq device registers */ #define ATA_DEVICE_DRIVE 0x10 #define ATA_DEVICE_HEAD 0x0F @@ -397,6 +398,32 @@ typedef struct RegH2DFIS { } __attribute__((__packed__)) RegH2DFIS; /** + * Register host-to-device FIS structure, for NCQ commands. + * Actually just a RegH2DFIS, but with fields repurposed. + * Repurposed fields are annotated below. + */ +typedef struct NCQFIS { + /* DW0 */ + uint8_t fis_type; + uint8_t flags; + uint8_t command; + uint8_t sector_low; /* H2D: Feature 7:0 */ + /* DW1 */ + uint8_t lba_lo[3]; + uint8_t device; + /* DW2 */ + uint8_t lba_hi[3]; + uint8_t sector_hi; /* H2D: Feature 15:8 */ + /* DW3 */ + uint8_t tag; /* H2D: Count 0:7 */ + uint8_t prio; /* H2D: Count 15:8 */ + uint8_t icc; + uint8_t control; + /* DW4 */ + uint8_t aux[4]; +} __attribute__((__packed__)) NCQFIS; + +/** * Command List entry structure. * The command list contains between 1-32 of these structures. */ |