diff --git a/sys/dev/ahci/ahci.c b/sys/dev/ahci/ahci.c index 2a064923cf3..5db3a04a36e 100644 --- a/sys/dev/ahci/ahci.c +++ b/sys/dev/ahci/ahci.c @@ -1835,9 +1835,11 @@ ahci_execute_transaction(struct ahci_slot *slot) if (!(ATA_INL(ch->r_mem, AHCI_P_CI) & (1 << slot->slot))) break; if (ATA_INL(ch->r_mem, AHCI_P_TFD) & ATA_S_ERROR) { +#if 0 device_printf(ch->dev, "Poll error on slot %d, TFD: %04x\n", slot->slot, ATA_INL(ch->r_mem, AHCI_P_TFD)); +#endif et = AHCI_ERR_TFE; break; } @@ -1877,14 +1879,12 @@ ahci_execute_transaction(struct ahci_slot *slot) } } } - ahci_end_transaction(slot, et); /* Kick controller into sane state and enable FBS. */ if ((ccb->ccb_h.func_code == XPT_ATA_IO) && (ccb->ataio.cmd.flags & CAM_ATAIO_CONTROL) && - (ccb->ataio.cmd.control & ATA_A_RESET) == 0) { - ahci_stop(ch->dev); - ahci_start(ch->dev, 1); - } + (ccb->ataio.cmd.control & ATA_A_RESET) == 0) + ch->eslots |= (1 << slot->slot); + ahci_end_transaction(slot, et); return; } /* Start command execution timeout */ @@ -2169,13 +2169,6 @@ ahci_end_transaction(struct ahci_slot *slot, enum ahci_err_type et) ch->numhslots++; } else xpt_done(ccb); - /* Unfreeze frozen command. */ - if (ch->frozen && !ahci_check_collision(dev, ch->frozen)) { - union ccb *fccb = ch->frozen; - ch->frozen = NULL; - ahci_begin_transaction(dev, fccb); - xpt_release_simq(ch->sim, TRUE); - } /* If we have no other active commands, ... */ if (ch->rslots == 0) { /* if there was fatal error - reset port. */ @@ -2185,6 +2178,7 @@ ahci_end_transaction(struct ahci_slot *slot, enum ahci_err_type et) /* if we have slots in error, we can reinit port. */ if (ch->eslots != 0) { ahci_stop(dev); + ahci_clo(dev); ahci_start(dev, 1); } /* if there commands on hold, we can do READ LOG. */ @@ -2195,6 +2189,13 @@ ahci_end_transaction(struct ahci_slot *slot, enum ahci_err_type et) } else if ((ch->rslots & ~ch->toslots) == 0 && et != AHCI_ERR_TIMEOUT) ahci_rearm_timeout(dev); + /* Unfreeze frozen command. */ + if (ch->frozen && !ahci_check_collision(dev, ch->frozen)) { + union ccb *fccb = ch->frozen; + ch->frozen = NULL; + ahci_begin_transaction(dev, fccb); + xpt_release_simq(ch->sim, TRUE); + } /* Start PM timer. */ if (ch->numrslots == 0 && ch->pm_level > 3 && (ch->curr[ch->pm_present ? 15 : 0].caps & CTS_SATA_CAPS_D_PMREQ)) { diff --git a/sys/dev/mvs/mvs.c b/sys/dev/mvs/mvs.c index 5dbe30cd1a7..54808c51b58 100644 --- a/sys/dev/mvs/mvs.c +++ b/sys/dev/mvs/mvs.c @@ -1738,13 +1738,6 @@ mvs_end_transaction(struct mvs_slot *slot, enum mvs_err_type et) ch->numhslots++; } else xpt_done(ccb); - /* Unfreeze frozen command. */ - if (ch->frozen && !mvs_check_collision(dev, ch->frozen)) { - union ccb *fccb = ch->frozen; - ch->frozen = NULL; - mvs_begin_transaction(dev, fccb); - xpt_release_simq(ch->sim, TRUE); - } /* If we have no other active commands, ... */ if (ch->rslots == 0) { /* if there was fatal error - reset port. */ @@ -1764,6 +1757,13 @@ mvs_end_transaction(struct mvs_slot *slot, enum mvs_err_type et) } else if ((ch->rslots & ~ch->toslots) == 0 && et != MVS_ERR_TIMEOUT) mvs_rearm_timeout(dev); + /* Unfreeze frozen command. */ + if (ch->frozen && !mvs_check_collision(dev, ch->frozen)) { + union ccb *fccb = ch->frozen; + ch->frozen = NULL; + mvs_begin_transaction(dev, fccb); + xpt_release_simq(ch->sim, TRUE); + } /* Start PM timer. */ if (ch->numrslots == 0 && ch->pm_level > 3 && (ch->curr[ch->pm_present ? 15 : 0].caps & CTS_SATA_CAPS_D_PMREQ)) { @@ -2080,7 +2080,8 @@ mvs_softreset(device_t dev, union ccb *ccb) { struct mvs_channel *ch = device_get_softc(dev); int port = ccb->ccb_h.target_id & 0x0f; - int i; + int i, stuck; + uint8_t status; mvs_set_edma_mode(dev, MVS_EDMA_OFF); ATA_OUTB(ch->r_mem, SATA_SATAICTL, port << SATA_SATAICTL_PMPTX_SHIFT); @@ -2089,12 +2090,35 @@ mvs_softreset(device_t dev, union ccb *ccb) ATA_OUTB(ch->r_mem, ATA_CONTROL, 0); ccb->ccb_h.status &= ~CAM_STATUS_MASK; /* Wait for clearing busy status. */ - if ((i = mvs_wait(dev, 0, ATA_S_BUSY | ATA_S_DRQ, ccb->ccb_h.timeout)) < 0) { + if ((i = mvs_wait(dev, 0, ATA_S_BUSY, ccb->ccb_h.timeout)) < 0) { ccb->ccb_h.status |= CAM_CMD_TIMEOUT; + stuck = 1; } else { - ccb->ccb_h.status |= CAM_REQ_CMP; + status = mvs_getstatus(dev, 0); + if (status & ATA_S_ERROR) + ccb->ccb_h.status |= CAM_ATA_STATUS_ERROR; + else + ccb->ccb_h.status |= CAM_REQ_CMP; + if (status & ATA_S_DRQ) + stuck = 1; + else + stuck = 0; } mvs_tfd_read(dev, ccb); + + /* + * XXX: If some device on PMP failed to soft-reset, + * try to recover by sending dummy soft-reset to PMP. + */ + if (stuck && ch->pm_present && port != 15) { + ATA_OUTB(ch->r_mem, SATA_SATAICTL, + 15 << SATA_SATAICTL_PMPTX_SHIFT); + ATA_OUTB(ch->r_mem, ATA_CONTROL, ATA_A_RESET); + DELAY(10000); + ATA_OUTB(ch->r_mem, ATA_CONTROL, 0); + mvs_wait(dev, 0, ATA_S_BUSY | ATA_S_DRQ, ccb->ccb_h.timeout); + } + xpt_done(ccb); } diff --git a/sys/dev/siis/siis.c b/sys/dev/siis/siis.c index 01edae368a5..a7b018a4321 100644 --- a/sys/dev/siis/siis.c +++ b/sys/dev/siis/siis.c @@ -1178,11 +1178,22 @@ siis_timeout(struct siis_slot *slot) { device_t dev = slot->dev; struct siis_channel *ch = device_get_softc(dev); + union ccb *ccb = slot->ccb; mtx_assert(&ch->mtx, MA_OWNED); /* Check for stale timeout. */ if (slot->state < SIIS_SLOT_RUNNING) return; + + /* Handle soft-reset timeouts without doing hard-reset. */ + if ((ccb->ccb_h.func_code == XPT_ATA_IO) && + (ccb->ataio.cmd.flags & CAM_ATAIO_CONTROL) && + (ccb->ataio.cmd.control & ATA_A_RESET)) { + xpt_freeze_simq(ch->sim, ch->numrslots); + siis_end_transaction(slot, SIIS_ERR_TFE); + return; + } + device_printf(dev, "Timeout on slot %d\n", slot->slot); device_printf(dev, "%s is %08x ss %08x rs %08x es %08x sts %08x serr %08x\n", __func__, ATA_INL(ch->r_mem, SIIS_P_IS), @@ -1331,13 +1342,6 @@ siis_end_transaction(struct siis_slot *slot, enum siis_err_type et) ch->numhslots++; } else xpt_done(ccb); - /* Unfreeze frozen command. */ - if (ch->frozen && !siis_check_collision(dev, ch->frozen)) { - union ccb *fccb = ch->frozen; - ch->frozen = NULL; - siis_begin_transaction(dev, fccb); - xpt_release_simq(ch->sim, TRUE); - } /* If we have no other active commands, ... */ if (ch->rslots == 0) { /* if there were timeouts or fatal error - reset port. */ @@ -1355,6 +1359,13 @@ siis_end_transaction(struct siis_slot *slot, enum siis_err_type et) } else if ((ch->rslots & ~ch->toslots) == 0 && et != SIIS_ERR_TIMEOUT) siis_rearm_timeout(dev); + /* Unfreeze frozen command. */ + if (ch->frozen && !siis_check_collision(dev, ch->frozen)) { + union ccb *fccb = ch->frozen; + ch->frozen = NULL; + siis_begin_transaction(dev, fccb); + xpt_release_simq(ch->sim, TRUE); + } } static void