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