Improve NCQ errors reporting for virtual AHCI disks.
While this implementation is still not perfect, previous was just broken. MFC after: 2 weeks
This commit is contained in:
parent
af1357897d
commit
9009f43407
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=279975
@ -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);
|
||||
@ -773,6 +787,29 @@ write_prdt(struct ahci_port *p, int slot, uint8_t *cfis,
|
||||
hdr->prdbc = size - len;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
@ -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);
|
||||
|
||||
/*
|
||||
|
Loading…
Reference in New Issue
Block a user