qtest/ahci: test different disk sectors

Test sector offset 0, 1, and the last sector(s)
in LBA28 and LBA48 modes.

Signed-off-by: John Snow <jsnow@redhat.com>
Acked-by: Stefan Hajnoczi <stefanha@redhat.com>
Message-id: 1426274523-22661-3-git-send-email-jsnow@redhat.com
This commit is contained in:
John Snow 2015-04-28 15:27:51 -04:00
parent 122fdf2d88
commit 727be1a755
3 changed files with 63 additions and 19 deletions

View File

@ -41,6 +41,8 @@
/* Test-specific defines -- in MiB */ /* Test-specific defines -- in MiB */
#define TEST_IMAGE_SIZE_MB (200 * 1024) #define TEST_IMAGE_SIZE_MB (200 * 1024)
#define TEST_IMAGE_SECTORS ((TEST_IMAGE_SIZE_MB / AHCI_SECTOR_SIZE) \
* 1024 * 1024)
/*** Globals ***/ /*** Globals ***/
static char tmp_path[] = "/tmp/qtest.XXXXXX"; static char tmp_path[] = "/tmp/qtest.XXXXXX";
@ -738,7 +740,7 @@ static void ahci_test_identify(AHCIQState *ahci)
ahci_port_clear(ahci, px); ahci_port_clear(ahci, px);
/* "Read" 512 bytes using CMD_IDENTIFY into the host buffer. */ /* "Read" 512 bytes using CMD_IDENTIFY into the host buffer. */
ahci_io(ahci, px, CMD_IDENTIFY, &buff, buffsize); ahci_io(ahci, px, CMD_IDENTIFY, &buff, buffsize, 0);
/* Check serial number/version in the buffer */ /* Check serial number/version in the buffer */
/* NB: IDENTIFY strings are packed in 16bit little endian chunks. /* NB: IDENTIFY strings are packed in 16bit little endian chunks.
@ -754,11 +756,12 @@ static void ahci_test_identify(AHCIQState *ahci)
g_assert_cmphex(rc, ==, 0); g_assert_cmphex(rc, ==, 0);
sect_size = le16_to_cpu(*((uint16_t *)(&buff[5]))); sect_size = le16_to_cpu(*((uint16_t *)(&buff[5])));
g_assert_cmphex(sect_size, ==, 0x200); g_assert_cmphex(sect_size, ==, AHCI_SECTOR_SIZE);
} }
static void ahci_test_io_rw_simple(AHCIQState *ahci, unsigned bufsize, static void ahci_test_io_rw_simple(AHCIQState *ahci, unsigned bufsize,
uint8_t read_cmd, uint8_t write_cmd) uint64_t sector, uint8_t read_cmd,
uint8_t write_cmd)
{ {
uint64_t ptr; uint64_t ptr;
uint8_t port; uint8_t port;
@ -781,9 +784,9 @@ static void ahci_test_io_rw_simple(AHCIQState *ahci, unsigned bufsize,
memwrite(ptr, tx, bufsize); memwrite(ptr, tx, bufsize);
/* Write this buffer to disk, then read it back to the DMA buffer. */ /* Write this buffer to disk, then read it back to the DMA buffer. */
ahci_guest_io(ahci, port, write_cmd, ptr, bufsize); ahci_guest_io(ahci, port, write_cmd, ptr, bufsize, sector);
qmemset(ptr, 0x00, bufsize); qmemset(ptr, 0x00, bufsize);
ahci_guest_io(ahci, port, read_cmd, ptr, bufsize); ahci_guest_io(ahci, port, read_cmd, ptr, bufsize, sector);
/*** Read back the Data ***/ /*** Read back the Data ***/
memread(ptr, rx, bufsize); memread(ptr, rx, bufsize);
@ -968,12 +971,45 @@ enum IOOps {
NUM_IO_OPS NUM_IO_OPS
}; };
enum OffsetType {
OFFSET_BEGIN = 0,
OFFSET_ZERO = OFFSET_BEGIN,
OFFSET_LOW,
OFFSET_HIGH,
NUM_OFFSETS
};
static const char *offset_str[NUM_OFFSETS] = { "zero", "low", "high" };
typedef struct AHCIIOTestOptions { typedef struct AHCIIOTestOptions {
enum BuffLen length; enum BuffLen length;
enum AddrMode address_type; enum AddrMode address_type;
enum IOMode io_type; enum IOMode io_type;
enum OffsetType offset;
} AHCIIOTestOptions; } AHCIIOTestOptions;
static uint64_t offset_sector(enum OffsetType ofst,
enum AddrMode addr_type,
uint64_t buffsize)
{
uint64_t ceil;
uint64_t nsectors;
switch (ofst) {
case OFFSET_ZERO:
return 0;
case OFFSET_LOW:
return 1;
case OFFSET_HIGH:
ceil = (addr_type == ADDR_MODE_LBA28) ? 0xfffffff : 0xffffffffffff;
ceil = MIN(ceil, TEST_IMAGE_SECTORS - 1);
nsectors = buffsize / AHCI_SECTOR_SIZE;
return ceil - nsectors + 1;
default:
g_assert_not_reached();
}
}
/** /**
* Table of possible I/O ATA commands given a set of enumerations. * Table of possible I/O ATA commands given a set of enumerations.
*/ */
@ -1001,12 +1037,12 @@ static const uint8_t io_cmds[NUM_MODES][NUM_ADDR_MODES][NUM_IO_OPS] = {
* transfer modes, and buffer sizes. * transfer modes, and buffer sizes.
*/ */
static void test_io_rw_interface(enum AddrMode lba48, enum IOMode dma, static void test_io_rw_interface(enum AddrMode lba48, enum IOMode dma,
unsigned bufsize) unsigned bufsize, uint64_t sector)
{ {
AHCIQState *ahci; AHCIQState *ahci;
ahci = ahci_boot_and_enable(); ahci = ahci_boot_and_enable();
ahci_test_io_rw_simple(ahci, bufsize, ahci_test_io_rw_simple(ahci, bufsize, sector,
io_cmds[dma][lba48][IO_READ], io_cmds[dma][lba48][IO_READ],
io_cmds[dma][lba48][IO_WRITE]); io_cmds[dma][lba48][IO_WRITE]);
ahci_shutdown(ahci); ahci_shutdown(ahci);
@ -1019,6 +1055,7 @@ static void test_io_interface(gconstpointer opaque)
{ {
AHCIIOTestOptions *opts = (AHCIIOTestOptions *)opaque; AHCIIOTestOptions *opts = (AHCIIOTestOptions *)opaque;
unsigned bufsize; unsigned bufsize;
uint64_t sector;
switch (opts->length) { switch (opts->length) {
case LEN_SIMPLE: case LEN_SIMPLE:
@ -1037,13 +1074,14 @@ static void test_io_interface(gconstpointer opaque)
g_assert_not_reached(); g_assert_not_reached();
} }
test_io_rw_interface(opts->address_type, opts->io_type, bufsize); sector = offset_sector(opts->offset, opts->address_type, bufsize);
test_io_rw_interface(opts->address_type, opts->io_type, bufsize, sector);
g_free(opts); g_free(opts);
return; return;
} }
static void create_ahci_io_test(enum IOMode type, enum AddrMode addr, static void create_ahci_io_test(enum IOMode type, enum AddrMode addr,
enum BuffLen len) enum BuffLen len, enum OffsetType offset)
{ {
static const char *arch; static const char *arch;
char *name; char *name;
@ -1052,15 +1090,17 @@ static void create_ahci_io_test(enum IOMode type, enum AddrMode addr,
opts->length = len; opts->length = len;
opts->address_type = addr; opts->address_type = addr;
opts->io_type = type; opts->io_type = type;
opts->offset = offset;
if (!arch) { if (!arch) {
arch = qtest_get_arch(); arch = qtest_get_arch();
} }
name = g_strdup_printf("/%s/ahci/io/%s/%s/%s", arch, name = g_strdup_printf("/%s/ahci/io/%s/%s/%s/%s", arch,
io_mode_str[type], io_mode_str[type],
addr_mode_str[addr], addr_mode_str[addr],
buff_len_str[len]); buff_len_str[len],
offset_str[offset]);
g_test_add_data_func(name, opts, test_io_interface); g_test_add_data_func(name, opts, test_io_interface);
g_free(name); g_free(name);
@ -1073,7 +1113,7 @@ int main(int argc, char **argv)
const char *arch; const char *arch;
int ret; int ret;
int c; int c;
int i, j, k; int i, j, k, m;
static struct option long_options[] = { static struct option long_options[] = {
{"pedantic", no_argument, 0, 'p' }, {"pedantic", no_argument, 0, 'p' },
@ -1122,7 +1162,9 @@ int main(int argc, char **argv)
for (i = MODE_BEGIN; i < NUM_MODES; i++) { for (i = MODE_BEGIN; i < NUM_MODES; i++) {
for (j = ADDR_MODE_BEGIN; j < NUM_ADDR_MODES; j++) { for (j = ADDR_MODE_BEGIN; j < NUM_ADDR_MODES; j++) {
for (k = LEN_BEGIN; k < NUM_LENGTHS; k++) { for (k = LEN_BEGIN; k < NUM_LENGTHS; k++) {
create_ahci_io_test(i, j, k); for (m = OFFSET_BEGIN; m < NUM_OFFSETS; m++) {
create_ahci_io_test(i, j, k, m);
}
} }
} }
} }

View File

@ -568,13 +568,15 @@ inline unsigned size_to_prdtl(unsigned bytes, unsigned bytes_per_prd)
/* Given a guest buffer address, perform an IO operation */ /* Given a guest buffer address, perform an IO operation */
void ahci_guest_io(AHCIQState *ahci, uint8_t port, uint8_t ide_cmd, void ahci_guest_io(AHCIQState *ahci, uint8_t port, uint8_t ide_cmd,
uint64_t buffer, size_t bufsize) uint64_t buffer, size_t bufsize, uint64_t sector)
{ {
AHCICommand *cmd; AHCICommand *cmd;
cmd = ahci_command_create(ide_cmd); cmd = ahci_command_create(ide_cmd);
ahci_command_set_buffer(cmd, buffer); ahci_command_set_buffer(cmd, buffer);
ahci_command_set_size(cmd, bufsize); ahci_command_set_size(cmd, bufsize);
if (sector) {
ahci_command_set_offset(cmd, sector);
}
ahci_command_commit(ahci, cmd, port); ahci_command_commit(ahci, cmd, port);
ahci_command_issue(ahci, cmd); ahci_command_issue(ahci, cmd);
ahci_command_verify(ahci, cmd); ahci_command_verify(ahci, cmd);
@ -612,7 +614,7 @@ static AHCICommandProp *ahci_command_find(uint8_t command_name)
/* Given a HOST buffer, create a buffer address and perform an IO operation. */ /* Given a HOST buffer, create a buffer address and perform an IO operation. */
void ahci_io(AHCIQState *ahci, uint8_t port, uint8_t ide_cmd, void ahci_io(AHCIQState *ahci, uint8_t port, uint8_t ide_cmd,
void *buffer, size_t bufsize) void *buffer, size_t bufsize, uint64_t sector)
{ {
uint64_t ptr; uint64_t ptr;
AHCICommandProp *props; AHCICommandProp *props;
@ -626,7 +628,7 @@ void ahci_io(AHCIQState *ahci, uint8_t port, uint8_t ide_cmd,
memwrite(ptr, buffer, bufsize); memwrite(ptr, buffer, bufsize);
} }
ahci_guest_io(ahci, port, ide_cmd, ptr, bufsize); ahci_guest_io(ahci, port, ide_cmd, ptr, bufsize, sector);
if (props->read) { if (props->read) {
memread(ptr, buffer, bufsize); memread(ptr, buffer, bufsize);

View File

@ -523,9 +523,9 @@ void ahci_write_fis(AHCIQState *ahci, RegH2DFIS *fis, uint64_t addr);
unsigned ahci_pick_cmd(AHCIQState *ahci, uint8_t port); unsigned ahci_pick_cmd(AHCIQState *ahci, uint8_t port);
unsigned size_to_prdtl(unsigned bytes, unsigned bytes_per_prd); unsigned size_to_prdtl(unsigned bytes, unsigned bytes_per_prd);
void ahci_guest_io(AHCIQState *ahci, uint8_t port, uint8_t ide_cmd, void ahci_guest_io(AHCIQState *ahci, uint8_t port, uint8_t ide_cmd,
uint64_t gbuffer, size_t size); uint64_t gbuffer, size_t size, uint64_t sector);
void ahci_io(AHCIQState *ahci, uint8_t port, uint8_t ide_cmd, void ahci_io(AHCIQState *ahci, uint8_t port, uint8_t ide_cmd,
void *buffer, size_t bufsize); void *buffer, size_t bufsize, uint64_t sector);
/* Command Lifecycle */ /* Command Lifecycle */
AHCICommand *ahci_command_create(uint8_t command_name); AHCICommand *ahci_command_create(uint8_t command_name);