Pull request
-----BEGIN PGP SIGNATURE----- iQIcBAABAgAGBQJbGsDwAAoJEH3vgQaq/DkOpiUP/24TYTN6FcfBRQbpHJp2/p5Z Z0uu1Wo3OFVEPQ63IOqoubMgYJwiw7DnM9dVtY7TfMsvlEX+FVGPp59Rd1L0ciec /c4L2ZhkLFk0VZB8moVpBCyJHHcHl0Do0v6dkxvJC5B82lkL59M3oCQzr9ADRJ+t 7IpgvnYBHQ2P1hEOF+df/2mbUDErioIb+3yEJEwfP/4/wvJZxYrtykZKYQOySHty NDyHoTgbIVecE5FeDMyij4WFt25F/OafH6p4Z1w5ieqmN7LT5sfR6oLzpyYmf7fM uDpCGQrQdeaFNgwcPbxnpuXFig0Tf2E8g319uJAtLfEUxy68yEcNgiGpavhAprxN P/vj+PR4n+eKv74sRG+td6nsIgmm9AjKr2rV1CgZcIL0F6sMu104E6kthAVzCYJD wQY/t14RdSdLBlVvsC+A0I1WUTtir/cjT0+ZE9w5z1nJ25tqJ3wli8MK/73cGZEk sNRHmHCOlP7MrkliOmXD3DVd1MpnIjHfRuHhMvOPSpYxO5qm00v6Gbg8ypmvCT3q iNgrXC9L/WJO3+RKezGspcGqGvnTQeVcZvu3y3Np6gCERGJ2WFqcNnu1h0uoGlNo NoRLToLuWyYSfqhk8URW/DclUUGWgnlDjSRxcv1eA8c9aWXnUroyXzQBqUhwQEbC yamyJ2rujwjDa8uwCO3F =QZ8V -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/jnsnow/tags/ide-pull-request' into staging Pull request # gpg: Signature made Fri 08 Jun 2018 18:46:24 BST # gpg: using RSA key 7DEF8106AAFC390E # gpg: Good signature from "John Snow (John Huston) <jsnow@redhat.com>" # Primary key fingerprint: FAEB 9711 A12C F475 812F 18F2 88A9 064D 1835 61EB # Subkey fingerprint: F9B7 ABDB BCAC DF95 BE76 CBD0 7DEF 8106 AAFC 390E * remotes/jnsnow/tags/ide-pull-request: (30 commits) ide: introduce ide_transfer_start_norecurse atapi: call ide_set_irq before ide_transfer_start ide: make ide_transfer_stop idempotent ide: call ide_cmd_done from ide_transfer_stop ide: push end_transfer_func out of start_transfer callback, rename callback ahci: move PIO Setup FIS before transfer, fix it for ATAPI commands libqos/ahci: track sector size MAINTAINERS: Add the cdrom-test to John's section tests/cdrom-test: Test that -cdrom parameter is working tests/cdrom-test: Test booting from CD-ROM ISO image file tests/boot-sector: Add magic bytes to s390x boot code header ahci: make ahci_mem_write traces more descriptive ahci: delete old host register address definitions ahci: adjust ahci_mem_write to work on registers ahci: fix spacing damage on ahci_mem_write ahci: make mem_read_32 traces more descriptive ahci: modify ahci_mem_read_32 to work on register numbers ahci: fix host register max address ahci: add host register enumeration ahci: delete old port register address definitions ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
a7a7309ca5
@ -1003,6 +1003,7 @@ F: hw/block/cdrom.c
|
||||
F: hw/block/hd-geometry.c
|
||||
F: tests/ide-test.c
|
||||
F: tests/ahci-test.c
|
||||
F: tests/cdrom-test.c
|
||||
F: tests/libqos/ahci*
|
||||
T: git git://github.com/jnsnow/qemu.git ide
|
||||
|
||||
|
369
hw/ide/ahci.c
369
hw/ide/ahci.c
@ -27,6 +27,7 @@
|
||||
#include "hw/pci/pci.h"
|
||||
|
||||
#include "qemu/error-report.h"
|
||||
#include "qemu/log.h"
|
||||
#include "sysemu/block-backend.h"
|
||||
#include "sysemu/dma.h"
|
||||
#include "hw/ide/internal.h"
|
||||
@ -46,6 +47,44 @@ static bool ahci_map_fis_address(AHCIDevice *ad);
|
||||
static void ahci_unmap_clb_address(AHCIDevice *ad);
|
||||
static void ahci_unmap_fis_address(AHCIDevice *ad);
|
||||
|
||||
static const char *AHCIHostReg_lookup[AHCI_HOST_REG__COUNT] = {
|
||||
[AHCI_HOST_REG_CAP] = "CAP",
|
||||
[AHCI_HOST_REG_CTL] = "GHC",
|
||||
[AHCI_HOST_REG_IRQ_STAT] = "IS",
|
||||
[AHCI_HOST_REG_PORTS_IMPL] = "PI",
|
||||
[AHCI_HOST_REG_VERSION] = "VS",
|
||||
[AHCI_HOST_REG_CCC_CTL] = "CCC_CTL",
|
||||
[AHCI_HOST_REG_CCC_PORTS] = "CCC_PORTS",
|
||||
[AHCI_HOST_REG_EM_LOC] = "EM_LOC",
|
||||
[AHCI_HOST_REG_EM_CTL] = "EM_CTL",
|
||||
[AHCI_HOST_REG_CAP2] = "CAP2",
|
||||
[AHCI_HOST_REG_BOHC] = "BOHC",
|
||||
};
|
||||
|
||||
static const char *AHCIPortReg_lookup[AHCI_PORT_REG__COUNT] = {
|
||||
[AHCI_PORT_REG_LST_ADDR] = "PxCLB",
|
||||
[AHCI_PORT_REG_LST_ADDR_HI] = "PxCLBU",
|
||||
[AHCI_PORT_REG_FIS_ADDR] = "PxFB",
|
||||
[AHCI_PORT_REG_FIS_ADDR_HI] = "PxFBU",
|
||||
[AHCI_PORT_REG_IRQ_STAT] = "PxIS",
|
||||
[AHCI_PORT_REG_IRQ_MASK] = "PXIE",
|
||||
[AHCI_PORT_REG_CMD] = "PxCMD",
|
||||
[7] = "Reserved",
|
||||
[AHCI_PORT_REG_TFDATA] = "PxTFD",
|
||||
[AHCI_PORT_REG_SIG] = "PxSIG",
|
||||
[AHCI_PORT_REG_SCR_STAT] = "PxSSTS",
|
||||
[AHCI_PORT_REG_SCR_CTL] = "PxSCTL",
|
||||
[AHCI_PORT_REG_SCR_ERR] = "PxSERR",
|
||||
[AHCI_PORT_REG_SCR_ACT] = "PxSACT",
|
||||
[AHCI_PORT_REG_CMD_ISSUE] = "PxCI",
|
||||
[AHCI_PORT_REG_SCR_NOTIF] = "PxSNTF",
|
||||
[AHCI_PORT_REG_FIS_CTL] = "PxFBS",
|
||||
[AHCI_PORT_REG_DEV_SLEEP] = "PxDEVSLP",
|
||||
[18 ... 27] = "Reserved",
|
||||
[AHCI_PORT_REG_VENDOR_1 ...
|
||||
AHCI_PORT_REG_VENDOR_4] = "PxVS",
|
||||
};
|
||||
|
||||
static const char *AHCIPortIRQ_lookup[AHCI_PORT_IRQ__COUNT] = {
|
||||
[AHCI_PORT_IRQ_BIT_DHRS] = "DHRS",
|
||||
[AHCI_PORT_IRQ_BIT_PSS] = "PSS",
|
||||
@ -68,41 +107,42 @@ static const char *AHCIPortIRQ_lookup[AHCI_PORT_IRQ__COUNT] = {
|
||||
[AHCI_PORT_IRQ_BIT_CPDS] = "CPDS"
|
||||
};
|
||||
|
||||
static uint32_t ahci_port_read(AHCIState *s, int port, int offset)
|
||||
static uint32_t ahci_port_read(AHCIState *s, int port, int offset)
|
||||
{
|
||||
uint32_t val;
|
||||
AHCIPortRegs *pr;
|
||||
pr = &s->dev[port].port_regs;
|
||||
AHCIPortRegs *pr = &s->dev[port].port_regs;
|
||||
enum AHCIPortReg regnum = offset / sizeof(uint32_t);
|
||||
assert(regnum < (AHCI_PORT_ADDR_OFFSET_LEN / sizeof(uint32_t)));
|
||||
|
||||
switch (offset) {
|
||||
case PORT_LST_ADDR:
|
||||
switch (regnum) {
|
||||
case AHCI_PORT_REG_LST_ADDR:
|
||||
val = pr->lst_addr;
|
||||
break;
|
||||
case PORT_LST_ADDR_HI:
|
||||
case AHCI_PORT_REG_LST_ADDR_HI:
|
||||
val = pr->lst_addr_hi;
|
||||
break;
|
||||
case PORT_FIS_ADDR:
|
||||
case AHCI_PORT_REG_FIS_ADDR:
|
||||
val = pr->fis_addr;
|
||||
break;
|
||||
case PORT_FIS_ADDR_HI:
|
||||
case AHCI_PORT_REG_FIS_ADDR_HI:
|
||||
val = pr->fis_addr_hi;
|
||||
break;
|
||||
case PORT_IRQ_STAT:
|
||||
case AHCI_PORT_REG_IRQ_STAT:
|
||||
val = pr->irq_stat;
|
||||
break;
|
||||
case PORT_IRQ_MASK:
|
||||
case AHCI_PORT_REG_IRQ_MASK:
|
||||
val = pr->irq_mask;
|
||||
break;
|
||||
case PORT_CMD:
|
||||
case AHCI_PORT_REG_CMD:
|
||||
val = pr->cmd;
|
||||
break;
|
||||
case PORT_TFDATA:
|
||||
case AHCI_PORT_REG_TFDATA:
|
||||
val = pr->tfdata;
|
||||
break;
|
||||
case PORT_SIG:
|
||||
case AHCI_PORT_REG_SIG:
|
||||
val = pr->sig;
|
||||
break;
|
||||
case PORT_SCR_STAT:
|
||||
case AHCI_PORT_REG_SCR_STAT:
|
||||
if (s->dev[port].port.ifs[0].blk) {
|
||||
val = SATA_SCR_SSTATUS_DET_DEV_PRESENT_PHY_UP |
|
||||
SATA_SCR_SSTATUS_SPD_GEN1 | SATA_SCR_SSTATUS_IPM_ACTIVE;
|
||||
@ -110,28 +150,29 @@ static uint32_t ahci_port_read(AHCIState *s, int port, int offset)
|
||||
val = SATA_SCR_SSTATUS_DET_NODEV;
|
||||
}
|
||||
break;
|
||||
case PORT_SCR_CTL:
|
||||
case AHCI_PORT_REG_SCR_CTL:
|
||||
val = pr->scr_ctl;
|
||||
break;
|
||||
case PORT_SCR_ERR:
|
||||
case AHCI_PORT_REG_SCR_ERR:
|
||||
val = pr->scr_err;
|
||||
break;
|
||||
case PORT_SCR_ACT:
|
||||
case AHCI_PORT_REG_SCR_ACT:
|
||||
val = pr->scr_act;
|
||||
break;
|
||||
case PORT_CMD_ISSUE:
|
||||
case AHCI_PORT_REG_CMD_ISSUE:
|
||||
val = pr->cmd_issue;
|
||||
break;
|
||||
case PORT_RESERVED:
|
||||
default:
|
||||
trace_ahci_port_read_default(s, port, AHCIPortReg_lookup[regnum],
|
||||
offset);
|
||||
val = 0;
|
||||
}
|
||||
|
||||
trace_ahci_port_read(s, port, offset, val);
|
||||
trace_ahci_port_read(s, port, AHCIPortReg_lookup[regnum], offset, val);
|
||||
return val;
|
||||
}
|
||||
|
||||
static void ahci_irq_raise(AHCIState *s, AHCIDevice *dev)
|
||||
static void ahci_irq_raise(AHCIState *s)
|
||||
{
|
||||
DeviceState *dev_state = s->container;
|
||||
PCIDevice *pci_dev = (PCIDevice *) object_dynamic_cast(OBJECT(dev_state),
|
||||
@ -146,7 +187,7 @@ static void ahci_irq_raise(AHCIState *s, AHCIDevice *dev)
|
||||
}
|
||||
}
|
||||
|
||||
static void ahci_irq_lower(AHCIState *s, AHCIDevice *dev)
|
||||
static void ahci_irq_lower(AHCIState *s)
|
||||
{
|
||||
DeviceState *dev_state = s->container;
|
||||
PCIDevice *pci_dev = (PCIDevice *) object_dynamic_cast(OBJECT(dev_state),
|
||||
@ -174,9 +215,9 @@ static void ahci_check_irq(AHCIState *s)
|
||||
trace_ahci_check_irq(s, old_irq, s->control_regs.irqstatus);
|
||||
if (s->control_regs.irqstatus &&
|
||||
(s->control_regs.ghc & HOST_CTL_IRQ_EN)) {
|
||||
ahci_irq_raise(s, NULL);
|
||||
ahci_irq_raise(s);
|
||||
} else {
|
||||
ahci_irq_lower(s, NULL);
|
||||
ahci_irq_lower(s);
|
||||
}
|
||||
}
|
||||
|
||||
@ -253,85 +294,88 @@ static int ahci_cond_start_engines(AHCIDevice *ad)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ahci_port_write(AHCIState *s, int port, int offset, uint32_t val)
|
||||
static void ahci_port_write(AHCIState *s, int port, int offset, uint32_t val)
|
||||
{
|
||||
AHCIPortRegs *pr = &s->dev[port].port_regs;
|
||||
enum AHCIPortReg regnum = offset / sizeof(uint32_t);
|
||||
assert(regnum < (AHCI_PORT_ADDR_OFFSET_LEN / sizeof(uint32_t)));
|
||||
trace_ahci_port_write(s, port, AHCIPortReg_lookup[regnum], offset, val);
|
||||
|
||||
trace_ahci_port_write(s, port, offset, val);
|
||||
switch (offset) {
|
||||
case PORT_LST_ADDR:
|
||||
pr->lst_addr = val;
|
||||
break;
|
||||
case PORT_LST_ADDR_HI:
|
||||
pr->lst_addr_hi = val;
|
||||
break;
|
||||
case PORT_FIS_ADDR:
|
||||
pr->fis_addr = val;
|
||||
break;
|
||||
case PORT_FIS_ADDR_HI:
|
||||
pr->fis_addr_hi = val;
|
||||
break;
|
||||
case PORT_IRQ_STAT:
|
||||
pr->irq_stat &= ~val;
|
||||
ahci_check_irq(s);
|
||||
break;
|
||||
case PORT_IRQ_MASK:
|
||||
pr->irq_mask = val & 0xfdc000ff;
|
||||
ahci_check_irq(s);
|
||||
break;
|
||||
case PORT_CMD:
|
||||
/* Block any Read-only fields from being set;
|
||||
* including LIST_ON and FIS_ON.
|
||||
* The spec requires to set ICC bits to zero after the ICC change
|
||||
* is done. We don't support ICC state changes, therefore always
|
||||
* force the ICC bits to zero.
|
||||
*/
|
||||
pr->cmd = (pr->cmd & PORT_CMD_RO_MASK) |
|
||||
(val & ~(PORT_CMD_RO_MASK|PORT_CMD_ICC_MASK));
|
||||
switch (regnum) {
|
||||
case AHCI_PORT_REG_LST_ADDR:
|
||||
pr->lst_addr = val;
|
||||
break;
|
||||
case AHCI_PORT_REG_LST_ADDR_HI:
|
||||
pr->lst_addr_hi = val;
|
||||
break;
|
||||
case AHCI_PORT_REG_FIS_ADDR:
|
||||
pr->fis_addr = val;
|
||||
break;
|
||||
case AHCI_PORT_REG_FIS_ADDR_HI:
|
||||
pr->fis_addr_hi = val;
|
||||
break;
|
||||
case AHCI_PORT_REG_IRQ_STAT:
|
||||
pr->irq_stat &= ~val;
|
||||
ahci_check_irq(s);
|
||||
break;
|
||||
case AHCI_PORT_REG_IRQ_MASK:
|
||||
pr->irq_mask = val & 0xfdc000ff;
|
||||
ahci_check_irq(s);
|
||||
break;
|
||||
case AHCI_PORT_REG_CMD:
|
||||
/* Block any Read-only fields from being set;
|
||||
* including LIST_ON and FIS_ON.
|
||||
* The spec requires to set ICC bits to zero after the ICC change
|
||||
* is done. We don't support ICC state changes, therefore always
|
||||
* force the ICC bits to zero.
|
||||
*/
|
||||
pr->cmd = (pr->cmd & PORT_CMD_RO_MASK) |
|
||||
(val & ~(PORT_CMD_RO_MASK | PORT_CMD_ICC_MASK));
|
||||
|
||||
/* Check FIS RX and CLB engines */
|
||||
ahci_cond_start_engines(&s->dev[port]);
|
||||
/* Check FIS RX and CLB engines */
|
||||
ahci_cond_start_engines(&s->dev[port]);
|
||||
|
||||
/* XXX usually the FIS would be pending on the bus here and
|
||||
issuing deferred until the OS enables FIS receival.
|
||||
Instead, we only submit it once - which works in most
|
||||
cases, but is a hack. */
|
||||
if ((pr->cmd & PORT_CMD_FIS_ON) &&
|
||||
!s->dev[port].init_d2h_sent) {
|
||||
ahci_init_d2h(&s->dev[port]);
|
||||
}
|
||||
/* XXX usually the FIS would be pending on the bus here and
|
||||
issuing deferred until the OS enables FIS receival.
|
||||
Instead, we only submit it once - which works in most
|
||||
cases, but is a hack. */
|
||||
if ((pr->cmd & PORT_CMD_FIS_ON) &&
|
||||
!s->dev[port].init_d2h_sent) {
|
||||
ahci_init_d2h(&s->dev[port]);
|
||||
}
|
||||
|
||||
check_cmd(s, port);
|
||||
break;
|
||||
case PORT_TFDATA:
|
||||
/* Read Only. */
|
||||
break;
|
||||
case PORT_SIG:
|
||||
/* Read Only */
|
||||
break;
|
||||
case PORT_SCR_STAT:
|
||||
/* Read Only */
|
||||
break;
|
||||
case PORT_SCR_CTL:
|
||||
if (((pr->scr_ctl & AHCI_SCR_SCTL_DET) == 1) &&
|
||||
((val & AHCI_SCR_SCTL_DET) == 0)) {
|
||||
ahci_reset_port(s, port);
|
||||
}
|
||||
pr->scr_ctl = val;
|
||||
break;
|
||||
case PORT_SCR_ERR:
|
||||
pr->scr_err &= ~val;
|
||||
break;
|
||||
case PORT_SCR_ACT:
|
||||
/* RW1 */
|
||||
pr->scr_act |= val;
|
||||
break;
|
||||
case PORT_CMD_ISSUE:
|
||||
pr->cmd_issue |= val;
|
||||
check_cmd(s, port);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
check_cmd(s, port);
|
||||
break;
|
||||
case AHCI_PORT_REG_TFDATA:
|
||||
case AHCI_PORT_REG_SIG:
|
||||
case AHCI_PORT_REG_SCR_STAT:
|
||||
/* Read Only */
|
||||
break;
|
||||
case AHCI_PORT_REG_SCR_CTL:
|
||||
if (((pr->scr_ctl & AHCI_SCR_SCTL_DET) == 1) &&
|
||||
((val & AHCI_SCR_SCTL_DET) == 0)) {
|
||||
ahci_reset_port(s, port);
|
||||
}
|
||||
pr->scr_ctl = val;
|
||||
break;
|
||||
case AHCI_PORT_REG_SCR_ERR:
|
||||
pr->scr_err &= ~val;
|
||||
break;
|
||||
case AHCI_PORT_REG_SCR_ACT:
|
||||
/* RW1 */
|
||||
pr->scr_act |= val;
|
||||
break;
|
||||
case AHCI_PORT_REG_CMD_ISSUE:
|
||||
pr->cmd_issue |= val;
|
||||
check_cmd(s, port);
|
||||
break;
|
||||
default:
|
||||
trace_ahci_port_write_unimpl(s, port, AHCIPortReg_lookup[regnum],
|
||||
offset, val);
|
||||
qemu_log_mask(LOG_UNIMP, "Attempted write to unimplemented register: "
|
||||
"AHCI port %d register %s, offset 0x%x: 0x%"PRIx32,
|
||||
port, AHCIPortReg_lookup[regnum], offset, val);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -341,28 +385,37 @@ static uint64_t ahci_mem_read_32(void *opaque, hwaddr addr)
|
||||
uint32_t val = 0;
|
||||
|
||||
if (addr < AHCI_GENERIC_HOST_CONTROL_REGS_MAX_ADDR) {
|
||||
switch (addr) {
|
||||
case HOST_CAP:
|
||||
enum AHCIHostReg regnum = addr / 4;
|
||||
assert(regnum < AHCI_HOST_REG__COUNT);
|
||||
|
||||
switch (regnum) {
|
||||
case AHCI_HOST_REG_CAP:
|
||||
val = s->control_regs.cap;
|
||||
break;
|
||||
case HOST_CTL:
|
||||
case AHCI_HOST_REG_CTL:
|
||||
val = s->control_regs.ghc;
|
||||
break;
|
||||
case HOST_IRQ_STAT:
|
||||
case AHCI_HOST_REG_IRQ_STAT:
|
||||
val = s->control_regs.irqstatus;
|
||||
break;
|
||||
case HOST_PORTS_IMPL:
|
||||
case AHCI_HOST_REG_PORTS_IMPL:
|
||||
val = s->control_regs.impl;
|
||||
break;
|
||||
case HOST_VERSION:
|
||||
case AHCI_HOST_REG_VERSION:
|
||||
val = s->control_regs.version;
|
||||
break;
|
||||
default:
|
||||
trace_ahci_mem_read_32_host_default(s, AHCIHostReg_lookup[regnum],
|
||||
addr);
|
||||
}
|
||||
trace_ahci_mem_read_32_host(s, AHCIHostReg_lookup[regnum], addr, val);
|
||||
} else if ((addr >= AHCI_PORT_REGS_START_ADDR) &&
|
||||
(addr < (AHCI_PORT_REGS_START_ADDR +
|
||||
(s->ports * AHCI_PORT_ADDR_OFFSET_LEN)))) {
|
||||
val = ahci_port_read(s, (addr - AHCI_PORT_REGS_START_ADDR) >> 7,
|
||||
addr & AHCI_PORT_ADDR_OFFSET_MASK);
|
||||
} else {
|
||||
trace_ahci_mem_read_32_default(s, addr, val);
|
||||
}
|
||||
|
||||
trace_ahci_mem_read_32(s, addr, val);
|
||||
@ -415,38 +468,53 @@ static void ahci_mem_write(void *opaque, hwaddr addr,
|
||||
}
|
||||
|
||||
if (addr < AHCI_GENERIC_HOST_CONTROL_REGS_MAX_ADDR) {
|
||||
switch (addr) {
|
||||
case HOST_CAP: /* R/WO, RO */
|
||||
/* FIXME handle R/WO */
|
||||
break;
|
||||
case HOST_CTL: /* R/W */
|
||||
if (val & HOST_CTL_RESET) {
|
||||
ahci_reset(s);
|
||||
} else {
|
||||
s->control_regs.ghc = (val & 0x3) | HOST_CTL_AHCI_EN;
|
||||
ahci_check_irq(s);
|
||||
}
|
||||
break;
|
||||
case HOST_IRQ_STAT: /* R/WC, RO */
|
||||
s->control_regs.irqstatus &= ~val;
|
||||
enum AHCIHostReg regnum = addr / 4;
|
||||
assert(regnum < AHCI_HOST_REG__COUNT);
|
||||
|
||||
switch (regnum) {
|
||||
case AHCI_HOST_REG_CAP: /* R/WO, RO */
|
||||
/* FIXME handle R/WO */
|
||||
break;
|
||||
case AHCI_HOST_REG_CTL: /* R/W */
|
||||
if (val & HOST_CTL_RESET) {
|
||||
ahci_reset(s);
|
||||
} else {
|
||||
s->control_regs.ghc = (val & 0x3) | HOST_CTL_AHCI_EN;
|
||||
ahci_check_irq(s);
|
||||
break;
|
||||
case HOST_PORTS_IMPL: /* R/WO, RO */
|
||||
/* FIXME handle R/WO */
|
||||
break;
|
||||
case HOST_VERSION: /* RO */
|
||||
/* FIXME report write? */
|
||||
break;
|
||||
default:
|
||||
trace_ahci_mem_write_unknown(s, size, addr, val);
|
||||
}
|
||||
break;
|
||||
case AHCI_HOST_REG_IRQ_STAT: /* R/WC, RO */
|
||||
s->control_regs.irqstatus &= ~val;
|
||||
ahci_check_irq(s);
|
||||
break;
|
||||
case AHCI_HOST_REG_PORTS_IMPL: /* R/WO, RO */
|
||||
/* FIXME handle R/WO */
|
||||
break;
|
||||
case AHCI_HOST_REG_VERSION: /* RO */
|
||||
/* FIXME report write? */
|
||||
break;
|
||||
default:
|
||||
qemu_log_mask(LOG_UNIMP,
|
||||
"Attempted write to unimplemented register: "
|
||||
"AHCI host register %s, "
|
||||
"offset 0x%"PRIx64": 0x%"PRIx64,
|
||||
AHCIHostReg_lookup[regnum], addr, val);
|
||||
trace_ahci_mem_write_host_unimpl(s, size,
|
||||
AHCIHostReg_lookup[regnum], addr);
|
||||
}
|
||||
trace_ahci_mem_write_host(s, size, AHCIHostReg_lookup[regnum],
|
||||
addr, val);
|
||||
} else if ((addr >= AHCI_PORT_REGS_START_ADDR) &&
|
||||
(addr < (AHCI_PORT_REGS_START_ADDR +
|
||||
(s->ports * AHCI_PORT_ADDR_OFFSET_LEN)))) {
|
||||
(s->ports * AHCI_PORT_ADDR_OFFSET_LEN)))) {
|
||||
ahci_port_write(s, (addr - AHCI_PORT_REGS_START_ADDR) >> 7,
|
||||
addr & AHCI_PORT_ADDR_OFFSET_MASK, val);
|
||||
} else {
|
||||
qemu_log_mask(LOG_UNIMP, "Attempted write to unimplemented register: "
|
||||
"AHCI global register at offset 0x%"PRIx64": 0x%"PRIx64,
|
||||
addr, val);
|
||||
trace_ahci_mem_write_unimpl(s, size, addr, val);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static const MemoryRegionOps ahci_mem_ops = {
|
||||
@ -532,13 +600,6 @@ static void ahci_check_cmd_bh(void *opaque)
|
||||
qemu_bh_delete(ad->check_bh);
|
||||
ad->check_bh = NULL;
|
||||
|
||||
if ((ad->busy_slot != -1) &&
|
||||
!(ad->port.ifs[0].status & (BUSY_STAT|DRQ_STAT))) {
|
||||
/* no longer busy */
|
||||
ad->port_regs.cmd_issue &= ~(1 << ad->busy_slot);
|
||||
ad->busy_slot = -1;
|
||||
}
|
||||
|
||||
check_cmd(ad->hba, ad->port_no);
|
||||
}
|
||||
|
||||
@ -1198,7 +1259,6 @@ static void handle_reg_h2d_fis(AHCIState *s, int port,
|
||||
g_free(pretty_fis);
|
||||
}
|
||||
s->dev[port].done_atapi_packet = false;
|
||||
/* XXX send PIO setup FIS */
|
||||
}
|
||||
|
||||
ide_state->error = 0;
|
||||
@ -1280,8 +1340,8 @@ out:
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* DMA dev <-> ram */
|
||||
static void ahci_start_transfer(IDEDMA *dma)
|
||||
/* Transfer PIO data between RAM and device */
|
||||
static void ahci_pio_transfer(IDEDMA *dma)
|
||||
{
|
||||
AHCIDevice *ad = DO_UPCAST(AHCIDevice, dma, dma);
|
||||
IDEState *s = &ad->port.ifs[0];
|
||||
@ -1292,10 +1352,12 @@ static void ahci_start_transfer(IDEDMA *dma)
|
||||
int is_atapi = opts & AHCI_CMD_ATAPI;
|
||||
int has_sglist = 0;
|
||||
|
||||
/* PIO FIS gets written prior to transfer */
|
||||
ahci_write_fis_pio(ad, size);
|
||||
|
||||
if (is_atapi && !ad->done_atapi_packet) {
|
||||
/* already prepopulated iobuffer */
|
||||
ad->done_atapi_packet = true;
|
||||
size = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
@ -1303,9 +1365,9 @@ static void ahci_start_transfer(IDEDMA *dma)
|
||||
has_sglist = 1;
|
||||
}
|
||||
|
||||
trace_ahci_start_transfer(ad->hba, ad->port_no, is_write ? "writ" : "read",
|
||||
size, is_atapi ? "atapi" : "ata",
|
||||
has_sglist ? "" : "o");
|
||||
trace_ahci_pio_transfer(ad->hba, ad->port_no, is_write ? "writ" : "read",
|
||||
size, is_atapi ? "atapi" : "ata",
|
||||
has_sglist ? "" : "o");
|
||||
|
||||
if (has_sglist && size) {
|
||||
if (is_write) {
|
||||
@ -1315,19 +1377,11 @@ static void ahci_start_transfer(IDEDMA *dma)
|
||||
}
|
||||
}
|
||||
|
||||
/* Update number of transferred bytes, destroy sglist */
|
||||
dma_buf_commit(s, size);
|
||||
out:
|
||||
/* declare that we processed everything */
|
||||
s->data_ptr = s->data_end;
|
||||
|
||||
/* Update number of transferred bytes, destroy sglist */
|
||||
dma_buf_commit(s, size);
|
||||
|
||||
s->end_transfer_func(s);
|
||||
|
||||
if (!(s->status & DRQ_STAT)) {
|
||||
/* done with PIO send/receive */
|
||||
ahci_write_fis_pio(ad, le32_to_cpu(ad->cur_cmd->status));
|
||||
}
|
||||
}
|
||||
|
||||
static void ahci_start_dma(IDEDMA *dma, IDEState *s,
|
||||
@ -1425,11 +1479,16 @@ static void ahci_cmd_done(IDEDMA *dma)
|
||||
|
||||
trace_ahci_cmd_done(ad->hba, ad->port_no);
|
||||
|
||||
/* no longer busy */
|
||||
if (ad->busy_slot != -1) {
|
||||
ad->port_regs.cmd_issue &= ~(1 << ad->busy_slot);
|
||||
ad->busy_slot = -1;
|
||||
}
|
||||
|
||||
/* update d2h status */
|
||||
ahci_write_fis_d2h(ad);
|
||||
|
||||
if (!ad->check_bh) {
|
||||
/* maybe we still have something to process, check later */
|
||||
if (ad->port_regs.cmd_issue && !ad->check_bh) {
|
||||
ad->check_bh = qemu_bh_new(ahci_check_cmd_bh, ad);
|
||||
qemu_bh_schedule(ad->check_bh);
|
||||
}
|
||||
@ -1443,7 +1502,7 @@ static const IDEDMAOps ahci_dma_ops = {
|
||||
.start_dma = ahci_start_dma,
|
||||
.restart = ahci_restart,
|
||||
.restart_dma = ahci_restart_dma,
|
||||
.start_transfer = ahci_start_transfer,
|
||||
.pio_transfer = ahci_pio_transfer,
|
||||
.prepare_buf = ahci_dma_prepare_buf,
|
||||
.commit_buf = ahci_commit_buf,
|
||||
.rw_buf = ahci_dma_rw_buf,
|
||||
|
@ -55,11 +55,20 @@
|
||||
#define RX_FIS_UNK 0x60 /* offset of Unknown FIS data */
|
||||
|
||||
/* global controller registers */
|
||||
#define HOST_CAP 0x00 /* host capabilities */
|
||||
#define HOST_CTL 0x04 /* global host control */
|
||||
#define HOST_IRQ_STAT 0x08 /* interrupt status */
|
||||
#define HOST_PORTS_IMPL 0x0c /* bitmap of implemented ports */
|
||||
#define HOST_VERSION 0x10 /* AHCI spec. version compliancy */
|
||||
enum AHCIHostReg {
|
||||
AHCI_HOST_REG_CAP = 0, /* CAP: host capabilities */
|
||||
AHCI_HOST_REG_CTL = 1, /* GHC: global host control */
|
||||
AHCI_HOST_REG_IRQ_STAT = 2, /* IS: interrupt status */
|
||||
AHCI_HOST_REG_PORTS_IMPL = 3, /* PI: bitmap of implemented ports */
|
||||
AHCI_HOST_REG_VERSION = 4, /* VS: AHCI spec. version compliancy */
|
||||
AHCI_HOST_REG_CCC_CTL = 5, /* CCC_CTL: CCC Control */
|
||||
AHCI_HOST_REG_CCC_PORTS = 6, /* CCC_PORTS: CCC Ports */
|
||||
AHCI_HOST_REG_EM_LOC = 7, /* EM_LOC: Enclosure Mgmt Location */
|
||||
AHCI_HOST_REG_EM_CTL = 8, /* EM_CTL: Enclosure Mgmt Control */
|
||||
AHCI_HOST_REG_CAP2 = 9, /* CAP2: host capabilities, extended */
|
||||
AHCI_HOST_REG_BOHC = 10, /* BOHC: firmare/os handoff ctrl & status */
|
||||
AHCI_HOST_REG__COUNT = 11
|
||||
};
|
||||
|
||||
/* HOST_CTL bits */
|
||||
#define HOST_CTL_RESET (1 << 0) /* reset controller; self-clear */
|
||||
@ -75,21 +84,32 @@
|
||||
#define HOST_CAP_64 (1U << 31) /* PCI DAC (64-bit DMA) support */
|
||||
|
||||
/* registers for each SATA port */
|
||||
#define PORT_LST_ADDR 0x00 /* command list DMA addr */
|
||||
#define PORT_LST_ADDR_HI 0x04 /* command list DMA addr hi */
|
||||
#define PORT_FIS_ADDR 0x08 /* FIS rx buf addr */
|
||||
#define PORT_FIS_ADDR_HI 0x0c /* FIS rx buf addr hi */
|
||||
#define PORT_IRQ_STAT 0x10 /* interrupt status */
|
||||
#define PORT_IRQ_MASK 0x14 /* interrupt enable/disable mask */
|
||||
#define PORT_CMD 0x18 /* port command */
|
||||
#define PORT_TFDATA 0x20 /* taskfile data */
|
||||
#define PORT_SIG 0x24 /* device TF signature */
|
||||
#define PORT_SCR_STAT 0x28 /* SATA phy register: SStatus */
|
||||
#define PORT_SCR_CTL 0x2c /* SATA phy register: SControl */
|
||||
#define PORT_SCR_ERR 0x30 /* SATA phy register: SError */
|
||||
#define PORT_SCR_ACT 0x34 /* SATA phy register: SActive */
|
||||
#define PORT_CMD_ISSUE 0x38 /* command issue */
|
||||
#define PORT_RESERVED 0x3c /* reserved */
|
||||
enum AHCIPortReg {
|
||||
AHCI_PORT_REG_LST_ADDR = 0, /* PxCLB: command list DMA addr */
|
||||
AHCI_PORT_REG_LST_ADDR_HI = 1, /* PxCLBU: command list DMA addr hi */
|
||||
AHCI_PORT_REG_FIS_ADDR = 2, /* PxFB: FIS rx buf addr */
|
||||
AHCI_PORT_REG_FIS_ADDR_HI = 3, /* PxFBU: FIX rx buf addr hi */
|
||||
AHCI_PORT_REG_IRQ_STAT = 4, /* PxIS: interrupt status */
|
||||
AHCI_PORT_REG_IRQ_MASK = 5, /* PxIE: interrupt enable/disable mask */
|
||||
AHCI_PORT_REG_CMD = 6, /* PxCMD: port command */
|
||||
/* RESERVED */
|
||||
AHCI_PORT_REG_TFDATA = 8, /* PxTFD: taskfile data */
|
||||
AHCI_PORT_REG_SIG = 9, /* PxSIG: device TF signature */
|
||||
AHCI_PORT_REG_SCR_STAT = 10, /* PxSSTS: SATA phy register: SStatus */
|
||||
AHCI_PORT_REG_SCR_CTL = 11, /* PxSCTL: SATA phy register: SControl */
|
||||
AHCI_PORT_REG_SCR_ERR = 12, /* PxSERR: SATA phy register: SError */
|
||||
AHCI_PORT_REG_SCR_ACT = 13, /* PxSACT: SATA phy register: SActive */
|
||||
AHCI_PORT_REG_CMD_ISSUE = 14, /* PxCI: command issue */
|
||||
AHCI_PORT_REG_SCR_NOTIF = 15, /* PxSNTF: SATA phy register: SNotification */
|
||||
AHCI_PORT_REG_FIS_CTL = 16, /* PxFBS: Port multiplier switching ctl */
|
||||
AHCI_PORT_REG_DEV_SLEEP = 17, /* PxDEVSLP: device sleep control */
|
||||
/* RESERVED */
|
||||
AHCI_PORT_REG_VENDOR_1 = 28, /* PxVS: Vendor Specific */
|
||||
AHCI_PORT_REG_VENDOR_2 = 29,
|
||||
AHCI_PORT_REG_VENDOR_3 = 30,
|
||||
AHCI_PORT_REG_VENDOR_4 = 31,
|
||||
AHCI_PORT_REG__COUNT = 32
|
||||
};
|
||||
|
||||
/* Port interrupt bit descriptors */
|
||||
enum AHCIPortIRQ {
|
||||
@ -198,8 +218,7 @@ enum AHCIPortIRQ {
|
||||
#define SATA_SIGNATURE_CDROM 0xeb140101
|
||||
#define SATA_SIGNATURE_DISK 0x00000101
|
||||
|
||||
#define AHCI_GENERIC_HOST_CONTROL_REGS_MAX_ADDR 0x20
|
||||
/* Shouldn't this be 0x2c? */
|
||||
#define AHCI_GENERIC_HOST_CONTROL_REGS_MAX_ADDR 0x2c
|
||||
|
||||
#define AHCI_PORT_REGS_START_ADDR 0x100
|
||||
#define AHCI_PORT_ADDR_OFFSET_MASK 0x7f
|
||||
|
@ -245,15 +245,11 @@ static uint16_t atapi_byte_count_limit(IDEState *s)
|
||||
void ide_atapi_cmd_reply_end(IDEState *s)
|
||||
{
|
||||
int byte_count_limit, size, ret;
|
||||
trace_ide_atapi_cmd_reply_end(s, s->packet_transfer_size,
|
||||
s->elementary_transfer_size,
|
||||
s->io_buffer_index);
|
||||
if (s->packet_transfer_size <= 0) {
|
||||
/* end of transfer */
|
||||
ide_atapi_cmd_ok(s);
|
||||
ide_set_irq(s->bus);
|
||||
trace_ide_atapi_cmd_reply_end_eot(s, s->status);
|
||||
} else {
|
||||
while (s->packet_transfer_size > 0) {
|
||||
trace_ide_atapi_cmd_reply_end(s, s->packet_transfer_size,
|
||||
s->elementary_transfer_size,
|
||||
s->io_buffer_index);
|
||||
|
||||
/* see if a new sector must be read */
|
||||
if (s->lba != -1 && s->io_buffer_index >= s->cd_sector_size) {
|
||||
if (!s->elementary_transfer_size) {
|
||||
@ -279,14 +275,10 @@ void ide_atapi_cmd_reply_end(IDEState *s)
|
||||
size = s->cd_sector_size - s->io_buffer_index;
|
||||
if (size > s->elementary_transfer_size)
|
||||
size = s->elementary_transfer_size;
|
||||
s->packet_transfer_size -= size;
|
||||
s->elementary_transfer_size -= size;
|
||||
s->io_buffer_index += size;
|
||||
ide_transfer_start(s, s->io_buffer + s->io_buffer_index - size,
|
||||
size, ide_atapi_cmd_reply_end);
|
||||
} else {
|
||||
/* a new transfer is needed */
|
||||
s->nsector = (s->nsector & ~7) | ATAPI_INT_REASON_IO;
|
||||
ide_set_irq(s->bus);
|
||||
byte_count_limit = atapi_byte_count_limit(s);
|
||||
trace_ide_atapi_cmd_reply_end_bcl(s, byte_count_limit);
|
||||
size = s->packet_transfer_size;
|
||||
@ -304,15 +296,27 @@ void ide_atapi_cmd_reply_end(IDEState *s)
|
||||
if (size > (s->cd_sector_size - s->io_buffer_index))
|
||||
size = (s->cd_sector_size - s->io_buffer_index);
|
||||
}
|
||||
s->packet_transfer_size -= size;
|
||||
s->elementary_transfer_size -= size;
|
||||
s->io_buffer_index += size;
|
||||
ide_transfer_start(s, s->io_buffer + s->io_buffer_index - size,
|
||||
size, ide_atapi_cmd_reply_end);
|
||||
ide_set_irq(s->bus);
|
||||
trace_ide_atapi_cmd_reply_end_new(s, s->status);
|
||||
}
|
||||
s->packet_transfer_size -= size;
|
||||
s->elementary_transfer_size -= size;
|
||||
s->io_buffer_index += size;
|
||||
|
||||
/* Some adapters process PIO data right away. In that case, we need
|
||||
* to avoid mutual recursion between ide_transfer_start
|
||||
* and ide_atapi_cmd_reply_end.
|
||||
*/
|
||||
if (!ide_transfer_start_norecurse(s,
|
||||
s->io_buffer + s->io_buffer_index - size,
|
||||
size, ide_atapi_cmd_reply_end)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* end of transfer */
|
||||
trace_ide_atapi_cmd_reply_end_eot(s, s->status);
|
||||
ide_atapi_cmd_ok(s);
|
||||
ide_set_irq(s->bus);
|
||||
}
|
||||
|
||||
/* send a reply of 'size' bytes in s->io_buffer to an ATAPI command */
|
||||
|
@ -523,18 +523,28 @@ static void ide_clear_retry(IDEState *s)
|
||||
}
|
||||
|
||||
/* prepare data transfer and tell what to do after */
|
||||
void ide_transfer_start(IDEState *s, uint8_t *buf, int size,
|
||||
EndTransferFunc *end_transfer_func)
|
||||
bool ide_transfer_start_norecurse(IDEState *s, uint8_t *buf, int size,
|
||||
EndTransferFunc *end_transfer_func)
|
||||
{
|
||||
s->end_transfer_func = end_transfer_func;
|
||||
s->data_ptr = buf;
|
||||
s->data_end = buf + size;
|
||||
ide_set_retry(s);
|
||||
if (!(s->status & ERR_STAT)) {
|
||||
s->status |= DRQ_STAT;
|
||||
}
|
||||
if (s->bus->dma->ops->start_transfer) {
|
||||
s->bus->dma->ops->start_transfer(s->bus->dma);
|
||||
if (!s->bus->dma->ops->pio_transfer) {
|
||||
s->end_transfer_func = end_transfer_func;
|
||||
return false;
|
||||
}
|
||||
s->bus->dma->ops->pio_transfer(s->bus->dma);
|
||||
return true;
|
||||
}
|
||||
|
||||
void ide_transfer_start(IDEState *s, uint8_t *buf, int size,
|
||||
EndTransferFunc *end_transfer_func)
|
||||
{
|
||||
if (ide_transfer_start_norecurse(s, buf, size, end_transfer_func)) {
|
||||
end_transfer_func(s);
|
||||
}
|
||||
}
|
||||
|
||||
@ -545,27 +555,18 @@ static void ide_cmd_done(IDEState *s)
|
||||
}
|
||||
}
|
||||
|
||||
static void ide_transfer_halt(IDEState *s,
|
||||
void(*end_transfer_func)(IDEState *),
|
||||
bool notify)
|
||||
static void ide_transfer_halt(IDEState *s)
|
||||
{
|
||||
s->end_transfer_func = end_transfer_func;
|
||||
s->end_transfer_func = ide_transfer_stop;
|
||||
s->data_ptr = s->io_buffer;
|
||||
s->data_end = s->io_buffer;
|
||||
s->status &= ~DRQ_STAT;
|
||||
if (notify) {
|
||||
ide_cmd_done(s);
|
||||
}
|
||||
}
|
||||
|
||||
void ide_transfer_stop(IDEState *s)
|
||||
{
|
||||
ide_transfer_halt(s, ide_transfer_stop, true);
|
||||
}
|
||||
|
||||
static void ide_transfer_cancel(IDEState *s)
|
||||
{
|
||||
ide_transfer_halt(s, ide_transfer_cancel, false);
|
||||
ide_transfer_halt(s);
|
||||
ide_cmd_done(s);
|
||||
}
|
||||
|
||||
int64_t ide_get_sector(IDEState *s)
|
||||
@ -1362,7 +1363,7 @@ static bool cmd_nop(IDEState *s, uint8_t cmd)
|
||||
static bool cmd_device_reset(IDEState *s, uint8_t cmd)
|
||||
{
|
||||
/* Halt PIO (in the DRQ phase), then DMA */
|
||||
ide_transfer_cancel(s);
|
||||
ide_transfer_halt(s);
|
||||
ide_cancel_dma_sync(s);
|
||||
|
||||
/* Reset any PIO commands, reset signature, etc */
|
||||
|
@ -63,16 +63,23 @@ ide_atapi_cmd_read_dma_cb_aio(void *s, int lba, int n) "IDEState: %p; aio read:
|
||||
ide_atapi_cmd_packet(void *s, uint16_t limit, const char *packet) "IDEState: %p; limit=0x%x packet: %s"
|
||||
|
||||
# hw/ide/ahci.c
|
||||
ahci_port_read(void *s, int port, int offset, uint32_t ret) "ahci(%p)[%d]: port read @ 0x%x: 0x%08x"
|
||||
ahci_port_read(void *s, int port, const char *reg, int offset, uint32_t ret) "ahci(%p)[%d]: port read [reg:%s] @ 0x%x: 0x%08x"
|
||||
ahci_port_read_default(void *s, int port, const char *reg, int offset) "ahci(%p)[%d]: unimplemented port read [reg:%s] @ 0x%x"
|
||||
ahci_irq_raise(void *s) "ahci(%p): raise irq"
|
||||
ahci_irq_lower(void *s) "ahci(%p): lower irq"
|
||||
ahci_check_irq(void *s, uint32_t old, uint32_t new) "ahci(%p): check irq 0x%08x --> 0x%08x"
|
||||
ahci_trigger_irq(void *s, int port, const char *name, uint32_t val, uint32_t old, uint32_t new, uint32_t effective) "ahci(%p)[%d]: trigger irq +%s (0x%08x); irqstat: 0x%08x --> 0x%08x; effective: 0x%08x"
|
||||
ahci_port_write(void *s, int port, int offset, uint32_t val) "ahci(%p)[%d]: port write @ 0x%x: 0x%08x"
|
||||
ahci_port_write(void *s, int port, const char *reg, int offset, uint32_t val) "ahci(%p)[%d]: port write [reg:%s] @ 0x%x: 0x%08x"
|
||||
ahci_port_write_unimpl(void *s, int port, const char *reg, int offset, uint32_t val) "ahci(%p)[%d]: unimplemented port write [reg:%s] @ 0x%x: 0x%08x"
|
||||
ahci_mem_read_32(void *s, uint64_t addr, uint32_t val) "ahci(%p): mem read @ 0x%"PRIx64": 0x%08x"
|
||||
ahci_mem_read_32_default(void *s, uint64_t addr, uint32_t val) "ahci(%p): mem read @ 0x%"PRIx64": 0x%08x"
|
||||
ahci_mem_read_32_host(void *s, const char *reg, uint64_t addr, uint32_t val) "ahci(%p): mem read [reg:%s] @ 0x%"PRIx64": 0x%08x"
|
||||
ahci_mem_read_32_host_default(void *s, const char *reg, uint64_t addr) "ahci(%p): unimplemented mem read [reg:%s] @ 0x%"PRIx64
|
||||
ahci_mem_read(void *s, unsigned size, uint64_t addr, uint64_t val) "ahci(%p): read%u @ 0x%"PRIx64": 0x%016"PRIx64
|
||||
ahci_mem_write(void *s, unsigned size, uint64_t addr, uint64_t val) "ahci(%p): write%u @ 0x%"PRIx64": 0x%016"PRIx64
|
||||
ahci_mem_write_unknown(void *s, unsigned size, uint64_t addr, uint64_t val) "ahci(%p): write%u to unknown register 0x%"PRIx64": 0x%016"PRIx64
|
||||
ahci_mem_write_host_unimpl(void *s, unsigned size, const char *reg, uint64_t addr) "ahci(%p) unimplemented write%u [reg:%s] @ 0x%"PRIx64
|
||||
ahci_mem_write_host(void *s, unsigned size, const char *reg, uint64_t addr, uint64_t val) "ahci(%p) write%u [reg:%s] @ 0x%"PRIx64": 0x%016"PRIx64
|
||||
ahci_mem_write_unimpl(void *s, unsigned size, uint64_t addr, uint64_t val) "ahci(%p): write%u to unknown register 0x%"PRIx64": 0x%016"PRIx64
|
||||
ahci_set_signature(void *s, int port, uint8_t nsector, uint8_t sector, uint8_t lcyl, uint8_t hcyl, uint32_t sig) "ahci(%p)[%d]: set signature sector:0x%02x nsector:0x%02x lcyl:0x%02x hcyl:0x%02x (cumulatively: 0x%08x)"
|
||||
ahci_reset_port(void *s, int port) "ahci(%p)[%d]: reset port"
|
||||
ahci_unmap_fis_address_null(void *s, int port) "ahci(%p)[%d]: Attempt to unmap NULL FIS address"
|
||||
@ -101,7 +108,7 @@ handle_cmd_badport(void *s, int port) "ahci(%p)[%d]: guest accessed unused port"
|
||||
handle_cmd_badfis(void *s, int port) "ahci(%p)[%d]: guest provided an invalid cmd FIS"
|
||||
handle_cmd_badmap(void *s, int port, uint64_t len) "ahci(%p)[%d]: dma_memory_map failed, 0x%02"PRIx64" != 0x80"
|
||||
handle_cmd_unhandled_fis(void *s, int port, uint8_t b0, uint8_t b1, uint8_t b2) "ahci(%p)[%d]: unhandled FIS type. cmd_fis: 0x%02x-%02x-%02x"
|
||||
ahci_start_transfer(void *s, int port, const char *rw, uint32_t size, const char *tgt, const char *sgl) "ahci(%p)[%d]: %sing %d bytes on %s w/%s sglist"
|
||||
ahci_pio_transfer(void *s, int port, const char *rw, uint32_t size, const char *tgt, const char *sgl) "ahci(%p)[%d]: %sing %d bytes on %s w/%s sglist"
|
||||
ahci_start_dma(void *s, int port) "ahci(%p)[%d]: start dma"
|
||||
ahci_dma_prepare_buf(void *s, int port, int32_t io_buffer_size, int32_t limit) "ahci(%p)[%d]: prepare buf limit=%"PRId32" prepared=%"PRId32
|
||||
ahci_dma_prepare_buf_fail(void *s, int port) "ahci(%p)[%d]: sglist population failed"
|
||||
|
@ -444,7 +444,7 @@ struct IDEState {
|
||||
|
||||
struct IDEDMAOps {
|
||||
DMAStartFunc *start_dma;
|
||||
DMAVoidFunc *start_transfer;
|
||||
DMAVoidFunc *pio_transfer;
|
||||
DMAInt32Func *prepare_buf;
|
||||
DMAu32Func *commit_buf;
|
||||
DMAIntFunc *rw_buf;
|
||||
@ -623,6 +623,8 @@ void ide_exec_cmd(IDEBus *bus, uint32_t val);
|
||||
|
||||
void ide_transfer_start(IDEState *s, uint8_t *buf, int size,
|
||||
EndTransferFunc *end_transfer_func);
|
||||
bool ide_transfer_start_norecurse(IDEState *s, uint8_t *buf, int size,
|
||||
EndTransferFunc *end_transfer_func);
|
||||
void ide_transfer_stop(IDEState *s);
|
||||
void ide_set_inactive(IDEState *s, bool more);
|
||||
BlockAIOCB *ide_issue_trim(
|
||||
|
@ -179,6 +179,7 @@ check-qtest-generic-y = tests/qmp-test$(EXESUF)
|
||||
gcov-files-generic-y = monitor.c qapi/qmp-dispatch.c
|
||||
check-qtest-generic-y += tests/device-introspect-test$(EXESUF)
|
||||
gcov-files-generic-y = qdev-monitor.c qmp.c
|
||||
check-qtest-generic-y += tests/cdrom-test$(EXESUF)
|
||||
|
||||
gcov-files-ipack-y += hw/ipack/ipack.c
|
||||
check-qtest-ipack-y += tests/ipoctal232-test$(EXESUF)
|
||||
@ -844,6 +845,7 @@ tests/test-qapi-util$(EXESUF): tests/test-qapi-util.o $(test-util-obj-y)
|
||||
tests/numa-test$(EXESUF): tests/numa-test.o
|
||||
tests/vmgenid-test$(EXESUF): tests/vmgenid-test.o tests/boot-sector.o tests/acpi-utils.o
|
||||
tests/sdhci-test$(EXESUF): tests/sdhci-test.o $(libqos-pc-obj-y)
|
||||
tests/cdrom-test$(EXESUF): tests/cdrom-test.o tests/boot-sector.o $(libqos-obj-y)
|
||||
|
||||
tests/migration/stress$(EXESUF): tests/migration/stress.o
|
||||
$(call quiet-command, $(LINKPROG) -static -O3 $(PTHREAD_LIB) -o $@ $< ,"LINK","$(TARGET_DIR)$@")
|
||||
|
@ -68,8 +68,11 @@ static uint8_t x86_boot_sector[512] = {
|
||||
};
|
||||
|
||||
/* For s390x, use a mini "kernel" with the appropriate signature */
|
||||
static const uint8_t s390x_psw[] = {
|
||||
0x00, 0x08, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00
|
||||
static const uint8_t s390x_psw_and_magic[] = {
|
||||
0x00, 0x08, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, /* Program status word */
|
||||
0x02, 0x00, 0x00, 0x18, 0x60, 0x00, 0x00, 0x50, /* Magic: */
|
||||
0x02, 0x00, 0x00, 0x68, 0x60, 0x00, 0x00, 0x50, /* see linux_s390_magic */
|
||||
0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40 /* in the s390-ccw bios */
|
||||
};
|
||||
static const uint8_t s390x_code[] = {
|
||||
0xa7, 0xf4, 0x00, 0x0a, /* j 0x10010 */
|
||||
@ -110,7 +113,7 @@ int boot_sector_init(char *fname)
|
||||
} else if (g_str_equal(arch, "s390x")) {
|
||||
len = 0x10000 + sizeof(s390x_code);
|
||||
boot_code = g_malloc0(len);
|
||||
memcpy(boot_code, s390x_psw, sizeof(s390x_psw));
|
||||
memcpy(boot_code, s390x_psw_and_magic, sizeof(s390x_psw_and_magic));
|
||||
memcpy(&boot_code[0x10000], s390x_code, sizeof(s390x_code));
|
||||
} else {
|
||||
g_assert_not_reached();
|
||||
|
222
tests/cdrom-test.c
Normal file
222
tests/cdrom-test.c
Normal file
@ -0,0 +1,222 @@
|
||||
/*
|
||||
* Various tests for emulated CD-ROM drives.
|
||||
*
|
||||
* Copyright (c) 2018 Red Hat Inc.
|
||||
*
|
||||
* Author:
|
||||
* Thomas Huth <thuth@redhat.com>
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2
|
||||
* or later. See the COPYING file in the top-level directory.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "libqtest.h"
|
||||
#include "boot-sector.h"
|
||||
#include "qapi/qmp/qdict.h"
|
||||
|
||||
static char isoimage[] = "cdrom-boot-iso-XXXXXX";
|
||||
|
||||
static int exec_genisoimg(const char **args)
|
||||
{
|
||||
gchar *out_err = NULL;
|
||||
gint exit_status = -1;
|
||||
bool success;
|
||||
|
||||
success = g_spawn_sync(NULL, (gchar **)args, NULL,
|
||||
G_SPAWN_SEARCH_PATH | G_SPAWN_STDOUT_TO_DEV_NULL,
|
||||
NULL, NULL, NULL, &out_err, &exit_status, NULL);
|
||||
if (!success) {
|
||||
return -ENOENT;
|
||||
}
|
||||
if (out_err) {
|
||||
fputs(out_err, stderr);
|
||||
g_free(out_err);
|
||||
}
|
||||
|
||||
return exit_status;
|
||||
}
|
||||
|
||||
static int prepare_image(const char *arch, char *isoimage)
|
||||
{
|
||||
char srcdir[] = "cdrom-test-dir-XXXXXX";
|
||||
char *codefile = NULL;
|
||||
int ifh, ret = -1;
|
||||
const char *args[] = {
|
||||
"genisoimage", "-quiet", "-l", "-no-emul-boot",
|
||||
"-b", NULL, "-o", isoimage, srcdir, NULL
|
||||
};
|
||||
|
||||
ifh = mkstemp(isoimage);
|
||||
if (ifh < 0) {
|
||||
perror("Error creating temporary iso image file");
|
||||
return -1;
|
||||
}
|
||||
if (!mkdtemp(srcdir)) {
|
||||
perror("Error creating temporary directory");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (g_str_equal(arch, "i386") || g_str_equal(arch, "x86_64") ||
|
||||
g_str_equal(arch, "s390x")) {
|
||||
codefile = g_strdup_printf("%s/bootcode-XXXXXX", srcdir);
|
||||
ret = boot_sector_init(codefile);
|
||||
if (ret) {
|
||||
goto cleanup;
|
||||
}
|
||||
} else {
|
||||
/* Just create a dummy file */
|
||||
char txt[] = "empty disc";
|
||||
codefile = g_strdup_printf("%s/readme.txt", srcdir);
|
||||
if (!g_file_set_contents(codefile, txt, sizeof(txt) - 1, NULL)) {
|
||||
fprintf(stderr, "Failed to create '%s'\n", codefile);
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
args[5] = strchr(codefile, '/') + 1;
|
||||
ret = exec_genisoimg(args);
|
||||
if (ret) {
|
||||
fprintf(stderr, "genisoimage failed: %i\n", ret);
|
||||
}
|
||||
|
||||
unlink(codefile);
|
||||
|
||||
cleanup:
|
||||
g_free(codefile);
|
||||
rmdir(srcdir);
|
||||
close(ifh);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check that at least the -cdrom parameter is basically working, i.e. we can
|
||||
* see the filename of the ISO image in the output of "info block" afterwards
|
||||
*/
|
||||
static void test_cdrom_param(gconstpointer data)
|
||||
{
|
||||
QTestState *qts;
|
||||
char *resp;
|
||||
|
||||
qts = qtest_startf("-M %s -cdrom %s", (const char *)data, isoimage);
|
||||
resp = qtest_hmp(qts, "info block");
|
||||
g_assert(strstr(resp, isoimage) != 0);
|
||||
g_free(resp);
|
||||
qtest_quit(qts);
|
||||
}
|
||||
|
||||
static void add_cdrom_param_tests(const char **machines)
|
||||
{
|
||||
while (*machines) {
|
||||
char *testname = g_strdup_printf("cdrom/param/%s", *machines);
|
||||
qtest_add_data_func(testname, *machines, test_cdrom_param);
|
||||
g_free(testname);
|
||||
machines++;
|
||||
}
|
||||
}
|
||||
|
||||
static void test_cdboot(gconstpointer data)
|
||||
{
|
||||
QTestState *qts;
|
||||
|
||||
qts = qtest_startf("-accel kvm:tcg -no-shutdown %s%s", (const char *)data,
|
||||
isoimage);
|
||||
boot_sector_test(qts);
|
||||
qtest_quit(qts);
|
||||
}
|
||||
|
||||
static void add_x86_tests(void)
|
||||
{
|
||||
qtest_add_data_func("cdrom/boot/default", "-cdrom ", test_cdboot);
|
||||
qtest_add_data_func("cdrom/boot/virtio-scsi",
|
||||
"-device virtio-scsi -device scsi-cd,drive=cdr "
|
||||
"-blockdev file,node-name=cdr,filename=", test_cdboot);
|
||||
qtest_add_data_func("cdrom/boot/isapc", "-M isapc "
|
||||
"-drive if=ide,media=cdrom,file=", test_cdboot);
|
||||
qtest_add_data_func("cdrom/boot/am53c974",
|
||||
"-device am53c974 -device scsi-cd,drive=cd1 "
|
||||
"-drive if=none,id=cd1,format=raw,file=", test_cdboot);
|
||||
qtest_add_data_func("cdrom/boot/dc390",
|
||||
"-device dc390 -device scsi-cd,drive=cd1 "
|
||||
"-blockdev file,node-name=cd1,filename=", test_cdboot);
|
||||
qtest_add_data_func("cdrom/boot/lsi53c895a",
|
||||
"-device lsi53c895a -device scsi-cd,drive=cd1 "
|
||||
"-blockdev file,node-name=cd1,filename=", test_cdboot);
|
||||
qtest_add_data_func("cdrom/boot/megasas", "-M q35 "
|
||||
"-device megasas -device scsi-cd,drive=cd1 "
|
||||
"-blockdev file,node-name=cd1,filename=", test_cdboot);
|
||||
qtest_add_data_func("cdrom/boot/megasas-gen2", "-M q35 "
|
||||
"-device megasas-gen2 -device scsi-cd,drive=cd1 "
|
||||
"-blockdev file,node-name=cd1,filename=", test_cdboot);
|
||||
}
|
||||
|
||||
static void add_s390x_tests(void)
|
||||
{
|
||||
qtest_add_data_func("cdrom/boot/default", "-cdrom ", test_cdboot);
|
||||
qtest_add_data_func("cdrom/boot/virtio-scsi",
|
||||
"-device virtio-scsi -device scsi-cd,drive=cdr "
|
||||
"-blockdev file,node-name=cdr,filename=", test_cdboot);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int ret;
|
||||
const char *arch = qtest_get_arch();
|
||||
const char *genisocheck[] = { "genisoimage", "-version", NULL };
|
||||
|
||||
g_test_init(&argc, &argv, NULL);
|
||||
|
||||
if (exec_genisoimg(genisocheck)) {
|
||||
/* genisoimage not available - so can't run tests */
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = prepare_image(arch, isoimage);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (g_str_equal(arch, "i386") || g_str_equal(arch, "x86_64")) {
|
||||
add_x86_tests();
|
||||
} else if (g_str_equal(arch, "s390x")) {
|
||||
add_s390x_tests();
|
||||
} else if (g_str_equal(arch, "ppc64")) {
|
||||
const char *ppcmachines[] = {
|
||||
"pseries", "mac99", "g3beige", "40p", "prep", NULL
|
||||
};
|
||||
add_cdrom_param_tests(ppcmachines);
|
||||
} else if (g_str_equal(arch, "sparc")) {
|
||||
const char *sparcmachines[] = {
|
||||
"LX", "SPARCClassic", "SPARCbook", "SS-10", "SS-20", "SS-4",
|
||||
"SS-5", "SS-600MP", "Voyager", "leon3_generic", NULL
|
||||
};
|
||||
add_cdrom_param_tests(sparcmachines);
|
||||
} else if (g_str_equal(arch, "sparc64")) {
|
||||
const char *sparc64machines[] = {
|
||||
"niagara", "sun4u", "sun4v", NULL
|
||||
};
|
||||
add_cdrom_param_tests(sparc64machines);
|
||||
} else if (!strncmp(arch, "mips64", 6)) {
|
||||
const char *mips64machines[] = {
|
||||
"magnum", "malta", "mips", "pica61", NULL
|
||||
};
|
||||
add_cdrom_param_tests(mips64machines);
|
||||
} else if (g_str_equal(arch, "arm") || g_str_equal(arch, "aarch64")) {
|
||||
const char *armmachines[] = {
|
||||
"realview-eb", "realview-eb-mpcore", "realview-pb-a8",
|
||||
"realview-pbx-a9", "versatileab", "versatilepb", "vexpress-a15",
|
||||
"vexpress-a9", "virt", NULL
|
||||
};
|
||||
add_cdrom_param_tests(armmachines);
|
||||
} else {
|
||||
const char *nonemachine[] = { "none", NULL };
|
||||
add_cdrom_param_tests(nonemachine);
|
||||
}
|
||||
|
||||
ret = g_test_run();
|
||||
|
||||
unlink(isoimage);
|
||||
|
||||
return ret;
|
||||
}
|
@ -90,6 +90,7 @@ struct AHCICommand {
|
||||
uint32_t interrupts;
|
||||
uint64_t xbytes;
|
||||
uint32_t prd_size;
|
||||
uint32_t sector_size;
|
||||
uint64_t buffer;
|
||||
AHCICommandProp *props;
|
||||
/* Data to be transferred to the guest */
|
||||
@ -477,10 +478,10 @@ void ahci_port_check_d2h_sanity(AHCIQState *ahci, uint8_t port, uint8_t slot)
|
||||
g_free(d2h);
|
||||
}
|
||||
|
||||
void ahci_port_check_pio_sanity(AHCIQState *ahci, uint8_t port,
|
||||
uint8_t slot, size_t buffsize)
|
||||
void ahci_port_check_pio_sanity(AHCIQState *ahci, AHCICommand *cmd)
|
||||
{
|
||||
PIOSetupFIS *pio = g_malloc0(0x20);
|
||||
uint8_t port = cmd->port;
|
||||
|
||||
/* We cannot check the Status or E_Status registers, because
|
||||
* the status may have again changed between the PIO Setup FIS
|
||||
@ -488,15 +489,22 @@ void ahci_port_check_pio_sanity(AHCIQState *ahci, uint8_t port,
|
||||
qtest_memread(ahci->parent->qts, ahci->port[port].fb + 0x20, pio, 0x20);
|
||||
g_assert_cmphex(pio->fis_type, ==, 0x5f);
|
||||
|
||||
/* BUG: PIO Setup FIS as utilized by QEMU tries to fit the entire
|
||||
* transfer size in a uint16_t field. The maximum transfer size can
|
||||
* eclipse this; the field is meant to convey the size of data per
|
||||
* each Data FIS, not the entire operation as a whole. For now,
|
||||
* we will sanity check the broken case where applicable. */
|
||||
if (buffsize <= UINT16_MAX) {
|
||||
g_assert_cmphex(le16_to_cpu(pio->tx_count), ==, buffsize);
|
||||
/* Data transferred by PIO will either be:
|
||||
* (1) 12 or 16 bytes for an ATAPI command packet (QEMU always uses 12), or
|
||||
* (2) Actual data from the drive.
|
||||
* If we do both, (2) winds up erasing any evidence of (1).
|
||||
*/
|
||||
if (cmd->props->atapi && (cmd->xbytes == 0 || cmd->props->dma)) {
|
||||
g_assert(le16_to_cpu(pio->tx_count) == 12 ||
|
||||
le16_to_cpu(pio->tx_count) == 16);
|
||||
} else {
|
||||
/* The AHCI test suite here does not test any PIO command that specifies
|
||||
* a DRQ block larger than one sector (like 0xC4), so this should always
|
||||
* be one sector or less. */
|
||||
size_t pio_len = ((cmd->xbytes % cmd->sector_size) ?
|
||||
(cmd->xbytes % cmd->sector_size) : cmd->sector_size);
|
||||
g_assert_cmphex(le16_to_cpu(pio->tx_count), ==, pio_len);
|
||||
}
|
||||
|
||||
g_free(pio);
|
||||
}
|
||||
|
||||
@ -796,7 +804,7 @@ static void command_header_init(AHCICommand *cmd)
|
||||
static void command_table_init(AHCICommand *cmd)
|
||||
{
|
||||
RegH2DFIS *fis = &(cmd->fis);
|
||||
uint16_t sect_count = (cmd->xbytes / AHCI_SECTOR_SIZE);
|
||||
uint16_t sect_count = (cmd->xbytes / cmd->sector_size);
|
||||
|
||||
fis->fis_type = REG_H2D_FIS;
|
||||
fis->flags = REG_H2D_FIS_CMD; /* "Command" bit */
|
||||
@ -819,7 +827,7 @@ static void command_table_init(AHCICommand *cmd)
|
||||
if (cmd->props->lba28 || cmd->props->lba48) {
|
||||
fis->device = ATA_DEVICE_LBA;
|
||||
}
|
||||
fis->count = (cmd->xbytes / AHCI_SECTOR_SIZE);
|
||||
fis->count = (cmd->xbytes / cmd->sector_size);
|
||||
}
|
||||
fis->icc = 0x00;
|
||||
fis->control = 0x00;
|
||||
@ -831,9 +839,9 @@ void ahci_command_enable_atapi_dma(AHCICommand *cmd)
|
||||
RegH2DFIS *fis = &(cmd->fis);
|
||||
g_assert(cmd->props->atapi);
|
||||
fis->feature_low |= 0x01;
|
||||
cmd->interrupts &= ~AHCI_PX_IS_PSS;
|
||||
/* PIO is still used to transfer the ATAPI command */
|
||||
g_assert(cmd->props->pio);
|
||||
cmd->props->dma = true;
|
||||
cmd->props->pio = false;
|
||||
/* BUG: We expect the DMA Setup interrupt for DMA commands */
|
||||
/* cmd->interrupts |= AHCI_PX_IS_DSS; */
|
||||
}
|
||||
@ -845,7 +853,7 @@ AHCICommand *ahci_command_create(uint8_t command_name)
|
||||
|
||||
g_assert(props);
|
||||
cmd = g_new0(AHCICommand, 1);
|
||||
g_assert(!(props->dma && props->pio));
|
||||
g_assert(!(props->dma && props->pio) || props->atapi);
|
||||
g_assert(!(props->lba28 && props->lba48));
|
||||
g_assert(!(props->read && props->write));
|
||||
g_assert(!props->size || props->data);
|
||||
@ -857,6 +865,7 @@ AHCICommand *ahci_command_create(uint8_t command_name)
|
||||
cmd->xbytes = props->size;
|
||||
cmd->prd_size = 4096;
|
||||
cmd->buffer = 0xabad1dea;
|
||||
cmd->sector_size = props->atapi ? ATAPI_SECTOR_SIZE : AHCI_SECTOR_SIZE;
|
||||
|
||||
if (!cmd->props->ncq) {
|
||||
cmd->interrupts = AHCI_PX_IS_DHRS;
|
||||
@ -1033,7 +1042,7 @@ void ahci_command_set_buffer(AHCICommand *cmd, uint64_t buffer)
|
||||
static void ahci_atapi_set_size(AHCICommand *cmd, uint64_t xbytes)
|
||||
{
|
||||
unsigned char *cbd = cmd->atapi_cmd;
|
||||
uint64_t nsectors = xbytes / 2048;
|
||||
uint64_t nsectors = xbytes / ATAPI_SECTOR_SIZE;
|
||||
uint32_t tmp;
|
||||
g_assert(cbd);
|
||||
|
||||
@ -1080,7 +1089,7 @@ void ahci_command_set_sizes(AHCICommand *cmd, uint64_t xbytes,
|
||||
cmd->prd_size = prd_size;
|
||||
}
|
||||
cmd->xbytes = xbytes;
|
||||
sect_count = (cmd->xbytes / AHCI_SECTOR_SIZE);
|
||||
sect_count = (cmd->xbytes / cmd->sector_size);
|
||||
|
||||
if (cmd->props->ncq) {
|
||||
NCQFIS *nfis = (NCQFIS *)&(cmd->fis);
|
||||
@ -1216,7 +1225,7 @@ void ahci_command_verify(AHCIQState *ahci, AHCICommand *cmd)
|
||||
ahci_port_check_d2h_sanity(ahci, port, slot);
|
||||
}
|
||||
if (cmd->props->pio) {
|
||||
ahci_port_check_pio_sanity(ahci, port, slot, cmd->xbytes);
|
||||
ahci_port_check_pio_sanity(ahci, cmd);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -596,8 +596,7 @@ void ahci_port_check_interrupts(AHCIQState *ahci, uint8_t port,
|
||||
uint32_t intr_mask);
|
||||
void ahci_port_check_nonbusy(AHCIQState *ahci, uint8_t port, uint8_t slot);
|
||||
void ahci_port_check_d2h_sanity(AHCIQState *ahci, uint8_t port, uint8_t slot);
|
||||
void ahci_port_check_pio_sanity(AHCIQState *ahci, uint8_t port,
|
||||
uint8_t slot, size_t buffsize);
|
||||
void ahci_port_check_pio_sanity(AHCIQState *ahci, AHCICommand *cmd);
|
||||
void ahci_port_check_cmd_sanity(AHCIQState *ahci, AHCICommand *cmd);
|
||||
|
||||
/* Misc */
|
||||
|
Loading…
Reference in New Issue
Block a user