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:
Peter Maydell 2018-06-11 11:12:46 +01:00
commit a7a7309ca5
12 changed files with 572 additions and 244 deletions

View File

@ -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

View File

@ -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,

View File

@ -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

View File

@ -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 */

View File

@ -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 */

View File

@ -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"

View File

@ -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(

View File

@ -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)$@")

View File

@ -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
View 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;
}

View File

@ -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);
}
}

View File

@ -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 */