diff options
author | mav <mav@FreeBSD.org> | 2015-03-14 08:45:54 +0000 |
---|---|---|
committer | mav <mav@FreeBSD.org> | 2015-03-14 08:45:54 +0000 |
commit | 9ac55a7e33db84fbb28e2c649b8c95eb3ddb0278 (patch) | |
tree | bc38899f9972048a5764c05f64254ea9c1b6c7e1 /usr.sbin | |
parent | c9ee031d48e88ead1781becaf05574410baeeb32 (diff) | |
download | FreeBSD-src-9ac55a7e33db84fbb28e2c649b8c95eb3ddb0278.zip FreeBSD-src-9ac55a7e33db84fbb28e2c649b8c95eb3ddb0278.tar.gz |
Improve NCQ errors reporting for virtual AHCI disks.
While this implementation is still not perfect, previous was just broken.
MFC after: 2 weeks
Diffstat (limited to 'usr.sbin')
-rw-r--r-- | usr.sbin/bhyve/pci_ahci.c | 64 |
1 files changed, 53 insertions, 11 deletions
diff --git a/usr.sbin/bhyve/pci_ahci.c b/usr.sbin/bhyve/pci_ahci.c index 3687ad9..2b8a7d8 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; @@ -839,7 +876,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) @@ -866,6 +903,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)); @@ -1522,6 +1561,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: @@ -1684,10 +1727,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); /* |