Module Name: src
Committed By: jdolecek
Date: Wed Jul 19 20:02:40 UTC 2017
Modified Files:
src/sys/dev/ic [jdolecek-ncq]: siisata.c
Log Message:
convert over to new error handling world order:
- switch to ata_timeout()
- stop using ch_status/ch_error for passing state/error, stop setting
ATACH_IRQ_WAIT in ch_flags; pass the state via the last parameter
to c_intr() routine
- add NCQ recovery and KILL_REQUEUE
- only call atastart() in c_intr() if there was no error
several siisata specific tweaks:
- improve reset to better handle PM - need to reset couple more registers
- add timeouts for unbusy wait - ATA_DELAY (10s)
- siisata_bio_complete() do not use PRSO_RTC for byte count for NCQ transfers,
they never return partial reads; and that register might contain some random
junk, at least that's the case with ahcisata cmdh_prdbc
To generate a diff of this commit:
cvs rdiff -u -r1.30.4.25 -r1.30.4.26 src/sys/dev/ic/siisata.c
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/sys/dev/ic/siisata.c
diff -u src/sys/dev/ic/siisata.c:1.30.4.25 src/sys/dev/ic/siisata.c:1.30.4.26
--- src/sys/dev/ic/siisata.c:1.30.4.25 Tue Jun 27 20:13:56 2017
+++ src/sys/dev/ic/siisata.c Wed Jul 19 20:02:40 2017
@@ -1,4 +1,4 @@
-/* $NetBSD: siisata.c,v 1.30.4.25 2017/06/27 20:13:56 jdolecek Exp $ */
+/* $NetBSD: siisata.c,v 1.30.4.26 2017/07/19 20:02:40 jdolecek Exp $ */
/* from ahcisata_core.c */
@@ -79,7 +79,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: siisata.c,v 1.30.4.25 2017/06/27 20:13:56 jdolecek Exp $");
+__KERNEL_RCSID(0, "$NetBSD: siisata.c,v 1.30.4.26 2017/07/19 20:02:40 jdolecek Exp $");
#include <sys/types.h>
#include <sys/param.h>
@@ -148,7 +148,7 @@ void siisata_killpending(struct ata_driv
void siisata_cmd_start(struct ata_channel *, struct ata_xfer *);
int siisata_cmd_complete(struct ata_channel *, struct ata_xfer *, int);
-void siisata_cmd_done(struct ata_channel *, struct ata_xfer *);
+void siisata_cmd_done(struct ata_channel *, struct ata_xfer *, int);
static void siisata_cmd_done_end(struct ata_channel *, struct ata_xfer *);
void siisata_cmd_kill_xfer(struct ata_channel *, struct ata_xfer *, int);
@@ -157,14 +157,12 @@ int siisata_bio_complete(struct ata_chan
void siisata_bio_kill_xfer(struct ata_channel *, struct ata_xfer *, int);
int siisata_exec_command(struct ata_drive_datas *, struct ata_xfer *);
-void siisata_timeout(void *);
-
static void siisata_reinit_port(struct ata_channel *);
static void siisata_device_reset(struct ata_channel *);
static void siisata_activate_prb(struct siisata_channel *, int);
static void siisata_deactivate_prb(struct siisata_channel *, int);
-static int siisata_dma_setup(struct ata_channel *chp, int, void *,
- size_t, int);
+static int siisata_dma_setup(struct ata_channel *, int, void *, size_t, int);
+static void siisata_channel_recover(struct ata_channel *, int, int);
#if NATAPIBUS > 0
void siisata_atapibus_attach(struct atabus_softc *);
@@ -478,7 +476,6 @@ siisata_intr_port(struct siisata_channel
struct ata_xfer *xfer;
u_int slot;
uint32_t pss, pis;
- uint32_t prbfis;
sc = (struct siisata_softc *)schp->ata_channel.ch_atac;
chp = &schp->ata_channel;
@@ -489,12 +486,15 @@ siisata_intr_port(struct siisata_channel
SIISATANAME(sc), __func__, chp->ch_channel, pss), DEBUG_INTR);
for (slot = 0; slot < SIISATA_MAX_SLOTS; slot++) {
- if (((schp->sch_active_slots >> slot) & 1) == 0)
+ if (((schp->sch_active_slots >> slot) & 1) == 0) {
/* there's nothing executing here, skip */
continue;
- if (((pss >> slot) & 1) != 0)
- /* execution is incomplete or unsuccessful, skip for now */
+ }
+ if (((pss >> slot) & 1) != 0) {
+ /* execution is incomplete or unsuccessful, skip
+ * for now */
continue;
+ }
xfer = ata_queue_hwslot_to_xfer(chp, slot);
if (xfer->c_intr == NULL) {
wakeup(schp);
@@ -520,54 +520,145 @@ siisata_intr_port(struct siisata_channel
SIISATA_DEBUG_PRINT(("%s: %s port %d, pis 0x%x ", SIISATANAME(sc),
__func__, chp->ch_channel, pis), DEBUG_INTR);
+ /* clear */
+ PRWRITE(sc, PRX(chp->ch_channel, PRO_PIS), pis);
+
if (pis & PR_PIS_CMDERRR) {
uint32_t ec;
- uint32_t ps;
- ps = PRREAD(sc, PRX(chp->ch_channel, PRO_PS));
ec = PRREAD(sc, PRX(chp->ch_channel, PRO_PCE));
SIISATA_DEBUG_PRINT(("ec %d\n", ec), DEBUG_INTR);
- slot = PR_PS_ACTIVE_SLOT(ps); /* XXX invalid for NCQ? */
-
/* emulate a CRC error by default */
- chp->ch_status = WDCS_ERR;
- chp->ch_error = WDCE_CRC;
+ int tfd = ATACH_ERR_ST(WDCE_CRC, WDCS_ERR);
- if (ec <= PR_PCE_DATAFISERROR) {
- if (ec == PR_PCE_DEVICEERROR) {
- /* read in specific information about error */
- prbfis = bus_space_read_stream_4(
- sc->sc_prt, sc->sc_prh,
- PRSX(chp->ch_channel, slot,
- PRSO_FIS));
- /* set ch_status and ch_error */
- satafis_rdh_parse(chp, (uint8_t *)&prbfis);
- }
- siisata_reinit_port(chp);
+ if (ec <= PR_PCE_DATAFISERROR && !schp->sch_recovering) {
+ siisata_channel_recover(chp, ec, tfd);
} else {
aprint_error_dev(sc->sc_atac.atac_dev, "fatal error %d"
" on channel %d (ctx 0x%x), resetting\n",
ec, chp->ch_channel,
PRREAD(sc, PRX(chp->ch_channel, PRO_PCR)));
+
/* okay, we have a "Fatal Error" */
siisata_device_reset(chp);
+
+ /* Complete any non-finished commands with the error */
+ for (slot = 0; slot < SIISATA_MAX_SLOTS; slot++) {
+ if (((schp->sch_active_slots >> slot) & 1) == 0) {
+ /* nothing executing here, skip */
+ continue;
+ }
+ xfer = ata_queue_hwslot_to_xfer(chp, slot);
+ xfer->c_intr(chp, xfer, tfd);
+ }
}
- for (slot = 0; slot < SIISATA_MAX_SLOTS; slot++) {
- /* there's nothing executing here, skip */
- if (((schp->sch_active_slots >> slot) & 1) == 0)
- continue;
- xfer = ata_queue_hwslot_to_xfer(chp, slot);
- if (xfer == NULL)
- continue;
- xfer->c_intr(chp, xfer, 0);
+ }
+
+ return;
+}
+
+static void
+siisata_hold(struct siisata_channel *schp)
+{
+ schp->sch_hold_slots |= schp->sch_active_slots;
+ schp->sch_active_slots = 0;
+}
+
+static void
+siisata_unhold(struct siisata_channel *schp)
+{
+ schp->sch_active_slots = schp->sch_hold_slots;
+ schp->sch_hold_slots = 0;
+}
+
+/* Recover channel after transfer aborted */
+static void
+siisata_channel_recover(struct ata_channel *chp, int ec, int tfd)
+{
+ struct siisata_channel *schp = (struct siisata_channel *)chp;
+ struct siisata_softc *sc =
+ (struct siisata_softc *)schp->ata_channel.ch_atac;
+ struct ata_drive_datas *drvp;
+ int ps, drive, error;
+ uint8_t slot, st, err;
+ struct ata_xfer *xfer;
+ uint32_t prbfis;
+
+ KASSERT(!schp->sch_recovering);
+
+ schp->sch_recovering = true;
+
+ ps = PRREAD(sc, PRX(chp->ch_channel, PRO_PS));
+
+ if (chp->ch_ndrives > PMP_PORT_CTL) {
+ /* Get PM port number for the device in error */
+ int pcr = PRREAD(sc, PRX(chp->ch_channel, PRO_PCR));
+ drive = PRO_PCR_PMP(pcr);
+ } else
+ drive = 0;
+
+ drvp = &chp->ch_drive[drive];
+
+ siisata_hold(schp);
+
+ siisata_reinit_port(chp);
+
+ /*
+ * When running NCQ commands, READ LOG EXT is necessary to clear the
+ * error condition and unblock the device.
+ */
+ error = ata_read_log_ext_ncq(drvp, AT_POLL, &slot, &st, &err);
+
+ siisata_unhold(schp);
+
+ if (error == EOPNOTSUPP) {
+ /*
+ * Not NCQ command or not NCQ device, there is only
+ * one outstanding tranfer, so find the active one,
+ * and send the error.
+ */
+ xfer = ata_queue_drive_active_xfer(chp, drive);
+ if (ec == PR_PCE_DEVICEERROR) {
+ slot = PR_PS_ACTIVE_SLOT(ps);
+
+ /* read in specific information about error */
+ prbfis = bus_space_read_stream_4(
+ sc->sc_prt, sc->sc_prh,
+ PRSX(chp->ch_channel, slot,
+ PRSO_FIS));
+
+ /* get status and error */
+ int ntfd = satafis_rdh_parse(chp, (uint8_t *)&prbfis);
+
+ if (ATACH_ST(ntfd) & WDCS_ERR)
+ tfd = ntfd;
}
+
+ xfer->c_intr(chp, xfer, tfd);
+ } else if (error == 0) {
+ xfer = ata_queue_hwslot_to_xfer(chp, slot);
+ xfer->c_intr(chp, xfer, ATACH_ERR_ST(err, st));
+ } else {
+ /* Other error, do full device reset */
+ drive = -1;
+ siisata_device_reset(chp);
}
- /* clear */
- PRWRITE(sc, PRX(chp->ch_channel, PRO_PIS), pis);
+ /* Requeue the non-errorred commands */
+ for (slot = 0; slot < SIISATA_MAX_SLOTS; slot++) {
+ if (((schp->sch_active_slots >> slot) & 1) == 0)
+ continue;
- return;
+ xfer = ata_queue_hwslot_to_xfer(chp, slot);
+ if (drive >= 0 && xfer->c_drive != drive)
+ continue;
+
+ xfer->c_kill_xfer(chp, xfer,
+ drive >= 0 ? KILL_REQUEUE : KILL_RESET);
+ }
+
+ schp->sch_recovering = false;
}
void
@@ -629,10 +720,12 @@ siisata_reset_drive(struct ata_drive_dat
pis = PRREAD(sc, PRX(chp->ch_channel, PRO_PIS));
const uint32_t ps = PRREAD(sc, PRX(chp->ch_channel, PRO_PS));
const u_int slot = PR_PS_ACTIVE_SLOT(ps);
+
if (slot != xfer->c_slot)
device_printf(sc->sc_atac.atac_dev, "%s port %d "
"drive %d slot %d c_slot %d", __func__,
chp->ch_channel, drvp->drive, slot, xfer->c_slot);
+
PRWRITE(sc, PRX(chp->ch_channel, PRO_PIS), pis &
PR_PIS_CMDERRR);
}
@@ -657,29 +750,6 @@ siisata_reset_drive(struct ata_drive_dat
ata_free_xfer(chp, xfer);
-#if 1
- /* attempt to downgrade signaling in event of CRC error */
- /* XXX should be part of the MI (S)ATA subsystem */
- if (chp->ch_status == 0x51 && chp->ch_error == 0x84) {
- bus_space_write_4(sc->sc_prt, schp->sch_scontrol, 0,
- SControl_IPM_NONE | SControl_SPD_G1 | SControl_DET_INIT);
- DELAY(10);
- bus_space_write_4(sc->sc_prt, schp->sch_scontrol, 0,
- SControl_IPM_NONE | SControl_SPD_G1);
- DELAY(10);
- for (;;) {
- if ((bus_space_read_4(sc->sc_prt, schp->sch_sstatus, 0)
- & SStatus_DET_mask) == SStatus_DET_DEV)
- break;
- DELAY(10);
- }
- }
-#endif
-
-#if 1
- chp->ch_status = 0;
- chp->ch_error = 0;
-#endif
return;
}
@@ -902,9 +972,6 @@ siisata_cmd_start(struct ata_channel *ch
chp->ch_channel, xfer->c_drive, ata_c->r_command, xfer->c_slot),
DEBUG_FUNCS|DEBUG_XFERS);
- chp->ch_status = 0;
- chp->ch_error = 0;
-
prb = schp->sch_prb[xfer->c_slot];
memset(prb, 0, SIISATA_CMD_SIZE);
@@ -936,9 +1003,8 @@ siisata_cmd_start(struct ata_channel *ch
siisata_activate_prb(schp, xfer->c_slot);
if ((ata_c->flags & AT_POLL) == 0) {
- chp->ch_flags |= ATACH_IRQ_WAIT; /* wait for interrupt */
callout_reset(&xfer->c_timo_callout, mstohz(ata_c->timeout),
- siisata_timeout, xfer);
+ ata_timeout, xfer);
goto out;
}
@@ -953,7 +1019,7 @@ siisata_cmd_start(struct ata_channel *ch
}
if ((ata_c->flags & AT_DONE) == 0) {
- siisata_timeout(xfer);
+ ata_timeout(xfer);
}
/* reenable interrupts */
@@ -983,6 +1049,9 @@ siisata_cmd_kill_xfer(struct ata_channel
case KILL_RESET:
ata_c->flags |= AT_RESET;
break;
+ case KILL_REQUEUE:
+ panic("%s: not supposed to be requeued\n", __func__);
+ break;
default:
panic("%s: port %d: unknown reason %d",
__func__, chp->ch_channel, reason);
@@ -997,7 +1066,7 @@ siisata_cmd_kill_xfer(struct ata_channel
}
int
-siisata_cmd_complete(struct ata_channel *chp, struct ata_xfer *xfer, int is)
+siisata_cmd_complete(struct ata_channel *chp, struct ata_xfer *xfer, int tfd)
{
struct siisata_channel *schp = (struct siisata_channel *)chp;
struct ata_command *ata_c = &xfer->c_ata_c;
@@ -1017,24 +1086,23 @@ siisata_cmd_complete(struct ata_channel
siisata_deactivate_prb(schp, xfer->c_slot);
ata_deactivate_xfer(chp, xfer);
- chp->ch_flags &= ~ATACH_IRQ_WAIT;
if (xfer->c_flags & C_TIMEOU)
ata_c->flags |= AT_TIMEOU;
- if (chp->ch_status & WDCS_BSY) {
+ if (ATACH_ST(tfd) & WDCS_BSY) {
ata_c->flags |= AT_TIMEOU;
- } else if (chp->ch_status & WDCS_ERR) {
- ata_c->r_error = chp->ch_error;
+ } else if (ATACH_ST(tfd) & WDCS_ERR) {
+ ata_c->r_error = ATACH_ERR(tfd);
ata_c->flags |= AT_ERROR;
}
- siisata_cmd_done(chp, xfer);
+ siisata_cmd_done(chp, xfer, tfd);
return 0;
}
void
-siisata_cmd_done(struct ata_channel *chp, struct ata_xfer *xfer)
+siisata_cmd_done(struct ata_channel *chp, struct ata_xfer *xfer, int tfd)
{
uint32_t fis[howmany(RDH_FISLEN,sizeof(uint32_t))];
struct siisata_softc *sc = (struct siisata_softc *)chp->ch_atac;
@@ -1074,7 +1142,8 @@ siisata_cmd_done(struct ata_channel *chp
ata_c->flags |= AT_XFDONE;
siisata_cmd_done_end(chp, xfer);
- atastart(chp);
+ if ((ATACH_ST(tfd) & WDCS_ERR) == 0)
+ atastart(chp);
}
static void
@@ -1126,9 +1195,6 @@ siisata_bio_start(struct ata_channel *ch
SIISATANAME((struct siisata_softc *)chp->ch_atac), __func__,
chp->ch_channel, xfer->c_slot, xfer->c_drive), DEBUG_FUNCS);
- chp->ch_status = 0;
- chp->ch_error = 0;
-
prb = schp->sch_prb[xfer->c_slot];
memset(prb, 0, SIISATA_CMD_SIZE);
@@ -1153,9 +1219,8 @@ siisata_bio_start(struct ata_channel *ch
siisata_activate_prb(schp, xfer->c_slot);
if ((ata_bio->flags & ATA_POLL) == 0) {
- chp->ch_flags |= ATACH_IRQ_WAIT; /* wait for interrupt */
callout_reset(&xfer->c_timo_callout, mstohz(ATA_DELAY),
- siisata_timeout, xfer);
+ ata_timeout, xfer);
goto out;
}
@@ -1170,7 +1235,7 @@ siisata_bio_start(struct ata_channel *ch
}
if ((ata_bio->flags & ATA_ITSDONE) == 0) {
- siisata_timeout(xfer);
+ ata_timeout(xfer);
}
siisata_enable_port_interrupt(chp);
@@ -1205,6 +1270,9 @@ siisata_bio_kill_xfer(struct ata_channel
case KILL_RESET:
ata_bio->error = ERR_RESET;
break;
+ case KILL_REQUEUE:
+ ata_bio->error = REQUEUE;
+ break;
default:
panic("%s: port %d: unknown reason %d",
__func__, chp->ch_channel, reason);
@@ -1220,7 +1288,7 @@ siisata_bio_kill_xfer(struct ata_channel
}
int
-siisata_bio_complete(struct ata_channel *chp, struct ata_xfer *xfer, int is)
+siisata_bio_complete(struct ata_channel *chp, struct ata_xfer *xfer, int tfd)
{
struct siisata_softc *sc = (struct siisata_softc *)chp->ch_atac;
struct siisata_channel *schp = (struct siisata_channel *)chp;
@@ -1237,11 +1305,8 @@ siisata_bio_complete(struct ata_channel
siisata_deactivate_prb(schp, xfer->c_slot);
ata_deactivate_xfer(chp, xfer);
- chp->ch_flags &= ~ATACH_IRQ_WAIT;
if (xfer->c_flags & C_TIMEOU) {
ata_bio->error = TIMEOUT;
- } else {
- ata_bio->error = NOERROR;
}
bus_dmamap_sync(sc->sc_dmat, schp->sch_datad[xfer->c_slot], 0,
@@ -1251,18 +1316,18 @@ siisata_bio_complete(struct ata_channel
bus_dmamap_unload(sc->sc_dmat, schp->sch_datad[xfer->c_slot]);
ata_bio->flags |= ATA_ITSDONE;
- if (chp->ch_status & WDCS_DWF) {
+ if (ATACH_ST(tfd) & WDCS_DWF) {
ata_bio->error = ERR_DF;
- } else if (chp->ch_status & WDCS_ERR) {
+ } else if (ATACH_ST(tfd) & WDCS_ERR) {
ata_bio->error = ERROR;
- ata_bio->r_error = chp->ch_error;
- } else if (chp->ch_status & WDCS_CORR)
+ ata_bio->r_error = ATACH_ERR(tfd);
+ } else if (ATACH_ST(tfd) & WDCS_CORR)
ata_bio->flags |= ATA_CORR;
SIISATA_DEBUG_PRINT(("%s: %s bcount: %ld", SIISATANAME(sc), __func__,
ata_bio->bcount), DEBUG_XFERS);
if (ata_bio->error == NOERROR) {
- if (ata_bio->flags & ATA_READ)
+ if ((xfer->c_flags & C_NCQ) != 0 && ata_bio->flags & ATA_READ)
ata_bio->bcount -=
PRREAD(sc, PRSX(chp->ch_channel, xfer->c_slot, PRSO_RTC));
else
@@ -1270,25 +1335,11 @@ siisata_bio_complete(struct ata_channel
}
SIISATA_DEBUG_PRINT((" now %ld\n", ata_bio->bcount), DEBUG_XFERS);
(*chp->ch_drive[drive].drv_done)(chp->ch_drive[drive].drv_softc, xfer);
- atastart(chp);
+ if ((ATACH_ST(tfd) & WDCS_ERR) == 0)
+ atastart(chp);
return 0;
}
-void
-siisata_timeout(void *v)
-{
- struct ata_xfer *xfer = v;
- struct ata_channel *chp = xfer->c_chp;
- int s = splbio();
- SIISATA_DEBUG_PRINT(("%s: %p\n", __func__, xfer), DEBUG_INTR);
- siisata_device_reset(chp);
- if ((chp->ch_flags & ATACH_IRQ_WAIT) != 0) {
- xfer->c_flags |= C_TIMEOU;
- xfer->c_intr(chp, xfer, 0);
- }
- splx(s);
-}
-
static int
siisata_dma_setup(struct ata_channel *chp, int slot, void *data,
size_t count, int op)
@@ -1344,7 +1395,7 @@ siisata_activate_prb(struct siisata_chan
sc = (struct siisata_softc *)schp->ata_channel.ch_atac;
- KASSERTMSG((schp->sch_active_slots & __BIT(slot)) != __BIT(slot),
+ KASSERTMSG((schp->sch_active_slots & __BIT(slot)) == 0,
"%s: trying to activate active slot %d", SIISATANAME(sc), slot);
SIISATA_PRB_SYNC(sc, schp, slot, BUS_DMASYNC_PREWRITE);
@@ -1378,10 +1429,38 @@ static void
siisata_reinit_port(struct ata_channel *chp)
{
struct siisata_softc *sc = (struct siisata_softc *)chp->ch_atac;
+ int ps;
+
+
+ if (chp->ch_ndrives > 1) {
+ /*
+ * Proper recovery would SET this bit, which makes it
+ * not possible to submit new commands and resume execution
+ * on non-errored drives, then wait for those commands,
+ * to finish, and only then clear the bit and reset the state.
+ * For now this is okay, since we never queue commands for
+ * more than one drive.
+ * XXX FIS-based switching
+ */
+ PRWRITE(sc, PRX(chp->ch_channel, PRO_PCC), PR_PC_RESUME);
+
+ for (int i = 0; i < chp->ch_ndrives; i++) {
+ PRWRITE(sc, PRX(chp->ch_channel, PRO_PMPSTS(i)), 0);
+ PRWRITE(sc, PRX(chp->ch_channel, PRO_PMPQACT(i)), 0);
+ }
+ }
PRWRITE(sc, PRX(chp->ch_channel, PRO_PCS), PR_PC_PORT_INITIALIZE);
- while (!(PRREAD(sc, PRX(chp->ch_channel, PRO_PS)) & PR_PS_PORT_READY))
+ for (int i = 0; i < ATA_DELAY * 100; i++) {
+ ps = PRREAD(sc, PRX(chp->ch_channel, PRO_PS));
+ if ((ps & PR_PS_PORT_READY) != 0)
+ break;
+
DELAY(10);
+ }
+ if ((ps & PR_PS_PORT_READY) == 0)
+ printf("%s: timeout waiting for port to be ready", __func__);
+
if (chp->ch_ndrives > 1)
PRWRITE(sc, PRX(chp->ch_channel, PRO_PCS), PR_PC_PMP_ENABLE);
}
@@ -1390,10 +1469,19 @@ static void
siisata_device_reset(struct ata_channel *chp)
{
struct siisata_softc *sc = (struct siisata_softc *)chp->ch_atac;
+ int ps;
PRWRITE(sc, PRX(chp->ch_channel, PRO_PCS), PR_PC_DEVICE_RESET);
- while (!(PRREAD(sc, PRX(chp->ch_channel, PRO_PS)) & PR_PS_PORT_READY))
+
+ for (int i = 0; i < ATA_DELAY * 100; i++) {
+ ps = PRREAD(sc, PRX(chp->ch_channel, PRO_PS));
+ if ((ps & PR_PS_PORT_READY) != 0)
+ break;
+
DELAY(10);
+ }
+ if ((ps & PR_PS_PORT_READY) == 0)
+ printf("%s: timeout waiting for port to be ready", __func__);
}
@@ -1476,6 +1564,9 @@ siisata_atapi_kill_xfer(struct ata_chann
case KILL_RESET:
sc_xfer->error = XS_RESET;
break;
+ case KILL_REQUEUE:
+ sc_xfer->error = XS_REQUEUE;
+ break;
default:
panic("%s: port %d: unknown reason %d",
__func__, chp->ch_channel, reason);
@@ -1591,10 +1682,6 @@ siisata_atapi_probe_device(struct atapib
splx(s);
}
} else {
- SIISATA_DEBUG_PRINT(("%s: ATAPI_IDENTIFY_DEVICE "
- "failed for drive %s:%d:%d: error 0x%x\n",
- __func__, SIISATANAME(siic), chp->ch_channel, target,
- chp->ch_error), DEBUG_PROBE);
s = splbio();
drvp->drive_type &= ATA_DRIVET_NONE;
splx(s);
@@ -1677,9 +1764,6 @@ siisata_atapi_start(struct ata_channel *
chp->ch_drive[xfer->c_drive].drive, sc_xfer->xs_control),
DEBUG_XFERS);
- chp->ch_status = 0;
- chp->ch_error = 0;
-
prbp = schp->sch_prb[xfer->c_slot];
memset(prbp, 0, SIISATA_CMD_SIZE);
@@ -1714,9 +1798,8 @@ siisata_atapi_start(struct ata_channel *
siisata_activate_prb(schp, xfer->c_slot);
if ((xfer->c_flags & C_POLL) == 0) {
- chp->ch_flags |= ATACH_IRQ_WAIT; /* wait for interrupt */
callout_reset(&xfer->c_timo_callout, mstohz(sc_xfer->timeout),
- siisata_timeout, xfer);
+ ata_timeout, xfer);
goto out;
}
@@ -1730,7 +1813,7 @@ siisata_atapi_start(struct ata_channel *
DELAY(100);
}
if ((sc_xfer->xs_status & XS_STS_DONE) == 0) {
- siisata_timeout(xfer);
+ ata_timeout(xfer);
}
/* reenable interrupts */
siisata_enable_port_interrupt(chp);
@@ -1743,7 +1826,7 @@ out:
int
siisata_atapi_complete(struct ata_channel *chp, struct ata_xfer *xfer,
- int is)
+ int tfd)
{
struct siisata_softc *sc = (struct siisata_softc *)chp->ch_atac;
struct siisata_channel *schp = (struct siisata_channel *)chp;
@@ -1759,10 +1842,9 @@ siisata_atapi_complete(struct ata_channe
siisata_deactivate_prb(schp, xfer->c_slot);
ata_deactivate_xfer(chp, xfer);
- chp->ch_flags &= ~ATACH_IRQ_WAIT;
if (xfer->c_flags & C_TIMEOU) {
sc_xfer->error = XS_TIMEOUT;
- } else {
+ } else if ((ATACH_ST(tfd) & WDCS_ERR) == 0) {
sc_xfer->error = XS_NOERROR;
}
@@ -1772,17 +1854,16 @@ siisata_atapi_complete(struct ata_channe
BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE);
bus_dmamap_unload(sc->sc_dmat, schp->sch_datad[xfer->c_slot]);
- ata_free_xfer(chp, xfer);
sc_xfer->resid = sc_xfer->datalen;
sc_xfer->resid -= PRREAD(sc, PRSX(chp->ch_channel, xfer->c_slot,
PRSO_RTC));
SIISATA_DEBUG_PRINT(("%s: %s datalen %d resid %d\n", SIISATANAME(sc),
__func__, sc_xfer->datalen, sc_xfer->resid), DEBUG_XFERS);
- if ((chp->ch_status & WDCS_ERR) &&
+ if ((ATACH_ST(tfd) & WDCS_ERR) &&
((sc_xfer->xs_control & XS_CTL_REQSENSE) == 0 ||
sc_xfer->resid == sc_xfer->datalen)) {
sc_xfer->error = XS_SHORTSENSE;
- sc_xfer->sense.atapi_sense = chp->ch_error;
+ sc_xfer->sense.atapi_sense = ATACH_ERR(tfd);
if ((sc_xfer->xs_periph->periph_quirks &
PQUIRK_NOSENSE) == 0) {
/* request sense */
@@ -1790,9 +1871,11 @@ siisata_atapi_complete(struct ata_channe
sc_xfer->status = SCSI_CHECK;
}
}
+ ata_free_xfer(chp, xfer);
scsipi_done(sc_xfer);
- atastart(chp);
- return 0; /* XXX verify */
+ if ((ATACH_ST(tfd) & WDCS_ERR) == 0)
+ atastart(chp);
+ return 0;
}
#endif /* NATAPIBUS */