1 /* $NetBSD: ld.c,v 1.94 2016/02/27 08:54:49 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.94 2016/02/27 08:54:49 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 58 #include <dev/ldvar.h> 59 60 #include <prop/proplib.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) 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, BUFQ_DISK_DEFAULT_STRAT, 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 (sc->sc_flush != NULL && (*sc->sc_flush)(sc, LDFL_POLL) != 0) { 279 device_printf(dksc->sc_dev, "unable to flush cache\n"); 280 return false; 281 } 282 283 return true; 284 } 285 286 /* ARGSUSED */ 287 static int 288 ldopen(dev_t dev, int flags, int fmt, struct lwp *l) 289 { 290 struct ld_softc *sc; 291 struct dk_softc *dksc; 292 int unit; 293 294 unit = DISKUNIT(dev); 295 if ((sc = device_lookup_private(&ld_cd, unit)) == NULL) 296 return (ENXIO); 297 dksc = &sc->sc_dksc; 298 299 return dk_open(dksc, dev, flags, fmt, l); 300 } 301 302 static int 303 ld_lastclose(device_t self) 304 { 305 struct ld_softc *sc = device_private(self); 306 307 if (sc->sc_flush != NULL && (*sc->sc_flush)(sc, 0) != 0) 308 device_printf(self, "unable to flush cache\n"); 309 310 return 0; 311 } 312 313 /* ARGSUSED */ 314 static int 315 ldclose(dev_t dev, int flags, int fmt, struct lwp *l) 316 { 317 struct ld_softc *sc; 318 struct dk_softc *dksc; 319 int unit; 320 321 unit = DISKUNIT(dev); 322 sc = device_lookup_private(&ld_cd, unit); 323 dksc = &sc->sc_dksc; 324 325 return dk_close(dksc, dev, flags, fmt, l); 326 } 327 328 /* ARGSUSED */ 329 static int 330 ldread(dev_t dev, struct uio *uio, int ioflag) 331 { 332 333 return (physio(ldstrategy, NULL, dev, B_READ, ldminphys, uio)); 334 } 335 336 /* ARGSUSED */ 337 static int 338 ldwrite(dev_t dev, struct uio *uio, int ioflag) 339 { 340 341 return (physio(ldstrategy, NULL, dev, B_WRITE, ldminphys, uio)); 342 } 343 344 /* ARGSUSED */ 345 static int 346 ldioctl(dev_t dev, u_long cmd, void *addr, int32_t flag, struct lwp *l) 347 { 348 struct ld_softc *sc; 349 struct dk_softc *dksc; 350 int unit, error; 351 352 unit = DISKUNIT(dev); 353 sc = device_lookup_private(&ld_cd, unit); 354 dksc = &sc->sc_dksc; 355 356 error = dk_ioctl(dksc, dev, cmd, addr, flag, l); 357 if (error != EPASSTHROUGH) 358 return (error); 359 360 error = 0; 361 362 switch (cmd) { 363 case DIOCCACHESYNC: 364 /* 365 * XXX Do we really need to care about having a writable 366 * file descriptor here? 367 */ 368 if ((flag & FWRITE) == 0) 369 error = EBADF; 370 else if (sc->sc_flush) 371 error = (*sc->sc_flush)(sc, 0); 372 else 373 error = 0; /* XXX Error out instead? */ 374 break; 375 default: 376 error = ENOTTY; 377 break; 378 } 379 380 return (error); 381 } 382 383 static void 384 ldstrategy(struct buf *bp) 385 { 386 struct ld_softc *sc; 387 struct dk_softc *dksc; 388 int unit; 389 390 unit = DISKUNIT(bp->b_dev); 391 sc = device_lookup_private(&ld_cd, unit); 392 dksc = &sc->sc_dksc; 393 394 dk_strategy(dksc, bp); 395 } 396 397 static int 398 ld_diskstart(device_t dev, struct buf *bp) 399 { 400 struct ld_softc *sc = device_private(dev); 401 int error; 402 403 if (sc->sc_queuecnt >= sc->sc_maxqueuecnt) 404 return EAGAIN; 405 406 mutex_enter(&sc->sc_mutex); 407 408 if (sc->sc_queuecnt >= sc->sc_maxqueuecnt) 409 error = EAGAIN; 410 else { 411 error = (*sc->sc_start)(sc, bp); 412 if (error == 0) 413 sc->sc_queuecnt++; 414 } 415 416 mutex_exit(&sc->sc_mutex); 417 418 return error; 419 } 420 421 void 422 lddone(struct ld_softc *sc, struct buf *bp) 423 { 424 struct dk_softc *dksc = &sc->sc_dksc; 425 426 dk_done(dksc, bp); 427 428 mutex_enter(&sc->sc_mutex); 429 if (--sc->sc_queuecnt <= sc->sc_maxqueuecnt) { 430 if ((sc->sc_flags & LDF_DRAIN) != 0) { 431 sc->sc_flags &= ~LDF_DRAIN; 432 cv_broadcast(&sc->sc_drain); 433 } 434 mutex_exit(&sc->sc_mutex); 435 dk_start(dksc, NULL); 436 } else 437 mutex_exit(&sc->sc_mutex); 438 } 439 440 static int 441 ldsize(dev_t dev) 442 { 443 struct ld_softc *sc; 444 struct dk_softc *dksc; 445 int unit; 446 447 unit = DISKUNIT(dev); 448 if ((sc = device_lookup_private(&ld_cd, unit)) == NULL) 449 return (ENODEV); 450 dksc = &sc->sc_dksc; 451 452 if ((sc->sc_flags & LDF_ENABLED) == 0) 453 return (ENODEV); 454 455 return dk_size(dksc, dev); 456 } 457 458 /* 459 * Take a dump. 460 */ 461 static int 462 lddump(dev_t dev, daddr_t blkno, void *va, size_t size) 463 { 464 struct ld_softc *sc; 465 struct dk_softc *dksc; 466 int unit; 467 468 unit = DISKUNIT(dev); 469 if ((sc = device_lookup_private(&ld_cd, unit)) == NULL) 470 return (ENXIO); 471 dksc = &sc->sc_dksc; 472 473 if ((sc->sc_flags & LDF_ENABLED) == 0) 474 return (ENODEV); 475 476 return dk_dump(dksc, dev, blkno, va, size); 477 } 478 479 static int 480 ld_dumpblocks(device_t dev, void *va, daddr_t blkno, int nblk) 481 { 482 struct ld_softc *sc = device_private(dev); 483 484 if (sc->sc_dump == NULL) 485 return (ENODEV); 486 487 return (*sc->sc_dump)(sc, va, blkno, nblk); 488 } 489 490 /* 491 * Adjust the size of a transfer. 492 */ 493 static void 494 ldminphys(struct buf *bp) 495 { 496 int unit; 497 struct ld_softc *sc; 498 499 unit = DISKUNIT(bp->b_dev); 500 sc = device_lookup_private(&ld_cd, unit); 501 502 ld_iosize(sc->sc_dv, &bp->b_bcount); 503 minphys(bp); 504 } 505 506 static void 507 ld_iosize(device_t d, int *countp) 508 { 509 struct ld_softc *sc = device_private(d); 510 511 if (*countp > sc->sc_maxxfer) 512 *countp = sc->sc_maxxfer; 513 } 514 515 static void 516 ld_fake_geometry(struct ld_softc *sc) 517 { 518 uint64_t ncyl; 519 520 if (sc->sc_secperunit <= 528 * 2048) /* 528MB */ 521 sc->sc_nheads = 16; 522 else if (sc->sc_secperunit <= 1024 * 2048) /* 1GB */ 523 sc->sc_nheads = 32; 524 else if (sc->sc_secperunit <= 21504 * 2048) /* 21GB */ 525 sc->sc_nheads = 64; 526 else if (sc->sc_secperunit <= 43008 * 2048) /* 42GB */ 527 sc->sc_nheads = 128; 528 else 529 sc->sc_nheads = 255; 530 531 sc->sc_nsectors = 63; 532 sc->sc_ncylinders = INT_MAX; 533 ncyl = sc->sc_secperunit / 534 (sc->sc_nheads * sc->sc_nsectors); 535 if (ncyl < INT_MAX) 536 sc->sc_ncylinders = (int)ncyl; 537 } 538 539 static void 540 ld_set_geometry(struct ld_softc *sc) 541 { 542 struct dk_softc *dksc = &sc->sc_dksc; 543 struct disk_geom *dg = &dksc->sc_dkdev.dk_geom; 544 char tbuf[9]; 545 546 format_bytes(tbuf, sizeof(tbuf), sc->sc_secperunit * 547 sc->sc_secsize); 548 aprint_normal_dev(dksc->sc_dev, "%s, %d cyl, %d head, %d sec, " 549 "%d bytes/sect x %"PRIu64" sectors\n", 550 tbuf, sc->sc_ncylinders, sc->sc_nheads, 551 sc->sc_nsectors, sc->sc_secsize, sc->sc_secperunit); 552 553 memset(dg, 0, sizeof(*dg)); 554 dg->dg_secperunit = sc->sc_secperunit; 555 dg->dg_secsize = sc->sc_secsize; 556 dg->dg_nsectors = sc->sc_nsectors; 557 dg->dg_ntracks = sc->sc_nheads; 558 dg->dg_ncylinders = sc->sc_ncylinders; 559 560 disk_set_info(dksc->sc_dev, &dksc->sc_dkdev, NULL); 561 } 562 563 static void 564 ld_config_interrupts(device_t d) 565 { 566 struct ld_softc *sc = device_private(d); 567 struct dk_softc *dksc = &sc->sc_dksc; 568 569 dkwedge_discover(&dksc->sc_dkdev); 570 } 571 572 static int 573 ld_discard(device_t dev, off_t pos, off_t len) 574 { 575 struct ld_softc *sc = device_private(dev); 576 577 if (sc->sc_discard == NULL) 578 return (ENODEV); 579 580 return (*sc->sc_discard)(sc, pos, len); 581 } 582 583 static int 584 lddiscard(dev_t dev, off_t pos, off_t len) 585 { 586 struct ld_softc *sc; 587 struct dk_softc *dksc; 588 int unit; 589 590 unit = DISKUNIT(dev); 591 sc = device_lookup_private(&ld_cd, unit); 592 dksc = &sc->sc_dksc; 593 594 return dk_discard(dksc, dev, pos, len); 595 } 596