diff options
| author | bouyer <bouyer@NetBSD.org> | 2013-04-03 17:15:07 +0000 |
|---|---|---|
| committer | bouyer <bouyer@NetBSD.org> | 2013-04-03 17:15:07 +0000 |
| commit | a3b0601a795b28251903bb1ef097485b8ff704fa (patch) | |
| tree | 1357974b60f4397f0987772adb00192f5ca2dec5 /sys/dev | |
| parent | 92709f7e863ccc7bdc700a3cd94fa372825d8855 (diff) | |
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 (limited to 'sys/dev')
| -rw-r--r-- | sys/dev/ata/ata.c | 18 | ||||
| -rw-r--r-- | sys/dev/ata/atavar.h | 5 | ||||
| -rw-r--r-- | sys/dev/ata/sata_subr.c | 14 | ||||
| -rw-r--r-- | sys/dev/ata/satavar.h | 4 | ||||
| -rw-r--r-- | sys/dev/ic/ahcisata_core.c | 21 | ||||
| -rw-r--r-- | sys/dev/ic/mvsata.c | 13 | ||||
| -rw-r--r-- | sys/dev/ic/siisata.c | 8 | ||||
| -rw-r--r-- | sys/dev/ic/wdc.c | 6 | ||||
| -rw-r--r-- | sys/dev/usb/umass_isdata.c | 8 |
9 files changed, 55 insertions, 42 deletions
diff --git a/sys/dev/ata/ata.c b/sys/dev/ata/ata.c index 9e266cd7b31..ba655c8ed5d 100644 --- a/sys/dev/ata/ata.c +++ b/sys/dev/ata/ata.c @@ -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 *ifattr, const int *locators) 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 --git a/sys/dev/ata/atavar.h b/sys/dev/ata/atavar.h index 5b45d0da107..4d087053bec 100644 --- a/sys/dev/ata/atavar.h +++ b/sys/dev/ata/atavar.h @@ -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_datas *); 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 --git a/sys/dev/ata/sata_subr.c b/sys/dev/ata/sata_subr.c index 6945f3d864f..241fafea7b5 100644 --- a/sys/dev/ata/sata_subr.c +++ b/sys/dev/ata/sata_subr.c @@ -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 *chp, bus_space_tag_t sata_t, 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 *chp, bus_space_tag_t sata_t, */ 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 --git a/sys/dev/ata/satavar.h b/sys/dev/ata/satavar.h index 5e0d20e5699..8564bf43e44 100644 --- a/sys/dev/ata/satavar.h +++ b/sys/dev/ata/satavar.h @@ -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 --git a/sys/dev/ic/ahcisata_core.c b/sys/dev/ic/ahcisata_core.c index 85e93191784..a3446db28f8 100644 --- a/sys/dev/ic/ahcisata_core.c +++ b/sys/dev/ic/ahcisata_core.c @@ -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 *chp, int flags) 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 *chp, int flags) 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 *chp, int flags) 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, struct ata_xfer *xfer) /* * 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 --git a/sys/dev/ic/mvsata.c b/sys/dev/ic/mvsata.c index b90f79da796..5d674679057 100644 --- a/sys/dev/ic/mvsata.c +++ b/sys/dev/ic/mvsata.c @@ -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 *chp) 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 *chp, int flags) 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 *chp, int flags) 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 *mvport, struct ata_xfer *xfer, int timeout) 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 --git a/sys/dev/ic/siisata.c b/sys/dev/ic/siisata.c index 4391ca2dd53..f5f78c1198d 100644 --- a/sys/dev/ic/siisata.c +++ b/sys/dev/ic/siisata.c @@ -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 *chp, int flags) 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 *chp) 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)); diff --git a/sys/dev/ic/wdc.c b/sys/dev/ic/wdc.c index 1927355cf6a..ffa76962a1b 100644 --- a/sys/dev/ic/wdc.c +++ b/sys/dev/ic/wdc.c @@ -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++) { diff --git a/sys/dev/usb/umass_isdata.c b/sys/dev/usb/umass_isdata.c index e582e16d03a..42b008c555d 100644 --- a/sys/dev/usb/umass_isdata.c +++ b/sys/dev/usb/umass_isdata.c @@ -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, struct ata_bio *ata_bio) 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); |
