summaryrefslogtreecommitdiffstats
path: root/usr.sbin
diff options
context:
space:
mode:
authormav <mav@FreeBSD.org>2015-03-27 08:47:02 +0000
committermav <mav@FreeBSD.org>2015-03-27 08:47:02 +0000
commitadad7a7d84080ebb9c950cf3a8478ab8e408d2d2 (patch)
treed51156590f407d35edc1dfbef271a59e54781645 /usr.sbin
parente0d0bd28e8a92815d24a5882ae760f11d64824f0 (diff)
downloadFreeBSD-src-adad7a7d84080ebb9c950cf3a8478ab8e408d2d2.zip
FreeBSD-src-adad7a7d84080ebb9c950cf3a8478ab8e408d2d2.tar.gz
MFC r279975: Improve NCQ errors reporting for virtual AHCI disks.
While this implementation is still not perfect, previous was just broken.
Diffstat (limited to 'usr.sbin')
-rw-r--r--usr.sbin/bhyve/pci_ahci.c64
1 files changed, 53 insertions, 11 deletions
diff --git a/usr.sbin/bhyve/pci_ahci.c b/usr.sbin/bhyve/pci_ahci.c
index e50eff7..b50d26e 100644
--- a/usr.sbin/bhyve/pci_ahci.c
+++ b/usr.sbin/bhyve/pci_ahci.c
@@ -134,6 +134,7 @@ struct ahci_port {
int reset;
int mult_sectors;
uint8_t xfermode;
+ uint8_t err_cfis[20];
uint8_t sense_key;
uint8_t asc;
uint32_t pending;
@@ -299,18 +300,27 @@ ahci_write_fis_piosetup(struct ahci_port *p)
}
static void
-ahci_write_fis_sdb(struct ahci_port *p, int slot, uint32_t tfd)
+ahci_write_fis_sdb(struct ahci_port *p, int slot, uint8_t *cfis, uint32_t tfd)
{
uint8_t fis[8];
uint8_t error;
error = (tfd >> 8) & 0xff;
memset(fis, 0, sizeof(fis));
- fis[0] = error;
+ fis[0] = FIS_TYPE_SETDEVBITS;
+ fis[1] = (1 << 6);
fis[2] = tfd & 0x77;
- *(uint32_t *)(fis + 4) = (1 << slot);
- if (fis[2] & ATA_S_ERROR)
+ fis[3] = error;
+ if (fis[2] & ATA_S_ERROR) {
p->is |= AHCI_P_IX_TFE;
+ p->err_cfis[0] = slot;
+ p->err_cfis[2] = tfd & 0x77;
+ p->err_cfis[3] = error;
+ memcpy(&p->err_cfis[4], cfis + 4, 16);
+ } else {
+ *(uint32_t *)(fis + 4) = (1 << slot);
+ p->sact &= ~(1 << slot);
+ }
p->tfd = tfd;
ahci_write_fis(p, FIS_TYPE_SETDEVBITS, fis);
}
@@ -337,9 +347,13 @@ ahci_write_fis_d2h(struct ahci_port *p, int slot, uint8_t *cfis, uint32_t tfd)
fis[11] = cfis[11];
fis[12] = cfis[12];
fis[13] = cfis[13];
- if (fis[2] & ATA_S_ERROR)
+ if (fis[2] & ATA_S_ERROR) {
p->is |= AHCI_P_IX_TFE;
- else
+ p->err_cfis[0] = 0x80;
+ p->err_cfis[2] = tfd & 0xff;
+ p->err_cfis[3] = error;
+ memcpy(&p->err_cfis[4], cfis + 4, 16);
+ } else
p->ci &= ~(1 << slot);
p->tfd = tfd;
ahci_write_fis(p, FIS_TYPE_REGD2H, fis);
@@ -774,6 +788,29 @@ write_prdt(struct ahci_port *p, int slot, uint8_t *cfis,
}
static void
+ahci_handle_read_log(struct ahci_port *p, int slot, uint8_t *cfis)
+{
+ struct ahci_cmd_hdr *hdr;
+ uint8_t buf[512];
+
+ hdr = (struct ahci_cmd_hdr *)(p->cmd_lst + slot * AHCI_CL_SIZE);
+ if (p->atapi || hdr->prdtl == 0 || cfis[4] != 0x10 ||
+ cfis[5] != 0 || cfis[9] != 0 || cfis[12] != 1 || cfis[13] != 0) {
+ ahci_write_fis_d2h(p, slot, cfis,
+ (ATA_E_ABORT << 8) | ATA_S_READY | ATA_S_ERROR);
+ return;
+ }
+
+ memset(buf, 0, sizeof(buf));
+ memcpy(buf, p->err_cfis, sizeof(p->err_cfis));
+
+ if (cfis[2] == ATA_READ_LOG_EXT)
+ ahci_write_fis_piosetup(p);
+ write_prdt(p, slot, cfis, (void *)buf, sizeof(buf));
+ ahci_write_fis_d2h(p, slot, cfis, ATA_S_DSC | ATA_S_READY);
+}
+
+static void
handle_identify(struct ahci_port *p, int slot, uint8_t *cfis)
{
struct ahci_cmd_hdr *hdr;
@@ -840,7 +877,7 @@ handle_identify(struct ahci_port *p, int slot, uint8_t *cfis)
buf[85] = (ATA_SUPPORT_POWERMGT | ATA_SUPPORT_WRITECACHE|
ATA_SUPPORT_LOOKAHEAD | ATA_SUPPORT_NOP);
buf[86] = (ATA_SUPPORT_ADDRESS48 | ATA_SUPPORT_FLUSHCACHE |
- ATA_SUPPORT_FLUSHCACHE48);
+ ATA_SUPPORT_FLUSHCACHE48 | 1 << 15);
buf[87] = (1 << 14);
buf[88] = 0x7f;
if (p->xfermode & ATA_UDMA0)
@@ -867,6 +904,8 @@ handle_identify(struct ahci_port *p, int slot, uint8_t *cfis)
buf[117] = sectsz / 2;
buf[118] = ((sectsz / 2) >> 16);
}
+ buf[119] = (ATA_SUPPORT_RWLOGDMAEXT | 1 << 14);
+ buf[120] = (ATA_SUPPORT_RWLOGDMAEXT | 1 << 14);
buf[222] = 0x1020;
ahci_write_fis_piosetup(p);
write_prdt(p, slot, cfis, (void *)buf, sizeof(buf));
@@ -1523,6 +1562,10 @@ ahci_handle_cmd(struct ahci_port *p, int slot, uint8_t *cfis)
ahci_write_fis_d2h(p, slot, cfis,
(ATA_E_ABORT << 8) | ATA_S_READY | ATA_S_ERROR);
break;
+ case ATA_READ_LOG_EXT:
+ case ATA_READ_LOG_DMA_EXT:
+ ahci_handle_read_log(p, slot, cfis);
+ break;
case ATA_STANDBY_CMD:
break;
case ATA_NOP:
@@ -1685,10 +1728,9 @@ ata_ioreq_cb(struct blockif_req *br, int err)
tfd = (ATA_E_ABORT << 8) | ATA_S_READY | ATA_S_ERROR;
}
- if (ncq) {
- p->sact &= ~(1 << slot);
- ahci_write_fis_sdb(p, slot, tfd);
- } else
+ if (ncq)
+ ahci_write_fis_sdb(p, slot, cfis, tfd);
+ else
ahci_write_fis_d2h(p, slot, cfis, tfd);
/*
OpenPOWER on IntegriCloud