Module Name: src Committed By: jdolecek Date: Sat Aug 12 22:43:22 UTC 2017
Modified Files: src/sys/dev/ata [jdolecek-ncq]: TODO.ncq src/sys/dev/ic [jdolecek-ncq]: mvsata.c mvsatavar.h Log Message: add NCQ error recovery for mvsata(4) fix wait flags for mvsata_bio_start(), AT_* constants are only valid for cmd change the debug logging to similar form as ahcisata/siisata, so it's easier to selectively show To generate a diff of this commit: cvs rdiff -u -r1.1.2.34 -r1.1.2.35 src/sys/dev/ata/TODO.ncq cvs rdiff -u -r1.35.6.21 -r1.35.6.22 src/sys/dev/ic/mvsata.c cvs rdiff -u -r1.2.48.3 -r1.2.48.4 src/sys/dev/ic/mvsatavar.h 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/ata/TODO.ncq diff -u src/sys/dev/ata/TODO.ncq:1.1.2.34 src/sys/dev/ata/TODO.ncq:1.1.2.35 --- src/sys/dev/ata/TODO.ncq:1.1.2.34 Sat Aug 12 14:41:54 2017 +++ src/sys/dev/ata/TODO.ncq Sat Aug 12 22:43:22 2017 @@ -5,9 +5,6 @@ siisata - fix all new XXX and unmergable test wd* at umass?, confirm the ata_channel kludge works -do proper NCQ error recovery -- update mvsata to do same as ahcisata/siisata (read log ext, timeouts, et.al) - do biodone() in wddone() starting the dump to not leak bufs when dumping from active system? make sure to not trigger atastart() - call ata_kill_active() + ata_kill_pending() when dumping Index: src/sys/dev/ic/mvsata.c diff -u src/sys/dev/ic/mvsata.c:1.35.6.21 src/sys/dev/ic/mvsata.c:1.35.6.22 --- src/sys/dev/ic/mvsata.c:1.35.6.21 Sat Aug 12 14:41:54 2017 +++ src/sys/dev/ic/mvsata.c Sat Aug 12 22:43:22 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: mvsata.c,v 1.35.6.21 2017/08/12 14:41:54 jdolecek Exp $ */ +/* $NetBSD: mvsata.c,v 1.35.6.22 2017/08/12 22:43:22 jdolecek Exp $ */ /* * Copyright (c) 2008 KIYOHARA Takashi * All rights reserved. @@ -26,7 +26,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: mvsata.c,v 1.35.6.21 2017/08/12 14:41:54 jdolecek Exp $"); +__KERNEL_RCSID(0, "$NetBSD: mvsata.c,v 1.35.6.22 2017/08/12 22:43:22 jdolecek Exp $"); #include "opt_mvsata.h" @@ -86,12 +86,16 @@ __KERNEL_RCSID(0, "$NetBSD: mvsata.c,v 1 SHADOW_REG_BLOCK_OFFSET + (reg), (val)) #ifdef MVSATA_DEBUG -#define DPRINTF(x) if (mvsata_debug) printf x -#define DPRINTFN(n,x) if (mvsata_debug >= (n)) printf x -int mvsata_debug = 2; + +#define DEBUG_INTR 0x01 +#define DEBUG_XFERS 0x02 +#define DEBUG_FUNCS 0x08 +#define DEBUG_PROBE 0x10 + +#define DPRINTF(n,x) if (mvsata_debug & (n)) printf x +int mvsata_debug = 0; #else -#define DPRINTF(x) -#define DPRINTFN(n,x) +#define DPRINTF(n,x) #endif #define ATA_DELAY 10000 /* 10s for a drive I/O */ @@ -160,6 +164,7 @@ static void mvsata_bdma_start(struct mvs #endif static int mvsata_nondma_handle(struct mvsata_port *); +static void mvsata_channel_recover(struct mvsata_port *); static int mvsata_port_init(struct mvsata_hc *, int); static int mvsata_wdc_reg_init(struct mvsata_port *, struct wdc_regs *); @@ -398,7 +403,7 @@ mvsata_intr(struct mvsata_hc *mvhc) cause = MVSATA_HC_READ_4(mvhc, SATAHC_IC); - DPRINTFN(3, ("%s:%d: mvsata_intr: cause=0x%08x\n", + DPRINTF(DEBUG_INTR, ("%s:%d: mvsata_intr: cause=0x%08x\n", device_xname(MVSATA_DEV(sc)), mvhc->hc, cause)); if (cause & SATAHC_IC_SAINTCOAL) @@ -432,22 +437,23 @@ mvsata_nondma_handle(struct mvsata_port { struct ata_channel *chp = &mvport->port_ata_channel; struct ata_xfer *xfer; - int ret, quetag; + int ret; /* * The chip doesn't support several pending non-DMA commands, * and the ata middle layer never issues several non-NCQ commands, * so there must be exactly one active command at this moment. */ - for (quetag = 0; quetag < MVSATA_EDMAQ_LEN; quetag++) { - if ((mvport->port_quetagidx & __BIT(quetag)) == 0) - continue; - - break; + xfer = ata_queue_get_active_xfer(chp); + if (xfer == NULL) { + /* Can happen after error recovery, ignore */ + DPRINTF(DEBUG_FUNCS|DEBUG_XFERS, + ("%s:%d: %s: intr without xfer\n", + device_xname(MVSATA_DEV2(mvport)), chp->ch_channel, + __func__)); + return 0; } - KASSERT(quetag < MVSATA_EDMAQ_LEN); - xfer = ata_queue_hwslot_to_xfer(chp, quetag); ret = xfer->c_intr(chp, xfer, 1); return (ret); } @@ -473,7 +479,7 @@ mvsata_error(struct mvsata_port *mvport) } MVSATA_EDMA_WRITE_4(mvport, EDMA_IEC, ~cause); - DPRINTFN(3, ("%s:%d:%d:" + DPRINTF(DEBUG_INTR, ("%s:%d:%d:" " mvsata_error: cause=0x%08x, mask=0x%08x, status=0x%08x\n", device_xname(MVSATA_DEV2(mvport)), mvport->port_hc->hc, mvport->port, cause, MVSATA_EDMA_READ_4(mvport, EDMA_IEM), @@ -492,8 +498,9 @@ mvsata_error(struct mvsata_port *mvport) if (sc->sc_gen == gen1) mvsata_devconn_gen1(mvport); - DPRINTFN(3, (" device connected\n")); + DPRINTF(DEBUG_INTR, (" device connected\n")); } + #ifndef MVSATA_WITHOUTDMA if ((sc->sc_gen == gen1 && cause & EDMA_IE_ETRANSINT) || (sc->sc_gen != gen1 && cause & EDMA_IE_ESELFDIS)) { @@ -524,10 +531,138 @@ mvsata_error(struct mvsata_port *mvport) device_xname(MVSATA_DEV2(mvport)), mvport->port_hc->hc, mvport->port); } + if (cause & EDMA_IE_EDEVERR) { + aprint_error("%s:%d:%d: device error, recovering\n", + device_xname(MVSATA_DEV2(mvport)), + mvport->port_hc->hc, mvport->port); + + if (!mvport->port_recovering) + mvsata_channel_recover(mvport); + } return 1; } +static void +mvsata_hold(struct mvsata_port *mvport) +{ + mvport->port_hold_slots |= mvport->port_quetagidx; + mvport->port_quetagidx = 0; +} + +static void +mvsata_unhold(struct mvsata_port *mvport) +{ + mvport->port_quetagidx = mvport->port_hold_slots; + mvport->port_hold_slots = 0; +} + +static void +mvsata_channel_recover(struct mvsata_port *mvport) +{ + struct ata_channel *chp = &mvport->port_ata_channel; + struct ata_drive_datas *drvp; + int drive, error; + uint8_t eslot, slot, st, err; + struct ata_xfer *xfer; + + KASSERT(!mvport->port_recovering); + + mvport->port_recovering = true; + + if (chp->ch_ndrives > PMP_PORT_CTL) { + /* Get PM port number for the device in error. This device + * doesn't seem to have dedicated register for this, so just + * assume last selected port was the one. */ + /* XXX FIS-based switching */ + drive = MVSATA_EDMA_READ_4(mvport, SATA_SATAICTL) & 0xf; + } else + drive = 0; + + drvp = &chp->ch_drive[drive]; + + /* + * Controller doesn't need any special action. Simply execute + * READ LOG EXT for NCQ to unblock device processing, then continue + * as if nothing happened. + */ + KASSERT(drive >= 0); + + mvsata_hold(mvport); + + /* + * 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, &eslot, &st, &err); + + mvsata_unhold(mvport); + + switch (error) { + case 0: + /* Error out the particular NCQ xfer, then requeue the others */ + if ((mvport->port_quetagidx & (1 << eslot)) != 0) { + xfer = ata_queue_hwslot_to_xfer(chp, eslot); + xfer->c_flags |= C_RECOVERED; + xfer->c_bio.error = ERROR; + xfer->c_bio.r_error = err; + xfer->c_intr(chp, xfer, 1); + } + break; + + case EOPNOTSUPP: + /* + * Non-NCQ command error, just find the slot and end it with + * an error. Handler figures the error itself. + */ + for (slot = 0; slot < MVSATA_EDMAQ_LEN; slot++) { + if ((mvport->port_quetagidx & (1 << slot)) != 0) { + xfer = ata_queue_hwslot_to_xfer(chp, slot); + if (xfer->c_drive != drive) + continue; + + xfer->c_intr(chp, xfer, 1); + } + } + break; + + case EAGAIN: + /* + * Failed to get resources to run the recovery command, must + * reset the drive. This will also kill all still outstanding + * transfers. + */ + mvsata_reset_channel(chp, AT_POLL); + goto out; + /* NOTREACHED */ + + default: + /* + * The command to get the slot failed. Kill outstanding + * commands for the same drive only. No need to reset + * the drive, it's unblocked nevertheless. + */ + break; + } + + /* Requeue the non-errorred commands */ + for (slot = 0; slot < MVSATA_EDMAQ_LEN; slot++) { + if (((mvport->port_quetagidx >> slot) & 1) == 0) + continue; + + xfer = ata_queue_hwslot_to_xfer(chp, slot); + if (xfer->c_drive != drive) + continue; + + xfer->c_kill_xfer(chp, xfer, + (error == 0) ? KILL_REQUEUE : KILL_RESET); + } + +out: + /* Drive unblocked, back to normal operation */ + mvport->port_recovering = false; + atastart(chp); +} /* * ATA callback entry points @@ -561,7 +696,8 @@ mvsata_bio(struct ata_drive_datas *drvp, struct atac_softc *atac = chp->ch_atac; struct ata_bio *ata_bio = &xfer->c_bio; - DPRINTFN(1, ("%s:%d: mvsata_bio: drive=%d, blkno=%" PRId64 + DPRINTF(DEBUG_FUNCS|DEBUG_XFERS, + ("%s:%d: mvsata_bio: drive=%d, blkno=%" PRId64 ", bcount=%ld\n", device_xname(atac->atac_dev), chp->ch_channel, drvp->drive, ata_bio->blkno, ata_bio->bcount)); @@ -594,7 +730,8 @@ mvsata_reset_drive(struct ata_drive_data edma_c = MVSATA_EDMA_READ_4(mvport, EDMA_CMD); - DPRINTF(("%s:%d: mvsata_reset_drive: drive=%d (EDMA %sactive)\n", + DPRINTF(DEBUG_FUNCS, + ("%s:%d: mvsata_reset_drive: drive=%d (EDMA %sactive)\n", device_xname(MVSATA_DEV2(mvport)), chp->ch_channel, drvp->drive, (edma_c & EDMA_CMD_EENEDMA) ? "" : "not ")); @@ -622,7 +759,7 @@ mvsata_reset_channel(struct ata_channel struct mvsata_softc *sc = device_private(MVSATA_DEV2(mvport)); uint32_t sstat, ctrl; - DPRINTF(("%s: mvsata_reset_channel: channel=%d\n", + DPRINTF(DEBUG_FUNCS, ("%s: mvsata_reset_channel: channel=%d\n", device_xname(MVSATA_DEV2(mvport)), chp->ch_channel)); mvsata_hreset_port(mvport); @@ -664,7 +801,8 @@ mvsata_exec_command(struct ata_drive_dat struct ata_command *ata_c = &xfer->c_ata_c; int rv, s; - DPRINTFN(1, ("%s:%d: mvsata_exec_command: drive=%d, bcount=%d," + DPRINTF(DEBUG_FUNCS|DEBUG_XFERS, + ("%s:%d: mvsata_exec_command: drive=%d, bcount=%d," " r_lba=0x%012"PRIx64", r_count=0x%04x, r_features=0x%04x," " r_device=0x%02x, r_command=0x%02x\n", device_xname(MVSATA_DEV2(mvport)), chp->ch_channel, @@ -853,7 +991,7 @@ mvsata_atapi_probe_device(struct atapibu /* if no ATAPI device detected at attach time, skip */ if (drvp->drive_type != ATA_DRIVET_ATAPI) { - DPRINTF(("%s:%d: mvsata_atapi_probe_device:" + DPRINTF(DEBUG_PROBE, ("%s:%d: mvsata_atapi_probe_device:" " drive %d not present\n", device_xname(atac->atac_dev), chp->ch_channel, target)); return; @@ -929,7 +1067,7 @@ mvsata_atapi_probe_device(struct atapibu splx(s); } } else { - DPRINTF(("%s:%d: mvsata_atapi_probe_device:" + DPRINTF(DEBUG_PROBE, ("%s:%d: mvsata_atapi_probe_device:" " ATAPI_IDENTIFY_DEVICE failed for drive %d: error\n", device_xname(atac->atac_dev), chp->ch_channel, target)); s = splbio(); @@ -978,7 +1116,7 @@ mvsata_setup_channel(struct ata_channel const int eprd_buf_size = MVSATA_EPRD_MAX_SIZE * MVSATA_EDMAQ_LEN; #endif - DPRINTF(("%s:%d: mvsata_setup_channel: ", + DPRINTF(DEBUG_FUNCS, ("%s:%d: mvsata_setup_channel: ", device_xname(MVSATA_DEV2(mvport)), chp->ch_channel)); edma_mode = nodma; @@ -1004,7 +1142,8 @@ mvsata_setup_channel(struct ata_channel } } - DPRINTF(("EDMA %sactive mode\n", (edma_mode == nodma) ? "not " : "")); + DPRINTF(DEBUG_FUNCS, + ("EDMA %sactive mode\n", (edma_mode == nodma) ? "not " : "")); #ifndef MVSATA_WITHOUTDMA if (edma_mode == nodma) { @@ -1074,12 +1213,12 @@ mvsata_bio_start(struct ata_channel *chp struct wdc_softc *wdc = CHAN_TO_WDC(chp); struct ata_bio *ata_bio = &xfer->c_bio; struct ata_drive_datas *drvp = &chp->ch_drive[xfer->c_drive]; - int wait_flags = ata_bio->flags & (AT_WAIT|AT_POLL); + int wait_flags = (xfer->c_flags & C_POLL) ? AT_POLL : 0; u_int16_t cyl; u_int8_t head, sect, cmd = 0; int nblks, error, tfd; - DPRINTFN(2, ("%s:%d: mvsata_bio_start: drive=%d\n", + DPRINTF(DEBUG_FUNCS|DEBUG_XFERS, ("%s:%d: mvsata_bio_start: drive=%d\n", device_xname(atac->atac_dev), chp->ch_channel, xfer->c_drive)); if (xfer->c_flags & C_DMA) @@ -1320,7 +1459,7 @@ mvsata_bio_intr(struct ata_channel *chp, struct ata_drive_datas *drvp = &chp->ch_drive[xfer->c_drive]; int tfd; - DPRINTFN(2, ("%s:%d: %s: drive=%d\n", + DPRINTF(DEBUG_FUNCS|DEBUG_XFERS, ("%s:%d: %s: drive=%d\n", device_xname(atac->atac_dev), chp->ch_channel, __func__, xfer->c_drive)); @@ -1416,7 +1555,8 @@ mvsata_bio_kill_xfer(struct ata_channel int drive = xfer->c_drive; bool deactivate = true; - DPRINTFN(2, ("%s:%d: mvsata_bio_kill_xfer: drive=%d\n", + DPRINTF(DEBUG_FUNCS|DEBUG_XFERS, + ("%s:%d: mvsata_bio_kill_xfer: drive=%d\n", device_xname(atac->atac_dev), chp->ch_channel, xfer->c_drive)); /* EDMA restart, if enabled */ @@ -1436,6 +1576,9 @@ mvsata_bio_kill_xfer(struct ata_channel case KILL_RESET: ata_bio->error = ERR_RESET; break; + case KILL_REQUEUE: + ata_bio->error = REQUEUE; + break; default: aprint_error_dev(atac->atac_dev, "mvsata_bio_kill_xfer: unknown reason %d\n", reason); @@ -1457,8 +1600,10 @@ mvsata_bio_done(struct ata_channel *chp, struct mvsata_port *mvport = (struct mvsata_port *)chp; struct ata_bio *ata_bio = &xfer->c_bio; int drive = xfer->c_drive; + bool iserror = (ata_bio->error == NOERROR); - DPRINTFN(2, ("%s:%d: mvsata_bio_done: drive=%d, flags=0x%x\n", + DPRINTF(DEBUG_FUNCS|DEBUG_XFERS, + ("%s:%d: mvsata_bio_done: drive=%d, flags=0x%x\n", device_xname(MVSATA_DEV2(mvport)), chp->ch_channel, xfer->c_drive, (u_int)xfer->c_flags)); @@ -1480,7 +1625,8 @@ mvsata_bio_done(struct ata_channel *chp, ata_bio->flags |= ATA_ITSDONE; (*chp->ch_drive[drive].drv_done)(chp->ch_drive[drive].drv_softc, xfer); - atastart(chp); + if (!iserror) + atastart(chp); } static int @@ -1600,10 +1746,12 @@ mvsata_wdc_cmd_start(struct ata_channel struct ata_command *ata_c = &xfer->c_ata_c; int tfd; - DPRINTFN(1, ("%s:%d: mvsata_cmd_start: drive=%d\n", + DPRINTF(DEBUG_FUNCS|DEBUG_XFERS, + ("%s:%d: mvsata_cmd_start: drive=%d\n", device_xname(MVSATA_DEV2(mvport)), chp->ch_channel, drive)); /* First, EDMA disable, if enabled this channel. */ + KASSERT((chp->ch_flags & ATACH_NCQ) == 0); if (mvport->port_edmamode_curr != nodma) mvsata_edma_disable(mvport, 10 /* ms */, wait_flags); @@ -1687,7 +1835,7 @@ mvsata_wdc_cmd_intr(struct ata_channel * wflags = AT_POLL; again: - DPRINTFN(1, ("%s:%d: %s: drive=%d\n", + DPRINTF(DEBUG_FUNCS|DEBUG_XFERS, ("%s:%d: %s: drive=%d\n", device_xname(MVSATA_DEV2(mvport)), chp->ch_channel, __func__, xfer->c_drive)); @@ -1761,7 +1909,8 @@ mvsata_wdc_cmd_kill_xfer(struct ata_chan struct ata_command *ata_c = &xfer->c_ata_c; bool deactivate = true; - DPRINTFN(1, ("%s:%d: mvsata_cmd_kill_xfer: drive=%d\n", + DPRINTF(DEBUG_FUNCS|DEBUG_XFERS, + ("%s:%d: mvsata_cmd_kill_xfer: drive=%d\n", device_xname(MVSATA_DEV2(mvport)), chp->ch_channel, xfer->c_drive)); switch (reason) { @@ -1774,6 +1923,9 @@ mvsata_wdc_cmd_kill_xfer(struct ata_chan case KILL_RESET: ata_c->flags |= AT_RESET; break; + case KILL_REQUEUE: + panic("%s: not supposed to be requeued\n", __func__); + break; default: aprint_error_dev(MVSATA_DEV2(mvport), "mvsata_cmd_kill_xfer: unknown reason %d\n", reason); @@ -1795,7 +1947,8 @@ mvsata_wdc_cmd_done(struct ata_channel * struct atac_softc *atac = chp->ch_atac; struct ata_command *ata_c = &xfer->c_ata_c; - DPRINTFN(1, ("%s:%d: mvsata_cmd_done: drive=%d, flags=0x%x\n", + DPRINTF(DEBUG_FUNCS|DEBUG_XFERS, + ("%s:%d: mvsata_cmd_done: drive=%d, flags=0x%x\n", device_xname(atac->atac_dev), chp->ch_channel, xfer->c_drive, ata_c->flags)); @@ -1860,7 +2013,8 @@ mvsata_wdc_cmd_done(struct ata_channel * } mvsata_wdc_cmd_done_end(chp, xfer); - atastart(chp); + if ((ATACH_ST(tfd) & WDCS_ERR) == 0) + atastart(chp); } static void @@ -1893,10 +2047,12 @@ mvsata_atapi_start(struct ata_channel *c const char *errstring; int tfd; - DPRINTFN(2, ("%s:%d:%d: mvsata_atapi_start: scsi flags 0x%x\n", + DPRINTF(DEBUG_FUNCS|DEBUG_XFERS, + ("%s:%d:%d: mvsata_atapi_start: scsi flags 0x%x\n", device_xname(chp->ch_atac->atac_dev), chp->ch_channel, xfer->c_drive, sc_xfer->xs_control)); + KASSERT((chp->ch_flags & ATACH_NCQ) == 0); if (mvport->port_edmamode_curr != nodma) mvsata_edma_disable(mvport, 10 /* ms */, wait_flags); @@ -2074,7 +2230,8 @@ mvsata_atapi_intr(struct ata_channel *ch int tfd; void *cmd; - DPRINTFN(1, ("%s:%d:%d: mvsata_atapi_intr\n", + DPRINTF(DEBUG_FUNCS|DEBUG_XFERS, + ("%s:%d:%d: mvsata_atapi_intr\n", device_xname(atac->atac_dev), chp->ch_channel, xfer->c_drive)); /* Is it not a transfer, but a control operation? */ @@ -2131,14 +2288,14 @@ again: 256 * MVSATA_WDC_READ_1(mvport, SRB_LBAH); ire = MVSATA_WDC_READ_1(mvport, SRB_SC); phase = (ire & (WDCI_CMD | WDCI_IN)) | (ATACH_ST(tfd) & WDCS_DRQ); - DPRINTF(( + DPRINTF(DEBUG_FUNCS|DEBUG_XFERS, ( "mvsata_atapi_intr: c_bcount %d len %d st 0x%x err 0x%x ire 0x%x :", xfer->c_bcount, len, ATACH_ST(tfd), ATACH_ERR(tfd), ire)); switch (phase) { case PHASE_CMDOUT: cmd = sc_xfer->cmd; - DPRINTF(("PHASE_CMDOUT\n")); + DPRINTF(DEBUG_FUNCS|DEBUG_XFERS, ("PHASE_CMDOUT\n")); /* Init the DMA channel if necessary */ if (xfer->c_flags & C_DMA) { error = mvsata_bdma_init(mvport, xfer); @@ -2170,7 +2327,7 @@ again: case PHASE_DATAOUT: /* write data */ - DPRINTF(("PHASE_DATAOUT\n")); + DPRINTF(DEBUG_XFERS, ("PHASE_DATAOUT\n")); if ((sc_xfer->xs_control & XS_CTL_DATA_OUT) == 0 || (xfer->c_flags & C_DMA) != 0) { aprint_error_dev(atac->atac_dev, @@ -2204,7 +2361,7 @@ again: case PHASE_DATAIN: /* Read data */ - DPRINTF(("PHASE_DATAIN\n")); + DPRINTF(DEBUG_XFERS, ("PHASE_DATAIN\n")); if ((sc_xfer->xs_control & XS_CTL_DATA_IN) == 0 || (xfer->c_flags & C_DMA) != 0) { aprint_error_dev(atac->atac_dev, @@ -2238,7 +2395,7 @@ again: case PHASE_ABORTED: case PHASE_COMPLETED: - DPRINTF(("PHASE_COMPLETED\n")); + DPRINTF(DEBUG_XFERS, ("PHASE_COMPLETED\n")); if (xfer->c_flags & C_DMA) xfer->c_bcount -= sc_xfer->datalen; sc_xfer->resid = xfer->c_bcount; @@ -2269,8 +2426,10 @@ again: return (1); } } - DPRINTF(("mvsata_atapi_intr: mvsata_atapi_done() (end), error 0x%x " - "sense 0x%x\n", sc_xfer->error, sc_xfer->sense.atapi_sense)); + DPRINTF(DEBUG_FUNCS|DEBUG_XFERS, + ("mvsata_atapi_intr: %s (end), error 0x%x " + "sense 0x%x\n", __func__, + sc_xfer->error, sc_xfer->sense.atapi_sense)); mvsata_atapi_done(chp, xfer); return 1; } @@ -2294,6 +2453,9 @@ mvsata_atapi_kill_xfer(struct ata_channe case KILL_RESET: sc_xfer->error = XS_RESET; break; + case KILL_REQUEUE: + sc_xfer->error = XS_REQUEUE; + break; default: aprint_error_dev(MVSATA_DEV2(mvport), "mvsata_atapi_kill_xfer: unknown reason %d\n", reason); @@ -2343,7 +2505,7 @@ mvsata_atapi_phase_complete(struct ata_x /* wait for DSC if needed */ if (drvp->drive_flags & ATA_DRIVE_ATAPIDSCW) { - DPRINTFN(1, + DPRINTF(DEBUG_XFERS, ("%s:%d:%d: mvsata_atapi_phase_complete: polldsc %d\n", device_xname(atac->atac_dev), chp->ch_channel, xfer->c_drive, xfer->c_dscpoll)); @@ -2393,7 +2555,7 @@ mvsata_atapi_phase_complete(struct ata_x } } if (xfer->c_bcount != 0) { - DPRINTFN(1, ("%s:%d:%d: mvsata_atapi_intr:" + DPRINTF(DEBUG_XFERS, ("%s:%d:%d: mvsata_atapi_intr:" " bcount value is %d after io\n", device_xname(atac->atac_dev), chp->ch_channel, xfer->c_drive, xfer->c_bcount)); @@ -2407,7 +2569,8 @@ mvsata_atapi_phase_complete(struct ata_x } #endif - DPRINTFN(1, ("%s:%d:%d: mvsata_atapi_phase_complete:" + DPRINTF(DEBUG_XFERS, + ("%s:%d:%d: mvsata_atapi_phase_complete:" " mvsata_atapi_done(), error 0x%x sense 0x%x\n", device_xname(atac->atac_dev), chp->ch_channel, xfer->c_drive, sc_xfer->error, sc_xfer->sense.atapi_sense)); @@ -2419,8 +2582,10 @@ mvsata_atapi_done(struct ata_channel *ch { struct mvsata_port *mvport = (struct mvsata_port *)chp; struct scsipi_xfer *sc_xfer = xfer->c_scsipi; + bool iserror = (sc_xfer->error == XS_NOERROR); - DPRINTFN(1, ("%s:%d:%d: mvsata_atapi_done: flags 0x%x\n", + DPRINTF(DEBUG_FUNCS|DEBUG_XFERS, + ("%s:%d:%d: mvsata_atapi_done: flags 0x%x\n", device_xname(chp->ch_atac->atac_dev), chp->ch_channel, xfer->c_drive, (u_int)xfer->c_flags)); @@ -2433,13 +2598,16 @@ mvsata_atapi_done(struct ata_channel *ch ata_free_xfer(chp, xfer); - DPRINTFN(1, ("%s:%d: mvsata_atapi_done: scsipi_done\n", + DPRINTF(DEBUG_FUNCS|DEBUG_XFERS, + ("%s:%d: mvsata_atapi_done: scsipi_done\n", device_xname(chp->ch_atac->atac_dev), chp->ch_channel)); scsipi_done(sc_xfer); - DPRINTFN(1, ("%s:%d: atastart from wdc_atapi_done, flags 0x%x\n", + DPRINTF(DEBUG_FUNCS, + ("%s:%d: atastart from wdc_atapi_done, flags 0x%x\n", device_xname(chp->ch_atac->atac_dev), chp->ch_channel, chp->ch_flags)); - atastart(chp); + if (!iserror) + atastart(chp); } static void @@ -2468,7 +2636,7 @@ mvsata_edma_enqueue(struct mvsata_port * uint32_t reg; int erqqip, erqqop, next, rv, i; - DPRINTFN(2, ("%s:%d:%d: mvsata_edma_enqueue:" + DPRINTF(DEBUG_FUNCS|DEBUG_XFERS, ("%s:%d:%d: mvsata_edma_enqueue:" " blkno=0x%" PRIx64 ", nbytes=%d, flags=0x%x\n", device_xname(MVSATA_DEV2(mvport)), mvport->port_hc->hc, mvport->port, ata_bio->blkno, ata_bio->nbytes, ata_bio->flags)); @@ -2483,7 +2651,8 @@ mvsata_edma_enqueue(struct mvsata_port * /* queue full */ return EBUSY; } - DPRINTFN(2, (" erqqip=%d, quetag=%d\n", erqqip, xfer->c_slot)); + DPRINTF(DEBUG_XFERS, + (" erqqip=%d, quetag=%d\n", erqqip, xfer->c_slot)); rv = mvsata_dma_bufload(mvport, xfer->c_slot, databuf, ata_bio->nbytes, ata_bio->flags); @@ -2542,7 +2711,7 @@ mvsata_edma_handle(struct mvsata_port *m struct ata_xfer *xfer; uint32_t reg; int erqqip, erqqop, erpqip, erpqop, prev_erpqop, quetag, handled = 0, n; - int st, err, tfd; + int st, dmaerr; /* First, Sync for Request Queue buffer */ reg = MVSATA_EDMA_READ_4(mvport, EDMA_REQQOP); @@ -2572,7 +2741,8 @@ mvsata_edma_handle(struct mvsata_port *m reg = MVSATA_EDMA_READ_4(mvport, EDMA_RESQOP); erpqop = (reg & EDMA_RESQP_ERPQP_MASK) >> EDMA_RESQP_ERPQP_SHIFT; - DPRINTFN(3, ("%s:%d:%d: mvsata_edma_handle: erpqip=%d, erpqop=%d\n", + DPRINTF(DEBUG_XFERS, + ("%s:%d:%d: mvsata_edma_handle: erpqip=%d, erpqop=%d\n", device_xname(MVSATA_DEV2(mvport)), mvport->port_hc->hc, mvport->port, erpqip, erpqop)); @@ -2610,18 +2780,16 @@ mvsata_edma_handle(struct mvsata_port *m MVSATA_EPRD_MAX_SIZE, BUS_DMASYNC_POSTWRITE); st = CRPB_CDEVSTS(le16toh(crpb->rspflg)); - err = CRPB_CEDMASTS(le16toh(crpb->rspflg)); - - tfd = ATACH_ERR_ST(err, st); + dmaerr = CRPB_CEDMASTS(le16toh(crpb->rspflg)); ata_bio = &xfer->c_bio; ata_bio->error = NOERROR; ata_bio->r_error = 0; - if (ATACH_ST(tfd) & WDCS_ERR) + if (st & WDCS_ERR) ata_bio->error = ERROR; - if (ATACH_ST(tfd) & WDCS_BSY) + if (st & WDCS_BSY) ata_bio->error = TIMEOUT; - if (ATACH_ERR(tfd)) + if (dmaerr != 0) ata_bio->error = ERR_DMA; mvsata_dma_bufunload(mvport, quetag, ata_bio->flags); @@ -2680,7 +2848,7 @@ mvsata_edma_wait(struct mvsata_port *mvp DELAY(100); } - DPRINTF(("mvsata_edma_wait: timeout: %p\n", xfer)); + DPRINTF(DEBUG_FUNCS, ("%s: timeout: %p\n", __func__, xfer)); mvsata_edma_rqq_remove(mvport, xfer); xfer->c_flags |= C_TIMEOU; return 1; @@ -2695,7 +2863,7 @@ mvsata_edma_timeout(void *arg) int s; s = splbio(); - DPRINTF(("mvsata_edma_timeout: %p\n", xfer)); + DPRINTF(DEBUG_FUNCS, ("%s: %p\n", __func__, xfer)); if (ata_timo_xfer_check(xfer)) { /* Already logged */ @@ -2774,7 +2942,7 @@ mvsata_bdma_init(struct mvsata_port *mvp int i, rv; void *databuf = (uint8_t *)xfer->c_databuf + xfer->c_skip; - DPRINTFN(2, + DPRINTF(DEBUG_FUNCS|DEBUG_XFERS, ("%s:%d:%d: mvsata_bdma_init: datalen=%d, xs_control=0x%x\n", device_xname(MVSATA_DEV2(mvport)), mvport->port_hc->hc, mvport->port, sc_xfer->datalen, sc_xfer->xs_control)); Index: src/sys/dev/ic/mvsatavar.h diff -u src/sys/dev/ic/mvsatavar.h:1.2.48.3 src/sys/dev/ic/mvsatavar.h:1.2.48.4 --- src/sys/dev/ic/mvsatavar.h:1.2.48.3 Tue Aug 1 22:02:32 2017 +++ src/sys/dev/ic/mvsatavar.h Sat Aug 12 22:43:22 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: mvsatavar.h,v 1.2.48.3 2017/08/01 22:02:32 jdolecek Exp $ */ +/* $NetBSD: mvsatavar.h,v 1.2.48.4 2017/08/12 22:43:22 jdolecek Exp $ */ /* * Copyright (c) 2008 KIYOHARA Takashi * All rights reserved. @@ -96,6 +96,10 @@ struct mvsata_port { bus_space_handle_t port_sata_sstatus; /* SATA Interface status reg */ struct _fix_phy_param _fix_phy_param; + + /* Recovery context */ + uint32_t port_hold_slots; + bool port_recovering; }; struct mvsata_hc {