mirror of https://github.com/xqemu/xqemu.git
ahci-test: test atapi read_cd with bcl, nb_sectors = 0
Commit 9ef2e93f
introduced the concept of tagging ATAPI commands as
NONDATA, but this introduced a regression for certain commands better
described as CONDDATA. read_cd is such a command that both requires
a non-zero BCL if a transfer size is set, but is perfectly content to
accept a zero BCL if the transfer size is 0.
This test adds a regression test for the case where BCL and nb_sectors
are both 0.
Flesh out the CDROM tests by:
(1) Allowing the test to specify a BCL
(2) Allowing the buffer comparison test to compare a 0-size buffer
(3) Fix the BCL specification in libqos (It is LE, not BE)
(4) Add a nice human-readable message for future SCSI command additions
Signed-off-by: John Snow <jsnow@redhat.com>
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
Message-id: 1477970211-25754-4-git-send-email-jsnow@redhat.com
[Line length edit --js]
Signed-off-by: John Snow <jsnow@redhat.com>
This commit is contained in:
parent
53c05e6c20
commit
ebde93bf9a
|
@ -1473,8 +1473,13 @@ static int ahci_cb_cmp_buff(AHCIQState *ahci, AHCICommand *cmd,
|
||||||
const AHCIOpts *opts)
|
const AHCIOpts *opts)
|
||||||
{
|
{
|
||||||
unsigned char *tx = opts->opaque;
|
unsigned char *tx = opts->opaque;
|
||||||
unsigned char *rx = g_malloc0(opts->size);
|
unsigned char *rx;
|
||||||
|
|
||||||
|
if (!opts->size) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
rx = g_malloc0(opts->size);
|
||||||
bufread(opts->buffer, rx, opts->size);
|
bufread(opts->buffer, rx, opts->size);
|
||||||
g_assert_cmphex(memcmp(tx, rx, opts->size), ==, 0);
|
g_assert_cmphex(memcmp(tx, rx, opts->size), ==, 0);
|
||||||
g_free(rx);
|
g_free(rx);
|
||||||
|
@ -1482,7 +1487,8 @@ static int ahci_cb_cmp_buff(AHCIQState *ahci, AHCICommand *cmd,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ahci_test_cdrom(int nsectors, bool dma)
|
static void ahci_test_cdrom(int nsectors, bool dma, uint8_t cmd,
|
||||||
|
bool override_bcl, uint16_t bcl)
|
||||||
{
|
{
|
||||||
AHCIQState *ahci;
|
AHCIQState *ahci;
|
||||||
unsigned char *tx;
|
unsigned char *tx;
|
||||||
|
@ -1493,6 +1499,8 @@ static void ahci_test_cdrom(int nsectors, bool dma)
|
||||||
.atapi = true,
|
.atapi = true,
|
||||||
.atapi_dma = dma,
|
.atapi_dma = dma,
|
||||||
.post_cb = ahci_cb_cmp_buff,
|
.post_cb = ahci_cb_cmp_buff,
|
||||||
|
.set_bcl = override_bcl,
|
||||||
|
.bcl = bcl,
|
||||||
};
|
};
|
||||||
uint64_t iso_size = ATAPI_SECTOR_SIZE * (nsectors + 1);
|
uint64_t iso_size = ATAPI_SECTOR_SIZE * (nsectors + 1);
|
||||||
|
|
||||||
|
@ -1506,7 +1514,7 @@ static void ahci_test_cdrom(int nsectors, bool dma)
|
||||||
"-device ide-cd,drive=drive0 ", iso);
|
"-device ide-cd,drive=drive0 ", iso);
|
||||||
|
|
||||||
/* Build & Send AHCI command */
|
/* Build & Send AHCI command */
|
||||||
ahci_exec(ahci, ahci_port_select(ahci), CMD_ATAPI_READ_10, &opts);
|
ahci_exec(ahci, ahci_port_select(ahci), cmd, &opts);
|
||||||
|
|
||||||
/* Cleanup */
|
/* Cleanup */
|
||||||
g_free(tx);
|
g_free(tx);
|
||||||
|
@ -1514,24 +1522,36 @@ static void ahci_test_cdrom(int nsectors, bool dma)
|
||||||
remove_iso(fd, iso);
|
remove_iso(fd, iso);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void ahci_test_cdrom_read10(int nsectors, bool dma)
|
||||||
|
{
|
||||||
|
ahci_test_cdrom(nsectors, dma, CMD_ATAPI_READ_10, false, 0);
|
||||||
|
}
|
||||||
|
|
||||||
static void test_cdrom_dma(void)
|
static void test_cdrom_dma(void)
|
||||||
{
|
{
|
||||||
ahci_test_cdrom(1, true);
|
ahci_test_cdrom_read10(1, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_cdrom_dma_multi(void)
|
static void test_cdrom_dma_multi(void)
|
||||||
{
|
{
|
||||||
ahci_test_cdrom(3, true);
|
ahci_test_cdrom_read10(3, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_cdrom_pio(void)
|
static void test_cdrom_pio(void)
|
||||||
{
|
{
|
||||||
ahci_test_cdrom(1, false);
|
ahci_test_cdrom_read10(1, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_cdrom_pio_multi(void)
|
static void test_cdrom_pio_multi(void)
|
||||||
{
|
{
|
||||||
ahci_test_cdrom(3, false);
|
ahci_test_cdrom_read10(3, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Regression test: Test that a READ_CD command with a BCL of 0 but a size of 0
|
||||||
|
* completes as a NOP instead of erroring out. */
|
||||||
|
static void test_atapi_bcl(void)
|
||||||
|
{
|
||||||
|
ahci_test_cdrom(0, false, CMD_ATAPI_READ_CD, true, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
@ -1823,6 +1843,8 @@ int main(int argc, char **argv)
|
||||||
qtest_add_func("/ahci/cdrom/pio/single", test_cdrom_pio);
|
qtest_add_func("/ahci/cdrom/pio/single", test_cdrom_pio);
|
||||||
qtest_add_func("/ahci/cdrom/pio/multi", test_cdrom_pio_multi);
|
qtest_add_func("/ahci/cdrom/pio/multi", test_cdrom_pio_multi);
|
||||||
|
|
||||||
|
qtest_add_func("/ahci/cdrom/pio/bcl", test_atapi_bcl);
|
||||||
|
|
||||||
ret = g_test_run();
|
ret = g_test_run();
|
||||||
|
|
||||||
/* Cleanup */
|
/* Cleanup */
|
||||||
|
|
|
@ -633,7 +633,8 @@ void ahci_exec(AHCIQState *ahci, uint8_t port,
|
||||||
|
|
||||||
/* Command creation */
|
/* Command creation */
|
||||||
if (opts->atapi) {
|
if (opts->atapi) {
|
||||||
cmd = ahci_atapi_command_create(op);
|
uint16_t bcl = opts->set_bcl ? opts->bcl : ATAPI_SECTOR_SIZE;
|
||||||
|
cmd = ahci_atapi_command_create(op, bcl);
|
||||||
if (opts->atapi_dma) {
|
if (opts->atapi_dma) {
|
||||||
ahci_command_enable_atapi_dma(cmd);
|
ahci_command_enable_atapi_dma(cmd);
|
||||||
}
|
}
|
||||||
|
@ -864,16 +865,12 @@ AHCICommand *ahci_command_create(uint8_t command_name)
|
||||||
return cmd;
|
return cmd;
|
||||||
}
|
}
|
||||||
|
|
||||||
AHCICommand *ahci_atapi_command_create(uint8_t scsi_cmd)
|
AHCICommand *ahci_atapi_command_create(uint8_t scsi_cmd, uint16_t bcl)
|
||||||
{
|
{
|
||||||
AHCICommand *cmd = ahci_command_create(CMD_PACKET);
|
AHCICommand *cmd = ahci_command_create(CMD_PACKET);
|
||||||
cmd->atapi_cmd = g_malloc0(16);
|
cmd->atapi_cmd = g_malloc0(16);
|
||||||
cmd->atapi_cmd[0] = scsi_cmd;
|
cmd->atapi_cmd[0] = scsi_cmd;
|
||||||
/* ATAPI needs a PIO transfer chunk size set inside of the LBA registers.
|
stw_le_p(&cmd->fis.lba_lo[1], bcl);
|
||||||
* The block/sector size is a natural default. */
|
|
||||||
cmd->fis.lba_lo[1] = ATAPI_SECTOR_SIZE >> 8 & 0xFF;
|
|
||||||
cmd->fis.lba_lo[2] = ATAPI_SECTOR_SIZE & 0xFF;
|
|
||||||
|
|
||||||
return cmd;
|
return cmd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -901,12 +898,17 @@ static void ahci_atapi_command_set_offset(AHCICommand *cmd, uint64_t lba)
|
||||||
|
|
||||||
switch (cbd[0]) {
|
switch (cbd[0]) {
|
||||||
case CMD_ATAPI_READ_10:
|
case CMD_ATAPI_READ_10:
|
||||||
|
case CMD_ATAPI_READ_CD:
|
||||||
g_assert_cmpuint(lba, <=, UINT32_MAX);
|
g_assert_cmpuint(lba, <=, UINT32_MAX);
|
||||||
stl_be_p(&cbd[2], lba);
|
stl_be_p(&cbd[2], lba);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
/* SCSI doesn't have uniform packet formats,
|
/* SCSI doesn't have uniform packet formats,
|
||||||
* so you have to add support for it manually. Sorry! */
|
* so you have to add support for it manually. Sorry! */
|
||||||
|
fprintf(stderr, "The Libqos AHCI driver does not support the "
|
||||||
|
"set_offset operation for ATAPI command 0x%02x, "
|
||||||
|
"please add support.\n",
|
||||||
|
cbd[0]);
|
||||||
g_assert_not_reached();
|
g_assert_not_reached();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -951,6 +953,7 @@ static void ahci_atapi_set_size(AHCICommand *cmd, uint64_t xbytes)
|
||||||
{
|
{
|
||||||
unsigned char *cbd = cmd->atapi_cmd;
|
unsigned char *cbd = cmd->atapi_cmd;
|
||||||
uint64_t nsectors = xbytes / 2048;
|
uint64_t nsectors = xbytes / 2048;
|
||||||
|
uint32_t tmp;
|
||||||
g_assert(cbd);
|
g_assert(cbd);
|
||||||
|
|
||||||
switch (cbd[0]) {
|
switch (cbd[0]) {
|
||||||
|
@ -958,9 +961,20 @@ static void ahci_atapi_set_size(AHCICommand *cmd, uint64_t xbytes)
|
||||||
g_assert_cmpuint(nsectors, <=, UINT16_MAX);
|
g_assert_cmpuint(nsectors, <=, UINT16_MAX);
|
||||||
stw_be_p(&cbd[7], nsectors);
|
stw_be_p(&cbd[7], nsectors);
|
||||||
break;
|
break;
|
||||||
|
case CMD_ATAPI_READ_CD:
|
||||||
|
/* 24bit BE store */
|
||||||
|
g_assert_cmpuint(nsectors, <, 1ULL << 24);
|
||||||
|
tmp = nsectors;
|
||||||
|
cbd[6] = (tmp & 0xFF0000) >> 16;
|
||||||
|
cbd[7] = (tmp & 0xFF00) >> 8;
|
||||||
|
cbd[8] = (tmp & 0xFF);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
/* SCSI doesn't have uniform packet formats,
|
/* SCSI doesn't have uniform packet formats,
|
||||||
* so you have to add support for it manually. Sorry! */
|
* so you have to add support for it manually. Sorry! */
|
||||||
|
fprintf(stderr, "The Libqos AHCI driver does not support the set_size "
|
||||||
|
"operation for ATAPI command 0x%02x, please add support.\n",
|
||||||
|
cbd[0]);
|
||||||
g_assert_not_reached();
|
g_assert_not_reached();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -288,6 +288,7 @@ enum {
|
||||||
/* ATAPI Commands */
|
/* ATAPI Commands */
|
||||||
enum {
|
enum {
|
||||||
CMD_ATAPI_READ_10 = 0x28,
|
CMD_ATAPI_READ_10 = 0x28,
|
||||||
|
CMD_ATAPI_READ_CD = 0xbe,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* AHCI Command Header Flags & Masks*/
|
/* AHCI Command Header Flags & Masks*/
|
||||||
|
@ -462,12 +463,14 @@ typedef struct AHCICommand AHCICommand;
|
||||||
|
|
||||||
/* Options to ahci_exec */
|
/* Options to ahci_exec */
|
||||||
typedef struct AHCIOpts {
|
typedef struct AHCIOpts {
|
||||||
size_t size;
|
size_t size; /* Size of transfer */
|
||||||
unsigned prd_size;
|
unsigned prd_size; /* Size per-each PRD */
|
||||||
uint64_t lba;
|
bool set_bcl; /* Override the default BCL of ATAPI_SECTOR_SIZE */
|
||||||
uint64_t buffer;
|
unsigned bcl; /* Byte Count Limit, for ATAPI PIO */
|
||||||
bool atapi;
|
uint64_t lba; /* Starting LBA offset */
|
||||||
bool atapi_dma;
|
uint64_t buffer; /* Pointer to source or destination guest buffer */
|
||||||
|
bool atapi; /* ATAPI command? */
|
||||||
|
bool atapi_dma; /* Use DMA for ATAPI? */
|
||||||
bool error;
|
bool error;
|
||||||
int (*pre_cb)(AHCIQState*, AHCICommand*, const struct AHCIOpts *);
|
int (*pre_cb)(AHCIQState*, AHCICommand*, const struct AHCIOpts *);
|
||||||
int (*mid_cb)(AHCIQState*, AHCICommand*, const struct AHCIOpts *);
|
int (*mid_cb)(AHCIQState*, AHCICommand*, const struct AHCIOpts *);
|
||||||
|
@ -599,7 +602,7 @@ void ahci_exec(AHCIQState *ahci, uint8_t port,
|
||||||
|
|
||||||
/* Command: Fine-grained lifecycle */
|
/* Command: Fine-grained lifecycle */
|
||||||
AHCICommand *ahci_command_create(uint8_t command_name);
|
AHCICommand *ahci_command_create(uint8_t command_name);
|
||||||
AHCICommand *ahci_atapi_command_create(uint8_t scsi_cmd);
|
AHCICommand *ahci_atapi_command_create(uint8_t scsi_cmd, uint16_t bcl);
|
||||||
void ahci_command_commit(AHCIQState *ahci, AHCICommand *cmd, uint8_t port);
|
void ahci_command_commit(AHCIQState *ahci, AHCICommand *cmd, uint8_t port);
|
||||||
void ahci_command_issue(AHCIQState *ahci, AHCICommand *cmd);
|
void ahci_command_issue(AHCIQState *ahci, AHCICommand *cmd);
|
||||||
void ahci_command_issue_async(AHCIQState *ahci, AHCICommand *cmd);
|
void ahci_command_issue_async(AHCIQState *ahci, AHCICommand *cmd);
|
||||||
|
|
Loading…
Reference in New Issue