1 /* 2 * ---------------------------------------------------------------------------- 3 * "THE BEER-WARE LICENSE" (Revision 42): 4 * <phk@FreeBSD.ORG> wrote this file. As long as you retain this notice you 5 * can do whatever you want with this stuff. If we meet some day, and you think 6 * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp 7 * ---------------------------------------------------------------------------- 8 * 9 * Copyright (c) 1982, 1986, 1988, 1993 10 * The Regents of the University of California. All rights reserved. 11 * (c) UNIX System Laboratories, Inc. 12 * All or some portions of this file are derived from material licensed 13 * to the University of California by American Telephone and Telegraph 14 * Co. or Unix System Laboratories, Inc. and are reproduced herein with 15 * the permission of UNIX System Laboratories, Inc. 16 * 17 * Redistribution and use in source and binary forms, with or without 18 * modification, are permitted provided that the following conditions 19 * are met: 20 * 1. Redistributions of source code must retain the above copyright 21 * notice, this list of conditions and the following disclaimer. 22 * 2. Redistributions in binary form must reproduce the above copyright 23 * notice, this list of conditions and the following disclaimer in the 24 * documentation and/or other materials provided with the distribution. 25 * 3. All advertising materials mentioning features or use of this software 26 * must display the following acknowledgement: 27 * This product includes software developed by the University of 28 * California, Berkeley and its contributors. 29 * 4. Neither the name of the University nor the names of its contributors 30 * may be used to endorse or promote products derived from this software 31 * without specific prior written permission. 32 * 33 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 34 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 35 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 36 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 37 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 38 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 39 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 40 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 41 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 42 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 43 * SUCH DAMAGE. 44 * 45 * @(#)ufs_disksubr.c 8.5 (Berkeley) 1/21/94 46 * $FreeBSD: src/sys/kern/subr_disk.c,v 1.20.2.6 2001/10/05 07:14:57 peter Exp $ 47 * $FreeBSD: src/sys/ufs/ufs/ufs_disksubr.c,v 1.44.2.3 2001/03/05 05:42:19 obrien Exp $ 48 * $DragonFly: src/sys/kern/subr_disk.c,v 1.8 2004/02/18 06:59:15 dillon Exp $ 49 */ 50 51 #include <sys/param.h> 52 #include <sys/systm.h> 53 #include <sys/kernel.h> 54 #include <sys/proc.h> 55 #include <sys/sysctl.h> 56 #include <sys/buf.h> 57 #include <sys/conf.h> 58 #include <sys/disklabel.h> 59 #include <sys/diskslice.h> 60 #include <sys/disk.h> 61 #include <sys/malloc.h> 62 #include <sys/sysctl.h> 63 #include <machine/md_var.h> 64 #include <sys/ctype.h> 65 #include <sys/syslog.h> 66 #include <sys/device.h> 67 #include <sys/msgport.h> 68 #include <sys/msgport2.h> 69 #include <sys/buf2.h> 70 71 static MALLOC_DEFINE(M_DISK, "disk", "disk data"); 72 73 static d_strategy_t diskstrategy; 74 static d_open_t diskopen; 75 static d_close_t diskclose; 76 static d_ioctl_t diskioctl; 77 static d_psize_t diskpsize; 78 static int disk_putport(lwkt_port_t port, lwkt_msg_t msg); 79 80 static LIST_HEAD(, disk) disklist = LIST_HEAD_INITIALIZER(&disklist); 81 82 static void 83 inherit_raw(dev_t pdev, dev_t dev) 84 { 85 dev->si_disk = pdev->si_disk; 86 dev->si_drv1 = pdev->si_drv1; 87 dev->si_drv2 = pdev->si_drv2; 88 dev->si_iosize_max = pdev->si_iosize_max; 89 dev->si_bsize_phys = pdev->si_bsize_phys; 90 dev->si_bsize_best = pdev->si_bsize_best; 91 } 92 93 /* 94 * Create a slice and unit managed disk. The underlying raw disk device 95 * is specified by cdevsw. We create the device as a managed device by 96 * first creating it normally then overriding the message port with our 97 * own frontend (which will be responsible for assigning pblkno). 98 */ 99 dev_t 100 disk_create(int unit, struct disk *dp, int flags, struct cdevsw *cdevsw) 101 { 102 dev_t dev; 103 104 bzero(dp, sizeof(*dp)); 105 lwkt_initport(&dp->d_port, NULL); /* intercept port */ 106 dp->d_port.mp_putport = disk_putport; 107 108 dev = makedev(cdevsw->d_maj, 0); /* base device */ 109 dev->si_disk = dp; 110 /* forwarding port */ 111 dp->d_fwdport = cdevsw_add_override(cdevsw, &dp->d_port); 112 113 if (bootverbose) 114 printf("Creating DISK %s%d\n", cdevsw->d_name, unit); 115 116 /* 117 * The whole disk placemarker holds the disk structure. 118 */ 119 dev = make_dev(cdevsw, dkmakeminor(unit, WHOLE_DISK_SLICE, RAW_PART), 120 UID_ROOT, GID_OPERATOR, 0640, "%s%d", cdevsw->d_name, unit); 121 dev->si_disk = dp; 122 dp->d_dev = dev; 123 dp->d_dsflags = flags; 124 LIST_INSERT_HEAD(&disklist, dp, d_list); 125 return (dev); 126 } 127 128 void 129 disk_destroy(struct disk *disk) 130 { 131 dev_t dev = disk->d_dev; 132 133 LIST_REMOVE(disk, d_list); 134 bzero(disk, sizeof(*disk)); 135 dev->si_disk = NULL; 136 destroy_dev(dev); 137 /* YYY remove cdevsw entries? */ 138 return; 139 } 140 141 int 142 disk_dumpcheck(dev_t dev, u_int *count, u_int *blkno, u_int *secsize) 143 { 144 struct disk *dp; 145 struct disklabel *dl; 146 u_int boff; 147 148 dp = dev->si_disk; 149 if (!dp) 150 return (ENXIO); 151 if (!dp->d_slice) 152 return (ENXIO); 153 dl = dsgetlabel(dev, dp->d_slice); 154 if (!dl) 155 return (ENXIO); 156 *count = Maxmem * (PAGE_SIZE / dl->d_secsize); 157 if (dumplo <= LABELSECTOR || 158 (dumplo + *count > dl->d_partitions[dkpart(dev)].p_size)) 159 return (EINVAL); 160 boff = dl->d_partitions[dkpart(dev)].p_offset + 161 dp->d_slice->dss_slices[dkslice(dev)].ds_offset; 162 *blkno = boff + dumplo; 163 *secsize = dl->d_secsize; 164 return (0); 165 166 } 167 168 void 169 disk_invalidate (struct disk *disk) 170 { 171 if (disk->d_slice) 172 dsgone(&disk->d_slice); 173 } 174 175 struct disk * 176 disk_enumerate(struct disk *disk) 177 { 178 if (!disk) 179 return (LIST_FIRST(&disklist)); 180 else 181 return (LIST_NEXT(disk, d_list)); 182 } 183 184 static int 185 sysctl_disks(SYSCTL_HANDLER_ARGS) 186 { 187 struct disk *disk; 188 int error, first; 189 190 disk = NULL; 191 first = 1; 192 193 while ((disk = disk_enumerate(disk))) { 194 if (!first) { 195 error = SYSCTL_OUT(req, " ", 1); 196 if (error) 197 return error; 198 } else { 199 first = 0; 200 } 201 error = SYSCTL_OUT(req, disk->d_dev->si_name, strlen(disk->d_dev->si_name)); 202 if (error) 203 return error; 204 } 205 error = SYSCTL_OUT(req, "", 1); 206 return error; 207 } 208 209 SYSCTL_PROC(_kern, OID_AUTO, disks, CTLTYPE_STRING | CTLFLAG_RD, 0, NULL, 210 sysctl_disks, "A", "names of available disks"); 211 212 /* 213 * The port intercept functions 214 */ 215 static 216 int 217 disk_putport(lwkt_port_t port, lwkt_msg_t lmsg) 218 { 219 struct disk *disk = (struct disk *)port; 220 cdevallmsg_t msg = (cdevallmsg_t)lmsg; 221 int error; 222 223 switch(msg->am_lmsg.ms_cmd) { 224 case CDEV_CMD_OPEN: 225 error = diskopen( 226 msg->am_open.msg.dev, 227 msg->am_open.oflags, 228 msg->am_open.devtype, 229 msg->am_open.td); 230 break; 231 case CDEV_CMD_CLOSE: 232 error = diskclose( 233 msg->am_close.msg.dev, 234 msg->am_close.fflag, 235 msg->am_close.devtype, 236 msg->am_close.td); 237 break; 238 case CDEV_CMD_IOCTL: 239 error = diskioctl( 240 msg->am_ioctl.msg.dev, 241 msg->am_ioctl.cmd, 242 msg->am_ioctl.data, 243 msg->am_ioctl.fflag, 244 msg->am_ioctl.td); 245 break; 246 case CDEV_CMD_STRATEGY: 247 diskstrategy(msg->am_strategy.bp); 248 error = 0; 249 break; 250 case CDEV_CMD_PSIZE: 251 msg->am_psize.result = diskpsize(msg->am_psize.msg.dev); 252 error = 0; /* XXX */ 253 break; 254 default: 255 error = lwkt_forwardmsg(disk->d_fwdport, &msg->am_lmsg); 256 break; 257 } 258 return(error); 259 } 260 261 static int 262 diskopen(dev_t dev, int oflags, int devtype, struct thread *td) 263 { 264 dev_t pdev; 265 struct disk *dp; 266 int error; 267 268 error = 0; 269 pdev = dkmodpart(dkmodslice(dev, WHOLE_DISK_SLICE), RAW_PART); 270 271 dp = pdev->si_disk; 272 if (dp == NULL) 273 return (ENXIO); 274 275 while (dp->d_flags & DISKFLAG_LOCK) { 276 dp->d_flags |= DISKFLAG_WANTED; 277 error = tsleep(dp, PCATCH, "diskopen", hz); 278 if (error) 279 return (error); 280 } 281 dp->d_flags |= DISKFLAG_LOCK; 282 283 if (!dsisopen(dp->d_slice)) { 284 if (!pdev->si_iosize_max) 285 pdev->si_iosize_max = dev->si_iosize_max; 286 error = dev_port_dopen(dp->d_fwdport, pdev, oflags, devtype, td); 287 } 288 289 /* Inherit properties from the whole/raw dev_t */ 290 inherit_raw(pdev, dev); 291 292 if (error) 293 goto out; 294 295 error = dsopen(dev, devtype, dp->d_dsflags, &dp->d_slice, &dp->d_label); 296 297 if (!dsisopen(dp->d_slice)) 298 dev_port_dclose(dp->d_fwdport, pdev, oflags, devtype, td); 299 out: 300 dp->d_flags &= ~DISKFLAG_LOCK; 301 if (dp->d_flags & DISKFLAG_WANTED) { 302 dp->d_flags &= ~DISKFLAG_WANTED; 303 wakeup(dp); 304 } 305 306 return(error); 307 } 308 309 static int 310 diskclose(dev_t dev, int fflag, int devtype, struct thread *td) 311 { 312 struct disk *dp; 313 int error; 314 dev_t pdev; 315 316 error = 0; 317 pdev = dkmodpart(dkmodslice(dev, WHOLE_DISK_SLICE), RAW_PART); 318 dp = pdev->si_disk; 319 if (!dp) 320 return (ENXIO); 321 dsclose(dev, devtype, dp->d_slice); 322 if (!dsisopen(dp->d_slice)) 323 error = dev_port_dclose(dp->d_fwdport, pdev, fflag, devtype, td); 324 return (error); 325 } 326 327 static void 328 diskstrategy(struct buf *bp) 329 { 330 dev_t pdev; 331 struct disk *dp; 332 333 pdev = dkmodpart(dkmodslice(bp->b_dev, WHOLE_DISK_SLICE), RAW_PART); 334 dp = pdev->si_disk; 335 if (dp != bp->b_dev->si_disk) 336 inherit_raw(pdev, bp->b_dev); 337 338 if (!dp) { 339 bp->b_error = ENXIO; 340 bp->b_flags |= B_ERROR; 341 biodone(bp); 342 return; 343 } 344 345 if (dscheck(bp, dp->d_slice) <= 0) { 346 biodone(bp); 347 return; 348 } 349 dev_port_dstrategy(dp->d_fwdport, dp->d_dev, bp); 350 } 351 352 /* 353 * note: when forwarding the ioctl we use the original device rather then 354 * the whole disk slice. 355 */ 356 static int 357 diskioctl(dev_t dev, u_long cmd, caddr_t data, int fflag, struct thread *td) 358 { 359 struct disk *dp; 360 int error; 361 dev_t pdev; 362 363 pdev = dkmodpart(dkmodslice(dev, WHOLE_DISK_SLICE), RAW_PART); 364 dp = pdev->si_disk; 365 if (!dp) 366 return (ENXIO); 367 error = dsioctl(dev, cmd, data, fflag, &dp->d_slice); 368 if (error == ENOIOCTL) 369 error = dev_port_dioctl(dp->d_fwdport, dev, cmd, data, fflag, td); 370 return (error); 371 } 372 373 static int 374 diskpsize(dev_t dev) 375 { 376 struct disk *dp; 377 dev_t pdev; 378 379 pdev = dkmodpart(dkmodslice(dev, WHOLE_DISK_SLICE), RAW_PART); 380 dp = pdev->si_disk; 381 if (!dp) 382 return (-1); 383 if (dp != dev->si_disk) { 384 dev->si_drv1 = pdev->si_drv1; 385 dev->si_drv2 = pdev->si_drv2; 386 /* XXX: don't set bp->b_dev->si_disk (?) */ 387 } 388 return (dssize(dev, &dp->d_slice)); 389 } 390 391 SYSCTL_DECL(_debug_sizeof); 392 393 SYSCTL_INT(_debug_sizeof, OID_AUTO, disklabel, CTLFLAG_RD, 394 0, sizeof(struct disklabel), "sizeof(struct disklabel)"); 395 396 SYSCTL_INT(_debug_sizeof, OID_AUTO, diskslices, CTLFLAG_RD, 397 0, sizeof(struct diskslices), "sizeof(struct diskslices)"); 398 399 SYSCTL_INT(_debug_sizeof, OID_AUTO, disk, CTLFLAG_RD, 400 0, sizeof(struct disk), "sizeof(struct disk)"); 401 402 403 /* 404 * Seek sort for disks. 405 * 406 * The buf_queue keep two queues, sorted in ascending block order. The first 407 * queue holds those requests which are positioned after the current block 408 * (in the first request); the second, which starts at queue->switch_point, 409 * holds requests which came in after their block number was passed. Thus 410 * we implement a one way scan, retracting after reaching the end of the drive 411 * to the first request on the second queue, at which time it becomes the 412 * first queue. 413 * 414 * A one-way scan is natural because of the way UNIX read-ahead blocks are 415 * allocated. 416 */ 417 void 418 bufqdisksort(bufq, bp) 419 struct buf_queue_head *bufq; 420 struct buf *bp; 421 { 422 struct buf *bq; 423 struct buf *bn; 424 struct buf *be; 425 426 be = TAILQ_LAST(&bufq->queue, buf_queue); 427 /* 428 * If the queue is empty or we are an 429 * ordered transaction, then it's easy. 430 */ 431 if ((bq = bufq_first(bufq)) == NULL 432 || (bp->b_flags & B_ORDERED) != 0) { 433 bufq_insert_tail(bufq, bp); 434 return; 435 } else if (bufq->insert_point != NULL) { 436 437 /* 438 * A certain portion of the list is 439 * "locked" to preserve ordering, so 440 * we can only insert after the insert 441 * point. 442 */ 443 bq = bufq->insert_point; 444 } else { 445 446 /* 447 * If we lie before the last removed (currently active) 448 * request, and are not inserting ourselves into the 449 * "locked" portion of the list, then we must add ourselves 450 * to the second request list. 451 */ 452 if (bp->b_pblkno < bufq->last_pblkno) { 453 454 bq = bufq->switch_point; 455 /* 456 * If we are starting a new secondary list, 457 * then it's easy. 458 */ 459 if (bq == NULL) { 460 bufq->switch_point = bp; 461 bufq_insert_tail(bufq, bp); 462 return; 463 } 464 /* 465 * If we lie ahead of the current switch point, 466 * insert us before the switch point and move 467 * the switch point. 468 */ 469 if (bp->b_pblkno < bq->b_pblkno) { 470 bufq->switch_point = bp; 471 TAILQ_INSERT_BEFORE(bq, bp, b_act); 472 return; 473 } 474 } else { 475 if (bufq->switch_point != NULL) 476 be = TAILQ_PREV(bufq->switch_point, 477 buf_queue, b_act); 478 /* 479 * If we lie between last_pblkno and bq, 480 * insert before bq. 481 */ 482 if (bp->b_pblkno < bq->b_pblkno) { 483 TAILQ_INSERT_BEFORE(bq, bp, b_act); 484 return; 485 } 486 } 487 } 488 489 /* 490 * Request is at/after our current position in the list. 491 * Optimize for sequential I/O by seeing if we go at the tail. 492 */ 493 if (bp->b_pblkno > be->b_pblkno) { 494 TAILQ_INSERT_AFTER(&bufq->queue, be, bp, b_act); 495 return; 496 } 497 498 /* Otherwise, insertion sort */ 499 while ((bn = TAILQ_NEXT(bq, b_act)) != NULL) { 500 501 /* 502 * We want to go after the current request if it is the end 503 * of the first request list, or if the next request is a 504 * larger cylinder than our request. 505 */ 506 if (bn == bufq->switch_point 507 || bp->b_pblkno < bn->b_pblkno) 508 break; 509 bq = bn; 510 } 511 TAILQ_INSERT_AFTER(&bufq->queue, bq, bp, b_act); 512 } 513 514 515 /* 516 * Attempt to read a disk label from a device using the indicated strategy 517 * routine. The label must be partly set up before this: secpercyl, secsize 518 * and anything required in the strategy routine (e.g., dummy bounds for the 519 * partition containing the label) must be filled in before calling us. 520 * Returns NULL on success and an error string on failure. 521 */ 522 char * 523 readdisklabel(dev, lp) 524 dev_t dev; 525 struct disklabel *lp; 526 { 527 struct buf *bp; 528 struct disklabel *dlp; 529 char *msg = NULL; 530 531 bp = geteblk((int)lp->d_secsize); 532 bp->b_dev = dev; 533 bp->b_blkno = LABELSECTOR * ((int)lp->d_secsize/DEV_BSIZE); 534 bp->b_bcount = lp->d_secsize; 535 bp->b_flags &= ~B_INVAL; 536 bp->b_flags |= B_READ; 537 BUF_STRATEGY(bp, 1); 538 if (biowait(bp)) 539 msg = "I/O error"; 540 else for (dlp = (struct disklabel *)bp->b_data; 541 dlp <= (struct disklabel *)((char *)bp->b_data + 542 lp->d_secsize - sizeof(*dlp)); 543 dlp = (struct disklabel *)((char *)dlp + sizeof(long))) { 544 if (dlp->d_magic != DISKMAGIC || dlp->d_magic2 != DISKMAGIC) { 545 if (msg == NULL) 546 msg = "no disk label"; 547 } else if (dlp->d_npartitions > MAXPARTITIONS || 548 dkcksum(dlp) != 0) 549 msg = "disk label corrupted"; 550 else { 551 *lp = *dlp; 552 msg = NULL; 553 break; 554 } 555 } 556 bp->b_flags |= B_INVAL | B_AGE; 557 brelse(bp); 558 return (msg); 559 } 560 561 /* 562 * Check new disk label for sensibility before setting it. 563 */ 564 int 565 setdisklabel(olp, nlp, openmask) 566 struct disklabel *olp, *nlp; 567 u_long openmask; 568 { 569 int i; 570 struct partition *opp, *npp; 571 572 /* 573 * Check it is actually a disklabel we are looking at. 574 */ 575 if (nlp->d_magic != DISKMAGIC || nlp->d_magic2 != DISKMAGIC || 576 dkcksum(nlp) != 0) 577 return (EINVAL); 578 /* 579 * For each partition that we think is open, 580 */ 581 while ((i = ffs((long)openmask)) != 0) { 582 i--; 583 /* 584 * Check it is not changing.... 585 */ 586 openmask &= ~(1 << i); 587 if (nlp->d_npartitions <= i) 588 return (EBUSY); 589 opp = &olp->d_partitions[i]; 590 npp = &nlp->d_partitions[i]; 591 if (npp->p_offset != opp->p_offset || npp->p_size < opp->p_size) 592 return (EBUSY); 593 /* 594 * Copy internally-set partition information 595 * if new label doesn't include it. XXX 596 * (If we are using it then we had better stay the same type) 597 * This is possibly dubious, as someone else noted (XXX) 598 */ 599 if (npp->p_fstype == FS_UNUSED && opp->p_fstype != FS_UNUSED) { 600 npp->p_fstype = opp->p_fstype; 601 npp->p_fsize = opp->p_fsize; 602 npp->p_frag = opp->p_frag; 603 npp->p_cpg = opp->p_cpg; 604 } 605 } 606 nlp->d_checksum = 0; 607 nlp->d_checksum = dkcksum(nlp); 608 *olp = *nlp; 609 return (0); 610 } 611 612 /* 613 * Write disk label back to device after modification. 614 */ 615 int 616 writedisklabel(dev, lp) 617 dev_t dev; 618 struct disklabel *lp; 619 { 620 struct buf *bp; 621 struct disklabel *dlp; 622 int error = 0; 623 624 if (lp->d_partitions[RAW_PART].p_offset != 0) 625 return (EXDEV); /* not quite right */ 626 bp = geteblk((int)lp->d_secsize); 627 bp->b_dev = dkmodpart(dev, RAW_PART); 628 bp->b_blkno = LABELSECTOR * ((int)lp->d_secsize/DEV_BSIZE); 629 bp->b_bcount = lp->d_secsize; 630 #if 1 631 /* 632 * We read the label first to see if it's there, 633 * in which case we will put ours at the same offset into the block.. 634 * (I think this is stupid [Julian]) 635 * Note that you can't write a label out over a corrupted label! 636 * (also stupid.. how do you write the first one? by raw writes?) 637 */ 638 bp->b_flags &= ~B_INVAL; 639 bp->b_flags |= B_READ; 640 BUF_STRATEGY(bp, 1); 641 error = biowait(bp); 642 if (error) 643 goto done; 644 for (dlp = (struct disklabel *)bp->b_data; 645 dlp <= (struct disklabel *) 646 ((char *)bp->b_data + lp->d_secsize - sizeof(*dlp)); 647 dlp = (struct disklabel *)((char *)dlp + sizeof(long))) { 648 if (dlp->d_magic == DISKMAGIC && dlp->d_magic2 == DISKMAGIC && 649 dkcksum(dlp) == 0) { 650 *dlp = *lp; 651 bp->b_flags &= ~(B_DONE | B_READ); 652 bp->b_flags |= B_WRITE; 653 #ifdef __alpha__ 654 alpha_fix_srm_checksum(bp); 655 #endif 656 BUF_STRATEGY(bp, 1); 657 error = biowait(bp); 658 goto done; 659 } 660 } 661 error = ESRCH; 662 done: 663 #else 664 bzero(bp->b_data, lp->d_secsize); 665 dlp = (struct disklabel *)bp->b_data; 666 *dlp = *lp; 667 bp->b_flags &= ~B_INVAL; 668 bp->b_flags |= B_WRITE; 669 BUF_STRATEGY(bp, 1); 670 error = biowait(bp); 671 #endif 672 bp->b_flags |= B_INVAL | B_AGE; 673 brelse(bp); 674 return (error); 675 } 676 677 /* 678 * Disk error is the preface to plaintive error messages 679 * about failing disk transfers. It prints messages of the form 680 681 hp0g: hard error reading fsbn 12345 of 12344-12347 (hp0 bn %d cn %d tn %d sn %d) 682 683 * if the offset of the error in the transfer and a disk label 684 * are both available. blkdone should be -1 if the position of the error 685 * is unknown; the disklabel pointer may be null from drivers that have not 686 * been converted to use them. The message is printed with printf 687 * if pri is LOG_PRINTF, otherwise it uses log at the specified priority. 688 * The message should be completed (with at least a newline) with printf 689 * or addlog, respectively. There is no trailing space. 690 */ 691 void 692 diskerr(bp, what, pri, blkdone, lp) 693 struct buf *bp; 694 char *what; 695 int pri, blkdone; 696 struct disklabel *lp; 697 { 698 int unit = dkunit(bp->b_dev); 699 int slice = dkslice(bp->b_dev); 700 int part = dkpart(bp->b_dev); 701 char partname[2]; 702 char *sname; 703 daddr_t sn; 704 705 sname = dsname(bp->b_dev, unit, slice, part, partname); 706 printf("%s%s: %s %sing fsbn ", sname, partname, what, 707 bp->b_flags & B_READ ? "read" : "writ"); 708 sn = bp->b_blkno; 709 if (bp->b_bcount <= DEV_BSIZE) 710 printf("%ld", (long)sn); 711 else { 712 if (blkdone >= 0) { 713 sn += blkdone; 714 printf("%ld of ", (long)sn); 715 } 716 printf("%ld-%ld", (long)bp->b_blkno, 717 (long)(bp->b_blkno + (bp->b_bcount - 1) / DEV_BSIZE)); 718 } 719 if (lp && (blkdone >= 0 || bp->b_bcount <= lp->d_secsize)) { 720 #ifdef tahoe 721 sn *= DEV_BSIZE / lp->d_secsize; /* XXX */ 722 #endif 723 sn += lp->d_partitions[part].p_offset; 724 /* 725 * XXX should add slice offset and not print the slice, 726 * but we don't know the slice pointer. 727 * XXX should print bp->b_pblkno so that this will work 728 * independent of slices, labels and bad sector remapping, 729 * but some drivers don't set bp->b_pblkno. 730 */ 731 printf(" (%s bn %ld; cn %ld", sname, (long)sn, 732 (long)(sn / lp->d_secpercyl)); 733 sn %= (long)lp->d_secpercyl; 734 printf(" tn %ld sn %ld)", (long)(sn / lp->d_nsectors), 735 (long)(sn % lp->d_nsectors)); 736 } 737 } 738