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 {

Reply via email to