diff options
author | mav <mav@FreeBSD.org> | 2015-05-04 19:55:01 +0000 |
---|---|---|
committer | mav <mav@FreeBSD.org> | 2015-05-04 19:55:01 +0000 |
commit | 8e9264e9c597f1a7e8db08159fc73dc01f3fe136 (patch) | |
tree | 8376298b61c4fc5018cd4f0d8a433757548eba16 /usr.sbin/bhyve | |
parent | acfa1865000f67a72607322c5871a3f3195748d3 (diff) | |
download | FreeBSD-src-8e9264e9c597f1a7e8db08159fc73dc01f3fe136.zip FreeBSD-src-8e9264e9c597f1a7e8db08159fc73dc01f3fe136.tar.gz |
Implement in-order execution of non-NCQ commands.
Using status updates in r282364, block queue on BSY, DRQ or ERR bits set.
This can be a performance penalization for non-NCQ commands, but it is
required for proper error recovery and standard compliance.
MFC after: 2 weeks
Diffstat (limited to 'usr.sbin/bhyve')
-rw-r--r-- | usr.sbin/bhyve/pci_ahci.c | 21 |
1 files changed, 15 insertions, 6 deletions
diff --git a/usr.sbin/bhyve/pci_ahci.c b/usr.sbin/bhyve/pci_ahci.c index 2d05789..922a783 100644 --- a/usr.sbin/bhyve/pci_ahci.c +++ b/usr.sbin/bhyve/pci_ahci.c @@ -140,6 +140,7 @@ struct ahci_port { uint8_t err_cfis[20]; uint8_t sense_key; uint8_t asc; + u_int ccs; uint32_t pending; uint32_t clb; @@ -204,6 +205,8 @@ struct pci_ahci_softc { }; #define ahci_ctx(sc) ((sc)->asc_pi->pi_vmctx) +static void ahci_handle_port(struct ahci_port *p); + static inline void lba_to_msf(uint8_t *buf, int lba) { lba += 150; @@ -406,6 +409,7 @@ ahci_check_stopped(struct ahci_port *p) */ if (!(p->cmd & AHCI_P_CMD_ST)) { if (p->pending == 0) { + p->ccs = 0; p->cmd &= ~(AHCI_P_CMD_CR | AHCI_P_CMD_CCS_MASK); p->ci = 0; p->sact = 0; @@ -783,6 +787,8 @@ next: ahci_write_fis_d2h(p, slot, cfis, ATA_S_READY | ATA_S_DSC); p->pending &= ~(1 << slot); ahci_check_stopped(p); + if (!first) + ahci_handle_port(p); return; } goto next; @@ -1754,20 +1760,21 @@ ahci_handle_slot(struct ahci_port *p, int slot) static void ahci_handle_port(struct ahci_port *p) { - int i; if (!(p->cmd & AHCI_P_CMD_ST)) return; /* * Search for any new commands to issue ignoring those that - * are already in-flight. + * are already in-flight. Stop if device is busy or in error. */ - for (i = 0; (i < 32) && p->ci; i++) { - if ((p->ci & (1 << i)) && !(p->pending & (1 << i))) { + for (; (p->ci & ~p->pending) != 0; p->ccs = ((p->ccs + 1) & 31)) { + if ((p->tfd & (ATA_S_BUSY | ATA_S_DRQ | ATA_S_ERROR)) != 0) + break; + if ((p->ci & ~p->pending & (1 << p->ccs)) != 0) { p->cmd &= ~AHCI_P_CMD_CCS_MASK; - p->cmd |= i << AHCI_P_CMD_CCS_SHIFT; - ahci_handle_slot(p, i); + p->cmd |= p->ccs << AHCI_P_CMD_CCS_SHIFT; + ahci_handle_slot(p, p->ccs); } } } @@ -1844,6 +1851,7 @@ ata_ioreq_cb(struct blockif_req *br, int err) p->pending &= ~(1 << slot); ahci_check_stopped(p); + ahci_handle_port(p); out: pthread_mutex_unlock(&sc->mtx); DPRINTF("%s exit\n", __func__); @@ -1905,6 +1913,7 @@ atapi_ioreq_cb(struct blockif_req *br, int err) p->pending &= ~(1 << slot); ahci_check_stopped(p); + ahci_handle_port(p); out: pthread_mutex_unlock(&sc->mtx); DPRINTF("%s exit\n", __func__); |