| @@ -1,14 +1,14 @@ | | | @@ -1,14 +1,14 @@ |
1 | /* $NetBSD: ld.c,v 1.111 2020/08/02 01:17:56 riastradh Exp $ */ | | 1 | /* $NetBSD: ld.c,v 1.112 2021/05/30 11:24:02 riastradh Exp $ */ |
2 | | | 2 | |
3 | /*- | | 3 | /*- |
4 | * Copyright (c) 1998, 2000 The NetBSD Foundation, Inc. | | 4 | * Copyright (c) 1998, 2000 The NetBSD Foundation, Inc. |
5 | * All rights reserved. | | 5 | * All rights reserved. |
6 | * | | 6 | * |
7 | * This code is derived from software contributed to The NetBSD Foundation | | 7 | * This code is derived from software contributed to The NetBSD Foundation |
8 | * by Andrew Doran and Charles M. Hannum. | | 8 | * by Andrew Doran and Charles M. Hannum. |
9 | * | | 9 | * |
10 | * Redistribution and use in source and binary forms, with or without | | 10 | * Redistribution and use in source and binary forms, with or without |
11 | * modification, are permitted provided that the following conditions | | 11 | * modification, are permitted provided that the following conditions |
12 | * are met: | | 12 | * are met: |
13 | * 1. Redistributions of source code must retain the above copyright | | 13 | * 1. Redistributions of source code must retain the above copyright |
14 | * notice, this list of conditions and the following disclaimer. | | 14 | * notice, this list of conditions and the following disclaimer. |
| @@ -24,27 +24,27 @@ | | | @@ -24,27 +24,27 @@ |
24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | | 24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | | 25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | | 26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | | 27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | | 28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
29 | * POSSIBILITY OF SUCH DAMAGE. | | 29 | * POSSIBILITY OF SUCH DAMAGE. |
30 | */ | | 30 | */ |
31 | | | 31 | |
32 | /* | | 32 | /* |
33 | * Disk driver for use by RAID controllers. | | 33 | * Disk driver for use by RAID controllers. |
34 | */ | | 34 | */ |
35 | | | 35 | |
36 | #include <sys/cdefs.h> | | 36 | #include <sys/cdefs.h> |
37 | __KERNEL_RCSID(0, "$NetBSD: ld.c,v 1.111 2020/08/02 01:17:56 riastradh Exp $"); | | 37 | __KERNEL_RCSID(0, "$NetBSD: ld.c,v 1.112 2021/05/30 11:24:02 riastradh Exp $"); |
38 | | | 38 | |
39 | #include <sys/param.h> | | 39 | #include <sys/param.h> |
40 | #include <sys/systm.h> | | 40 | #include <sys/systm.h> |
41 | #include <sys/kernel.h> | | 41 | #include <sys/kernel.h> |
42 | #include <sys/device.h> | | 42 | #include <sys/device.h> |
43 | #include <sys/queue.h> | | 43 | #include <sys/queue.h> |
44 | #include <sys/proc.h> | | 44 | #include <sys/proc.h> |
45 | #include <sys/buf.h> | | 45 | #include <sys/buf.h> |
46 | #include <sys/bufq.h> | | 46 | #include <sys/bufq.h> |
47 | #include <sys/endian.h> | | 47 | #include <sys/endian.h> |
48 | #include <sys/disklabel.h> | | 48 | #include <sys/disklabel.h> |
49 | #include <sys/disk.h> | | 49 | #include <sys/disk.h> |
50 | #include <sys/dkio.h> | | 50 | #include <sys/dkio.h> |
| @@ -53,26 +53,27 @@ __KERNEL_RCSID(0, "$NetBSD: ld.c,v 1.111 | | | @@ -53,26 +53,27 @@ __KERNEL_RCSID(0, "$NetBSD: ld.c,v 1.111 |
53 | #include <sys/fcntl.h> | | 53 | #include <sys/fcntl.h> |
54 | #include <sys/vnode.h> | | 54 | #include <sys/vnode.h> |
55 | #include <sys/syslog.h> | | 55 | #include <sys/syslog.h> |
56 | #include <sys/mutex.h> | | 56 | #include <sys/mutex.h> |
57 | #include <sys/module.h> | | 57 | #include <sys/module.h> |
58 | #include <sys/reboot.h> | | 58 | #include <sys/reboot.h> |
59 | | | 59 | |
60 | #include <dev/ldvar.h> | | 60 | #include <dev/ldvar.h> |
61 | | | 61 | |
62 | #include "ioconf.h" | | 62 | #include "ioconf.h" |
63 | | | 63 | |
64 | static void ldminphys(struct buf *bp); | | 64 | static void ldminphys(struct buf *bp); |
65 | static bool ld_suspend(device_t, const pmf_qual_t *); | | 65 | static bool ld_suspend(device_t, const pmf_qual_t *); |
| | | 66 | static bool ld_resume(device_t, const pmf_qual_t *); |
66 | static bool ld_shutdown(device_t, int); | | 67 | static bool ld_shutdown(device_t, int); |
67 | static int ld_diskstart(device_t, struct buf *bp); | | 68 | static int ld_diskstart(device_t, struct buf *bp); |
68 | static void ld_iosize(device_t, int *); | | 69 | static void ld_iosize(device_t, int *); |
69 | static int ld_dumpblocks(device_t, void *, daddr_t, int); | | 70 | static int ld_dumpblocks(device_t, void *, daddr_t, int); |
70 | static void ld_fake_geometry(struct ld_softc *); | | 71 | static void ld_fake_geometry(struct ld_softc *); |
71 | static void ld_set_geometry(struct ld_softc *); | | 72 | static void ld_set_geometry(struct ld_softc *); |
72 | static void ld_config_interrupts (device_t); | | 73 | static void ld_config_interrupts (device_t); |
73 | static int ld_lastclose(device_t); | | 74 | static int ld_lastclose(device_t); |
74 | static int ld_discard(device_t, off_t, off_t); | | 75 | static int ld_discard(device_t, off_t, off_t); |
75 | static int ld_flush(device_t, bool); | | 76 | static int ld_flush(device_t, bool); |
76 | | | 77 | |
77 | static dev_type_open(ldopen); | | 78 | static dev_type_open(ldopen); |
78 | static dev_type_close(ldclose); | | 79 | static dev_type_close(ldclose); |
| @@ -156,27 +157,28 @@ ldattach(struct ld_softc *sc, const char | | | @@ -156,27 +157,28 @@ ldattach(struct ld_softc *sc, const char |
156 | sc->sc_disksize512 = sc->sc_secperunit * sc->sc_secsize / DEV_BSIZE; | | 157 | sc->sc_disksize512 = sc->sc_secperunit * sc->sc_secsize / DEV_BSIZE; |
157 | | | 158 | |
158 | if (sc->sc_flags & LDF_NO_RND) | | 159 | if (sc->sc_flags & LDF_NO_RND) |
159 | dksc->sc_flags |= DKF_NO_RND; | | 160 | dksc->sc_flags |= DKF_NO_RND; |
160 | | | 161 | |
161 | /* Attach dk and disk subsystems */ | | 162 | /* Attach dk and disk subsystems */ |
162 | dk_attach(dksc); | | 163 | dk_attach(dksc); |
163 | disk_attach(&dksc->sc_dkdev); | | 164 | disk_attach(&dksc->sc_dkdev); |
164 | ld_set_geometry(sc); | | 165 | ld_set_geometry(sc); |
165 | | | 166 | |
166 | bufq_alloc(&dksc->sc_bufq, default_strategy, BUFQ_SORT_RAWBLOCK); | | 167 | bufq_alloc(&dksc->sc_bufq, default_strategy, BUFQ_SORT_RAWBLOCK); |
167 | | | 168 | |
168 | /* Register with PMF */ | | 169 | /* Register with PMF */ |
169 | if (!pmf_device_register1(dksc->sc_dev, ld_suspend, NULL, ld_shutdown)) | | 170 | if (!pmf_device_register1(dksc->sc_dev, ld_suspend, ld_resume, |
| | | 171 | ld_shutdown)) |
170 | aprint_error_dev(dksc->sc_dev, | | 172 | aprint_error_dev(dksc->sc_dev, |
171 | "couldn't establish power handler\n"); | | 173 | "couldn't establish power handler\n"); |
172 | | | 174 | |
173 | /* Discover wedges on this disk. */ | | 175 | /* Discover wedges on this disk. */ |
174 | config_interrupts(sc->sc_dv, ld_config_interrupts); | | 176 | config_interrupts(sc->sc_dv, ld_config_interrupts); |
175 | } | | 177 | } |
176 | | | 178 | |
177 | int | | 179 | int |
178 | ldadjqparam(struct ld_softc *sc, int xmax) | | 180 | ldadjqparam(struct ld_softc *sc, int xmax) |
179 | { | | 181 | { |
180 | | | 182 | |
181 | mutex_enter(&sc->sc_mutex); | | 183 | mutex_enter(&sc->sc_mutex); |
182 | sc->sc_maxqueuecnt = xmax; | | 184 | sc->sc_maxqueuecnt = xmax; |
| @@ -266,27 +268,75 @@ ldenddetach(struct ld_softc *sc) | | | @@ -266,27 +268,75 @@ ldenddetach(struct ld_softc *sc) |
266 | * XXX perspective. | | 268 | * XXX perspective. |
267 | */ | | 269 | */ |
268 | #if 0 | | 270 | #if 0 |
269 | ld_flush(dksc->sc_dev, false); | | 271 | ld_flush(dksc->sc_dev, false); |
270 | #endif | | 272 | #endif |
271 | cv_destroy(&sc->sc_drain); | | 273 | cv_destroy(&sc->sc_drain); |
272 | mutex_destroy(&sc->sc_mutex); | | 274 | mutex_destroy(&sc->sc_mutex); |
273 | } | | 275 | } |
274 | | | 276 | |
275 | /* ARGSUSED */ | | 277 | /* ARGSUSED */ |
276 | static bool | | 278 | static bool |
277 | ld_suspend(device_t dev, const pmf_qual_t *qual) | | 279 | ld_suspend(device_t dev, const pmf_qual_t *qual) |
278 | { | | 280 | { |
279 | return ld_shutdown(dev, 0); | | 281 | struct ld_softc *sc = device_private(dev); |
| | | 282 | int queuecnt; |
| | | 283 | bool ok = false; |
| | | 284 | |
| | | 285 | /* Block new requests and wait for outstanding requests to drain. */ |
| | | 286 | mutex_enter(&sc->sc_mutex); |
| | | 287 | KASSERT((sc->sc_flags & LDF_SUSPEND) == 0); |
| | | 288 | sc->sc_flags |= LDF_SUSPEND; |
| | | 289 | while ((queuecnt = sc->sc_queuecnt) > 0) { |
| | | 290 | if (cv_timedwait(&sc->sc_drain, &sc->sc_mutex, 30 * hz)) |
| | | 291 | break; |
| | | 292 | } |
| | | 293 | mutex_exit(&sc->sc_mutex); |
| | | 294 | |
| | | 295 | /* Block suspend if we couldn't drain everything in 30sec. */ |
| | | 296 | if (queuecnt > 0) { |
| | | 297 | device_printf(dev, "timeout draining buffers\n"); |
| | | 298 | goto out; |
| | | 299 | } |
| | | 300 | |
| | | 301 | /* Flush cache before we lose power. If we can't, block suspend. */ |
| | | 302 | if (ld_flush(dev, /*poll*/false) != 0) { |
| | | 303 | device_printf(dev, "failed to flush cache\n"); |
| | | 304 | goto out; |
| | | 305 | } |
| | | 306 | |
| | | 307 | /* Success! */ |
| | | 308 | ok = true; |
| | | 309 | |
| | | 310 | out: if (!ok) |
| | | 311 | (void)ld_resume(dev, qual); |
| | | 312 | return ok; |
| | | 313 | } |
| | | 314 | |
| | | 315 | static bool |
| | | 316 | ld_resume(device_t dev, const pmf_qual_t *qual) |
| | | 317 | { |
| | | 318 | struct ld_softc *sc = device_private(dev); |
| | | 319 | |
| | | 320 | /* Allow new requests to come in. */ |
| | | 321 | mutex_enter(&sc->sc_mutex); |
| | | 322 | KASSERT(sc->sc_flags & LDF_SUSPEND); |
| | | 323 | sc->sc_flags &= ~LDF_SUSPEND; |
| | | 324 | mutex_exit(&sc->sc_mutex); |
| | | 325 | |
| | | 326 | /* Restart any pending queued requests. */ |
| | | 327 | dk_start(&sc->sc_dksc, NULL); |
| | | 328 | |
| | | 329 | return true; |
280 | } | | 330 | } |
281 | | | 331 | |
282 | /* ARGSUSED */ | | 332 | /* ARGSUSED */ |
283 | static bool | | 333 | static bool |
284 | ld_shutdown(device_t dev, int flags) | | 334 | ld_shutdown(device_t dev, int flags) |
285 | { | | 335 | { |
286 | if ((flags & RB_NOSYNC) == 0 && ld_flush(dev, true) != 0) | | 336 | if ((flags & RB_NOSYNC) == 0 && ld_flush(dev, true) != 0) |
287 | return false; | | 337 | return false; |
288 | | | 338 | |
289 | return true; | | 339 | return true; |
290 | } | | 340 | } |
291 | | | 341 | |
292 | /* ARGSUSED */ | | 342 | /* ARGSUSED */ |
| @@ -428,37 +478,44 @@ ldstrategy(struct buf *bp) | | | @@ -428,37 +478,44 @@ ldstrategy(struct buf *bp) |
428 | unit = DISKUNIT(bp->b_dev); | | 478 | unit = DISKUNIT(bp->b_dev); |
429 | sc = device_lookup_private(&ld_cd, unit); | | 479 | sc = device_lookup_private(&ld_cd, unit); |
430 | dksc = &sc->sc_dksc; | | 480 | dksc = &sc->sc_dksc; |
431 | | | 481 | |
432 | dk_strategy(dksc, bp); | | 482 | dk_strategy(dksc, bp); |
433 | } | | 483 | } |
434 | | | 484 | |
435 | static int | | 485 | static int |
436 | ld_diskstart(device_t dev, struct buf *bp) | | 486 | ld_diskstart(device_t dev, struct buf *bp) |
437 | { | | 487 | { |
438 | struct ld_softc *sc = device_private(dev); | | 488 | struct ld_softc *sc = device_private(dev); |
439 | int error; | | 489 | int error; |
440 | | | 490 | |
441 | if (sc->sc_queuecnt >= sc->sc_maxqueuecnt) | | 491 | if (sc->sc_queuecnt >= sc->sc_maxqueuecnt || |
| | | 492 | sc->sc_flags & LDF_SUSPEND) { |
| | | 493 | if (sc->sc_flags & LDF_SUSPEND) |
| | | 494 | aprint_debug_dev(dev, "i/o blocked while suspended\n"); |
442 | return EAGAIN; | | 495 | return EAGAIN; |
| | | 496 | } |
443 | | | 497 | |
444 | if ((sc->sc_flags & LDF_MPSAFE) == 0) | | 498 | if ((sc->sc_flags & LDF_MPSAFE) == 0) |
445 | KERNEL_LOCK(1, curlwp); | | 499 | KERNEL_LOCK(1, curlwp); |
446 | | | 500 | |
447 | mutex_enter(&sc->sc_mutex); | | 501 | mutex_enter(&sc->sc_mutex); |
448 | | | 502 | |
449 | if (sc->sc_queuecnt >= sc->sc_maxqueuecnt) | | 503 | if (sc->sc_queuecnt >= sc->sc_maxqueuecnt || |
| | | 504 | sc->sc_flags & LDF_SUSPEND) { |
| | | 505 | if (sc->sc_flags & LDF_SUSPEND) |
| | | 506 | aprint_debug_dev(dev, "i/o blocked while suspended\n"); |
450 | error = EAGAIN; | | 507 | error = EAGAIN; |
451 | else { | | 508 | } else { |
452 | error = (*sc->sc_start)(sc, bp); | | 509 | error = (*sc->sc_start)(sc, bp); |
453 | if (error == 0) | | 510 | if (error == 0) |
454 | sc->sc_queuecnt++; | | 511 | sc->sc_queuecnt++; |
455 | } | | 512 | } |
456 | | | 513 | |
457 | mutex_exit(&sc->sc_mutex); | | 514 | mutex_exit(&sc->sc_mutex); |
458 | | | 515 | |
459 | if ((sc->sc_flags & LDF_MPSAFE) == 0) | | 516 | if ((sc->sc_flags & LDF_MPSAFE) == 0) |
460 | KERNEL_UNLOCK_ONE(curlwp); | | 517 | KERNEL_UNLOCK_ONE(curlwp); |
461 | | | 518 | |
462 | return error; | | 519 | return error; |
463 | } | | 520 | } |
464 | | | 521 | |