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