Module Name:    src
Committed By:   jdolecek
Date:           Fri Jun 16 20:40:49 UTC 2017

Modified Files:
        src/sys/dev/ata [jdolecek-ncq]: ata.c ata_wdc.c atavar.h wd.c
        src/sys/dev/ic [jdolecek-ncq]: ahcisata_core.c mvsata.c siisata.c wdc.c
        src/sys/dev/scsipi [jdolecek-ncq]: atapi_wdc.c

Log Message:
adjust reset channel and dump paths
- channel reset now always kills active transfer, even on dump path, but
  now doesn't touch the queued waiting transfers; also kill_xfer hook is
  always called, so that HBA can free any private xfer resources and thus
  the dump request has chance to work
- kill_xfer routines now always call ata_deactivate_xfer(); added KASSERT()s
  to ata_free_xfer() to expect deactivated xfer
- when called during channel reset before dump, ata_kill_active() drops
  any queued waiting transfers without processing
- do not (re)queue any transfers in wddone() when dumping
- kill AT_RST_NOCMD flag

This should also hopefully fix the 'polled command has been queued' panic
as reported in:
PR kern/11811 by John Hawkinson
PR kern/47041 by Taylor R Campbell
PR kern/51979 by Martin Husemann

dump tested working with piixide(4) and ahci(4). mvsata(4) dump times out,
but otherwise tested working, will be fixed separately. siisata(4) mechanically
changed and not tested.


To generate a diff of this commit:
cvs rdiff -u -r1.132.8.8 -r1.132.8.9 src/sys/dev/ata/ata.c
cvs rdiff -u -r1.105.6.3 -r1.105.6.4 src/sys/dev/ata/ata_wdc.c
cvs rdiff -u -r1.92.8.8 -r1.92.8.9 src/sys/dev/ata/atavar.h
cvs rdiff -u -r1.428.2.15 -r1.428.2.16 src/sys/dev/ata/wd.c
cvs rdiff -u -r1.57.6.12 -r1.57.6.13 src/sys/dev/ic/ahcisata_core.c
cvs rdiff -u -r1.35.6.10 -r1.35.6.11 src/sys/dev/ic/mvsata.c
cvs rdiff -u -r1.30.4.15 -r1.30.4.16 src/sys/dev/ic/siisata.c
cvs rdiff -u -r1.283.2.4 -r1.283.2.5 src/sys/dev/ic/wdc.c
cvs rdiff -u -r1.123.4.4 -r1.123.4.5 src/sys/dev/scsipi/atapi_wdc.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/ata/ata.c
diff -u src/sys/dev/ata/ata.c:1.132.8.8 src/sys/dev/ata/ata.c:1.132.8.9
--- src/sys/dev/ata/ata.c:1.132.8.8	Mon Apr 24 22:20:23 2017
+++ src/sys/dev/ata/ata.c	Fri Jun 16 20:40:49 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: ata.c,v 1.132.8.8 2017/04/24 22:20:23 jdolecek Exp $	*/
+/*	$NetBSD: ata.c,v 1.132.8.9 2017/06/16 20:40:49 jdolecek Exp $	*/
 
 /*
  * Copyright (c) 1998, 2001 Manuel Bouyer.  All rights reserved.
@@ -25,7 +25,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ata.c,v 1.132.8.8 2017/04/24 22:20:23 jdolecek Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ata.c,v 1.132.8.9 2017/06/16 20:40:49 jdolecek Exp $");
 
 #include "opt_ata.h"
 
@@ -187,6 +187,8 @@ ata_queue_reset(struct ata_queue *chq)
 	TAILQ_INIT(&chq->active_xfers);
 	chq->queue_freeze = 0;
 	chq->queue_active = 0;
+	chq->active_xfers_used = 0;
+	chq->queue_xfers_avail = (1 << chq->queue_openings) - 1;
 }
 
 struct ata_xfer *
@@ -207,6 +209,18 @@ ata_queue_hwslot_to_xfer(struct ata_queu
 	    chq->active_xfers_used);
 }
 
+/*
+ * This interface is supposed only to be used when there is exactly
+ * one outstanding command, and there is no information about the slot,
+ * which triggered the command. ata_queue_hwslot_to_xfer() interface
+ * is preferred in all standard cases.
+ */
+struct ata_xfer *
+ata_queue_active_xfer_peek(struct ata_queue *chq)
+{
+	return TAILQ_FIRST(&chq->active_xfers);
+}
+
 void
 ata_xfer_init(struct ata_xfer *xfer, bool zero)
 {
@@ -241,7 +255,6 @@ ata_queue_alloc(uint8_t openings)
 	    M_DEVBUF, M_WAITOK | M_ZERO);
 
 	chq->queue_openings = openings;
-	chq->queue_xfers_avail = (1 << openings) - 1;
 	ata_queue_reset(chq);
 
 	for (uint8_t i = 0; i < openings; i++)
@@ -258,7 +271,6 @@ ata_queue_downsize(struct ata_queue *chq
 	KASSERT(openings < chq->queue_openings);
 
 	chq->queue_openings = openings;
-	chq->queue_xfers_avail = (1 << openings) - 1;
 	ata_queue_reset(chq);
 }
 
@@ -1136,6 +1148,8 @@ ata_get_xfer(struct ata_channel *chp)
 	xfer = &chq->queue_xfers[slot];
 	chq->queue_xfers_avail &= ~__BIT(slot);
 
+	KASSERT((chq->active_xfers_used & __BIT(slot)) == 0);
+
 	/* zero everything after the callout member */
 	memset(&xfer->c_startzero, 0,
 	    sizeof(struct ata_xfer) - offsetof(struct ata_xfer, c_startzero));
@@ -1146,6 +1160,9 @@ out:
 	return xfer;
 }
 
+/*
+ * ata_deactivate_xfer() must be always called prior to ata_free_xfer()
+ */
 void
 ata_free_xfer(struct ata_channel *chp, struct ata_xfer *xfer)
 {
@@ -1171,6 +1188,7 @@ ata_free_xfer(struct ata_channel *chp, s
 #endif
 
 	s = splbio();
+	KASSERT((chq->active_xfers_used & __BIT(xfer->c_slot)) == 0);
 	KASSERT((chq->queue_xfers_avail & __BIT(xfer->c_slot)) == 0);
 	chq->queue_xfers_avail |= __BIT(xfer->c_slot);
 	splx(s);
@@ -1236,7 +1254,7 @@ ata_waitdrain_xfer_check(struct ata_chan
  * Must be called at splbio().
  */
 void
-ata_kill_active(struct ata_channel *chp, int reason)
+ata_kill_active(struct ata_channel *chp, int reason, int flags)
 {
 	struct ata_queue * const chq = chp->ch_queue;
 	struct ata_xfer *xfer, *xfernext;
@@ -1244,6 +1262,9 @@ ata_kill_active(struct ata_channel *chp,
 	TAILQ_FOREACH_SAFE(xfer, &chq->active_xfers, c_activechain, xfernext) {
 		(*xfer->c_kill_xfer)(xfer->c_chp, xfer, reason);
 	}
+
+	if (flags & AT_RST_EMERG)
+		ata_queue_reset(chq);
 }
 
 /*
@@ -1322,7 +1343,7 @@ ata_reset_channel(struct ata_channel *ch
 			return;
 		}
 		chp->ch_flags |= ATACH_TH_RESET;
-		chp->ch_reset_flags = flags & (AT_RST_EMERG | AT_RST_NOCMD);
+		chp->ch_reset_flags = flags & AT_RST_EMERG;
 		wakeup(&chp->ch_thread);
 		return;
 	}
@@ -1486,7 +1507,7 @@ ata_downgrade_mode(struct ata_drive_data
 	(*atac->atac_set_modes)(chp);
 	ata_print_modes(chp);
 	/* reset the channel, which will schedule all drives for setup */
-	ata_reset_channel(chp, flags | AT_RST_NOCMD);
+	ata_reset_channel(chp, flags);
 	return 1;
 }
 #endif	/* NATA_DMA */

Index: src/sys/dev/ata/ata_wdc.c
diff -u src/sys/dev/ata/ata_wdc.c:1.105.6.3 src/sys/dev/ata/ata_wdc.c:1.105.6.4
--- src/sys/dev/ata/ata_wdc.c:1.105.6.3	Wed Apr 19 20:49:17 2017
+++ src/sys/dev/ata/ata_wdc.c	Fri Jun 16 20:40:49 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: ata_wdc.c,v 1.105.6.3 2017/04/19 20:49:17 jdolecek Exp $	*/
+/*	$NetBSD: ata_wdc.c,v 1.105.6.4 2017/06/16 20:40:49 jdolecek Exp $	*/
 
 /*
  * Copyright (c) 1998, 2001, 2003 Manuel Bouyer.
@@ -54,7 +54,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ata_wdc.c,v 1.105.6.3 2017/04/19 20:49:17 jdolecek Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ata_wdc.c,v 1.105.6.4 2017/06/16 20:40:49 jdolecek Exp $");
 
 #include "opt_ata.h"
 #include "opt_wdc.h"
@@ -775,6 +775,8 @@ wdc_ata_bio_kill_xfer(struct ata_channel
 	struct ata_bio *ata_bio = &xfer->c_bio;
 	int drive = xfer->c_drive;
 
+	ata_deactivate_xfer(chp, xfer);
+
 	ata_bio->flags |= ATA_ITSDONE;
 	switch (reason) {
 	case KILL_GONE:

Index: src/sys/dev/ata/atavar.h
diff -u src/sys/dev/ata/atavar.h:1.92.8.8 src/sys/dev/ata/atavar.h:1.92.8.9
--- src/sys/dev/ata/atavar.h:1.92.8.8	Mon Apr 24 22:20:23 2017
+++ src/sys/dev/ata/atavar.h	Fri Jun 16 20:40:49 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: atavar.h,v 1.92.8.8 2017/04/24 22:20:23 jdolecek Exp $	*/
+/*	$NetBSD: atavar.h,v 1.92.8.9 2017/06/16 20:40:49 jdolecek Exp $	*/
 
 /*
  * Copyright (c) 1998, 2001 Manuel Bouyer.
@@ -185,7 +185,7 @@ struct ata_xfer {
 
 /* Per-channel queue of ata_xfers */
 struct ata_queue {
-	TAILQ_HEAD(, ata_xfer) queue_xfer; /* queue of pending commands */
+	TAILQ_HEAD(, ata_xfer) queue_xfer; 	/* queue of pending commands */
 	int queue_freeze; /* freeze count for the queue */
 	int queue_flags;	/* flags for this queue */
 #define QF_IDLE_WAIT	0x01    /* someone wants the controller idle */
@@ -322,7 +322,6 @@ struct ata_bustype {
 	void	(*ata_reset_channel)(struct ata_channel *, int);
 /* extra flags for ata_reset_*(), in addition to AT_* */
 #define AT_RST_EMERG 0x10000 /* emergency - e.g. for a dump */
-#define	AT_RST_NOCMD 0x20000 /* XXX has to go - temporary until we have tagged queuing */
 
 	int	(*ata_exec_command)(struct ata_drive_datas *,
 				    struct ata_xfer *);
@@ -482,7 +481,7 @@ void	ata_deactivate_xfer(struct ata_chan
 
 void	ata_exec_xfer(struct ata_channel *, struct ata_xfer *);
 void	ata_kill_pending(struct ata_drive_datas *);
-void	ata_kill_active(struct ata_channel *, int);
+void	ata_kill_active(struct ata_channel *, int, int);
 void	ata_reset_channel(struct ata_channel *, int);
 
 int	ata_addref(struct ata_channel *);
@@ -505,6 +504,8 @@ struct ata_queue *
 void	ata_queue_free(struct ata_queue *);
 struct ata_xfer *
 	ata_queue_hwslot_to_xfer(struct ata_queue *, int);
+struct ata_xfer *
+	ata_queue_active_xfer_peek(struct ata_queue *);
 
 void	ata_delay(int, const char *, int);
 

Index: src/sys/dev/ata/wd.c
diff -u src/sys/dev/ata/wd.c:1.428.2.15 src/sys/dev/ata/wd.c:1.428.2.16
--- src/sys/dev/ata/wd.c:1.428.2.15	Wed Jun 14 20:17:46 2017
+++ src/sys/dev/ata/wd.c	Fri Jun 16 20:40:49 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: wd.c,v 1.428.2.15 2017/06/14 20:17:46 jdolecek Exp $ */
+/*	$NetBSD: wd.c,v 1.428.2.16 2017/06/16 20:40:49 jdolecek Exp $ */
 
 /*
  * Copyright (c) 1998, 2001 Manuel Bouyer.  All rights reserved.
@@ -54,7 +54,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: wd.c,v 1.428.2.15 2017/06/14 20:17:46 jdolecek Exp $");
+__KERNEL_RCSID(0, "$NetBSD: wd.c,v 1.428.2.16 2017/06/16 20:40:49 jdolecek Exp $");
 
 #include "opt_ata.h"
 
@@ -168,6 +168,10 @@ const struct cdevsw wd_cdevsw = {
 	.d_flag = D_DISK | D_MPSAFE
 };
 
+/* #define WD_DUMP_NOT_TRUSTED if you just want to watch */
+static int wddoingadump = 0;
+static int wddumprecalibrated = 0;
+
 /*
  * Glue necessary to hook WDCIOCCOMMAND into physio
  */
@@ -742,6 +746,11 @@ wddone(void *v, struct ata_xfer *xfer)
 
 	ATADEBUG_PRINT(("wddone %s\n", device_xname(wd->sc_dev)),
 	    DEBUG_XFERS);
+	if (wddoingadump) {
+		/* just drop it to the floor */
+		ata_free_xfer(wd->drvp->chnl_softc, xfer);
+		return;
+	}
 
 	mutex_enter(&wd->sc_lock);
 
@@ -770,7 +779,7 @@ wddone(void *v, struct ata_xfer *xfer)
 		errmsg = "error";
 		do_perror = 1;
 retry:		/* Just reset and retry. Can we do more ? */
-		(*wd->atabus->ata_reset_drive)(wd->drvp, AT_RST_NOCMD, NULL);
+		(*wd->atabus->ata_reset_drive)(wd->drvp, 0, NULL);
 retry2:
 		diskerr(bp, "wd", errmsg, LOG_PRINTF,
 		    xfer->c_bio.blkdone, wd->sc_dk.dk_label);
@@ -1583,10 +1592,6 @@ wdsize(dev_t dev)
 	return (size);
 }
 
-/* #define WD_DUMP_NOT_TRUSTED if you just want to watch */
-static int wddoingadump = 0;
-static int wddumprecalibrated = 0;
-
 /*
  * Dump core after a system crash.
  */
@@ -1683,8 +1688,6 @@ wddump(dev_t dev, daddr_t blkno, void *v
 		panic("wddump: unknown error type %d", err);
 	}
 
-	ata_free_xfer(wd->drvp->chnl_softc, xfer);
-
 	if (err != 0) {
 		printf("\n");
 		return err;

Index: src/sys/dev/ic/ahcisata_core.c
diff -u src/sys/dev/ic/ahcisata_core.c:1.57.6.12 src/sys/dev/ic/ahcisata_core.c:1.57.6.13
--- src/sys/dev/ic/ahcisata_core.c:1.57.6.12	Tue Apr 25 20:55:05 2017
+++ src/sys/dev/ic/ahcisata_core.c	Fri Jun 16 20:40:49 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: ahcisata_core.c,v 1.57.6.12 2017/04/25 20:55:05 jdolecek Exp $	*/
+/*	$NetBSD: ahcisata_core.c,v 1.57.6.13 2017/06/16 20:40:49 jdolecek Exp $	*/
 
 /*
  * Copyright (c) 2006 Manuel Bouyer.
@@ -26,7 +26,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ahcisata_core.c,v 1.57.6.12 2017/04/25 20:55:05 jdolecek Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ahcisata_core.c,v 1.57.6.13 2017/06/16 20:40:49 jdolecek Exp $");
 
 #include <sys/types.h>
 #include <sys/malloc.h>
@@ -673,10 +673,7 @@ ahci_exec_fis(struct ata_channel *chp, i
 			    AHCINAME(sc), chp->ch_channel, is);
 			return ERR_DF;
 		}
-		if (flags & AT_WAIT)
-			tsleep(&sc, PRIBIO, "ahcifis", 1);
-		else
-			delay(10000);
+		ata_delay(10, "ahcifis", flags);
 	}
 
 	aprint_debug("%s channel %d: timeout sending FIS\n",
@@ -779,10 +776,7 @@ skip_reset:
 		sig = AHCI_READ(sc, AHCI_P_TFD(chp->ch_channel));
 		if ((__SHIFTOUT(sig, AHCI_P_TFD_ST) & WDCS_BSY) == 0)
 			break;
-		if (flags & AT_WAIT)
-			tsleep(&sc, PRIBIO, "ahcid2h", mstohz(10));
-		else
-			delay(10000);
+		ata_delay(10, "ahcid2h", flags);
 	}
 	if (i == AHCI_RST_WAIT) {
 		aprint_error("%s: BSY never cleared, TD 0x%x\n",
@@ -801,10 +795,7 @@ skip_reset:
 	    AHCI_READ(sc, AHCI_P_CMD(chp->ch_channel))), DEBUG_PROBE);
 end:
 	ahci_channel_stop(sc, chp, flags);
-	if (flags & AT_WAIT)
-		tsleep(&sc, PRIBIO, "ahcirst", mstohz(500));
-	else
-		delay(500000);
+	ata_delay(500, "ahcirst", flags);
 	/* clear port interrupt register */
 	AHCI_WRITE(sc, AHCI_P_IS(chp->ch_channel), 0xffffffff);
 	ahci_channel_start(sc, chp, flags,
@@ -825,7 +816,7 @@ ahci_reset_channel(struct ata_channel *c
 		printf("%s: port %d reset failed\n", AHCINAME(sc), chp->ch_channel);
 		/* XXX and then ? */
 	}
-	ata_kill_active(chp, KILL_RESET);
+	ata_kill_active(chp, KILL_RESET, flags);
 	ata_delay(500, "ahcirst", flags);
 	/* clear port interrupt register */
 	AHCI_WRITE(sc, AHCI_P_IS(chp->ch_channel), 0xffffffff);
@@ -1035,10 +1026,7 @@ ahci_cmd_start(struct ata_channel *chp, 
 		if (ata_c->flags & AT_DONE)
 			break;
 		ahci_intr_port(sc, achp);
-		if (ata_c->flags & AT_WAIT)
-			tsleep(&xfer, PRIBIO, "ahcipl", mstohz(10));
-		else
-			delay(10000);
+		ata_delay(10, "ahcipl", ata_c->flags);
 	}
 	AHCIDEBUG_PRINT(("%s port %d poll end GHC 0x%x IS 0x%x list 0x%x%x fis 0x%x%x CMD 0x%x CI 0x%x\n", AHCINAME(sc), channel, 
 	    AHCI_READ(sc, AHCI_GHC), AHCI_READ(sc, AHCI_IS),
@@ -1061,6 +1049,8 @@ ahci_cmd_kill_xfer(struct ata_channel *c
 	AHCIDEBUG_PRINT(("ahci_cmd_kill_xfer channel %d\n", chp->ch_channel),
 	    DEBUG_FUNCS);
 
+	ata_deactivate_xfer(chp, xfer);
+
 	switch (reason) {
 	case KILL_GONE:
 		ata_c->flags |= AT_GONE;
@@ -1271,6 +1261,8 @@ ahci_bio_kill_xfer(struct ata_channel *c
 	    DEBUG_FUNCS);
 
 	achp->ahcic_cmds_active &= ~(1 << xfer->c_slot);
+	ata_deactivate_xfer(chp, xfer);
+
 	ata_bio->flags |= ATA_ITSDONE;
 	switch (reason) {
 	case KILL_GONE:
@@ -1299,6 +1291,7 @@ ahci_bio_complete(struct ata_channel *ch
 	    DEBUG_FUNCS);
 
 	achp->ahcic_cmds_active &= ~(1 << xfer->c_slot);
+
 	chp->ch_flags &= ~ATACH_IRQ_WAIT;
 	if (xfer->c_flags & C_TIMEOU) {
 		ata_bio->error = TIMEOUT;
@@ -1364,10 +1357,7 @@ ahci_channel_stop(struct ahci_softc *sc,
 		if ((AHCI_READ(sc, AHCI_P_CMD(chp->ch_channel)) & AHCI_P_CMD_CR)
 		    == 0)
 			break;
-		if (flags & AT_WAIT)
-			tsleep(&sc, PRIBIO, "ahcistop", mstohz(10));
-		else
-			delay(10000);
+		ata_delay(10, "ahcistop", flags);
 	}
 	if (AHCI_READ(sc, AHCI_P_CMD(chp->ch_channel)) & AHCI_P_CMD_CR) {
 		printf("%s: channel wouldn't stop\n", AHCINAME(sc));
@@ -1399,10 +1389,7 @@ ahci_channel_start(struct ahci_softc *sc
 			if ((AHCI_READ(sc, AHCI_P_CMD(chp->ch_channel)) &
 			    AHCI_P_CMD_CLO) == 0)
 				break;
-			if (flags & AT_WAIT)
-				tsleep(&sc, PRIBIO, "ahciclo", mstohz(10));
-			else
-				delay(10000);
+			ata_delay(10, "ahciclo", flags);
 		}
 		if (AHCI_READ(sc, AHCI_P_CMD(chp->ch_channel)) & AHCI_P_CMD_CLO) {
 			printf("%s: channel wouldn't CLO\n", AHCINAME(sc));
@@ -1709,6 +1696,7 @@ ahci_atapi_complete(struct ata_channel *
 	    DEBUG_FUNCS);
 
 	achp->ahcic_cmds_active &= ~(1 << xfer->c_slot);
+
 	chp->ch_flags &= ~ATACH_IRQ_WAIT;
 	if (xfer->c_flags & C_TIMEOU) {
 		sc_xfer->error = XS_TIMEOUT;
@@ -1762,6 +1750,7 @@ ahci_atapi_kill_xfer(struct ata_channel 
 	struct ahci_channel *achp = (struct ahci_channel *)chp;
 
 	achp->ahcic_cmds_active &= ~(1 << xfer->c_slot);
+	ata_deactivate_xfer(chp, xfer);
 
 	/* remove this command from xfer queue */
 	switch (reason) {

Index: src/sys/dev/ic/mvsata.c
diff -u src/sys/dev/ic/mvsata.c:1.35.6.10 src/sys/dev/ic/mvsata.c:1.35.6.11
--- src/sys/dev/ic/mvsata.c:1.35.6.10	Tue Jun 13 19:15:32 2017
+++ src/sys/dev/ic/mvsata.c	Fri Jun 16 20:40:49 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: mvsata.c,v 1.35.6.10 2017/06/13 19:15:32 jdolecek Exp $	*/
+/*	$NetBSD: mvsata.c,v 1.35.6.11 2017/06/16 20:40:49 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.10 2017/06/13 19:15:32 jdolecek Exp $");
+__KERNEL_RCSID(0, "$NetBSD: mvsata.c,v 1.35.6.11 2017/06/16 20:40:49 jdolecek Exp $");
 
 #include "opt_mvsata.h"
 
@@ -624,9 +624,7 @@ mvsata_reset_channel(struct ata_channel 
 {
 	struct mvsata_port *mvport = (struct mvsata_port *)chp;
 	struct mvsata_softc *sc = device_private(MVSATA_DEV2(mvport));
-	struct ata_xfer *xfer;
 	uint32_t sstat, ctrl;
-	int i;
 
 	DPRINTF(("%s: mvsata_reset_channel: channel=%d\n",
 	    device_xname(MVSATA_DEV2(mvport)), chp->ch_channel));
@@ -653,13 +651,7 @@ mvsata_reset_channel(struct ata_channel 
 		    flags);
 	}
 
-	for (i = 0; i < MVSATA_EDMAQ_LEN; i++) {
-		if ((mvport->port_quetagidx & __BIT(i)) == 0)
-			continue;
-
-		xfer = ata_queue_hwslot_to_xfer(chp->ch_queue, i);
-		xfer->c_kill_xfer(chp, xfer, KILL_RESET);
-	}
+	ata_kill_active(chp, KILL_RESET, flags);
 
 	mvsata_edma_config(mvport, mvport->port_edmamode);
 	mvsata_edma_reset_qptr(mvport);
@@ -1434,6 +1426,9 @@ mvsata_bio_kill_xfer(struct ata_channel 
 		mvsata_edma_enable(mvport);
 	}
 
+	mvsata_quetag_put(mvport, xfer->c_slot);
+	ata_deactivate_xfer(chp, xfer);
+
 	ata_bio->flags |= ATA_ITSDONE;
 	switch (reason) {
 	case KILL_GONE:
@@ -1448,7 +1443,6 @@ mvsata_bio_kill_xfer(struct ata_channel 
 		panic("mvsata_bio_kill_xfer");
 	}
 	ata_bio->r_error = WDCE_ABRT;
-	mvsata_quetag_put(mvport, xfer->c_slot);
 	(*chp->ch_drive[drive].drv_done)(chp->ch_drive[drive].drv_softc, xfer);
 }
 
@@ -1763,6 +1757,9 @@ mvsata_wdc_cmd_kill_xfer(struct ata_chan
 	DPRINTFN(1, ("%s:%d: mvsata_cmd_kill_xfer: drive=%d\n",
 	    device_xname(MVSATA_DEV2(mvport)), chp->ch_channel, xfer->c_drive));
 
+	mvsata_quetag_put(mvport, xfer->c_slot);
+	ata_deactivate_xfer(chp, xfer);
+
 	switch (reason) {
 	case KILL_GONE:
 		ata_c->flags |= AT_GONE;
@@ -1775,7 +1772,6 @@ mvsata_wdc_cmd_kill_xfer(struct ata_chan
 		    "mvsata_cmd_kill_xfer: unknown reason %d\n", reason);
 		panic("mvsata_cmd_kill_xfer");
 	}
-	mvsata_quetag_put(mvport, xfer->c_slot);
 	mvsata_wdc_cmd_done_end(chp, xfer);
 }
 
@@ -2277,6 +2273,9 @@ mvsata_atapi_kill_xfer(struct ata_channe
 	struct mvsata_port *mvport = (struct mvsata_port *)chp;
 	struct scsipi_xfer *sc_xfer = xfer->c_scsipi;
 
+	mvsata_quetag_put(mvport, xfer->c_slot);
+	ata_deactivate_xfer(chp, xfer);
+
 	/* remove this command from xfer queue */
 	switch (reason) {
 	case KILL_GONE:
@@ -2292,7 +2291,6 @@ mvsata_atapi_kill_xfer(struct ata_channe
 		    "mvsata_atapi_kill_xfer: unknown reason %d\n", reason);
 		panic("mvsata_atapi_kill_xfer");
 	}
-	mvsata_quetag_put(mvport, xfer->c_slot);
 	ata_free_xfer(chp, xfer);
 	scsipi_done(sc_xfer);
 }
@@ -2661,10 +2659,7 @@ mvsata_edma_wait(struct mvsata_port *mvp
 	for (xtime = 0;  xtime < timeout / 10; xtime++) {
 		if (mvsata_edma_handle(mvport, xfer))
 			return 0;
-		if (ata_bio->flags & ATA_POLL)
-			delay(10000);
-		else
-			tsleep(&xfer, PRIBIO, "mvsataipl", mstohz(10));
+		ata_delay(10, "mvsataipl", ata_bio->flags);
 	}
 
 	DPRINTF(("mvsata_edma_wait: timeout: %p\n", xfer));

Index: src/sys/dev/ic/siisata.c
diff -u src/sys/dev/ic/siisata.c:1.30.4.15 src/sys/dev/ic/siisata.c:1.30.4.16
--- src/sys/dev/ic/siisata.c:1.30.4.15	Tue Jun 13 00:02:19 2017
+++ src/sys/dev/ic/siisata.c	Fri Jun 16 20:40:49 2017
@@ -1,4 +1,4 @@
-/* $NetBSD: siisata.c,v 1.30.4.15 2017/06/13 00:02:19 jakllsch Exp $ */
+/* $NetBSD: siisata.c,v 1.30.4.16 2017/06/16 20:40:49 jdolecek Exp $ */
 
 /* from ahcisata_core.c */
 
@@ -79,7 +79,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: siisata.c,v 1.30.4.15 2017/06/13 00:02:19 jakllsch Exp $");
+__KERNEL_RCSID(0, "$NetBSD: siisata.c,v 1.30.4.16 2017/06/16 20:40:49 jdolecek Exp $");
 
 #include <sys/types.h>
 #include <sys/param.h>
@@ -609,10 +609,7 @@ siisata_reset_drive(struct ata_drive_dat
 		pss = PR_PXSS(xfer->c_slot);
 		/* XXX DO NOT MERGE UNTIL THIS IS FIXED XXX */
 #endif
-		if ((flags & AT_POLL) == 0)
-			tsleep(schp, PRIBIO, "siiprb", mstohz(10));
-		else
-			DELAY(10000);
+		ata_delay(10, "siiprb", flags);
 	}
 
 	siisata_deactivate_prb(schp, xfer->c_slot);
@@ -694,7 +691,7 @@ siisata_reset_channel(struct ata_channel
 		DELAY(10);
 	PRWRITE(sc, PRX(chp->ch_channel, PRO_SERROR),
 	    PRREAD(sc, PRX(chp->ch_channel, PRO_SERROR)));
-	ata_kill_active(chp, KILL_RESET);
+	ata_kill_active(chp, KILL_RESET, flags);
 
 	return;
 }
@@ -952,6 +949,7 @@ siisata_cmd_kill_xfer(struct ata_channel
 	struct siisata_channel *schp = (struct siisata_channel *)chp;
 
 	siisata_deactivate_prb(schp, xfer->c_slot);
+	ata_deactivate_xfer(chp, xfer);
 	
 	switch (reason) {
 	case KILL_GONE:
@@ -1155,6 +1153,7 @@ siisata_bio_kill_xfer(struct ata_channel
 	    chp->ch_channel, xfer->c_slot), DEBUG_FUNCS);
 
 	siisata_deactivate_prb(schp, xfer->c_slot);
+	ata_deactivate_xfer(chp, xfer);
 
 	ata_bio->flags |= ATA_ITSDONE;
 	switch (reason) {
@@ -1422,6 +1421,7 @@ siisata_atapi_kill_xfer(struct ata_chann
 	struct siisata_channel *schp = (struct siisata_channel *)chp;
 
 	siisata_deactivate_prb(schp, xfer->c_slot);
+	ata_deactivate_xfer(chp, xfer);
 
 	/* remove this command from xfer queue */
 	switch (reason) {

Index: src/sys/dev/ic/wdc.c
diff -u src/sys/dev/ic/wdc.c:1.283.2.4 src/sys/dev/ic/wdc.c:1.283.2.5
--- src/sys/dev/ic/wdc.c:1.283.2.4	Wed Apr 19 20:49:17 2017
+++ src/sys/dev/ic/wdc.c	Fri Jun 16 20:40:49 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: wdc.c,v 1.283.2.4 2017/04/19 20:49:17 jdolecek Exp $ */
+/*	$NetBSD: wdc.c,v 1.283.2.5 2017/06/16 20:40:49 jdolecek Exp $ */
 
 /*
  * Copyright (c) 1998, 2001, 2003 Manuel Bouyer.  All rights reserved.
@@ -58,7 +58,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: wdc.c,v 1.283.2.4 2017/04/19 20:49:17 jdolecek Exp $");
+__KERNEL_RCSID(0, "$NetBSD: wdc.c,v 1.283.2.5 2017/06/16 20:40:49 jdolecek Exp $");
 
 #include "opt_ata.h"
 #include "opt_wdc.h"
@@ -921,21 +921,19 @@ wdc_reset_drive(struct ata_drive_datas *
 void
 wdc_reset_channel(struct ata_channel *chp, int flags)
 {
-	TAILQ_HEAD(, ata_xfer) reset_xfer;
-	struct ata_xfer *xfer, *next_xfer;
+	struct ata_xfer *xfer;
 #if NATA_DMA || NATA_PIOBM
 	struct wdc_softc *wdc = CHAN_TO_WDC(chp);
 #endif
-	TAILQ_INIT(&reset_xfer);
 
 	chp->ch_flags &= ~ATACH_IRQ_WAIT;
 
 	/*
-	 * if the current command if on an ATAPI device, issue a
+	 * if the current command is on an ATAPI device, issue a
 	 * ATAPI_SOFT_RESET
 	 */
 	KASSERT(chp->ch_queue->queue_openings == 1);
-	xfer = ata_queue_hwslot_to_xfer(chp->ch_queue, 0);
+	xfer = ata_queue_active_xfer_peek(chp->ch_queue);
 	if (xfer && xfer->c_chp == chp && (xfer->c_flags & C_ATAPI)) {
 		wdccommandshort(chp, xfer->c_drive, ATAPI_SOFT_RESET);
 		if (flags & AT_WAIT)
@@ -958,59 +956,33 @@ wdc_reset_channel(struct ata_channel *ch
 		tsleep(&flags, PRIBIO, "atardl", mstohz(1) + 1);
 	else
 		delay(1000);
+
 	/*
-	 * look for pending xfers. If we have a shared queue, we'll also reset
+	 * Look for pending xfers. If we have a shared queue, we'll also reset
 	 * the other channel if the current xfer is running on it.
-	 * Then we'll dequeue only the xfers for this channel.
+	 * Then we'll kill the eventual active transfer explicitely, so that
+	 * it is queued for retry immediatelly without waiting for I/O timeout.
 	 */
-	if ((flags & AT_RST_NOCMD) == 0) {
-		/*
-		 * move all xfers queued for this channel to the reset queue,
-		 * and then process the current xfer and then the reset queue.
-		 * We have to use a temporary queue because c_kill_xfer()
-		 * may requeue commands.
-		 */
-		for (xfer = TAILQ_FIRST(&chp->ch_queue->queue_xfer);
-		    xfer != NULL; xfer = next_xfer) {
-			next_xfer = TAILQ_NEXT(xfer, c_xferchain);
-			if (xfer->c_chp != chp)
-				continue;
-			TAILQ_REMOVE(&chp->ch_queue->queue_xfer,
-			    xfer, c_xferchain);
-			TAILQ_INSERT_TAIL(&reset_xfer, xfer, c_xferchain);
-		}
-		xfer = ata_queue_hwslot_to_xfer(chp->ch_queue, 0);
-		if (xfer) {
-			if (xfer->c_chp != chp)
-				ata_reset_channel(xfer->c_chp, flags);
-			else {
+	if (xfer) {
+		if (xfer->c_chp != chp)
+			ata_reset_channel(xfer->c_chp, flags);
+		else {
 #if NATA_DMA || NATA_PIOBM
-				/*
-				 * If we're waiting for DMA, stop the
-				 * DMA engine
-				 */
-				if (chp->ch_flags & ATACH_DMA_WAIT) {
-					(*wdc->dma_finish)(wdc->dma_arg,
-					    chp->ch_channel, xfer->c_drive,
-					    WDC_DMAEND_ABRT_QUIET);
-					chp->ch_flags &= ~ATACH_DMA_WAIT;
-				}
-#endif
-				ata_deactivate_xfer(chp, xfer);
-				if ((flags & AT_RST_EMERG) == 0)
-					xfer->c_kill_xfer(
-					    chp, xfer, KILL_RESET);
+			/*
+			 * If we're waiting for DMA, stop the
+			 * DMA engine
+			 */
+			if (chp->ch_flags & ATACH_DMA_WAIT) {
+				(*wdc->dma_finish)(wdc->dma_arg,
+				    chp->ch_channel, xfer->c_drive,
+				    WDC_DMAEND_ABRT_QUIET);
+				chp->ch_flags &= ~ATACH_DMA_WAIT;
 			}
-		}
-
-		for (xfer = TAILQ_FIRST(&reset_xfer);
-		    xfer != NULL; xfer = next_xfer) {
-			next_xfer = TAILQ_NEXT(xfer, c_xferchain);
-			TAILQ_REMOVE(&reset_xfer, xfer, c_xferchain);
-			if ((flags & AT_RST_EMERG) == 0)
-				xfer->c_kill_xfer(chp, xfer, KILL_RESET);
+#endif
 		}
 	}
+
+	ata_kill_active(chp, KILL_RESET, flags);
 }
 
 static int
@@ -1694,6 +1666,8 @@ __wdccommand_kill_xfer(struct ata_channe
 {
 	struct ata_command *ata_c = &xfer->c_ata_c;
 
+	ata_deactivate_xfer(chp, xfer);
+
 	switch (reason) {
 	case KILL_GONE:
 		ata_c->flags |= AT_GONE;

Index: src/sys/dev/scsipi/atapi_wdc.c
diff -u src/sys/dev/scsipi/atapi_wdc.c:1.123.4.4 src/sys/dev/scsipi/atapi_wdc.c:1.123.4.5
--- src/sys/dev/scsipi/atapi_wdc.c:1.123.4.4	Wed Apr 19 20:49:17 2017
+++ src/sys/dev/scsipi/atapi_wdc.c	Fri Jun 16 20:40:49 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: atapi_wdc.c,v 1.123.4.4 2017/04/19 20:49:17 jdolecek Exp $	*/
+/*	$NetBSD: atapi_wdc.c,v 1.123.4.5 2017/06/16 20:40:49 jdolecek Exp $	*/
 
 /*
  * Copyright (c) 1998, 2001 Manuel Bouyer.
@@ -25,7 +25,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: atapi_wdc.c,v 1.123.4.4 2017/04/19 20:49:17 jdolecek Exp $");
+__KERNEL_RCSID(0, "$NetBSD: atapi_wdc.c,v 1.123.4.5 2017/06/16 20:40:49 jdolecek Exp $");
 
 #ifndef ATADEBUG
 #define ATADEBUG
@@ -171,6 +171,8 @@ wdc_atapi_kill_xfer(struct ata_channel *
 {
 	struct scsipi_xfer *sc_xfer = xfer->c_scsipi;
 
+	ata_deactivate_xfer(chp, xfer);
+
 	/* remove this command from xfer queue */
 	switch (reason) {
 	case KILL_GONE:

Reply via email to