summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--tests/ahci-test.c63
-rw-r--r--tests/libqos/ahci.c25
-rw-r--r--tests/libqos/ahci.h2
3 files changed, 52 insertions, 38 deletions
diff --git a/tests/ahci-test.c b/tests/ahci-test.c
index 6e7b76533f..47491fe96c 100644
--- a/tests/ahci-test.c
+++ b/tests/ahci-test.c
@@ -657,56 +657,43 @@ static void ahci_test_port_spec(AHCIQState *ahci, uint8_t port)
*/
static void ahci_test_identify(AHCIQState *ahci)
{
- uint32_t data_ptr;
uint16_t buff[256];
- unsigned i;
+ unsigned px;
int rc;
- AHCICommand *cmd;
+ const size_t buffsize = 512;
g_assert(ahci != NULL);
- /* We need to:
- * (1) Create a data buffer for the IDENTIFY response to be sent to,
- * (2) Create a Command Table Buffer
+ /**
+ * This serves as a bit of a tutorial on AHCI device programming:
+ *
+ * (1) Create a data buffer for the IDENTIFY response to be sent to
+ * (2) Create a Command Table buffer, where we will store the
+ * command and PRDT (Physical Region Descriptor Table)
* (3) Construct an FIS host-to-device command structure, and write it to
- * the top of the command table buffer.
- * (4) Create a Physical Region Descriptor that points to the data buffer,
- * and write it to the bottom (offset 0x80) of the command table.
- * (5) Obtain a Command List slot, and update this header to point to
- * the Command Table we built above.
- * (6) Now, PxCLB points to the command list, command 0 points to
- * our table, and our table contains an FIS instruction and a
- * PRD that points to our rx buffer.
- * (7) We inform the HBA via PxCI that there is a command ready in slot #0.
+ * the top of the Command Table buffer.
+ * (4) Create one or more Physical Region Descriptors (PRDs) that describe
+ * a location in memory where data may be stored/retrieved.
+ * (5) Write these PRDTs to the bottom (offset 0x80) of the Command Table.
+ * (6) Each AHCI port has up to 32 command slots. Each slot contains a
+ * header that points to a Command Table buffer. Pick an unused slot
+ * and update it to point to the Command Table we have built.
+ * (7) Now: Command #n points to our Command Table, and our Command Table
+ * contains the FIS (that describes our command) and the PRDTL, which
+ * describes our buffer.
+ * (8) We inform the HBA via PxCI (Command Issue) that the command in slot
+ * #n is ready for processing.
*/
/* Pick the first implemented and running port */
- i = ahci_port_select(ahci);
- g_test_message("Selected port %u for test", i);
+ px = ahci_port_select(ahci);
+ g_test_message("Selected port %u for test", px);
/* Clear out the FIS Receive area and any pending interrupts. */
- ahci_port_clear(ahci, i);
-
- /* Create a data buffer where we will dump the IDENTIFY data to. */
- data_ptr = ahci_alloc(ahci, 512);
- g_assert(data_ptr);
-
- /* Construct the Command Table (FIS and PRDT) and Command Header */
- cmd = ahci_command_create(CMD_IDENTIFY);
- ahci_command_set_buffer(cmd, data_ptr);
- /* Write the command header and PRDT to guest memory */
- ahci_command_commit(ahci, cmd, i);
-
- /* Everything is in place, but we haven't given the go-ahead yet,
- * so we should find that there are no pending interrupts yet. */
- g_assert_cmphex(ahci_px_rreg(ahci, i, AHCI_PX_IS), ==, 0);
-
- /* Issue command and sanity check response. */
- ahci_command_issue(ahci, cmd);
- ahci_command_verify(ahci, cmd);
+ ahci_port_clear(ahci, px);
- /* Last, but not least: Investigate the IDENTIFY response data. */
- memread(data_ptr, &buff, 512);
+ /* "Read" 512 bytes using CMD_IDENTIFY into the host buffer. */
+ ahci_io(ahci, px, CMD_IDENTIFY, &buff, buffsize);
/* Check serial number/version in the buffer */
/* NB: IDENTIFY strings are packed in 16bit little endian chunks.
diff --git a/tests/libqos/ahci.c b/tests/libqos/ahci.c
index 345d1f190b..85222248b6 100644
--- a/tests/libqos/ahci.c
+++ b/tests/libqos/ahci.c
@@ -592,6 +592,31 @@ static AHCICommandProp *ahci_command_find(uint8_t command_name)
return NULL;
}
+/* 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)
+{
+ uint64_t ptr;
+ AHCICommandProp *props;
+
+ props = ahci_command_find(ide_cmd);
+ g_assert(props);
+ ptr = ahci_alloc(ahci, bufsize);
+ g_assert(ptr);
+
+ if (props->write) {
+ memwrite(ptr, buffer, bufsize);
+ }
+
+ ahci_guest_io(ahci, port, ide_cmd, ptr, bufsize);
+
+ if (props->read) {
+ memread(ptr, buffer, bufsize);
+ }
+
+ ahci_free(ahci, ptr);
+}
+
/**
* Initializes a basic command header in memory.
* We assume that this is for an ATA command using RegH2DFIS.
diff --git a/tests/libqos/ahci.h b/tests/libqos/ahci.h
index 1206c7abab..9133033f1c 100644
--- a/tests/libqos/ahci.h
+++ b/tests/libqos/ahci.h
@@ -523,6 +523,8 @@ 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);
+void ahci_io(AHCIQState *ahci, uint8_t port, uint8_t ide_cmd,
+ void *buffer, size_t bufsize);
/* Command Lifecycle */
AHCICommand *ahci_command_create(uint8_t command_name);