Teach ahci(4), siis(4) and ATA_CAM ata(4) wrapper report to CAM residual
I/O length on underruns, that often happens for some SCSI commands.
This commit is contained in:
parent
1828dd7478
commit
78df14851a
@ -1625,12 +1625,13 @@ ahci_execute_transaction(struct ahci_slot *slot)
|
||||
/* Setup the command list entry */
|
||||
clp = (struct ahci_cmd_list *)
|
||||
(ch->dma.work + AHCI_CL_OFFSET + (AHCI_CL_SIZE * slot->slot));
|
||||
clp->prd_length = slot->dma.nsegs;
|
||||
clp->cmd_flags = (ccb->ccb_h.flags & CAM_DIR_OUT ? AHCI_CMD_WRITE : 0) |
|
||||
(ccb->ccb_h.func_code == XPT_SCSI_IO ?
|
||||
(AHCI_CMD_ATAPI | AHCI_CMD_PREFETCH) : 0) |
|
||||
(fis_size / sizeof(u_int32_t)) |
|
||||
(port << 12);
|
||||
clp->cmd_flags = htole16(
|
||||
(ccb->ccb_h.flags & CAM_DIR_OUT ? AHCI_CMD_WRITE : 0) |
|
||||
(ccb->ccb_h.func_code == XPT_SCSI_IO ?
|
||||
(AHCI_CMD_ATAPI | AHCI_CMD_PREFETCH) : 0) |
|
||||
(fis_size / sizeof(u_int32_t)) |
|
||||
(port << 12));
|
||||
clp->prd_length = htole16(slot->dma.nsegs);
|
||||
/* Special handling for Soft Reset command. */
|
||||
if ((ccb->ccb_h.func_code == XPT_ATA_IO) &&
|
||||
(ccb->ataio.cmd.flags & CAM_ATAIO_CONTROL)) {
|
||||
@ -1650,7 +1651,7 @@ ahci_execute_transaction(struct ahci_slot *slot)
|
||||
clp->cmd_table_phys = htole64(ch->dma.work_bus + AHCI_CT_OFFSET +
|
||||
(AHCI_CT_SIZE * slot->slot));
|
||||
bus_dmamap_sync(ch->dma.work_tag, ch->dma.work_map,
|
||||
BUS_DMASYNC_PREWRITE);
|
||||
BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
|
||||
bus_dmamap_sync(ch->dma.rfis_tag, ch->dma.rfis_map,
|
||||
BUS_DMASYNC_PREREAD);
|
||||
/* Set ACTIVE bit for NCQ commands. */
|
||||
@ -1855,10 +1856,13 @@ ahci_end_transaction(struct ahci_slot *slot, enum ahci_err_type et)
|
||||
device_t dev = slot->dev;
|
||||
struct ahci_channel *ch = device_get_softc(dev);
|
||||
union ccb *ccb = slot->ccb;
|
||||
struct ahci_cmd_list *clp;
|
||||
int lastto;
|
||||
|
||||
bus_dmamap_sync(ch->dma.work_tag, ch->dma.work_map,
|
||||
BUS_DMASYNC_POSTWRITE);
|
||||
BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
|
||||
clp = (struct ahci_cmd_list *)
|
||||
(ch->dma.work + AHCI_CL_OFFSET + (AHCI_CL_SIZE * slot->slot));
|
||||
/* Read result registers to the result struct
|
||||
* May be incorrect if several commands finished same time,
|
||||
* so read only when sure or have to.
|
||||
@ -1893,6 +1897,16 @@ ahci_end_transaction(struct ahci_slot *slot, enum ahci_err_type et)
|
||||
res->sector_count_exp = fis[13];
|
||||
} else
|
||||
bzero(res, sizeof(*res));
|
||||
if ((ccb->ataio.cmd.flags & CAM_ATAIO_FPDMA) == 0 &&
|
||||
(ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE) {
|
||||
ccb->ataio.resid =
|
||||
ccb->ataio.dxfer_len - le32toh(clp->bytecount);
|
||||
}
|
||||
} else {
|
||||
if ((ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE) {
|
||||
ccb->csio.resid =
|
||||
ccb->csio.dxfer_len - le32toh(clp->bytecount);
|
||||
}
|
||||
}
|
||||
if ((ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE) {
|
||||
bus_dmamap_sync(ch->dma.data_tag, slot->dma.data_map,
|
||||
|
@ -1517,6 +1517,15 @@ ata_cam_end_transaction(device_t dev, struct ata_request *request)
|
||||
res->sector_count = request->u.ata.count;
|
||||
res->sector_count_exp = request->u.ata.count >> 8;
|
||||
}
|
||||
if ((ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE) {
|
||||
if (ccb->ccb_h.func_code == XPT_ATA_IO) {
|
||||
ccb->ataio.resid =
|
||||
ccb->ataio.dxfer_len - request->donecount;
|
||||
} else {
|
||||
ccb->csio.resid =
|
||||
ccb->csio.dxfer_len - request->donecount;
|
||||
}
|
||||
}
|
||||
ata_free_request(request);
|
||||
xpt_done(ccb);
|
||||
/* Do error recovery if needed. */
|
||||
|
@ -1208,6 +1208,17 @@ siis_end_transaction(struct siis_slot *slot, enum siis_err_type et)
|
||||
res->sector_count_exp = ATA_INB(ch->r_mem, offs + 13);
|
||||
} else
|
||||
bzero(res, sizeof(*res));
|
||||
if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN &&
|
||||
ch->numrslots == 1) {
|
||||
ccb->ataio.resid = ccb->ataio.dxfer_len -
|
||||
ATA_INL(ch->r_mem, SIIS_P_LRAM_SLOT(slot->slot) + 4);
|
||||
}
|
||||
} else {
|
||||
if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN &&
|
||||
ch->numrslots == 1) {
|
||||
ccb->csio.resid = ccb->csio.dxfer_len -
|
||||
ATA_INL(ch->r_mem, SIIS_P_LRAM_SLOT(slot->slot) + 4);
|
||||
}
|
||||
}
|
||||
if ((ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE) {
|
||||
bus_dmamap_sync(ch->dma.data_tag, slot->dma.data_map,
|
||||
|
Loading…
Reference in New Issue
Block a user