Commit 727be1a7 authored by John Snow's avatar John Snow
Browse files

qtest/ahci: test different disk sectors



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

Signed-off-by: default avatarJohn Snow <jsnow@redhat.com>
Acked-by: default avatarStefan Hajnoczi <stefanha@redhat.com>
Message-id: 1426274523-22661-3-git-send-email-jsnow@redhat.com
parent 122fdf2d
Loading
Loading
Loading
Loading
+55 −13
Original line number Diff line number Diff line
@@ -41,6 +41,8 @@

/* Test-specific defines -- in MiB */
#define TEST_IMAGE_SIZE_MB (200 * 1024)
#define TEST_IMAGE_SECTORS ((TEST_IMAGE_SIZE_MB / AHCI_SECTOR_SIZE)     \
                            * 1024 * 1024)

/*** Globals ***/
static char tmp_path[] = "/tmp/qtest.XXXXXX";
@@ -738,7 +740,7 @@ static void ahci_test_identify(AHCIQState *ahci)
    ahci_port_clear(ahci, px);

    /* "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 */
    /* 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);

    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,
                                   uint8_t read_cmd, uint8_t write_cmd)
                                   uint64_t sector, uint8_t read_cmd,
                                   uint8_t write_cmd)
{
    uint64_t ptr;
    uint8_t port;
@@ -781,9 +784,9 @@ static void ahci_test_io_rw_simple(AHCIQState *ahci, unsigned bufsize,
    memwrite(ptr, tx, bufsize);

    /* 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);
    ahci_guest_io(ahci, port, read_cmd, ptr, bufsize);
    ahci_guest_io(ahci, port, read_cmd, ptr, bufsize, sector);

    /*** Read back the Data ***/
    memread(ptr, rx, bufsize);
@@ -968,12 +971,45 @@ enum IOOps {
    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 {
    enum BuffLen length;
    enum AddrMode address_type;
    enum IOMode io_type;
    enum OffsetType offset;
} 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.
 */
@@ -1001,12 +1037,12 @@ static const uint8_t io_cmds[NUM_MODES][NUM_ADDR_MODES][NUM_IO_OPS] = {
 * transfer modes, and buffer sizes.
 */
static void test_io_rw_interface(enum AddrMode lba48, enum IOMode dma,
                                 unsigned bufsize)
                                 unsigned bufsize, uint64_t sector)
{
    AHCIQState *ahci;

    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_WRITE]);
    ahci_shutdown(ahci);
@@ -1019,6 +1055,7 @@ static void test_io_interface(gconstpointer opaque)
{
    AHCIIOTestOptions *opts = (AHCIIOTestOptions *)opaque;
    unsigned bufsize;
    uint64_t sector;

    switch (opts->length) {
    case LEN_SIMPLE:
@@ -1037,13 +1074,14 @@ static void test_io_interface(gconstpointer opaque)
        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);
    return;
}

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;
    char *name;
@@ -1052,15 +1090,17 @@ static void create_ahci_io_test(enum IOMode type, enum AddrMode addr,
    opts->length = len;
    opts->address_type = addr;
    opts->io_type = type;
    opts->offset = offset;

    if (!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],
                           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_free(name);
@@ -1073,7 +1113,7 @@ int main(int argc, char **argv)
    const char *arch;
    int ret;
    int c;
    int i, j, k;
    int i, j, k, m;

    static struct option long_options[] = {
        {"pedantic", no_argument, 0, 'p' },
@@ -1122,7 +1162,9 @@ int main(int argc, char **argv)
    for (i = MODE_BEGIN; i < NUM_MODES; i++) {
        for (j = ADDR_MODE_BEGIN; j < NUM_ADDR_MODES; j++) {
            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);
                }
            }
        }
    }
+6 −4
Original line number Diff line number Diff line
@@ -568,13 +568,15 @@ inline unsigned size_to_prdtl(unsigned bytes, unsigned bytes_per_prd)

/* Given a guest buffer address, perform an IO operation */
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;

    cmd = ahci_command_create(ide_cmd);
    ahci_command_set_buffer(cmd, buffer);
    ahci_command_set_size(cmd, bufsize);
    if (sector) {
        ahci_command_set_offset(cmd, sector);
    }
    ahci_command_commit(ahci, cmd, port);
    ahci_command_issue(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. */
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;
    AHCICommandProp *props;
@@ -626,7 +628,7 @@ void ahci_io(AHCIQState *ahci, uint8_t port, uint8_t ide_cmd,
        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) {
        memread(ptr, buffer, bufsize);
+2 −2
Original line number Diff line number Diff line
@@ -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 size_to_prdtl(unsigned bytes, unsigned bytes_per_prd);
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 *buffer, size_t bufsize);
             void *buffer, size_t bufsize, uint64_t sector);

/* Command Lifecycle */
AHCICommand *ahci_command_create(uint8_t command_name);