Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/dev Fix kernel dump on ahci controller, by making sure w...



details:   https://anonhg.NetBSD.org/src/rev/202b9b443e2e
branches:  trunk
changeset: 785861:202b9b443e2e
user:      bouyer <bouyer%NetBSD.org@localhost>
date:      Wed Apr 03 17:15:07 2013 +0000

description:
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

diffstat:

 sys/dev/ata/ata.c          |  18 ++++++++++++++++--
 sys/dev/ata/atavar.h       |   5 +++--
 sys/dev/ata/sata_subr.c    |  14 +++++++-------
 sys/dev/ata/satavar.h      |   4 ++--
 sys/dev/ic/ahcisata_core.c |  21 +++++++++------------
 sys/dev/ic/mvsata.c        |  13 +++++++------
 sys/dev/ic/siisata.c       |   8 ++++----
 sys/dev/ic/wdc.c           |   6 +++---
 sys/dev/usb/umass_isdata.c |   8 ++++----
 9 files changed, 55 insertions(+), 42 deletions(-)

diffs (truncated from 364 to 300 lines):

diff -r 7177b591ba87 -r 202b9b443e2e sys/dev/ata/ata.c
--- a/sys/dev/ata/ata.c Wed Apr 03 15:57:44 2013 +0000
+++ b/sys/dev/ata/ata.c Wed Apr 03 17:15:07 2013 +0000
@@ -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 @@
 
        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);
+       }
+}
diff -r 7177b591ba87 -r 202b9b443e2e sys/dev/ata/atavar.h
--- a/sys/dev/ata/atavar.h      Wed Apr 03 15:57:44 2013 +0000
+++ b/sys/dev/ata/atavar.h      Wed Apr 03 17:15:07 2013 +0000
@@ -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_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_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_ */
diff -r 7177b591ba87 -r 202b9b443e2e sys/dev/ata/sata_subr.c
--- a/sys/dev/ata/sata_subr.c   Wed Apr 03 15:57:44 2013 +0000
+++ b/sys/dev/ata/sata_subr.c   Wed Apr 03 17:15:07 2013 +0000
@@ -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 @@
  */
 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 @@
        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 @@
         */
        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;
diff -r 7177b591ba87 -r 202b9b443e2e sys/dev/ata/satavar.h
--- a/sys/dev/ata/satavar.h     Wed Apr 03 15:57:44 2013 +0000
+++ b/sys/dev/ata/satavar.h     Wed Apr 03 17:15:07 2013 +0000
@@ -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_ */
diff -r 7177b591ba87 -r 202b9b443e2e sys/dev/ic/ahcisata_core.c
--- a/sys/dev/ic/ahcisata_core.c        Wed Apr 03 15:57:44 2013 +0000
+++ b/sys/dev/ic/ahcisata_core.c        Wed Apr 03 17:15:07 2013 +0000
@@ -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 @@
                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_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 @@
                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 @@
                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_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 @@
        /*
         * 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),
diff -r 7177b591ba87 -r 202b9b443e2e sys/dev/ic/mvsata.c
--- a/sys/dev/ic/mvsata.c       Wed Apr 03 15:57:44 2013 +0000
+++ b/sys/dev/ic/mvsata.c       Wed Apr 03 17:15:07 2013 +0000
@@ -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 @@
        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_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_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 @@
        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));
diff -r 7177b591ba87 -r 202b9b443e2e sys/dev/ic/siisata.c
--- a/sys/dev/ic/siisata.c      Wed Apr 03 15:57:44 2013 +0000
+++ b/sys/dev/ic/siisata.c      Wed Apr 03 17:15:07 2013 +0000
@@ -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 @@
            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 @@



Home | Main Index | Thread Index | Old Index