Module Name: src Committed By: jdolecek Date: Fri Jun 23 22:11:13 UTC 2017
Modified Files: src/sys/dev/ata [jdolecek-ncq]: wd.c Log Message: change wd_standby() to remove the ata_channel_start() call - the purpose of that particular command is to make the drive idle fix locking bug in wddetach() exposed by calling ata_channel_start() in wd_standby() - move wd_standby() call out of the section protected by drive mutex, to avoid lock against itself should it need to get the lock change wd_flushcache() to only call ata_channel_start() when called from the ioctl; particularly, don't call it when suspending, closing, or on shutdown To generate a diff of this commit: cvs rdiff -u -r1.428.2.20 -r1.428.2.21 src/sys/dev/ata/wd.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/wd.c diff -u src/sys/dev/ata/wd.c:1.428.2.20 src/sys/dev/ata/wd.c:1.428.2.21 --- src/sys/dev/ata/wd.c:1.428.2.20 Fri Jun 23 20:40:51 2017 +++ src/sys/dev/ata/wd.c Fri Jun 23 22:11:13 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: wd.c,v 1.428.2.20 2017/06/23 20:40:51 jdolecek Exp $ */ +/* $NetBSD: wd.c,v 1.428.2.21 2017/06/23 22:11:13 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.20 2017/06/23 20:40:51 jdolecek Exp $"); +__KERNEL_RCSID(0, "$NetBSD: wd.c,v 1.428.2.21 2017/06/23 22:11:13 jdolecek Exp $"); #include "opt_ata.h" @@ -198,7 +198,7 @@ void wdrestart(void *); void wddone(device_t, struct ata_xfer *); static void wd_params_to_properties(struct wd_softc *); int wd_get_params(struct wd_softc *, uint8_t, struct ataparams *); -int wd_flushcache(struct wd_softc *, int); +int wd_flushcache(struct wd_softc *, int, bool); int wd_trim(struct wd_softc *, int, daddr_t, long); bool wd_shutdown(device_t, int); @@ -458,7 +458,7 @@ wd_suspend(device_t dv, const pmf_qual_t if (sc->atabus->ata_addref(sc->drvp)) return true; /* no need to complain */ - wd_flushcache(sc, AT_WAIT); + wd_flushcache(sc, AT_WAIT, false); wd_standby(sc, AT_WAIT); sc->atabus->ata_delref(sc->drvp); @@ -494,10 +494,11 @@ wddetach(device_t self, int flags) bufq_drain(sc->sc_q); sc->atabus->ata_killpending(sc->drvp); + mutex_exit(&sc->sc_lock); + if (flags & DETACH_POWEROFF) wd_standby(sc, AT_POLL); - mutex_exit(&sc->sc_lock); bufq_free(sc->sc_q); /* Detach disk. */ @@ -1035,7 +1036,7 @@ wdlastclose(device_t self) { struct wd_softc *wd = device_private(self); - wd_flushcache(wd, AT_WAIT); + wd_flushcache(wd, AT_WAIT, false); if (! (wd->sc_flags & WDF_KLABEL)) wd->sc_flags &= ~WDF_LOADED; @@ -1416,7 +1417,7 @@ wdioctl(dev_t dev, u_long xfer, void *ad return wd_setcache(wd, *(int *)addr); case DIOCCACHESYNC: - return wd_flushcache(wd, AT_WAIT); + return wd_flushcache(wd, AT_WAIT, true); case ATAIOCCOMMAND: /* @@ -1917,12 +1918,12 @@ wd_standby(struct wd_softc *wd, int flag out: ata_free_xfer(wd->drvp->chnl_softc, xfer); - ata_channel_start(wd->drvp->chnl_softc, wd->drvp->drive); + /* drive is supposed to go idle, do not call ata_channel_start() */ return error; } int -wd_flushcache(struct wd_softc *wd, int flags) +wd_flushcache(struct wd_softc *wd, int flags, bool start) { struct ata_xfer *xfer; int error; @@ -1989,7 +1990,8 @@ out_xfer: out: /* kick queue processing blocked while waiting for flush xfer */ - ata_channel_start(wd->drvp->chnl_softc, wd->drvp->drive); + if (start) + ata_channel_start(wd->drvp->chnl_softc, wd->drvp->drive); return error; } @@ -2067,7 +2069,7 @@ wd_shutdown(device_t dev, int how) if (wd->atabus->ata_addref(wd->drvp)) return true; /* no need to complain */ - wd_flushcache(wd, AT_POLL); + wd_flushcache(wd, AT_POLL, false); if ((how & RB_POWERDOWN) == RB_POWERDOWN) wd_standby(wd, AT_POLL); return true;