Module Name:    src
Committed By:   bouyer
Date:           Wed Apr  3 17:15:07 UTC 2013

Modified Files:
        src/sys/dev/ata: ata.c atavar.h sata_subr.c satavar.h
        src/sys/dev/ic: ahcisata_core.c mvsata.c siisata.c wdc.c
        src/sys/dev/usb: umass_isdata.c

Log Message:
Fix kernel dump on ahci controller, by making sure we won't sleep
while dumping:
- introduce ata_delay() which either use delay() or kpause()
  depending on flags. use it in sata_reset_interface() and
  some ahci functions
- kill ATA_NOSLEEP, it was tested but never set. use ATA_POLL instead.
- reduce delay while polling in ahci, to speed up the dump

Should fix PR kern/41095


To generate a diff of this commit:
cvs rdiff -u -r1.126 -r1.127 src/sys/dev/ata/ata.c
cvs rdiff -u -r1.90 -r1.91 src/sys/dev/ata/atavar.h
cvs rdiff -u -r1.20 -r1.21 src/sys/dev/ata/sata_subr.c
cvs rdiff -u -r1.8 -r1.9 src/sys/dev/ata/satavar.h
cvs rdiff -u -r1.46 -r1.47 src/sys/dev/ic/ahcisata_core.c
cvs rdiff -u -r1.29 -r1.30 src/sys/dev/ic/mvsata.c
cvs rdiff -u -r1.23 -r1.24 src/sys/dev/ic/siisata.c
cvs rdiff -u -r1.277 -r1.278 src/sys/dev/ic/wdc.c
cvs rdiff -u -r1.27 -r1.28 src/sys/dev/usb/umass_isdata.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.126 src/sys/dev/ata/ata.c:1.127
--- src/sys/dev/ata/ata.c:1.126	Thu Nov  1 13:46:52 2012
+++ src/sys/dev/ata/ata.c	Wed Apr  3 17:15:07 2013
@@ -1,4 +1,4 @@
-/*	$NetBSD: ata.c,v 1.126 2012/11/01 13:46:52 abs Exp $	*/
+/*	$NetBSD: ata.c,v 1.127 2013/04/03 17:15:07 bouyer 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.126 2012/11/01 13:46:52 abs Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ata.c,v 1.127 2013/04/03 17:15:07 bouyer Exp $");
 
 #include "opt_ata.h"
 
@@ -1719,3 +1719,17 @@ atabus_rescan(device_t self, const char 
 
 	return 0;
 }
+
+void
+ata_delay(int ms, const char *msg, int flags)
+{
+	if ((flags & (AT_WAIT | AT_POLL)) == AT_POLL) {
+		/*
+		 * can't use tsleep(), we may be in interrupt context
+		 * or taking a crash dump
+		 */
+		delay(ms * 1000);
+	} else {
+		kpause(msg, false, mstohz(ms), NULL);
+	}
+}

Index: src/sys/dev/ata/atavar.h
diff -u src/sys/dev/ata/atavar.h:1.90 src/sys/dev/ata/atavar.h:1.91
--- src/sys/dev/ata/atavar.h:1.90	Tue Jul 31 15:50:34 2012
+++ src/sys/dev/ata/atavar.h	Wed Apr  3 17:15:07 2013
@@ -1,4 +1,4 @@
-/*	$NetBSD: atavar.h,v 1.90 2012/07/31 15:50:34 bouyer Exp $	*/
+/*	$NetBSD: atavar.h,v 1.91 2013/04/03 17:15:07 bouyer Exp $	*/
 
 /*
  * Copyright (c) 1998, 2001 Manuel Bouyer.
@@ -193,7 +193,7 @@ struct ata_drive_datas {
  */
 struct ata_bio {
 	volatile u_int16_t flags;/* cmd flags */
-#define	ATA_NOSLEEP	0x0001	/* Can't sleep */
+/* 			0x0001	free, was ATA_NOSLEEP */
 #define	ATA_POLL	0x0002	/* poll for completion */
 #define	ATA_ITSDONE	0x0004	/* the transfer is as done as it gets */
 #define	ATA_SINGLE	0x0008	/* transfer must be done in singlesector mode */
@@ -464,6 +464,7 @@ void	ata_probe_caps(struct ata_drive_dat
 void	ata_dmaerr(struct ata_drive_datas *, int);
 #endif
 void	ata_queue_idle(struct ata_queue *);
+void	ata_delay(int, const char *, int);
 #endif /* _KERNEL */
 
 #endif /* _DEV_ATA_ATAVAR_H_ */

Index: src/sys/dev/ata/sata_subr.c
diff -u src/sys/dev/ata/sata_subr.c:1.20 src/sys/dev/ata/sata_subr.c:1.21
--- src/sys/dev/ata/sata_subr.c:1.20	Tue Jul 31 15:50:34 2012
+++ src/sys/dev/ata/sata_subr.c	Wed Apr  3 17:15:07 2013
@@ -1,4 +1,4 @@
-/*	$NetBSD: sata_subr.c,v 1.20 2012/07/31 15:50:34 bouyer Exp $	*/
+/*	$NetBSD: sata_subr.c,v 1.21 2013/04/03 17:15:07 bouyer Exp $	*/
 
 /*-
  * Copyright (c) 2004 The NetBSD Foundation, Inc.
@@ -33,7 +33,7 @@
  * Common functions for Serial ATA.
  */
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: sata_subr.c,v 1.20 2012/07/31 15:50:34 bouyer Exp $");
+__KERNEL_RCSID(0, "$NetBSD: sata_subr.c,v 1.21 2013/04/03 17:15:07 bouyer Exp $");
 
 #include <sys/param.h>
 #include <sys/kernel.h>
@@ -80,7 +80,7 @@ sata_speed(uint32_t sstatus)
  */
 uint32_t
 sata_reset_interface(struct ata_channel *chp, bus_space_tag_t sata_t,
-    bus_space_handle_t scontrol_r, bus_space_handle_t sstatus_r)
+    bus_space_handle_t scontrol_r, bus_space_handle_t sstatus_r, int flags)
 {
 	uint32_t scontrol, sstatus;
 	int i;
@@ -94,17 +94,17 @@ sata_reset_interface(struct ata_channel 
 	scontrol = SControl_IPM_NONE | SControl_SPD_ANY | SControl_DET_INIT;
 	bus_space_write_4 (sata_t, scontrol_r, 0, scontrol);
 
-	tsleep(chp, PRIBIO, "sataup", mstohz(50));
+	ata_delay(50, "sataup", flags);
 	scontrol &= ~SControl_DET_INIT;
 	bus_space_write_4(sata_t, scontrol_r, 0, scontrol);
 
-	tsleep(chp, PRIBIO, "sataup", mstohz(50));
+	ata_delay(50, "sataup", flags);
 	/* wait up to 1s for device to come up */
 	for (i = 0; i < 100; i++) {
 		sstatus = bus_space_read_4(sata_t, sstatus_r, 0);
 		if ((sstatus & SStatus_DET_mask) == SStatus_DET_DEV)
 			break;
-		tsleep(chp, PRIBIO, "sataup", mstohz(10));
+		ata_delay(10, "sataup", flags);
 	}
 	/*
 	 * if we have a link up without device, wait a few more seconds
@@ -112,7 +112,7 @@ sata_reset_interface(struct ata_channel 
 	 */
 	if ((sstatus & SStatus_DET_mask) == SStatus_DET_DEV_NE) {
 		for (i = 0; i < 500; i++) {
-			tsleep(chp, PRIBIO, "sataup", mstohz(10));
+			ata_delay(10, "sataup", flags);
 			sstatus = bus_space_read_4(sata_t, sstatus_r, 0);
 			if ((sstatus & SStatus_DET_mask) == SStatus_DET_DEV)
 				break;

Index: src/sys/dev/ata/satavar.h
diff -u src/sys/dev/ata/satavar.h:1.8 src/sys/dev/ata/satavar.h:1.9
--- src/sys/dev/ata/satavar.h:1.8	Tue Jul 31 15:50:34 2012
+++ src/sys/dev/ata/satavar.h	Wed Apr  3 17:15:07 2013
@@ -1,4 +1,4 @@
-/*	$NetBSD: satavar.h,v 1.8 2012/07/31 15:50:34 bouyer Exp $	*/
+/*	$NetBSD: satavar.h,v 1.9 2013/04/03 17:15:07 bouyer Exp $	*/
 
 /*-
  * Copyright (c) 2004 The NetBSD Foundation, Inc.
@@ -41,7 +41,7 @@
 
 const char *sata_speed(uint32_t);
 uint32_t sata_reset_interface(struct ata_channel *, bus_space_tag_t,
-    bus_space_handle_t, bus_space_handle_t);
+    bus_space_handle_t, bus_space_handle_t, int);
 void	sata_interpret_sig(struct ata_channel *, int, uint32_t);
 
 #endif /* _DEV_ATA_SATAVAR_H_ */

Index: src/sys/dev/ic/ahcisata_core.c
diff -u src/sys/dev/ic/ahcisata_core.c:1.46 src/sys/dev/ic/ahcisata_core.c:1.47
--- src/sys/dev/ic/ahcisata_core.c:1.46	Sat Feb  2 14:11:37 2013
+++ src/sys/dev/ic/ahcisata_core.c	Wed Apr  3 17:15:07 2013
@@ -1,4 +1,4 @@
-/*	$NetBSD: ahcisata_core.c,v 1.46 2013/02/02 14:11:37 matt Exp $	*/
+/*	$NetBSD: ahcisata_core.c,v 1.47 2013/04/03 17:15:07 bouyer Exp $	*/
 
 /*
  * Copyright (c) 2006 Manuel Bouyer.
@@ -26,7 +26,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ahcisata_core.c,v 1.46 2013/02/02 14:11:37 matt Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ahcisata_core.c,v 1.47 2013/04/03 17:15:07 bouyer Exp $");
 
 #include <sys/types.h>
 #include <sys/malloc.h>
@@ -748,7 +748,7 @@ end:
 		delay(500000);
 	/* clear port interrupt register */
 	AHCI_WRITE(sc, AHCI_P_IS(chp->ch_channel), 0xffffffff);
-	ahci_channel_start(sc, chp, AT_WAIT,
+	ahci_channel_start(sc, chp, flags,
 	    (sc->sc_ahci_cap & AHCI_CAP_CLO) ? 1 : 0);
 	return 0;
 }
@@ -762,7 +762,7 @@ ahci_reset_channel(struct ata_channel *c
 
 	ahci_channel_stop(sc, chp, flags);
 	if (sata_reset_interface(chp, sc->sc_ahcit, achp->ahcic_scontrol,
-	    achp->ahcic_sstatus) != SStatus_DET_DEV) {
+	    achp->ahcic_sstatus, flags) != SStatus_DET_DEV) {
 		printf("%s: port %d reset failed\n", AHCINAME(sc), chp->ch_channel);
 		/* XXX and then ? */
 	}
@@ -770,7 +770,7 @@ ahci_reset_channel(struct ata_channel *c
 		chp->ch_queue->active_xfer->c_kill_xfer(chp,
 		    chp->ch_queue->active_xfer, KILL_RESET);
 	}
-	tsleep(&sc, PRIBIO, "ahcirst", mstohz(500));
+	ata_delay(500, "ahcirst", flags);
 	/* clear port interrupt register */
 	AHCI_WRITE(sc, AHCI_P_IS(chp->ch_channel), 0xffffffff);
 	/* clear SErrors and start operations */
@@ -781,7 +781,7 @@ ahci_reset_channel(struct ata_channel *c
 		if ((((tfd & AHCI_P_TFD_ST) >> AHCI_P_TFD_ST_SHIFT)
 		    & WDCS_BSY) == 0)
 			break;
-		tsleep(&sc, PRIBIO, "ahcid2h", mstohz(10));
+		ata_delay(10, "ahcid2h", flags);
 	}
 	if (i == AHCI_RST_WAIT)
 		aprint_error("%s: BSY never cleared, TD 0x%x\n",
@@ -825,7 +825,7 @@ ahci_probe_drive(struct ata_channel *chp
 	    AHCI_P_CMD_POD | AHCI_P_CMD_SUD);
 	/* reset the PHY and bring online */
 	switch (sata_reset_interface(chp, sc->sc_ahcit, achp->ahcic_scontrol,
-	    achp->ahcic_sstatus)) {
+	    achp->ahcic_sstatus, AT_WAIT)) {
 	case SStatus_DET_DEV:
 		tsleep(&sc, PRIBIO, "ahcidv", mstohz(500));
 		if (sc->sc_ahci_cap & AHCI_CAP_SPM) {
@@ -1198,14 +1198,11 @@ ahci_bio_start(struct ata_channel *chp, 
 	/*
 	 * Polled command. 
 	 */
-	for (i = 0; i < ATA_DELAY / 10; i++) {
+	for (i = 0; i < ATA_DELAY * 10; i++) {
 		if (ata_bio->flags & ATA_ITSDONE)
 			break;
 		ahci_intr_port(sc, achp);
-		if (ata_bio->flags & ATA_NOSLEEP)
-			delay(10000);
-		else
-			tsleep(&xfer, PRIBIO, "ahcipl", mstohz(10));
+		delay(100);
 	}
 	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),

Index: src/sys/dev/ic/mvsata.c
diff -u src/sys/dev/ic/mvsata.c:1.29 src/sys/dev/ic/mvsata.c:1.30
--- src/sys/dev/ic/mvsata.c:1.29	Sun Feb 10 21:21:29 2013
+++ src/sys/dev/ic/mvsata.c	Wed Apr  3 17:15:07 2013
@@ -1,4 +1,4 @@
-/*	$NetBSD: mvsata.c,v 1.29 2013/02/10 21:21:29 jakllsch Exp $	*/
+/*	$NetBSD: mvsata.c,v 1.30 2013/04/03 17:15:07 bouyer 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.29 2013/02/10 21:21:29 jakllsch Exp $");
+__KERNEL_RCSID(0, "$NetBSD: mvsata.c,v 1.30 2013/04/03 17:15:07 bouyer Exp $");
 
 #include "opt_mvsata.h"
 
@@ -517,7 +517,7 @@ mvsata_probe_drive(struct ata_channel *c
 	uint32_t sstat, sig;
 
 	sstat = sata_reset_interface(chp, mvport->port_iot,
-	    mvport->port_sata_scontrol, mvport->port_sata_sstatus);
+	    mvport->port_sata_scontrol, mvport->port_sata_sstatus, AT_WAIT);
 	switch (sstat) {
 	case SStatus_DET_DEV:
 		mvsata_pmp_select(mvport, PMP_PORT_CTL);
@@ -607,7 +607,7 @@ mvsata_reset_channel(struct ata_channel 
 
 	mvsata_hreset_port(mvport);
 	sstat = sata_reset_interface(chp, mvport->port_iot,
-	    mvport->port_sata_scontrol, mvport->port_sata_sstatus);
+	    mvport->port_sata_scontrol, mvport->port_sata_sstatus, flags);
 
 	if (flags & AT_WAIT && sstat == SStatus_DET_DEV_NE &&
 	    sc->sc_gen != gen1) {
@@ -623,7 +623,8 @@ mvsata_reset_channel(struct ata_channel 
 
 		mvsata_hreset_port(mvport);
 		sata_reset_interface(chp, mvport->port_iot,
-		    mvport->port_sata_scontrol, mvport->port_sata_sstatus);
+		    mvport->port_sata_scontrol, mvport->port_sata_sstatus,
+		    flags);
 	}
 
 	for (i = 0; i < MVSATA_EDMAQ_LEN; i++) {
@@ -2651,7 +2652,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_NOSLEEP)
+		if (ata_bio->flags & ATA_POLL)
 			delay(10000);
 		else
 			tsleep(&xfer, PRIBIO, "mvsataipl", mstohz(10));

Index: src/sys/dev/ic/siisata.c
diff -u src/sys/dev/ic/siisata.c:1.23 src/sys/dev/ic/siisata.c:1.24
--- src/sys/dev/ic/siisata.c:1.23	Mon Oct 22 16:43:05 2012
+++ src/sys/dev/ic/siisata.c	Wed Apr  3 17:15:07 2013
@@ -1,4 +1,4 @@
-/* $NetBSD: siisata.c,v 1.23 2012/10/22 16:43:05 jakllsch Exp $ */
+/* $NetBSD: siisata.c,v 1.24 2013/04/03 17:15:07 bouyer Exp $ */
 
 /* from ahcisata_core.c */
 
@@ -79,7 +79,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: siisata.c,v 1.23 2012/10/22 16:43:05 jakllsch Exp $");
+__KERNEL_RCSID(0, "$NetBSD: siisata.c,v 1.24 2013/04/03 17:15:07 bouyer Exp $");
 
 #include <sys/types.h>
 #include <sys/malloc.h>
@@ -630,7 +630,7 @@ siisata_reset_channel(struct ata_channel
 	    DEBUG_FUNCS);
 
 	if (sata_reset_interface(chp, sc->sc_prt, schp->sch_scontrol,
-	    schp->sch_sstatus) != SStatus_DET_DEV) {
+	    schp->sch_sstatus, flags) != SStatus_DET_DEV) {
 		aprint_error("%s port %d: reset failed\n",
 		    SIISATANAME(sc), chp->ch_channel);
 		/* XXX and then ? */
@@ -687,7 +687,7 @@ siisata_probe_drive(struct ata_channel *
 	siisata_disable_port_interrupt(chp);
 
 	switch(sata_reset_interface(chp, sc->sc_prt, schp->sch_scontrol,
-		schp->sch_sstatus)) {
+		schp->sch_sstatus, AT_WAIT)) {
 	case SStatus_DET_DEV:
 		/* clear any interrupts */
 		(void)PRREAD(sc, PRX(chp->ch_channel, PRO_PSS));

Index: src/sys/dev/ic/wdc.c
diff -u src/sys/dev/ic/wdc.c:1.277 src/sys/dev/ic/wdc.c:1.278
--- src/sys/dev/ic/wdc.c:1.277	Sun Feb  3 20:13:28 2013
+++ src/sys/dev/ic/wdc.c	Wed Apr  3 17:15:07 2013
@@ -1,4 +1,4 @@
-/*	$NetBSD: wdc.c,v 1.277 2013/02/03 20:13:28 jakllsch Exp $ */
+/*	$NetBSD: wdc.c,v 1.278 2013/04/03 17:15:07 bouyer 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.277 2013/02/03 20:13:28 jakllsch Exp $");
+__KERNEL_RCSID(0, "$NetBSD: wdc.c,v 1.278 2013/04/03 17:15:07 bouyer Exp $");
 
 #include "opt_ata.h"
 #include "opt_wdc.h"
@@ -211,7 +211,7 @@ wdc_sataprobe(struct ata_channel *chp)
 
 	/* reset the PHY and bring online */
 	switch (sata_reset_interface(chp, wdr->sata_iot, wdr->sata_control,
-	    wdr->sata_status)) {
+	    wdr->sata_status, AT_WAIT)) {
 	case SStatus_DET_DEV:
 		/* wait 5s for BSY to clear */
 		for (i = 0; i < WDC_PROBE_WAIT * hz; i++) {

Index: src/sys/dev/usb/umass_isdata.c
diff -u src/sys/dev/usb/umass_isdata.c:1.27 src/sys/dev/usb/umass_isdata.c:1.28
--- src/sys/dev/usb/umass_isdata.c:1.27	Tue Jul 31 15:50:37 2012
+++ src/sys/dev/usb/umass_isdata.c	Wed Apr  3 17:15:07 2013
@@ -1,4 +1,4 @@
-/*	$NetBSD: umass_isdata.c,v 1.27 2012/07/31 15:50:37 bouyer Exp $	*/
+/*	$NetBSD: umass_isdata.c,v 1.28 2013/04/03 17:15:07 bouyer Exp $	*/
 
 /*
  * TODO:
@@ -37,7 +37,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: umass_isdata.c,v 1.27 2012/07/31 15:50:37 bouyer Exp $");
+__KERNEL_RCSID(0, "$NetBSD: umass_isdata.c,v 1.28 2013/04/03 17:15:07 bouyer Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_umass.h"
@@ -288,8 +288,8 @@ uisdata_bio1(struct ata_drive_datas *drv
 	DPRINTF(("%s\n", __func__));
 	/* XXX */
 
-	if (ata_bio->flags & ATA_NOSLEEP) {
-		printf("%s: ATA_NOSLEEP not supported\n", __func__);
+	if (ata_bio->flags & ATA_POLL) {
+		printf("%s: ATA_POLL not supported\n", __func__);
 		ata_bio->error = TIMEOUT;
 		ata_bio->flags |= ATA_ITSDONE;
 		return (ATACMD_COMPLETE);

Reply via email to