libqos/ahci: add ahci_io
authorJohn Snow <jsnow@redhat.com>
Thu, 5 Feb 2015 17:41:27 +0000 (12:41 -0500)
committerStefan Hajnoczi <stefanha@redhat.com>
Mon, 16 Feb 2015 15:07:17 +0000 (15:07 +0000)
ahci_io is a wrapper around ahci_guest_io that takes a pointer to host
memory instead, and will create a guest memory buffer and copy the data
to/from as needed and as appropriate for a read/write command, such that
after a read, the guest data will be in a host buffer, and for a write,
the data will be transmitted to guest memory prior to the block operation.

Now that we have all the syntactic sugar functions in place for AHCI,
we can convert the identify test to be very, very short.

Signed-off-by: John Snow <jsnow@redhat.com>
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
Message-id: 1423158090-25580-17-git-send-email-jsnow@redhat.com
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
tests/ahci-test.c
tests/libqos/ahci.c
tests/libqos/ahci.h

index 6e7b76533ffb2c08a1aea7ad41f17f33c86c31cb..47491fe96c5d0e5d09153a26c3f8cb1865fa50dd 100644 (file)
@@ -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.
index 345d1f190b6f7b7ffcf692e5806e10eae37f3eee..85222248b6ec929656412b833d99246a33a17831 100644 (file)
@@ -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.
index 1206c7abab30493a66be14276f97f897e419982a..9133033f1c1cf1dbab0655b7fe134c3dbba2428a 100644 (file)
@@ -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);