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:
		
							parent
							
								
									122fdf2d88
								
							
						
					
					
						commit
						727be1a755
					
				| 
						 | 
				
			
			@ -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);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue