mirror of
https://gitlab.com/qemu-project/qemu
synced 2024-11-05 20:35:44 +00:00
libqos/ahci: add ahci_io
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>
This commit is contained in:
parent
113221956c
commit
ae02962017
3 changed files with 52 additions and 38 deletions
|
@ -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);
|
||||
ahci_port_clear(ahci, px);
|
||||
|
||||
/* 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);
|
||||
|
||||
/* 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.
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue