1 /* $NetBSD: ld.c,v 1.72 2014/03/16 05:20:26 dholland 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.72 2014/03/16 05:20:26 dholland 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/rnd.h> 58 59 #include <dev/ldvar.h> 60 61 #include <prop/proplib.h> 62 63 static void ldgetdefaultlabel(struct ld_softc *, struct disklabel *); 64 static void ldgetdisklabel(struct ld_softc *); 65 static void ldminphys(struct buf *bp); 66 static bool ld_suspend(device_t, const pmf_qual_t *); 67 static bool ld_shutdown(device_t, int); 68 static void ldstart(struct ld_softc *, struct buf *); 69 static void ld_set_geometry(struct ld_softc *); 70 static void ld_config_interrupts (device_t); 71 static int ldlastclose(device_t); 72 73 extern struct cfdriver ld_cd; 74 75 static dev_type_open(ldopen); 76 static dev_type_close(ldclose); 77 static dev_type_read(ldread); 78 static dev_type_write(ldwrite); 79 static dev_type_ioctl(ldioctl); 80 static dev_type_strategy(ldstrategy); 81 static dev_type_dump(lddump); 82 static dev_type_size(ldsize); 83 84 const struct bdevsw ld_bdevsw = { 85 .d_open = ldopen, 86 .d_close = ldclose, 87 .d_strategy = ldstrategy, 88 .d_ioctl = ldioctl, 89 .d_dump = lddump, 90 .d_psize = ldsize, 91 .d_flag = D_DISK 92 }; 93 94 const struct cdevsw ld_cdevsw = { 95 .d_open = ldopen, 96 .d_close = ldclose, 97 .d_read = ldread, 98 .d_write = ldwrite, 99 .d_ioctl = ldioctl, 100 .d_stop = nostop, 101 .d_tty = notty, 102 .d_poll = nopoll, 103 .d_mmap = nommap, 104 .d_kqfilter = nokqfilter, 105 .d_flag = D_DISK 106 }; 107 108 static struct dkdriver lddkdriver = { ldstrategy, ldminphys }; 109 110 void 111 ldattach(struct ld_softc *sc) 112 { 113 char tbuf[9]; 114 115 mutex_init(&sc->sc_mutex, MUTEX_DEFAULT, IPL_VM); 116 117 if ((sc->sc_flags & LDF_ENABLED) == 0) { 118 aprint_normal_dev(sc->sc_dv, "disabled\n"); 119 return; 120 } 121 122 /* Initialise and attach the disk structure. */ 123 disk_init(&sc->sc_dk, device_xname(sc->sc_dv), &lddkdriver); 124 disk_attach(&sc->sc_dk); 125 126 if (sc->sc_maxxfer > MAXPHYS) 127 sc->sc_maxxfer = MAXPHYS; 128 129 /* Build synthetic geometry if necessary. */ 130 if (sc->sc_nheads == 0 || sc->sc_nsectors == 0 || 131 sc->sc_ncylinders == 0) { 132 uint64_t ncyl; 133 134 if (sc->sc_secperunit <= 528 * 2048) /* 528MB */ 135 sc->sc_nheads = 16; 136 else if (sc->sc_secperunit <= 1024 * 2048) /* 1GB */ 137 sc->sc_nheads = 32; 138 else if (sc->sc_secperunit <= 21504 * 2048) /* 21GB */ 139 sc->sc_nheads = 64; 140 else if (sc->sc_secperunit <= 43008 * 2048) /* 42GB */ 141 sc->sc_nheads = 128; 142 else 143 sc->sc_nheads = 255; 144 145 sc->sc_nsectors = 63; 146 sc->sc_ncylinders = INT_MAX; 147 ncyl = sc->sc_secperunit / 148 (sc->sc_nheads * sc->sc_nsectors); 149 if (ncyl < INT_MAX) 150 sc->sc_ncylinders = (int)ncyl; 151 } 152 153 format_bytes(tbuf, sizeof(tbuf), sc->sc_secperunit * 154 sc->sc_secsize); 155 aprint_normal_dev(sc->sc_dv, "%s, %d cyl, %d head, %d sec, " 156 "%d bytes/sect x %"PRIu64" sectors\n", 157 tbuf, sc->sc_ncylinders, sc->sc_nheads, 158 sc->sc_nsectors, sc->sc_secsize, sc->sc_secperunit); 159 sc->sc_disksize512 = sc->sc_secperunit * sc->sc_secsize / DEV_BSIZE; 160 161 ld_set_geometry(sc); 162 163 /* Attach the device into the rnd source list. */ 164 rnd_attach_source(&sc->sc_rnd_source, device_xname(sc->sc_dv), 165 RND_TYPE_DISK, 0); 166 167 /* Register with PMF */ 168 if (!pmf_device_register1(sc->sc_dv, ld_suspend, NULL, ld_shutdown)) 169 aprint_error_dev(sc->sc_dv, 170 "couldn't establish power handler\n"); 171 172 bufq_alloc(&sc->sc_bufq, BUFQ_DISK_DEFAULT_STRAT, BUFQ_SORT_RAWBLOCK); 173 174 /* Discover wedges on this disk. */ 175 config_interrupts(sc->sc_dv, ld_config_interrupts); 176 } 177 178 int 179 ldadjqparam(struct ld_softc *sc, int xmax) 180 { 181 int s; 182 183 s = splbio(); 184 sc->sc_maxqueuecnt = xmax; 185 splx(s); 186 187 return (0); 188 } 189 190 int 191 ldbegindetach(struct ld_softc *sc, int flags) 192 { 193 int s, rv = 0; 194 195 if ((sc->sc_flags & LDF_ENABLED) == 0) 196 return (0); 197 198 rv = disk_begindetach(&sc->sc_dk, ldlastclose, sc->sc_dv, flags); 199 200 if (rv != 0) 201 return rv; 202 203 s = splbio(); 204 sc->sc_maxqueuecnt = 0; 205 sc->sc_flags |= LDF_DETACH; 206 while (sc->sc_queuecnt > 0) { 207 sc->sc_flags |= LDF_DRAIN; 208 rv = tsleep(&sc->sc_queuecnt, PRIBIO, "lddrn", 0); 209 if (rv) 210 break; 211 } 212 splx(s); 213 214 return (rv); 215 } 216 217 void 218 ldenddetach(struct ld_softc *sc) 219 { 220 int s, bmaj, cmaj, i, mn; 221 222 if ((sc->sc_flags & LDF_ENABLED) == 0) 223 return; 224 225 /* Wait for commands queued with the hardware to complete. */ 226 if (sc->sc_queuecnt != 0) 227 if (tsleep(&sc->sc_queuecnt, PRIBIO, "lddtch", 30 * hz)) 228 printf("%s: not drained\n", device_xname(sc->sc_dv)); 229 230 /* Locate the major numbers. */ 231 bmaj = bdevsw_lookup_major(&ld_bdevsw); 232 cmaj = cdevsw_lookup_major(&ld_cdevsw); 233 234 /* Kill off any queued buffers. */ 235 s = splbio(); 236 bufq_drain(sc->sc_bufq); 237 splx(s); 238 239 bufq_free(sc->sc_bufq); 240 241 /* Nuke the vnodes for any open instances. */ 242 for (i = 0; i < MAXPARTITIONS; i++) { 243 mn = DISKMINOR(device_unit(sc->sc_dv), i); 244 vdevgone(bmaj, mn, mn, VBLK); 245 vdevgone(cmaj, mn, mn, VCHR); 246 } 247 248 /* Delete all of our wedges. */ 249 dkwedge_delall(&sc->sc_dk); 250 251 /* Detach from the disk list. */ 252 disk_detach(&sc->sc_dk); 253 disk_destroy(&sc->sc_dk); 254 255 /* Unhook the entropy source. */ 256 rnd_detach_source(&sc->sc_rnd_source); 257 258 /* Deregister with PMF */ 259 pmf_device_deregister(sc->sc_dv); 260 261 /* 262 * XXX We can't really flush the cache here, beceause the 263 * XXX device may already be non-existent from the controller's 264 * XXX perspective. 265 */ 266 #if 0 267 /* Flush the device's cache. */ 268 if (sc->sc_flush != NULL) 269 if ((*sc->sc_flush)(sc, 0) != 0) 270 aprint_error_dev(sc->sc_dv, "unable to flush cache\n"); 271 #endif 272 mutex_destroy(&sc->sc_mutex); 273 } 274 275 /* ARGSUSED */ 276 static bool 277 ld_suspend(device_t dev, const pmf_qual_t *qual) 278 { 279 return ld_shutdown(dev, 0); 280 } 281 282 /* ARGSUSED */ 283 static bool 284 ld_shutdown(device_t dev, int flags) 285 { 286 struct ld_softc *sc = device_private(dev); 287 288 if (sc->sc_flush != NULL && (*sc->sc_flush)(sc, LDFL_POLL) != 0) { 289 printf("%s: unable to flush cache\n", device_xname(dev)); 290 return false; 291 } 292 293 return true; 294 } 295 296 /* ARGSUSED */ 297 static int 298 ldopen(dev_t dev, int flags, int fmt, struct lwp *l) 299 { 300 struct ld_softc *sc; 301 int error, unit, part; 302 303 unit = DISKUNIT(dev); 304 if ((sc = device_lookup_private(&ld_cd, unit)) == NULL) 305 return (ENXIO); 306 if ((sc->sc_flags & LDF_ENABLED) == 0) 307 return (ENODEV); 308 part = DISKPART(dev); 309 310 mutex_enter(&sc->sc_dk.dk_openlock); 311 312 if (sc->sc_dk.dk_openmask == 0) { 313 /* Load the partition info if not already loaded. */ 314 if ((sc->sc_flags & LDF_VLABEL) == 0) 315 ldgetdisklabel(sc); 316 } 317 318 /* Check that the partition exists. */ 319 if (part != RAW_PART && (part >= sc->sc_dk.dk_label->d_npartitions || 320 sc->sc_dk.dk_label->d_partitions[part].p_fstype == FS_UNUSED)) { 321 error = ENXIO; 322 goto bad1; 323 } 324 325 /* Ensure only one open at a time. */ 326 switch (fmt) { 327 case S_IFCHR: 328 sc->sc_dk.dk_copenmask |= (1 << part); 329 break; 330 case S_IFBLK: 331 sc->sc_dk.dk_bopenmask |= (1 << part); 332 break; 333 } 334 sc->sc_dk.dk_openmask = 335 sc->sc_dk.dk_copenmask | sc->sc_dk.dk_bopenmask; 336 337 error = 0; 338 bad1: 339 mutex_exit(&sc->sc_dk.dk_openlock); 340 return (error); 341 } 342 343 static int 344 ldlastclose(device_t self) 345 { 346 struct ld_softc *sc = device_private(self); 347 348 if (sc->sc_flush != NULL && (*sc->sc_flush)(sc, 0) != 0) 349 aprint_error_dev(self, "unable to flush cache\n"); 350 if ((sc->sc_flags & LDF_KLABEL) == 0) 351 sc->sc_flags &= ~LDF_VLABEL; 352 353 return 0; 354 } 355 356 /* ARGSUSED */ 357 static int 358 ldclose(dev_t dev, int flags, int fmt, struct lwp *l) 359 { 360 struct ld_softc *sc; 361 int part, unit; 362 363 unit = DISKUNIT(dev); 364 part = DISKPART(dev); 365 sc = device_lookup_private(&ld_cd, unit); 366 367 mutex_enter(&sc->sc_dk.dk_openlock); 368 369 switch (fmt) { 370 case S_IFCHR: 371 sc->sc_dk.dk_copenmask &= ~(1 << part); 372 break; 373 case S_IFBLK: 374 sc->sc_dk.dk_bopenmask &= ~(1 << part); 375 break; 376 } 377 sc->sc_dk.dk_openmask = 378 sc->sc_dk.dk_copenmask | sc->sc_dk.dk_bopenmask; 379 380 if (sc->sc_dk.dk_openmask == 0) 381 ldlastclose(sc->sc_dv); 382 383 mutex_exit(&sc->sc_dk.dk_openlock); 384 return (0); 385 } 386 387 /* ARGSUSED */ 388 static int 389 ldread(dev_t dev, struct uio *uio, int ioflag) 390 { 391 392 return (physio(ldstrategy, NULL, dev, B_READ, ldminphys, uio)); 393 } 394 395 /* ARGSUSED */ 396 static int 397 ldwrite(dev_t dev, struct uio *uio, int ioflag) 398 { 399 400 return (physio(ldstrategy, NULL, dev, B_WRITE, ldminphys, uio)); 401 } 402 403 /* ARGSUSED */ 404 static int 405 ldioctl(dev_t dev, u_long cmd, void *addr, int32_t flag, struct lwp *l) 406 { 407 struct ld_softc *sc; 408 int part, unit, error; 409 #ifdef __HAVE_OLD_DISKLABEL 410 struct disklabel newlabel; 411 #endif 412 struct disklabel *lp; 413 414 unit = DISKUNIT(dev); 415 part = DISKPART(dev); 416 sc = device_lookup_private(&ld_cd, unit); 417 418 error = disk_ioctl(&sc->sc_dk, cmd, addr, flag, l); 419 if (error != EPASSTHROUGH) 420 return (error); 421 422 error = 0; 423 switch (cmd) { 424 case DIOCGDINFO: 425 memcpy(addr, sc->sc_dk.dk_label, sizeof(struct disklabel)); 426 return (0); 427 428 #ifdef __HAVE_OLD_DISKLABEL 429 case ODIOCGDINFO: 430 newlabel = *(sc->sc_dk.dk_label); 431 if (newlabel.d_npartitions > OLDMAXPARTITIONS) 432 return ENOTTY; 433 memcpy(addr, &newlabel, sizeof(struct olddisklabel)); 434 return (0); 435 #endif 436 437 case DIOCGPART: 438 ((struct partinfo *)addr)->disklab = sc->sc_dk.dk_label; 439 ((struct partinfo *)addr)->part = 440 &sc->sc_dk.dk_label->d_partitions[part]; 441 break; 442 443 case DIOCWDINFO: 444 case DIOCSDINFO: 445 #ifdef __HAVE_OLD_DISKLABEL 446 case ODIOCWDINFO: 447 case ODIOCSDINFO: 448 449 if (cmd == ODIOCSDINFO || cmd == ODIOCWDINFO) { 450 memset(&newlabel, 0, sizeof newlabel); 451 memcpy(&newlabel, addr, sizeof (struct olddisklabel)); 452 lp = &newlabel; 453 } else 454 #endif 455 lp = (struct disklabel *)addr; 456 457 if ((flag & FWRITE) == 0) 458 return (EBADF); 459 460 mutex_enter(&sc->sc_dk.dk_openlock); 461 sc->sc_flags |= LDF_LABELLING; 462 463 error = setdisklabel(sc->sc_dk.dk_label, 464 lp, /*sc->sc_dk.dk_openmask : */0, 465 sc->sc_dk.dk_cpulabel); 466 if (error == 0 && (cmd == DIOCWDINFO 467 #ifdef __HAVE_OLD_DISKLABEL 468 || cmd == ODIOCWDINFO 469 #endif 470 )) 471 error = writedisklabel( 472 MAKEDISKDEV(major(dev), DISKUNIT(dev), RAW_PART), 473 ldstrategy, sc->sc_dk.dk_label, 474 sc->sc_dk.dk_cpulabel); 475 476 sc->sc_flags &= ~LDF_LABELLING; 477 mutex_exit(&sc->sc_dk.dk_openlock); 478 break; 479 480 case DIOCKLABEL: 481 if ((flag & FWRITE) == 0) 482 return (EBADF); 483 if (*(int *)addr) 484 sc->sc_flags |= LDF_KLABEL; 485 else 486 sc->sc_flags &= ~LDF_KLABEL; 487 break; 488 489 case DIOCWLABEL: 490 if ((flag & FWRITE) == 0) 491 return (EBADF); 492 if (*(int *)addr) 493 sc->sc_flags |= LDF_WLABEL; 494 else 495 sc->sc_flags &= ~LDF_WLABEL; 496 break; 497 498 case DIOCGDEFLABEL: 499 ldgetdefaultlabel(sc, (struct disklabel *)addr); 500 break; 501 502 #ifdef __HAVE_OLD_DISKLABEL 503 case ODIOCGDEFLABEL: 504 ldgetdefaultlabel(sc, &newlabel); 505 if (newlabel.d_npartitions > OLDMAXPARTITIONS) 506 return ENOTTY; 507 memcpy(addr, &newlabel, sizeof (struct olddisklabel)); 508 break; 509 #endif 510 511 case DIOCCACHESYNC: 512 /* 513 * XXX Do we really need to care about having a writable 514 * file descriptor here? 515 */ 516 if ((flag & FWRITE) == 0) 517 error = EBADF; 518 else if (sc->sc_flush) 519 error = (*sc->sc_flush)(sc, 0); 520 else 521 error = 0; /* XXX Error out instead? */ 522 break; 523 524 case DIOCAWEDGE: 525 { 526 struct dkwedge_info *dkw = (void *) addr; 527 528 if ((flag & FWRITE) == 0) 529 return (EBADF); 530 531 /* If the ioctl happens here, the parent is us. */ 532 strlcpy(dkw->dkw_parent, device_xname(sc->sc_dv), 533 sizeof(dkw->dkw_parent)); 534 return (dkwedge_add(dkw)); 535 } 536 537 case DIOCDWEDGE: 538 { 539 struct dkwedge_info *dkw = (void *) addr; 540 541 if ((flag & FWRITE) == 0) 542 return (EBADF); 543 544 /* If the ioctl happens here, the parent is us. */ 545 strlcpy(dkw->dkw_parent, device_xname(sc->sc_dv), 546 sizeof(dkw->dkw_parent)); 547 return (dkwedge_del(dkw)); 548 } 549 550 case DIOCLWEDGES: 551 { 552 struct dkwedge_list *dkwl = (void *) addr; 553 554 return (dkwedge_list(&sc->sc_dk, dkwl, l)); 555 } 556 case DIOCGSTRATEGY: 557 { 558 struct disk_strategy *dks = (void *)addr; 559 560 mutex_enter(&sc->sc_mutex); 561 strlcpy(dks->dks_name, bufq_getstrategyname(sc->sc_bufq), 562 sizeof(dks->dks_name)); 563 mutex_exit(&sc->sc_mutex); 564 dks->dks_paramlen = 0; 565 566 return 0; 567 } 568 case DIOCSSTRATEGY: 569 { 570 struct disk_strategy *dks = (void *)addr; 571 struct bufq_state *new, *old; 572 573 if ((flag & FWRITE) == 0) 574 return EPERM; 575 576 if (dks->dks_param != NULL) 577 return EINVAL; 578 579 dks->dks_name[sizeof(dks->dks_name) - 1] = 0; /* ensure term */ 580 error = bufq_alloc(&new, dks->dks_name, 581 BUFQ_EXACT|BUFQ_SORT_RAWBLOCK); 582 if (error) 583 return error; 584 585 mutex_enter(&sc->sc_mutex); 586 old = sc->sc_bufq; 587 bufq_move(new, old); 588 sc->sc_bufq = new; 589 mutex_exit(&sc->sc_mutex); 590 bufq_free(old); 591 592 return 0; 593 } 594 default: 595 error = ENOTTY; 596 break; 597 } 598 599 return (error); 600 } 601 602 static void 603 ldstrategy(struct buf *bp) 604 { 605 struct ld_softc *sc; 606 struct disklabel *lp; 607 daddr_t blkno; 608 int s, part; 609 610 sc = device_lookup_private(&ld_cd, DISKUNIT(bp->b_dev)); 611 part = DISKPART(bp->b_dev); 612 613 if ((sc->sc_flags & LDF_DETACH) != 0) { 614 bp->b_error = EIO; 615 goto done; 616 } 617 618 lp = sc->sc_dk.dk_label; 619 620 /* 621 * The transfer must be a whole number of blocks and the offset must 622 * not be negative. 623 */ 624 if ((bp->b_bcount % lp->d_secsize) != 0 || bp->b_blkno < 0) { 625 bp->b_error = EINVAL; 626 goto done; 627 } 628 629 /* If it's a null transfer, return immediately. */ 630 if (bp->b_bcount == 0) 631 goto done; 632 633 /* 634 * Do bounds checking and adjust the transfer. If error, process. 635 * If past the end of partition, just return. 636 */ 637 if (part == RAW_PART) { 638 if (bounds_check_with_mediasize(bp, DEV_BSIZE, 639 sc->sc_disksize512) <= 0) 640 goto done; 641 } else { 642 if (bounds_check_with_label(&sc->sc_dk, bp, 643 (sc->sc_flags & (LDF_WLABEL | LDF_LABELLING)) != 0) <= 0) 644 goto done; 645 } 646 647 /* 648 * Convert the block number to absolute and put it in terms 649 * of the device's logical block size. 650 */ 651 if (lp->d_secsize == DEV_BSIZE) 652 blkno = bp->b_blkno; 653 else if (lp->d_secsize > DEV_BSIZE) 654 blkno = bp->b_blkno / (lp->d_secsize / DEV_BSIZE); 655 else 656 blkno = bp->b_blkno * (DEV_BSIZE / lp->d_secsize); 657 658 if (part != RAW_PART) 659 blkno += lp->d_partitions[part].p_offset; 660 661 bp->b_rawblkno = blkno; 662 663 s = splbio(); 664 ldstart(sc, bp); 665 splx(s); 666 return; 667 668 done: 669 bp->b_resid = bp->b_bcount; 670 biodone(bp); 671 } 672 673 static void 674 ldstart(struct ld_softc *sc, struct buf *bp) 675 { 676 int error; 677 678 mutex_enter(&sc->sc_mutex); 679 680 if (bp != NULL) 681 bufq_put(sc->sc_bufq, bp); 682 683 while (sc->sc_queuecnt < sc->sc_maxqueuecnt) { 684 /* See if there is work to do. */ 685 if ((bp = bufq_peek(sc->sc_bufq)) == NULL) 686 break; 687 688 disk_busy(&sc->sc_dk); 689 sc->sc_queuecnt++; 690 691 if (__predict_true((error = (*sc->sc_start)(sc, bp)) == 0)) { 692 /* 693 * The back-end is running the job; remove it from 694 * the queue. 695 */ 696 (void) bufq_get(sc->sc_bufq); 697 } else { 698 disk_unbusy(&sc->sc_dk, 0, (bp->b_flags & B_READ)); 699 sc->sc_queuecnt--; 700 if (error == EAGAIN) { 701 /* 702 * Temporary resource shortage in the 703 * back-end; just defer the job until 704 * later. 705 * 706 * XXX We might consider a watchdog timer 707 * XXX to make sure we are kicked into action. 708 */ 709 break; 710 } else { 711 (void) bufq_get(sc->sc_bufq); 712 bp->b_error = error; 713 bp->b_resid = bp->b_bcount; 714 mutex_exit(&sc->sc_mutex); 715 biodone(bp); 716 mutex_enter(&sc->sc_mutex); 717 } 718 } 719 } 720 721 mutex_exit(&sc->sc_mutex); 722 } 723 724 void 725 lddone(struct ld_softc *sc, struct buf *bp) 726 { 727 728 if (bp->b_error != 0) { 729 diskerr(bp, "ld", "error", LOG_PRINTF, 0, sc->sc_dk.dk_label); 730 printf("\n"); 731 } 732 733 disk_unbusy(&sc->sc_dk, bp->b_bcount - bp->b_resid, 734 (bp->b_flags & B_READ)); 735 rnd_add_uint32(&sc->sc_rnd_source, bp->b_rawblkno); 736 biodone(bp); 737 738 mutex_enter(&sc->sc_mutex); 739 if (--sc->sc_queuecnt <= sc->sc_maxqueuecnt) { 740 if ((sc->sc_flags & LDF_DRAIN) != 0) { 741 sc->sc_flags &= ~LDF_DRAIN; 742 wakeup(&sc->sc_queuecnt); 743 } 744 mutex_exit(&sc->sc_mutex); 745 ldstart(sc, NULL); 746 } else 747 mutex_exit(&sc->sc_mutex); 748 } 749 750 static int 751 ldsize(dev_t dev) 752 { 753 struct ld_softc *sc; 754 int part, unit, omask, size; 755 756 unit = DISKUNIT(dev); 757 if ((sc = device_lookup_private(&ld_cd, unit)) == NULL) 758 return (ENODEV); 759 if ((sc->sc_flags & LDF_ENABLED) == 0) 760 return (ENODEV); 761 part = DISKPART(dev); 762 763 omask = sc->sc_dk.dk_openmask & (1 << part); 764 765 if (omask == 0 && ldopen(dev, 0, S_IFBLK, NULL) != 0) 766 return (-1); 767 else if (sc->sc_dk.dk_label->d_partitions[part].p_fstype != FS_SWAP) 768 size = -1; 769 else 770 size = sc->sc_dk.dk_label->d_partitions[part].p_size * 771 (sc->sc_dk.dk_label->d_secsize / DEV_BSIZE); 772 if (omask == 0 && ldclose(dev, 0, S_IFBLK, NULL) != 0) 773 return (-1); 774 775 return (size); 776 } 777 778 /* 779 * Load the label information from the specified device. 780 */ 781 static void 782 ldgetdisklabel(struct ld_softc *sc) 783 { 784 const char *errstring; 785 786 ldgetdefaultlabel(sc, sc->sc_dk.dk_label); 787 788 /* Call the generic disklabel extraction routine. */ 789 errstring = readdisklabel(MAKEDISKDEV(0, device_unit(sc->sc_dv), 790 RAW_PART), ldstrategy, sc->sc_dk.dk_label, sc->sc_dk.dk_cpulabel); 791 if (errstring != NULL) 792 printf("%s: %s\n", device_xname(sc->sc_dv), errstring); 793 794 /* In-core label now valid. */ 795 sc->sc_flags |= LDF_VLABEL; 796 } 797 798 /* 799 * Construct a ficticious label. 800 */ 801 static void 802 ldgetdefaultlabel(struct ld_softc *sc, struct disklabel *lp) 803 { 804 805 memset(lp, 0, sizeof(struct disklabel)); 806 807 lp->d_secsize = sc->sc_secsize; 808 lp->d_ntracks = sc->sc_nheads; 809 lp->d_nsectors = sc->sc_nsectors; 810 lp->d_ncylinders = sc->sc_ncylinders; 811 lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors; 812 lp->d_type = DTYPE_LD; 813 strlcpy(lp->d_typename, "unknown", sizeof(lp->d_typename)); 814 strlcpy(lp->d_packname, "fictitious", sizeof(lp->d_packname)); 815 lp->d_secperunit = sc->sc_secperunit; 816 lp->d_rpm = 7200; 817 lp->d_interleave = 1; 818 lp->d_flags = 0; 819 820 lp->d_partitions[RAW_PART].p_offset = 0; 821 lp->d_partitions[RAW_PART].p_size = 822 lp->d_secperunit * (lp->d_secsize / DEV_BSIZE); 823 lp->d_partitions[RAW_PART].p_fstype = FS_UNUSED; 824 lp->d_npartitions = RAW_PART + 1; 825 826 lp->d_magic = DISKMAGIC; 827 lp->d_magic2 = DISKMAGIC; 828 lp->d_checksum = dkcksum(lp); 829 } 830 831 /* 832 * Take a dump. 833 */ 834 static int 835 lddump(dev_t dev, daddr_t blkno, void *vav, size_t size) 836 { 837 char *va = vav; 838 struct ld_softc *sc; 839 struct disklabel *lp; 840 int unit, part, nsects, sectoff, towrt, nblk, maxblkcnt, rv; 841 static int dumping; 842 843 unit = DISKUNIT(dev); 844 if ((sc = device_lookup_private(&ld_cd, unit)) == NULL) 845 return (ENXIO); 846 if ((sc->sc_flags & LDF_ENABLED) == 0) 847 return (ENODEV); 848 if (sc->sc_dump == NULL) 849 return (ENXIO); 850 851 /* Check if recursive dump; if so, punt. */ 852 if (dumping) 853 return (EFAULT); 854 dumping = 1; 855 856 /* Convert to disk sectors. Request must be a multiple of size. */ 857 part = DISKPART(dev); 858 lp = sc->sc_dk.dk_label; 859 if ((size % lp->d_secsize) != 0) 860 return (EFAULT); 861 towrt = size / lp->d_secsize; 862 blkno = dbtob(blkno) / lp->d_secsize; /* blkno in DEV_BSIZE units */ 863 864 nsects = lp->d_partitions[part].p_size; 865 sectoff = lp->d_partitions[part].p_offset; 866 867 /* Check transfer bounds against partition size. */ 868 if ((blkno < 0) || ((blkno + towrt) > nsects)) 869 return (EINVAL); 870 871 /* Offset block number to start of partition. */ 872 blkno += sectoff; 873 874 /* Start dumping and return when done. */ 875 maxblkcnt = sc->sc_maxxfer / sc->sc_secsize - 1; 876 while (towrt > 0) { 877 nblk = min(maxblkcnt, towrt); 878 879 if ((rv = (*sc->sc_dump)(sc, va, blkno, nblk)) != 0) 880 return (rv); 881 882 towrt -= nblk; 883 blkno += nblk; 884 va += nblk * sc->sc_secsize; 885 } 886 887 dumping = 0; 888 return (0); 889 } 890 891 /* 892 * Adjust the size of a transfer. 893 */ 894 static void 895 ldminphys(struct buf *bp) 896 { 897 struct ld_softc *sc; 898 899 sc = device_lookup_private(&ld_cd, DISKUNIT(bp->b_dev)); 900 901 if (bp->b_bcount > sc->sc_maxxfer) 902 bp->b_bcount = sc->sc_maxxfer; 903 minphys(bp); 904 } 905 906 static void 907 ld_set_geometry(struct ld_softc *ld) 908 { 909 struct disk_geom *dg = &ld->sc_dk.dk_geom; 910 911 memset(dg, 0, sizeof(*dg)); 912 913 dg->dg_secperunit = ld->sc_secperunit; 914 dg->dg_secsize = ld->sc_secsize; 915 dg->dg_nsectors = ld->sc_nsectors; 916 dg->dg_ntracks = ld->sc_nheads; 917 dg->dg_ncylinders = ld->sc_ncylinders; 918 919 disk_set_info(ld->sc_dv, &ld->sc_dk, NULL); 920 } 921 922 static void 923 ld_config_interrupts(device_t d) 924 { 925 struct ld_softc *sc = device_private(d); 926 dkwedge_discover(&sc->sc_dk); 927 } 928