1 /*        $NetBSD: ld.c,v 1.117 2025/04/13 14:00:59 jakllsch Exp $    */
2 
3 /*-
4  * Copyright (c) 1998, 2000 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Andrew Doran and Charles M. Hannum.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
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
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
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 /*
33  * Disk driver for use by RAID controllers.
34  */
35 
36 #include <sys/cdefs.h>
37 __KERNEL_RCSID(0, "$NetBSD: ld.c,v 1.117 2025/04/13 14:00:59 jakllsch Exp $");
38 
39 #include <sys/param.h>
40 #include <sys/systm.h>
41 #include <sys/kernel.h>
42 #include <sys/device.h>
43 #include <sys/queue.h>
44 #include <sys/proc.h>
45 #include <sys/buf.h>
46 #include <sys/bufq.h>
47 #include <sys/endian.h>
48 #include <sys/disklabel.h>
49 #include <sys/disk.h>
50 #include <sys/dkio.h>
51 #include <sys/stat.h>
52 #include <sys/conf.h>
53 #include <sys/fcntl.h>
54 #include <sys/vnode.h>
55 #include <sys/syslog.h>
56 #include <sys/mutex.h>
57 #include <sys/module.h>
58 #include <sys/reboot.h>
59 
60 #include <dev/ldvar.h>
61 
62 #include "ioconf.h"
63 
64 static void         ldminphys(struct buf *bp);
65 static bool         ld_suspend(device_t, const pmf_qual_t *);
66 static bool         ld_resume(device_t, const pmf_qual_t *);
67 static bool         ld_shutdown(device_t, int);
68 static int          ld_diskstart(device_t, struct buf *bp);
69 static void         ld_iosize(device_t, int *);
70 static int          ld_dumpblocks(device_t, void *, daddr_t, int);
71 static void         ld_fake_geometry(struct ld_softc *);
72 static void         ld_set_geometry(struct ld_softc *);
73 static void         ld_config_interrupts (device_t);
74 static int          ld_lastclose(device_t);
75 static int          ld_discard(device_t, off_t, off_t);
76 static int          ld_flush(device_t, bool);
77 
78 static dev_type_open(ldopen);
79 static dev_type_close(ldclose);
80 static dev_type_read(ldread);
81 static dev_type_write(ldwrite);
82 static dev_type_ioctl(ldioctl);
83 static dev_type_strategy(ldstrategy);
84 static dev_type_dump(lddump);
85 static dev_type_size(ldsize);
86 static dev_type_discard(lddiscard);
87 
88 const struct bdevsw ld_bdevsw = {
89           .d_open = ldopen,
90           .d_close = ldclose,
91           .d_strategy = ldstrategy,
92           .d_ioctl = ldioctl,
93           .d_dump = lddump,
94           .d_psize = ldsize,
95           .d_discard = lddiscard,
96           .d_flag = D_DISK | D_MPSAFE
97 };
98 
99 const struct cdevsw ld_cdevsw = {
100           .d_open = ldopen,
101           .d_close = ldclose,
102           .d_read = ldread,
103           .d_write = ldwrite,
104           .d_ioctl = ldioctl,
105           .d_stop = nostop,
106           .d_tty = notty,
107           .d_poll = nopoll,
108           .d_mmap = nommap,
109           .d_kqfilter = nokqfilter,
110           .d_discard = lddiscard,
111           .d_flag = D_DISK | D_MPSAFE
112 };
113 
114 static const struct dkdriver lddkdriver = {
115           .d_open = ldopen,
116           .d_close = ldclose,
117           .d_strategy = ldstrategy,
118           .d_iosize = ld_iosize,
119           .d_minphys  = ldminphys,
120           .d_diskstart = ld_diskstart,
121           .d_dumpblocks = ld_dumpblocks,
122           .d_lastclose = ld_lastclose,
123           .d_discard = ld_discard
124 };
125 
126 void
ldattach(struct ld_softc * sc,const char * default_strategy)127 ldattach(struct ld_softc *sc, const char *default_strategy)
128 {
129           device_t self = sc->sc_dv;
130           struct dk_softc *dksc = &sc->sc_dksc;
131 
132           mutex_init(&sc->sc_mutex, MUTEX_DEFAULT, IPL_VM);
133           cv_init(&sc->sc_drain, "lddrain");
134 
135           if ((sc->sc_flags & LDF_ENABLED) == 0) {
136                     return;
137           }
138 
139           /* don't attach a disk that we cannot handle */
140           if (sc->sc_secsize < DEV_BSIZE) {
141                     sc->sc_flags &= ~LDF_ENABLED;
142                     return;
143           }
144 
145           /* Initialise dk and disk structure. */
146           dk_init(dksc, self, DKTYPE_LD);
147           disk_init(&dksc->sc_dkdev, dksc->sc_xname, &lddkdriver);
148 
149           if (sc->sc_maxxfer > MAXPHYS)
150                     sc->sc_maxxfer = MAXPHYS;
151 
152           /* Build synthetic geometry if necessary. */
153           if (sc->sc_nheads == 0 || sc->sc_nsectors == 0 ||
154               sc->sc_ncylinders == 0)
155               ld_fake_geometry(sc);
156 
157           sc->sc_disksize512 = sc->sc_secperunit * sc->sc_secsize / DEV_BSIZE;
158 
159           if (sc->sc_flags & LDF_NO_RND)
160                     dksc->sc_flags |= DKF_NO_RND;
161 
162           /* Attach dk and disk subsystems */
163           dk_attach(dksc);
164           disk_attach(&dksc->sc_dkdev);
165           ld_set_geometry(sc);
166 
167           bufq_alloc(&dksc->sc_bufq, default_strategy, BUFQ_SORT_RAWBLOCK);
168 
169           /* Register with PMF */
170           if (!pmf_device_register1(dksc->sc_dev, ld_suspend, ld_resume,
171                     ld_shutdown))
172                     aprint_error_dev(dksc->sc_dev,
173                         "couldn't establish power handler\n");
174 
175           /* Discover wedges on this disk. */
176           config_interrupts(sc->sc_dv, ld_config_interrupts);
177 }
178 
179 int
ldadjqparam(struct ld_softc * sc,int xmax)180 ldadjqparam(struct ld_softc *sc, int xmax)
181 {
182 
183           mutex_enter(&sc->sc_mutex);
184           sc->sc_maxqueuecnt = xmax;
185           mutex_exit(&sc->sc_mutex);
186 
187           return (0);
188 }
189 
190 int
ldbegindetach(struct ld_softc * sc,int flags)191 ldbegindetach(struct ld_softc *sc, int flags)
192 {
193           struct dk_softc *dksc = &sc->sc_dksc;
194           int error;
195 
196           /* If we never attached properly, no problem with detaching.  */
197           if ((sc->sc_flags & LDF_ENABLED) == 0)
198                     return 0;
199 
200           /*
201            * If the disk is still open, back out before we commit to
202            * detaching.
203            */
204           error = disk_begindetach(&dksc->sc_dkdev, ld_lastclose, dksc->sc_dev,
205               flags);
206           if (error)
207                     return error;
208 
209           /* We are now committed to detaching.  Prevent new xfers.  */
210           ldadjqparam(sc, 0);
211 
212           return 0;
213 }
214 
215 void
ldenddetach(struct ld_softc * sc)216 ldenddetach(struct ld_softc *sc)
217 {
218           struct dk_softc *dksc = &sc->sc_dksc;
219           int bmaj, cmaj, i, mn;
220 
221           if ((sc->sc_flags & LDF_ENABLED) == 0)
222                     return;
223 
224           /* Wait for commands queued with the hardware to complete. */
225           mutex_enter(&sc->sc_mutex);
226           while (sc->sc_queuecnt > 0) {
227                     if (cv_timedwait(&sc->sc_drain, &sc->sc_mutex, 30 * hz)) {
228                               /*
229                                * XXX This seems like a recipe for crashing on
230                                * use after free...
231                                */
232                               printf("%s: not drained\n", dksc->sc_xname);
233                               break;
234                     }
235           }
236           mutex_exit(&sc->sc_mutex);
237 
238           /* Kill off any queued buffers. */
239           dk_drain(dksc);
240           bufq_free(dksc->sc_bufq);
241 
242           /* Locate the major numbers. */
243           bmaj = bdevsw_lookup_major(&ld_bdevsw);
244           cmaj = cdevsw_lookup_major(&ld_cdevsw);
245 
246           /* Nuke the vnodes for any open instances. */
247           for (i = 0; i < MAXPARTITIONS; i++) {
248                     mn = DISKMINOR(device_unit(dksc->sc_dev), i);
249                     vdevgone(bmaj, mn, mn, VBLK);
250                     vdevgone(cmaj, mn, mn, VCHR);
251           }
252 
253           /* Delete all of our wedges. */
254           dkwedge_delall(&dksc->sc_dkdev);
255 
256           /* Detach from the disk list. */
257           disk_detach(&dksc->sc_dkdev);
258           disk_destroy(&dksc->sc_dkdev);
259 
260           dk_detach(dksc);
261 
262           /* Deregister with PMF */
263           pmf_device_deregister(dksc->sc_dev);
264 
265           /*
266            * XXX We can't really flush the cache here, because the
267            * XXX device may already be non-existent from the controller's
268            * XXX perspective.
269            */
270 #if 0
271           ld_flush(dksc->sc_dev, false);
272 #endif
273           cv_destroy(&sc->sc_drain);
274           mutex_destroy(&sc->sc_mutex);
275 }
276 
277 /* ARGSUSED */
278 static bool
ld_suspend(device_t dev,const pmf_qual_t * qual)279 ld_suspend(device_t dev, const pmf_qual_t *qual)
280 {
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
ld_resume(device_t dev,const pmf_qual_t * qual)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;
330 }
331 
332 /* ARGSUSED */
333 static bool
ld_shutdown(device_t dev,int flags)334 ld_shutdown(device_t dev, int flags)
335 {
336           if ((flags & RB_NOSYNC) == 0 && ld_flush(dev, true) != 0)
337                     return false;
338 
339           return true;
340 }
341 
342 /* ARGSUSED */
343 static int
ldopen(dev_t dev,int flags,int fmt,struct lwp * l)344 ldopen(dev_t dev, int flags, int fmt, struct lwp *l)
345 {
346           struct ld_softc *sc;
347           struct dk_softc *dksc;
348           int unit;
349 
350           unit = DISKUNIT(dev);
351           if ((sc = device_lookup_private(&ld_cd, unit)) == NULL)
352                     return (ENXIO);
353 
354           if ((sc->sc_flags & LDF_ENABLED) == 0)
355                     return (ENODEV);
356 
357           dksc = &sc->sc_dksc;
358 
359           return dk_open(dksc, dev, flags, fmt, l);
360 }
361 
362 static int
ld_lastclose(device_t self)363 ld_lastclose(device_t self)
364 {
365           ld_flush(self, false);
366 
367           return 0;
368 }
369 
370 /* ARGSUSED */
371 static int
ldclose(dev_t dev,int flags,int fmt,struct lwp * l)372 ldclose(dev_t dev, int flags, int fmt, struct lwp *l)
373 {
374           struct ld_softc *sc;
375           struct dk_softc *dksc;
376           int unit;
377 
378           unit = DISKUNIT(dev);
379           sc = device_lookup_private(&ld_cd, unit);
380           dksc = &sc->sc_dksc;
381 
382           return dk_close(dksc, dev, flags, fmt, l);
383 }
384 
385 /* ARGSUSED */
386 static int
ldread(dev_t dev,struct uio * uio,int ioflag)387 ldread(dev_t dev, struct uio *uio, int ioflag)
388 {
389 
390           return (physio(ldstrategy, NULL, dev, B_READ, ldminphys, uio));
391 }
392 
393 /* ARGSUSED */
394 static int
ldwrite(dev_t dev,struct uio * uio,int ioflag)395 ldwrite(dev_t dev, struct uio *uio, int ioflag)
396 {
397 
398           return (physio(ldstrategy, NULL, dev, B_WRITE, ldminphys, uio));
399 }
400 
401 /* ARGSUSED */
402 static int
ldioctl(dev_t dev,u_long cmd,void * addr,int32_t flag,struct lwp * l)403 ldioctl(dev_t dev, u_long cmd, void *addr, int32_t flag, struct lwp *l)
404 {
405           struct ld_softc *sc;
406           struct dk_softc *dksc;
407           int unit, error;
408 
409           unit = DISKUNIT(dev);
410           sc = device_lookup_private(&ld_cd, unit);
411           dksc = &sc->sc_dksc;
412 
413           error = 0;
414 
415           /*
416            * Some common checks so that individual attachments wouldn't need
417            * to duplicate them.
418            */
419           switch (cmd) {
420           case DIOCCACHESYNC:
421                     /*
422                      * XXX Do we really need to care about having a writable
423                      * file descriptor here?
424                      */
425                     if ((flag & FWRITE) == 0)
426                               error = EBADF;
427                     else
428                               error = 0;
429                     break;
430           }
431 
432           if (error != 0)
433                     return (error);
434 
435           if (sc->sc_ioctl) {
436                     if ((sc->sc_flags & LDF_MPSAFE) == 0)
437                               KERNEL_LOCK(1, curlwp);
438                     error = (*sc->sc_ioctl)(sc, cmd, addr, flag, 0);
439                     if ((sc->sc_flags & LDF_MPSAFE) == 0)
440                               KERNEL_UNLOCK_ONE(curlwp);
441                     if (error != EPASSTHROUGH)
442                               return (error);
443           }
444 
445           /* something not handled by the attachment */
446           return dk_ioctl(dksc, dev, cmd, addr, flag, l);
447 }
448 
449 /*
450  * Flush the device's cache.
451  */
452 static int
ld_flush(device_t self,bool poll)453 ld_flush(device_t self, bool poll)
454 {
455           int error = 0;
456           struct ld_softc *sc = device_private(self);
457 
458           if (sc->sc_ioctl) {
459                     if ((sc->sc_flags & LDF_MPSAFE) == 0)
460                               KERNEL_LOCK(1, curlwp);
461                     error = (*sc->sc_ioctl)(sc, DIOCCACHESYNC, NULL, 0, poll);
462                     if ((sc->sc_flags & LDF_MPSAFE) == 0)
463                               KERNEL_UNLOCK_ONE(curlwp);
464                     if (error != 0)
465                               device_printf(self, "unable to flush cache\n");
466           }
467 
468           return error;
469 }
470 
471 static void
ldstrategy(struct buf * bp)472 ldstrategy(struct buf *bp)
473 {
474           struct ld_softc *sc;
475           struct dk_softc *dksc;
476           int unit;
477 
478           unit = DISKUNIT(bp->b_dev);
479           sc = device_lookup_private(&ld_cd, unit);
480           dksc = &sc->sc_dksc;
481 
482           dk_strategy(dksc, bp);
483 }
484 
485 static int
ld_diskstart(device_t dev,struct buf * bp)486 ld_diskstart(device_t dev, struct buf *bp)
487 {
488           struct ld_softc *sc = device_private(dev);
489           int error;
490 
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");
495                     return EAGAIN;
496           }
497 
498           if ((sc->sc_flags & LDF_MPSAFE) == 0)
499                     KERNEL_LOCK(1, curlwp);
500 
501           mutex_enter(&sc->sc_mutex);
502 
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");
507                     error = EAGAIN;
508           } else {
509                     error = (*sc->sc_start)(sc, bp);
510                     if (error == 0)
511                               sc->sc_queuecnt++;
512           }
513 
514           mutex_exit(&sc->sc_mutex);
515 
516           if ((sc->sc_flags & LDF_MPSAFE) == 0)
517                     KERNEL_UNLOCK_ONE(curlwp);
518 
519           return error;
520 }
521 
522 void
lddone(struct ld_softc * sc,struct buf * bp)523 lddone(struct ld_softc *sc, struct buf *bp)
524 {
525           struct dk_softc *dksc = &sc->sc_dksc;
526 
527           dk_done(dksc, bp);
528 
529           mutex_enter(&sc->sc_mutex);
530           if (--sc->sc_queuecnt <= sc->sc_maxqueuecnt) {
531                     cv_broadcast(&sc->sc_drain);
532                     mutex_exit(&sc->sc_mutex);
533                     dk_start(dksc, NULL);
534           } else
535                     mutex_exit(&sc->sc_mutex);
536 }
537 
538 static int
ldsize(dev_t dev)539 ldsize(dev_t dev)
540 {
541           struct ld_softc *sc;
542           struct dk_softc *dksc;
543           int unit;
544 
545           unit = DISKUNIT(dev);
546           if ((sc = device_lookup_private(&ld_cd, unit)) == NULL)
547                     return (-1);
548           dksc = &sc->sc_dksc;
549 
550           if ((sc->sc_flags & LDF_ENABLED) == 0)
551                     return (-1);
552 
553           return dk_size(dksc, dev);
554 }
555 
556 /*
557  * Take a dump.
558  */
559 static int
lddump(dev_t dev,daddr_t blkno,void * va,size_t size)560 lddump(dev_t dev, daddr_t blkno, void *va, size_t size)
561 {
562           struct ld_softc *sc;
563           struct dk_softc *dksc;
564           int unit;
565 
566           unit = DISKUNIT(dev);
567           if ((sc = device_lookup_private(&ld_cd, unit)) == NULL)
568                     return (ENXIO);
569           dksc = &sc->sc_dksc;
570 
571           if ((sc->sc_flags & LDF_ENABLED) == 0)
572                     return (ENODEV);
573 
574           return dk_dump(dksc, dev, blkno, va, size, 0);
575 }
576 
577 static int
ld_dumpblocks(device_t dev,void * va,daddr_t blkno,int nblk)578 ld_dumpblocks(device_t dev, void *va, daddr_t blkno, int nblk)
579 {
580           struct ld_softc *sc = device_private(dev);
581 
582           if (sc->sc_dump == NULL)
583                     return (ENODEV);
584 
585           /*
586            * Minimum consistency check; sc_dump() should check
587            * device-dependent constraints if necessary.
588            */
589           if (blkno < 0)
590                     return (EIO);
591 
592           return (*sc->sc_dump)(sc, va, blkno, nblk);
593 }
594 
595 /*
596  * Adjust the size of a transfer.
597  */
598 static void
ldminphys(struct buf * bp)599 ldminphys(struct buf *bp)
600 {
601           int unit;
602           struct ld_softc *sc;
603 
604           unit = DISKUNIT(bp->b_dev);
605           sc = device_lookup_private(&ld_cd, unit);
606 
607           ld_iosize(sc->sc_dv, &bp->b_bcount);
608           minphys(bp);
609 }
610 
611 static void
ld_iosize(device_t d,int * countp)612 ld_iosize(device_t d, int *countp)
613 {
614           struct ld_softc *sc = device_private(d);
615 
616           if (*countp > sc->sc_maxxfer)
617                     *countp = sc->sc_maxxfer;
618 }
619 
620 static void
ld_fake_geometry(struct ld_softc * sc)621 ld_fake_geometry(struct ld_softc *sc)
622 {
623           uint64_t ncyl;
624 
625           if (sc->sc_secperunit <= 528 * 2048)              /* 528MB */
626                     sc->sc_nheads = 16;
627           else if (sc->sc_secperunit <= 1024 * 2048)        /* 1GB */
628                     sc->sc_nheads = 32;
629           else if (sc->sc_secperunit <= 21504 * 2048)       /* 21GB */
630                     sc->sc_nheads = 64;
631           else if (sc->sc_secperunit <= 43008 * 2048)       /* 42GB */
632                     sc->sc_nheads = 128;
633           else
634                     sc->sc_nheads = 255;
635 
636           sc->sc_nsectors = 63;
637           sc->sc_ncylinders = INT_MAX;
638           ncyl = sc->sc_secperunit /
639               (sc->sc_nheads * sc->sc_nsectors);
640           if (ncyl < INT_MAX)
641                     sc->sc_ncylinders = (int)ncyl;
642 }
643 
644 static void
ld_set_geometry(struct ld_softc * sc)645 ld_set_geometry(struct ld_softc *sc)
646 {
647           struct dk_softc *dksc = &sc->sc_dksc;
648           struct disk_geom *dg = &dksc->sc_dkdev.dk_geom;
649           char tbuf[9];
650 
651           format_bytes(tbuf, sizeof(tbuf), sc->sc_secperunit *
652               sc->sc_secsize);
653           aprint_normal_dev(dksc->sc_dev, "%s, %d cyl, %d head, %d sec, "
654               "%d bytes/sect x %"PRIu64" sectors",
655               tbuf, sc->sc_ncylinders, sc->sc_nheads,
656               sc->sc_nsectors, sc->sc_secsize, sc->sc_secperunit);
657           if (sc->sc_physsecsize != sc->sc_secsize) {
658                     aprint_normal(" (%d bytes/physsect", sc->sc_physsecsize);
659                     if (sc->sc_alignedsec != 0)
660                               aprint_normal("; first aligned sector %u",
661                                   sc->sc_alignedsec);
662                     aprint_normal(")");
663           }
664           aprint_normal("\n");
665 
666           memset(dg, 0, sizeof(*dg));
667           dg->dg_secperunit = sc->sc_secperunit;
668           dg->dg_secsize = sc->sc_secsize;
669           dg->dg_nsectors = sc->sc_nsectors;
670           dg->dg_ntracks = sc->sc_nheads;
671           dg->dg_ncylinders = sc->sc_ncylinders;
672           dg->dg_physsecsize = sc->sc_physsecsize;
673           dg->dg_alignedsec = sc->sc_alignedsec;
674 
675           disk_set_info(dksc->sc_dev, &dksc->sc_dkdev, sc->sc_typename);
676 }
677 
678 static void
ld_config_interrupts(device_t d)679 ld_config_interrupts(device_t d)
680 {
681           struct ld_softc *sc = device_private(d);
682           struct dk_softc *dksc = &sc->sc_dksc;
683 
684           dkwedge_discover(&dksc->sc_dkdev);
685 }
686 
687 static int
ld_discard(device_t dev,off_t pos,off_t len)688 ld_discard(device_t dev, off_t pos, off_t len)
689 {
690           struct ld_softc *sc = device_private(dev);
691           struct buf dbuf, *bp = &dbuf;
692           int error = 0;
693 
694           KASSERT(len <= INT_MAX);
695 
696           if (sc->sc_discard == NULL)
697                     return (ENODEV);
698 
699           if ((sc->sc_flags & LDF_MPSAFE) == 0)
700                     KERNEL_LOCK(1, curlwp);
701 
702           buf_init(bp);
703           bp->b_vp = NULL;
704           bp->b_data = NULL;
705           bp->b_bufsize = 0;
706           bp->b_rawblkno = pos / sc->sc_secsize;
707           bp->b_bcount = len;
708           bp->b_flags = B_WRITE;
709           bp->b_cflags = BC_BUSY;
710 
711           error = (*sc->sc_discard)(sc, bp);
712           if (error == 0)
713                     error = biowait(bp);
714 
715           buf_destroy(bp);
716 
717           if ((sc->sc_flags & LDF_MPSAFE) == 0)
718                     KERNEL_UNLOCK_ONE(curlwp);
719 
720           return error;
721 }
722 
723 void
lddiscardend(struct ld_softc * sc,struct buf * bp)724 lddiscardend(struct ld_softc *sc, struct buf *bp)
725 {
726 
727           if (bp->b_error)
728                     bp->b_resid = bp->b_bcount;
729           biodone(bp);
730 }
731 
732 static int
lddiscard(dev_t dev,off_t pos,off_t len)733 lddiscard(dev_t dev, off_t pos, off_t len)
734 {
735           struct ld_softc *sc;
736           struct dk_softc *dksc;
737           int unit;
738 
739           unit = DISKUNIT(dev);
740           sc = device_lookup_private(&ld_cd, unit);
741           dksc = &sc->sc_dksc;
742 
743           return dk_discard(dksc, dev, pos, len);
744 }
745 
746 MODULE(MODULE_CLASS_DRIVER, ld, "dk_subr");
747 
748 #ifdef _MODULE
749 CFDRIVER_DECL(ld, DV_DISK, NULL);
750 #endif
751 
752 static int
ld_modcmd(modcmd_t cmd,void * opaque)753 ld_modcmd(modcmd_t cmd, void *opaque)
754 {
755 #ifdef _MODULE
756           devmajor_t bmajor, cmajor;
757 #endif
758           int error = 0;
759 
760 #ifdef _MODULE
761           switch (cmd) {
762           case MODULE_CMD_INIT:
763                     bmajor = cmajor = -1;
764                     error = devsw_attach(ld_cd.cd_name, &ld_bdevsw, &bmajor,
765                         &ld_cdevsw, &cmajor);
766                     if (error)
767                               break;
768                     error = config_cfdriver_attach(&ld_cd);
769                     break;
770           case MODULE_CMD_FINI:
771                     error = config_cfdriver_detach(&ld_cd);
772                     if (error)
773                               break;
774                     devsw_detach(&ld_bdevsw, &ld_cdevsw);
775                     break;
776           default:
777                     error = ENOTTY;
778                     break;
779           }
780 #endif
781 
782           return error;
783 }
784