1 /* $NetBSD: ld.c,v 1.99 2016/11/26 12:32:03 mlelstv 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.99 2016/11/26 12:32:03 mlelstv 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 static void ldminphys(struct buf *bp); 63 static bool ld_suspend(device_t, const pmf_qual_t *); 64 static bool ld_shutdown(device_t, int); 65 static int ld_diskstart(device_t, struct buf *bp); 66 static void ld_iosize(device_t, int *); 67 static int ld_dumpblocks(device_t, void *, daddr_t, int); 68 static void ld_fake_geometry(struct ld_softc *); 69 static void ld_set_geometry(struct ld_softc *); 70 static void ld_config_interrupts (device_t); 71 static int ld_lastclose(device_t); 72 static int ld_discard(device_t, off_t, off_t); 73 74 extern struct cfdriver ld_cd; 75 76 static dev_type_open(ldopen); 77 static dev_type_close(ldclose); 78 static dev_type_read(ldread); 79 static dev_type_write(ldwrite); 80 static dev_type_ioctl(ldioctl); 81 static dev_type_strategy(ldstrategy); 82 static dev_type_dump(lddump); 83 static dev_type_size(ldsize); 84 static dev_type_discard(lddiscard); 85 86 const struct bdevsw ld_bdevsw = { 87 .d_open = ldopen, 88 .d_close = ldclose, 89 .d_strategy = ldstrategy, 90 .d_ioctl = ldioctl, 91 .d_dump = lddump, 92 .d_psize = ldsize, 93 .d_discard = lddiscard, 94 .d_flag = D_DISK | D_MPSAFE 95 }; 96 97 const struct cdevsw ld_cdevsw = { 98 .d_open = ldopen, 99 .d_close = ldclose, 100 .d_read = ldread, 101 .d_write = ldwrite, 102 .d_ioctl = ldioctl, 103 .d_stop = nostop, 104 .d_tty = notty, 105 .d_poll = nopoll, 106 .d_mmap = nommap, 107 .d_kqfilter = nokqfilter, 108 .d_discard = lddiscard, 109 .d_flag = D_DISK | D_MPSAFE 110 }; 111 112 static struct dkdriver lddkdriver = { 113 .d_open = ldopen, 114 .d_close = ldclose, 115 .d_strategy = ldstrategy, 116 .d_iosize = ld_iosize, 117 .d_minphys = ldminphys, 118 .d_diskstart = ld_diskstart, 119 .d_dumpblocks = ld_dumpblocks, 120 .d_lastclose = ld_lastclose, 121 .d_discard = ld_discard 122 }; 123 124 void 125 ldattach(struct ld_softc *sc, const char *default_strategy) 126 { 127 device_t self = sc->sc_dv; 128 struct dk_softc *dksc = &sc->sc_dksc; 129 130 mutex_init(&sc->sc_mutex, MUTEX_DEFAULT, IPL_VM); 131 cv_init(&sc->sc_drain, "lddrain"); 132 133 if ((sc->sc_flags & LDF_ENABLED) == 0) { 134 return; 135 } 136 137 /* Initialise dk and disk structure. */ 138 dk_init(dksc, self, DKTYPE_LD); 139 disk_init(&dksc->sc_dkdev, dksc->sc_xname, &lddkdriver); 140 141 if (sc->sc_maxxfer > MAXPHYS) 142 sc->sc_maxxfer = MAXPHYS; 143 144 /* Build synthetic geometry if necessary. */ 145 if (sc->sc_nheads == 0 || sc->sc_nsectors == 0 || 146 sc->sc_ncylinders == 0) 147 ld_fake_geometry(sc); 148 149 sc->sc_disksize512 = sc->sc_secperunit * sc->sc_secsize / DEV_BSIZE; 150 151 /* Attach dk and disk subsystems */ 152 dk_attach(dksc); 153 disk_attach(&dksc->sc_dkdev); 154 ld_set_geometry(sc); 155 156 bufq_alloc(&dksc->sc_bufq, default_strategy, BUFQ_SORT_RAWBLOCK); 157 158 /* Register with PMF */ 159 if (!pmf_device_register1(dksc->sc_dev, ld_suspend, NULL, ld_shutdown)) 160 aprint_error_dev(dksc->sc_dev, 161 "couldn't establish power handler\n"); 162 163 /* Discover wedges on this disk. */ 164 config_interrupts(sc->sc_dv, ld_config_interrupts); 165 } 166 167 int 168 ldadjqparam(struct ld_softc *sc, int xmax) 169 { 170 171 mutex_enter(&sc->sc_mutex); 172 sc->sc_maxqueuecnt = xmax; 173 mutex_exit(&sc->sc_mutex); 174 175 return (0); 176 } 177 178 int 179 ldbegindetach(struct ld_softc *sc, int flags) 180 { 181 struct dk_softc *dksc = &sc->sc_dksc; 182 int rv = 0; 183 184 if ((sc->sc_flags & LDF_ENABLED) == 0) 185 return (0); 186 187 rv = disk_begindetach(&dksc->sc_dkdev, ld_lastclose, dksc->sc_dev, flags); 188 189 if (rv != 0) 190 return rv; 191 192 mutex_enter(&sc->sc_mutex); 193 sc->sc_maxqueuecnt = 0; 194 195 while (sc->sc_queuecnt > 0) { 196 sc->sc_flags |= LDF_DRAIN; 197 cv_wait(&sc->sc_drain, &sc->sc_mutex); 198 } 199 mutex_exit(&sc->sc_mutex); 200 201 return (rv); 202 } 203 204 void 205 ldenddetach(struct ld_softc *sc) 206 { 207 struct dk_softc *dksc = &sc->sc_dksc; 208 int bmaj, cmaj, i, mn; 209 210 if ((sc->sc_flags & LDF_ENABLED) == 0) 211 return; 212 213 mutex_enter(&sc->sc_mutex); 214 215 /* Wait for commands queued with the hardware to complete. */ 216 if (sc->sc_queuecnt != 0) { 217 if (cv_timedwait(&sc->sc_drain, &sc->sc_mutex, 30 * hz)) 218 printf("%s: not drained\n", dksc->sc_xname); 219 } 220 mutex_exit(&sc->sc_mutex); 221 222 /* Kill off any queued buffers. */ 223 dk_drain(dksc); 224 bufq_free(dksc->sc_bufq); 225 226 /* Locate the major numbers. */ 227 bmaj = bdevsw_lookup_major(&ld_bdevsw); 228 cmaj = cdevsw_lookup_major(&ld_cdevsw); 229 230 /* Nuke the vnodes for any open instances. */ 231 for (i = 0; i < MAXPARTITIONS; i++) { 232 mn = DISKMINOR(device_unit(dksc->sc_dev), i); 233 vdevgone(bmaj, mn, mn, VBLK); 234 vdevgone(cmaj, mn, mn, VCHR); 235 } 236 237 /* Delete all of our wedges. */ 238 dkwedge_delall(&dksc->sc_dkdev); 239 240 /* Detach from the disk list. */ 241 disk_detach(&dksc->sc_dkdev); 242 disk_destroy(&dksc->sc_dkdev); 243 244 dk_detach(dksc); 245 246 /* Deregister with PMF */ 247 pmf_device_deregister(dksc->sc_dev); 248 249 /* 250 * XXX We can't really flush the cache here, beceause the 251 * XXX device may already be non-existent from the controller's 252 * XXX perspective. 253 */ 254 #if 0 255 /* Flush the device's cache. */ 256 if (sc->sc_flush != NULL) 257 if ((*sc->sc_flush)(sc, 0) != 0) 258 device_printf(dksc->sc_dev, "unable to flush cache\n"); 259 #endif 260 cv_destroy(&sc->sc_drain); 261 mutex_destroy(&sc->sc_mutex); 262 } 263 264 /* ARGSUSED */ 265 static bool 266 ld_suspend(device_t dev, const pmf_qual_t *qual) 267 { 268 return ld_shutdown(dev, 0); 269 } 270 271 /* ARGSUSED */ 272 static bool 273 ld_shutdown(device_t dev, int flags) 274 { 275 struct ld_softc *sc = device_private(dev); 276 struct dk_softc *dksc = &sc->sc_dksc; 277 278 if ((flags & RB_NOSYNC) == 0 && sc->sc_flush != NULL 279 && (*sc->sc_flush)(sc, LDFL_POLL) != 0) { 280 device_printf(dksc->sc_dev, "unable to flush cache\n"); 281 return false; 282 } 283 284 return true; 285 } 286 287 /* ARGSUSED */ 288 static int 289 ldopen(dev_t dev, int flags, int fmt, struct lwp *l) 290 { 291 struct ld_softc *sc; 292 struct dk_softc *dksc; 293 int unit; 294 295 unit = DISKUNIT(dev); 296 if ((sc = device_lookup_private(&ld_cd, unit)) == NULL) 297 return (ENXIO); 298 dksc = &sc->sc_dksc; 299 300 return dk_open(dksc, dev, flags, fmt, l); 301 } 302 303 static int 304 ld_lastclose(device_t self) 305 { 306 struct ld_softc *sc = device_private(self); 307 308 if (sc->sc_flush != NULL && (*sc->sc_flush)(sc, 0) != 0) 309 device_printf(self, "unable to flush cache\n"); 310 311 return 0; 312 } 313 314 /* ARGSUSED */ 315 static int 316 ldclose(dev_t dev, int flags, int fmt, struct lwp *l) 317 { 318 struct ld_softc *sc; 319 struct dk_softc *dksc; 320 int unit; 321 322 unit = DISKUNIT(dev); 323 sc = device_lookup_private(&ld_cd, unit); 324 dksc = &sc->sc_dksc; 325 326 return dk_close(dksc, dev, flags, fmt, l); 327 } 328 329 /* ARGSUSED */ 330 static int 331 ldread(dev_t dev, struct uio *uio, int ioflag) 332 { 333 334 return (physio(ldstrategy, NULL, dev, B_READ, ldminphys, uio)); 335 } 336 337 /* ARGSUSED */ 338 static int 339 ldwrite(dev_t dev, struct uio *uio, int ioflag) 340 { 341 342 return (physio(ldstrategy, NULL, dev, B_WRITE, ldminphys, uio)); 343 } 344 345 /* ARGSUSED */ 346 static int 347 ldioctl(dev_t dev, u_long cmd, void *addr, int32_t flag, struct lwp *l) 348 { 349 struct ld_softc *sc; 350 struct dk_softc *dksc; 351 int unit, error; 352 353 unit = DISKUNIT(dev); 354 sc = device_lookup_private(&ld_cd, unit); 355 dksc = &sc->sc_dksc; 356 357 error = 0; 358 359 switch (cmd) { 360 case DIOCCACHESYNC: 361 /* 362 * XXX Do we really need to care about having a writable 363 * file descriptor here? 364 */ 365 if ((flag & FWRITE) == 0) 366 error = EBADF; 367 else if (sc->sc_flush) 368 error = (*sc->sc_flush)(sc, 0); 369 else 370 error = 0; /* XXX Error out instead? */ 371 break; 372 373 default: 374 error = dk_ioctl(dksc, dev, cmd, addr, flag, l); 375 break; 376 } 377 378 return (error); 379 } 380 381 static void 382 ldstrategy(struct buf *bp) 383 { 384 struct ld_softc *sc; 385 struct dk_softc *dksc; 386 int unit; 387 388 unit = DISKUNIT(bp->b_dev); 389 sc = device_lookup_private(&ld_cd, unit); 390 dksc = &sc->sc_dksc; 391 392 dk_strategy(dksc, bp); 393 } 394 395 static int 396 ld_diskstart(device_t dev, struct buf *bp) 397 { 398 struct ld_softc *sc = device_private(dev); 399 int error; 400 401 if (sc->sc_queuecnt >= sc->sc_maxqueuecnt) 402 return EAGAIN; 403 404 mutex_enter(&sc->sc_mutex); 405 406 if (sc->sc_queuecnt >= sc->sc_maxqueuecnt) 407 error = EAGAIN; 408 else { 409 error = (*sc->sc_start)(sc, bp); 410 if (error == 0) 411 sc->sc_queuecnt++; 412 } 413 414 mutex_exit(&sc->sc_mutex); 415 416 return error; 417 } 418 419 void 420 lddone(struct ld_softc *sc, struct buf *bp) 421 { 422 struct dk_softc *dksc = &sc->sc_dksc; 423 424 dk_done(dksc, bp); 425 426 mutex_enter(&sc->sc_mutex); 427 if (--sc->sc_queuecnt <= sc->sc_maxqueuecnt) { 428 if ((sc->sc_flags & LDF_DRAIN) != 0) { 429 sc->sc_flags &= ~LDF_DRAIN; 430 cv_broadcast(&sc->sc_drain); 431 } 432 mutex_exit(&sc->sc_mutex); 433 dk_start(dksc, NULL); 434 } else 435 mutex_exit(&sc->sc_mutex); 436 } 437 438 static int 439 ldsize(dev_t dev) 440 { 441 struct ld_softc *sc; 442 struct dk_softc *dksc; 443 int unit; 444 445 unit = DISKUNIT(dev); 446 if ((sc = device_lookup_private(&ld_cd, unit)) == NULL) 447 return (-1); 448 dksc = &sc->sc_dksc; 449 450 if ((sc->sc_flags & LDF_ENABLED) == 0) 451 return (-1); 452 453 return dk_size(dksc, dev); 454 } 455 456 /* 457 * Take a dump. 458 */ 459 static int 460 lddump(dev_t dev, daddr_t blkno, void *va, size_t size) 461 { 462 struct ld_softc *sc; 463 struct dk_softc *dksc; 464 int unit; 465 466 unit = DISKUNIT(dev); 467 if ((sc = device_lookup_private(&ld_cd, unit)) == NULL) 468 return (ENXIO); 469 dksc = &sc->sc_dksc; 470 471 if ((sc->sc_flags & LDF_ENABLED) == 0) 472 return (ENODEV); 473 474 return dk_dump(dksc, dev, blkno, va, size); 475 } 476 477 static int 478 ld_dumpblocks(device_t dev, void *va, daddr_t blkno, int nblk) 479 { 480 struct ld_softc *sc = device_private(dev); 481 482 if (sc->sc_dump == NULL) 483 return (ENODEV); 484 485 return (*sc->sc_dump)(sc, va, blkno, nblk); 486 } 487 488 /* 489 * Adjust the size of a transfer. 490 */ 491 static void 492 ldminphys(struct buf *bp) 493 { 494 int unit; 495 struct ld_softc *sc; 496 497 unit = DISKUNIT(bp->b_dev); 498 sc = device_lookup_private(&ld_cd, unit); 499 500 ld_iosize(sc->sc_dv, &bp->b_bcount); 501 minphys(bp); 502 } 503 504 static void 505 ld_iosize(device_t d, int *countp) 506 { 507 struct ld_softc *sc = device_private(d); 508 509 if (*countp > sc->sc_maxxfer) 510 *countp = sc->sc_maxxfer; 511 } 512 513 static void 514 ld_fake_geometry(struct ld_softc *sc) 515 { 516 uint64_t ncyl; 517 518 if (sc->sc_secperunit <= 528 * 2048) /* 528MB */ 519 sc->sc_nheads = 16; 520 else if (sc->sc_secperunit <= 1024 * 2048) /* 1GB */ 521 sc->sc_nheads = 32; 522 else if (sc->sc_secperunit <= 21504 * 2048) /* 21GB */ 523 sc->sc_nheads = 64; 524 else if (sc->sc_secperunit <= 43008 * 2048) /* 42GB */ 525 sc->sc_nheads = 128; 526 else 527 sc->sc_nheads = 255; 528 529 sc->sc_nsectors = 63; 530 sc->sc_ncylinders = INT_MAX; 531 ncyl = sc->sc_secperunit / 532 (sc->sc_nheads * sc->sc_nsectors); 533 if (ncyl < INT_MAX) 534 sc->sc_ncylinders = (int)ncyl; 535 } 536 537 static void 538 ld_set_geometry(struct ld_softc *sc) 539 { 540 struct dk_softc *dksc = &sc->sc_dksc; 541 struct disk_geom *dg = &dksc->sc_dkdev.dk_geom; 542 char tbuf[9]; 543 544 format_bytes(tbuf, sizeof(tbuf), sc->sc_secperunit * 545 sc->sc_secsize); 546 aprint_normal_dev(dksc->sc_dev, "%s, %d cyl, %d head, %d sec, " 547 "%d bytes/sect x %"PRIu64" sectors\n", 548 tbuf, sc->sc_ncylinders, sc->sc_nheads, 549 sc->sc_nsectors, sc->sc_secsize, sc->sc_secperunit); 550 551 memset(dg, 0, sizeof(*dg)); 552 dg->dg_secperunit = sc->sc_secperunit; 553 dg->dg_secsize = sc->sc_secsize; 554 dg->dg_nsectors = sc->sc_nsectors; 555 dg->dg_ntracks = sc->sc_nheads; 556 dg->dg_ncylinders = sc->sc_ncylinders; 557 558 disk_set_info(dksc->sc_dev, &dksc->sc_dkdev, NULL); 559 } 560 561 static void 562 ld_config_interrupts(device_t d) 563 { 564 struct ld_softc *sc = device_private(d); 565 struct dk_softc *dksc = &sc->sc_dksc; 566 567 dkwedge_discover(&dksc->sc_dkdev); 568 } 569 570 static int 571 ld_discard(device_t dev, off_t pos, off_t len) 572 { 573 struct ld_softc *sc = device_private(dev); 574 575 if (sc->sc_discard == NULL) 576 return (ENODEV); 577 578 return (*sc->sc_discard)(sc, pos, len); 579 } 580 581 static int 582 lddiscard(dev_t dev, off_t pos, off_t len) 583 { 584 struct ld_softc *sc; 585 struct dk_softc *dksc; 586 int unit; 587 588 unit = DISKUNIT(dev); 589 sc = device_lookup_private(&ld_cd, unit); 590 dksc = &sc->sc_dksc; 591 592 return dk_discard(dksc, dev, pos, len); 593 } 594 595 MODULE(MODULE_CLASS_DRIVER, ld, "dk_subr"); 596 597 #ifdef _MODULE 598 CFDRIVER_DECL(ld, DV_DISK, NULL); 599 #endif 600 601 static int 602 ld_modcmd(modcmd_t cmd, void *opaque) 603 { 604 #ifdef _MODULE 605 devmajor_t bmajor, cmajor; 606 #endif 607 int error = 0; 608 609 #ifdef _MODULE 610 switch (cmd) { 611 case MODULE_CMD_INIT: 612 bmajor = cmajor = -1; 613 error = devsw_attach(ld_cd.cd_name, &ld_bdevsw, &bmajor, 614 &ld_cdevsw, &cmajor); 615 if (error) 616 break; 617 error = config_cfdriver_attach(&ld_cd); 618 break; 619 case MODULE_CMD_FINI: 620 error = config_cfdriver_detach(&ld_cd); 621 if (error) 622 break; 623 devsw_detach(&ld_bdevsw, &ld_cdevsw); 624 break; 625 default: 626 error = ENOTTY; 627 break; 628 } 629 #endif 630 631 return error; 632 } 633