1 /* $NetBSD: disksubr.c,v 1.41 2002/03/05 09:40:40 simonb Exp $ */ 2 3 /* 4 * Copyright (c) 1982, 1986, 1988 Regents of the University of California. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by the University of 18 * California, Berkeley and its contributors. 19 * 4. Neither the name of the University nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 * 35 * @(#)ufs_disksubr.c 7.16 (Berkeley) 5/4/91 36 */ 37 /*- 38 * Copyright (C) 1993 Allen K. Briggs, Chris P. Caputo, 39 * Michael L. Finch, Bradley A. Grantham, and 40 * Lawrence A. Kesteloot 41 * All rights reserved. 42 * 43 * Redistribution and use in source and binary forms, with or without 44 * modification, are permitted provided that the following conditions 45 * are met: 46 * 1. Redistributions of source code must retain the above copyright 47 * notice, this list of conditions and the following disclaimer. 48 * 2. Redistributions in binary form must reproduce the above copyright 49 * notice, this list of conditions and the following disclaimer in the 50 * documentation and/or other materials provided with the distribution. 51 * 3. All advertising materials mentioning features or use of this software 52 * must display the following acknowledgement: 53 * This product includes software developed by the Alice Group. 54 * 4. The names of the Alice Group or any of its members may not be used 55 * to endorse or promote products derived from this software without 56 * specific prior written permission. 57 * 58 * THIS SOFTWARE IS PROVIDED BY THE ALICE GROUP ``AS IS'' AND ANY EXPRESS OR 59 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 60 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 61 * IN NO EVENT SHALL THE ALICE GROUP BE LIABLE FOR ANY DIRECT, INDIRECT, 62 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 63 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 64 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 65 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 66 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 67 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 68 * 69 */ 70 71 #include <sys/param.h> 72 #include <sys/systm.h> 73 #include <sys/buf.h> 74 #include <sys/disk.h> 75 #include <sys/disklabel.h> 76 #include <sys/disklabel_mbr.h> 77 #include <sys/syslog.h> 78 79 #include <machine/bswap.h> 80 81 #define NUM_PARTS 32 82 83 #define ROOT_PART 1 84 #define UFS_PART 2 85 #define SWAP_PART 3 86 #define HFS_PART 4 87 #define SCRATCH_PART 5 88 89 int fat_types[] = { 90 MBR_PTYPE_FAT12, MBR_PTYPE_FAT16S, 91 MBR_PTYPE_FAT16B, MBR_PTYPE_FAT32, 92 MBR_PTYPE_FAT32L, MBR_PTYPE_FAT16L, 93 -1 94 }; 95 96 static int getFreeLabelEntry __P((struct disklabel *)); 97 static int whichType __P((struct part_map_entry *)); 98 static void setpartition __P((struct part_map_entry *, 99 struct partition *, int)); 100 static int getNamedType __P((struct part_map_entry *, int, 101 struct disklabel *, int, int, int *)); 102 static char *read_mac_label __P((char *, struct disklabel *, int *)); 103 static char *read_mbr_label __P((char *, struct disklabel *, int *)); 104 static char *read_bsd_label __P((char *, struct disklabel *, int *)); 105 106 107 /* 108 * Find an entry in the disk label that is unused and return it 109 * or -1 if no entry 110 */ 111 static int 112 getFreeLabelEntry(lp) 113 struct disklabel *lp; 114 { 115 int i; 116 117 for (i = 0; i < MAXPARTITIONS; i++) { 118 if ((i != RAW_PART) 119 && (lp->d_partitions[i].p_fstype == FS_UNUSED)) 120 return i; 121 } 122 return -1; 123 } 124 125 /* 126 * figure out what the type of the given part is and return it 127 */ 128 static int 129 whichType(part) 130 struct part_map_entry *part; 131 { 132 struct blockzeroblock *bzb; 133 char typestr[32], *s; 134 int type; 135 136 if (part->pmSig != PART_ENTRY_MAGIC || part->pmPartType[0] == '\0') 137 return 0; 138 139 strncpy(typestr, (char *)part->pmPartType, sizeof(typestr)); 140 typestr[sizeof(typestr) - 1] = '\0'; 141 for (s = typestr; *s; s++) 142 if ((*s >= 'a') && (*s <= 'z')) 143 *s = (*s - 'a' + 'A'); 144 145 if (strcmp(PART_TYPE_DRIVER, typestr) == 0 || 146 strcmp(PART_TYPE_DRIVER43, typestr) == 0 || 147 strcmp(PART_TYPE_DRIVERATA, typestr) == 0 || 148 strcmp(PART_TYPE_FWB_COMPONENT, typestr) == 0 || 149 strcmp(PART_TYPE_PARTMAP, typestr) == 0) 150 type = 0; 151 else if (strcmp(PART_TYPE_UNIX, typestr) == 0) { 152 /* unix part, swap, root, usr */ 153 bzb = (struct blockzeroblock *)(&part->pmBootArgs); 154 if (bzb->bzbMagic != BZB_MAGIC) 155 type = 0; 156 else if (bzb->bzbFlags & BZB_ROOTFS) 157 type = ROOT_PART; 158 else if (bzb->bzbFlags & BZB_USRFS) 159 type = UFS_PART; 160 else if (bzb->bzbType == BZB_TYPESWAP) 161 type = SWAP_PART; 162 else 163 type = SCRATCH_PART; 164 } else if (strcmp(PART_TYPE_MAC, typestr) == 0) 165 type = HFS_PART; 166 else 167 type = SCRATCH_PART; /* no known type */ 168 169 return type; 170 } 171 172 static void 173 setpartition(part, pp, fstype) 174 struct part_map_entry *part; 175 struct partition *pp; 176 int fstype; 177 { 178 pp->p_size = part->pmPartBlkCnt; 179 pp->p_offset = part->pmPyPartStart; 180 pp->p_fstype = fstype; 181 182 part->pmPartType[0] = '\0'; 183 } 184 185 static int 186 getNamedType(part, num_parts, lp, type, alt, maxslot) 187 struct part_map_entry *part; 188 int num_parts; 189 struct disklabel *lp; 190 int type, alt; 191 int *maxslot; 192 { 193 struct blockzeroblock *bzb; 194 int i; 195 196 for (i = 0; i < num_parts; i++) { 197 if (whichType(part + i) != type) 198 continue; 199 200 if (type == ROOT_PART) { 201 bzb = (struct blockzeroblock *) 202 (&(part + i)->pmBootArgs); 203 if (alt >= 0 && alt != bzb->bzbCluster) 204 continue; 205 setpartition(part + i, &lp->d_partitions[0], FS_BSDFFS); 206 } else if (type == UFS_PART) { 207 bzb = (struct blockzeroblock *) 208 (&(part + i)->pmBootArgs); 209 if (alt >= 0 && alt != bzb->bzbCluster) 210 continue; 211 setpartition(part + i, &lp->d_partitions[6], FS_BSDFFS); 212 if (*maxslot < 6) 213 *maxslot = 6; 214 } else if (type == SWAP_PART) { 215 setpartition(part + i, &lp->d_partitions[1], FS_SWAP); 216 if (*maxslot < 1) 217 *maxslot = 1; 218 } else 219 printf("disksubr.c: can't do type %d\n", type); 220 221 return 0; 222 } 223 224 return -1; 225 } 226 227 /* 228 * MF -- 229 * here's what i'm gonna do: 230 * read in the entire diskpartition table, it may be bigger or smaller 231 * than NUM_PARTS but read that many entries. Each entry has a magic 232 * number so we'll know if an entry is crap. 233 * next fill in the disklabel with info like this 234 * next fill in the root, usr, and swap parts. 235 * then look for anything else and fit it in. 236 * A: root 237 * B: Swap 238 * C: Whole disk 239 * G: Usr 240 * 241 * 242 * I'm not entirely sure what netbsd386 wants in c & d 243 * 386bsd wants other stuff, so i'll leave them alone 244 * 245 * AKB -- I added to Mike's original algorithm by searching for a bzbCluster 246 * of zero for root, first. This allows A/UX to live on cluster 1 and 247 * NetBSD to live on cluster 0--regardless of the actual order on the 248 * disk. This whole algorithm should probably be changed in the future. 249 */ 250 251 /* 252 * This uses sector zero. If this contains what looks like a valid 253 * Macintosh boot sector, we attempt to fill in the disklabel structure 254 * with the partition data from block #1 on. 255 */ 256 static char * 257 read_mac_label(dlbuf, lp, match) 258 char *dlbuf; 259 struct disklabel *lp; 260 int *match; 261 { 262 u_int16_t *sbSigp; 263 struct part_map_entry *part; 264 struct partition *pp; 265 char *msg; 266 int i, slot, maxslot; 267 268 maxslot = 0; 269 *match = 0; 270 msg = NULL; 271 272 sbSigp = (u_int16_t *)dlbuf; 273 if (*sbSigp != DRIVER_MAP_MAGIC) 274 return msg; 275 276 /* Found Macintosh partition magic number; set up disklabel */ 277 *match = (-1); 278 279 /* the Macintosh partition table starts at sector #1 */ 280 part = (struct part_map_entry *)(dlbuf + DEV_BSIZE); 281 282 /* Fill in standard partitions */ 283 lp->d_npartitions = RAW_PART + 1; 284 if (getNamedType(part, NUM_PARTS, lp, ROOT_PART, 0, &maxslot)) 285 getNamedType(part, NUM_PARTS, lp, ROOT_PART, -1, &maxslot); 286 if (getNamedType(part, NUM_PARTS, lp, UFS_PART, 0, &maxslot)) 287 getNamedType(part, NUM_PARTS, lp, UFS_PART, -1, &maxslot); 288 getNamedType(part, NUM_PARTS, lp, SWAP_PART, -1, &maxslot); 289 290 /* Now get as many of the rest of the partitions as we can */ 291 for (i = 0; i < NUM_PARTS; i++) { 292 slot = getFreeLabelEntry(lp); 293 if (slot < 0) 294 break; 295 296 pp = &lp->d_partitions[slot]; 297 298 switch (whichType(part + i)) { 299 case ROOT_PART: 300 /* 301 * another root part will turn into a plain old 302 * UFS_PART partition, live with it. 303 */ 304 case UFS_PART: 305 setpartition(part + i, pp, FS_BSDFFS); 306 break; 307 case SWAP_PART: 308 setpartition(part + i, pp, FS_SWAP); 309 break; 310 case HFS_PART: 311 setpartition(part + i, pp, FS_HFS); 312 break; 313 case SCRATCH_PART: 314 setpartition(part + i, pp, FS_OTHER); 315 break; 316 default: 317 slot = 0; 318 break; 319 } 320 if (slot > maxslot) 321 maxslot = slot; 322 } 323 lp->d_npartitions = ((maxslot >= RAW_PART) ? maxslot : RAW_PART) + 1; 324 return msg; 325 } 326 327 /* 328 * Scan the disk buffer for a DOS style master boot record. 329 * Return if no match; otherwise, set up an in-core disklabel . 330 * 331 * XXX stuff like this really should be MI 332 * 333 * Since FFS is endian sensitive, we pay no effort in attempting to 334 * dig up *BSD/i386 disk labels that may be present on the disk. 335 * Hence anything but DOS partitions is treated as unknown FS type, but 336 * this should suffice to mount_msdos Zip and other removable media. 337 */ 338 static char * 339 read_mbr_label(dlbuf, lp, match) 340 char *dlbuf; 341 struct disklabel *lp; 342 int *match; 343 { 344 struct mbr_partition *dp; 345 struct partition *pp; 346 char *msg; 347 size_t mbr_lbl_off; 348 int i, *ip, slot, maxslot; 349 350 maxslot = 0; 351 *match = 0; 352 msg = NULL; 353 354 if (MBR_MAGIC != bswap16(*(u_int16_t *)(dlbuf + MBR_MAGICOFF))) 355 return msg; 356 357 /* Found MBR magic number; set up disklabel */ 358 *match = (-1); 359 mbr_lbl_off = MBR_BBSECTOR * lp->d_secsize + MBR_PARTOFF; 360 361 dp = (struct mbr_partition *)(dlbuf + mbr_lbl_off); 362 for (i = 0; i < NMBRPART; i++, dp++) { 363 if (dp->mbrp_typ == 0) 364 continue; 365 366 slot = getFreeLabelEntry(lp); 367 maxslot = (slot > maxslot) ? maxslot : slot; 368 369 pp = &lp->d_partitions[slot]; 370 pp->p_fstype = FS_OTHER; 371 pp->p_offset = bswap32(dp->mbrp_start); 372 pp->p_size = bswap32(dp->mbrp_size); 373 374 for (ip = fat_types; *ip != -1; ip++) { 375 if (dp->mbrp_typ == *ip) { 376 pp->p_fstype = FS_MSDOS; 377 break; 378 } 379 } 380 } 381 lp->d_npartitions = ((maxslot >= RAW_PART) ? maxslot : RAW_PART) + 1; 382 return msg; 383 } 384 385 /* 386 * Scan the disk buffer in four byte steps for a native BSD disklabel 387 * (different ports have variable-sized bootcode before the label) 388 */ 389 static char * 390 read_bsd_label(dlbuf, lp, match) 391 char *dlbuf; 392 struct disklabel *lp; 393 int *match; 394 { 395 struct disklabel *dlp; 396 char *msg; 397 struct disklabel *blk_start, *blk_end; 398 399 *match = 0; 400 msg = NULL; 401 402 blk_start = (struct disklabel *)dlbuf; 403 blk_end = (struct disklabel *)(dlbuf + (NUM_PARTS << DEV_BSHIFT) - 404 sizeof(struct disklabel)); 405 406 for (dlp = blk_start; dlp <= blk_end; 407 dlp = (struct disklabel *)((char *)dlp + sizeof(long))) { 408 if (dlp->d_magic == DISKMAGIC && dlp->d_magic2 == DISKMAGIC) { 409 /* Sanity check */ 410 if (dlp->d_npartitions <= MAXPARTITIONS && 411 dkcksum(dlp) == 0) { 412 *lp = *dlp; 413 *match = (-1); 414 } else 415 msg = "Disk label corrupted"; 416 break; 417 } 418 } 419 return msg; 420 } 421 422 /* 423 * Attempt to read a disk label from a device using the indicated strategy 424 * routine. The label must be partly set up before this: secpercyl and 425 * anything required in the strategy routine (e.g., sector size) must be 426 * filled in before calling us. Returns null on success and an error 427 * string on failure. 428 */ 429 char * 430 readdisklabel(dev, strat, lp, osdep) 431 dev_t dev; 432 void (*strat)(struct buf *); 433 struct disklabel *lp; 434 struct cpu_disklabel *osdep; 435 { 436 struct buf *bp; 437 char *msg; 438 int size; 439 440 if (lp->d_secperunit == 0) 441 lp->d_secperunit = 0x1fffffff; 442 443 if (lp->d_secpercyl == 0) 444 return msg = "Zero secpercyl"; 445 446 msg = NULL; 447 448 /* 449 * Read in the first #(NUM_PARTS + 1) blocks of the disk. 450 * The native Macintosh partition table starts at 451 * sector #1, but we want #0 too for the BSD label. 452 */ 453 454 size = roundup((NUM_PARTS + 1) << DEV_BSHIFT, lp->d_secsize); 455 bp = geteblk(size); 456 457 bp->b_dev = dev; 458 bp->b_blkno = 0; 459 bp->b_resid = 0; 460 bp->b_bcount = size; 461 bp->b_flags |= B_READ; 462 bp->b_cylinder = 1 / lp->d_secpercyl; 463 (*strat)(bp); 464 465 if (biowait(bp)) { 466 msg = "I/O error reading block zero"; 467 } else { 468 int match; 469 470 /* Add any offsets in the table handlers */ 471 msg = read_mac_label(bp->b_data, lp, &match); 472 if (!match && msg == NULL) 473 msg = read_mbr_label(bp->b_data, lp, &match); 474 if (!match && msg == NULL) 475 msg = read_bsd_label(bp->b_data, lp, &match); 476 if (!match && msg == NULL) 477 msg = "no disk label"; 478 } 479 480 brelse(bp); 481 return (msg); 482 } 483 484 /* 485 * Check new disk label for sensibility before setting it. 486 */ 487 int 488 setdisklabel(olp, nlp, openmask, osdep) 489 struct disklabel *olp, *nlp; 490 u_long openmask; 491 struct cpu_disklabel *osdep; 492 { 493 #if 0 494 int i; 495 struct partition *opp, *npp; 496 497 /* sanity clause */ 498 if (nlp->d_secpercyl == 0 || nlp->d_secsize == 0 || 499 (nlp->d_secsize % DEV_BSIZE) != 0) 500 return(EINVAL); 501 502 /* special case to allow disklabel to be invalidated */ 503 if (nlp->d_magic == 0xffffffff) { 504 *olp = *nlp; 505 return (0); 506 } 507 508 if (nlp->d_magic != DISKMAGIC || nlp->d_magic2 != DISKMAGIC || 509 dkcksum(nlp) != 0) 510 return (EINVAL); 511 512 /* 513 * XXX We are missing any sort of check if other partition types, 514 * e.g. Macintosh or (PC) BIOS, will be overwritten. 515 */ 516 517 while ((i = ffs(openmask)) != 0) { 518 i--; 519 openmask &= ~(1 << i); 520 if (nlp->d_npartitions <= i) 521 return (EBUSY); 522 opp = &olp->d_partitions[i]; 523 npp = &nlp->d_partitions[i]; 524 if (npp->p_offset != opp->p_offset || npp->p_size < opp->p_size) 525 return (EBUSY); 526 /* 527 * Copy internally-set partition information 528 * if new label doesn't include it. XXX 529 */ 530 if (npp->p_fstype == FS_UNUSED && opp->p_fstype != FS_UNUSED) { 531 npp->p_fstype = opp->p_fstype; 532 npp->p_fsize = opp->p_fsize; 533 npp->p_frag = opp->p_frag; 534 npp->p_cpg = opp->p_cpg; 535 } 536 } 537 nlp->d_checksum = 0; 538 nlp->d_checksum = dkcksum(nlp); 539 *olp = *nlp; 540 #endif 541 return (0); 542 } 543 544 /* 545 * Write disk label back to device after modification. 546 * 547 * MF - 8-14-93 This function is never called. It is here just in case 548 * we want to write dos disklabels some day. Really! 549 */ 550 int 551 writedisklabel(dev, strat, lp, osdep) 552 dev_t dev; 553 void (*strat)(struct buf *); 554 struct disklabel *lp; 555 struct cpu_disklabel *osdep; 556 { 557 #if 0 558 struct buf *bp; 559 struct disklabel *dlp; 560 int labelpart; 561 int error = 0; 562 563 labelpart = DISKPART(dev); 564 if (lp->d_partitions[labelpart].p_offset != 0) { 565 if (lp->d_partitions[0].p_offset != 0) 566 return (EXDEV); /* not quite right */ 567 labelpart = 0; 568 } 569 bp = geteblk((int)lp->d_secsize); 570 bp->b_dev = MAKEDISKDEV(major(dev), DISKUNIT(dev), labelpart); 571 bp->b_blkno = LABELSECTOR; 572 bp->b_bcount = lp->d_secsize; 573 bp->b_flags |= B_READ; 574 (*strat)(bp); 575 if (error = biowait(bp)) 576 goto done; 577 for (dlp = (struct disklabel *)bp->b_data; 578 dlp <= (struct disklabel *) 579 (bp->b_data + lp->d_secsize - sizeof(*dlp)); 580 dlp = (struct disklabel *)((char *)dlp + sizeof(long))) { 581 if (dlp->d_magic == DISKMAGIC && dlp->d_magic2 == DISKMAGIC && 582 dkcksum(dlp) == 0) { 583 *dlp = *lp; 584 bp->b_flags &= ~(B_READ|B_DONE); 585 bp->b_flags |= B_WRITE; 586 (*strat)(bp); 587 error = biowait(bp); 588 goto done; 589 } 590 } 591 error = ESRCH; 592 done: 593 brelse(bp); 594 return (error); 595 #else 596 /* 597 * Re-analyze the ondisk Apple Disk Partition Map and recompute 598 * the faked incore disk label. This is necessary for sysinst, 599 * which may have modified the disk layout. We don't (yet) 600 * support writing real BSD disk labels, so this hack instead 601 * causes the DIOCWDINFO ioctl invoked by sysinst to update the 602 * in-core disk label when it is "written" to disk. 603 * This code was originally developed by Bob Nestor on 9/13/99. 604 */ 605 return (readdisklabel(dev, strat, lp, osdep) ? EINVAL : 0); 606 #endif 607 } 608 609 /* 610 * Determine the size of the transfer, and make sure it is 611 * within the boundaries of the partition. Adjust transfer 612 * if needed, and signal errors or early completion. 613 */ 614 int 615 bounds_check_with_label(bp, lp, wlabel) 616 struct buf *bp; 617 struct disklabel *lp; 618 int wlabel; 619 { 620 struct partition *p = lp->d_partitions + DISKPART(bp->b_dev); 621 #if 0 622 int labelsector = lp->d_partitions[2].p_offset + LABELSECTOR; 623 #endif 624 int sz; 625 626 sz = howmany(bp->b_bcount, lp->d_secsize); 627 628 if (bp->b_blkno + sz > p->p_size) { 629 sz = p->p_size - bp->b_blkno; 630 if (sz == 0) { 631 /* If exactly at end of disk, return EOF. */ 632 bp->b_resid = bp->b_bcount; 633 goto done; 634 } 635 if (sz < 0) { 636 /* If past end of disk, return EINVAL. */ 637 bp->b_error = EINVAL; 638 goto bad; 639 } 640 /* Otherwise, truncate request. */ 641 bp->b_bcount = sz << DEV_BSHIFT; 642 } 643 644 #if 0 645 /* Overwriting disk label? */ 646 if (bp->b_blkno + p->p_offset <= labelsector && 647 #if LABELSECTOR != 0 648 bp->b_blkno + p->p_offset + sz > labelsector && 649 #endif 650 (bp->b_flags & B_READ) == 0 && !wlabel) { 651 bp->b_error = EROFS; 652 goto bad; 653 } 654 #endif 655 656 /* calculate cylinder for disksort to order transfers with */ 657 bp->b_cylinder = (bp->b_blkno + p->p_offset) / 658 (lp->d_secsize / DEV_BSIZE) / lp->d_secpercyl; 659 return (1); 660 661 bad: 662 bp->b_flags |= B_ERROR; 663 done: 664 return (0); 665 } 666