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