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