1 /* $OpenBSD: softraid_riscv64.c,v 1.3 2023/01/16 21:30:46 kn Exp $ */ 2 3 /* 4 * Copyright (c) 2012 Joel Sing <jsing@openbsd.org> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <sys/param.h> 20 #include <sys/queue.h> 21 #include <sys/disklabel.h> 22 #include <sys/reboot.h> 23 24 #include <dev/biovar.h> 25 #include <dev/softraidvar.h> 26 27 #include <lib/libsa/aes_xts.h> 28 #include <lib/libsa/softraid.h> 29 #include <lib/libz/zlib.h> 30 31 #include <efi.h> 32 33 #include "libsa.h" 34 #include "disk.h" 35 #include "efidev.h" 36 #include "softraid_riscv64.h" 37 38 static int gpt_chk_mbr(struct dos_partition *, u_int64_t); 39 static uint64_t findopenbsd_gpt(struct sr_boot_volume *, const char **); 40 41 void 42 srprobe_meta_opt_load(struct sr_metadata *sm, struct sr_meta_opt_head *som) 43 { 44 struct sr_meta_opt_hdr *omh; 45 struct sr_meta_opt_item *omi; 46 #if 0 47 u_int8_t checksum[MD5_DIGEST_LENGTH]; 48 #endif 49 int i; 50 51 /* Process optional metadata. */ 52 omh = (struct sr_meta_opt_hdr *)((u_int8_t *)(sm + 1) + 53 sizeof(struct sr_meta_chunk) * sm->ssdi.ssd_chunk_no); 54 for (i = 0; i < sm->ssdi.ssd_opt_no; i++) { 55 56 #ifdef BIOS_DEBUG 57 printf("Found optional metadata of type %u, length %u\n", 58 omh->som_type, omh->som_length); 59 #endif 60 61 /* Unsupported old fixed length optional metadata. */ 62 if (omh->som_length == 0) { 63 omh = (struct sr_meta_opt_hdr *)((void *)omh + 64 SR_OLD_META_OPT_SIZE); 65 continue; 66 } 67 68 /* Load variable length optional metadata. */ 69 omi = alloc(sizeof(struct sr_meta_opt_item)); 70 bzero(omi, sizeof(struct sr_meta_opt_item)); 71 SLIST_INSERT_HEAD(som, omi, omi_link); 72 omi->omi_som = alloc(omh->som_length); 73 bzero(omi->omi_som, omh->som_length); 74 bcopy(omh, omi->omi_som, omh->som_length); 75 76 #if 0 77 /* XXX - Validate checksum. */ 78 bcopy(&omi->omi_som->som_checksum, &checksum, 79 MD5_DIGEST_LENGTH); 80 bzero(&omi->omi_som->som_checksum, MD5_DIGEST_LENGTH); 81 sr_checksum(sc, omi->omi_som, 82 &omi->omi_som->som_checksum, omh->som_length); 83 if (bcmp(&checksum, &omi->omi_som->som_checksum, 84 sizeof(checksum))) 85 panic("%s: invalid optional metadata checksum", 86 DEVNAME(sc)); 87 #endif 88 89 omh = (struct sr_meta_opt_hdr *)((void *)omh + 90 omh->som_length); 91 } 92 } 93 94 void 95 srprobe_keydisk_load(struct sr_metadata *sm) 96 { 97 struct sr_meta_opt_hdr *omh; 98 struct sr_meta_keydisk *skm; 99 struct sr_boot_keydisk *kd; 100 int i; 101 102 /* Process optional metadata. */ 103 omh = (struct sr_meta_opt_hdr *)((u_int8_t *)(sm + 1) + 104 sizeof(struct sr_meta_chunk) * sm->ssdi.ssd_chunk_no); 105 for (i = 0; i < sm->ssdi.ssd_opt_no; i++) { 106 107 /* Unsupported old fixed length optional metadata. */ 108 if (omh->som_length == 0) { 109 omh = (struct sr_meta_opt_hdr *)((void *)omh + 110 SR_OLD_META_OPT_SIZE); 111 continue; 112 } 113 114 if (omh->som_type != SR_OPT_KEYDISK) { 115 omh = (struct sr_meta_opt_hdr *)((void *)omh + 116 omh->som_length); 117 continue; 118 } 119 120 kd = alloc(sizeof(struct sr_boot_keydisk)); 121 bcopy(&sm->ssdi.ssd_uuid, &kd->kd_uuid, sizeof(kd->kd_uuid)); 122 skm = (struct sr_meta_keydisk*)omh; 123 bcopy(&skm->skm_maskkey, &kd->kd_key, sizeof(kd->kd_key)); 124 SLIST_INSERT_HEAD(&sr_keydisks, kd, kd_link); 125 } 126 } 127 128 void 129 srprobe(void) 130 { 131 struct sr_boot_volume *bv, *bv1, *bv2; 132 struct sr_boot_chunk *bc, *bc1, *bc2; 133 struct sr_meta_chunk *mc; 134 struct sr_metadata *md; 135 struct diskinfo *dip; 136 struct partition *pp; 137 int i, error, volno; 138 daddr_t off; 139 140 /* Probe for softraid volumes. */ 141 SLIST_INIT(&sr_volumes); 142 SLIST_INIT(&sr_keydisks); 143 144 md = alloc(SR_META_SIZE * DEV_BSIZE); 145 146 TAILQ_FOREACH(dip, &disklist, list) { 147 148 /* Make sure disklabel has been read. */ 149 if ((dip->flags & DISKINFO_FLAG_GOODLABEL) == 0) 150 continue; 151 152 for (i = 0; i < MAXPARTITIONS; i++) { 153 154 pp = &dip->disklabel.d_partitions[i]; 155 if (pp->p_fstype != FS_RAID || pp->p_size == 0) 156 continue; 157 158 /* Read softraid metadata. */ 159 bzero(md, SR_META_SIZE * DEV_BSIZE); 160 off = DL_SECTOBLK(&dip->disklabel, DL_GETPOFFSET(pp)); 161 off += SR_META_OFFSET; 162 error = dip->diskio(F_READ, dip, off, SR_META_SIZE, md); 163 if (error) 164 continue; 165 166 /* Is this valid softraid metadata? */ 167 if (md->ssdi.ssd_magic != SR_MAGIC) 168 continue; 169 170 /* XXX - validate checksum. */ 171 172 /* Handle key disks separately... */ 173 if (md->ssdi.ssd_level == SR_KEYDISK_LEVEL) { 174 srprobe_keydisk_load(md); 175 continue; 176 } 177 178 /* Locate chunk-specific metadata for this chunk. */ 179 mc = (struct sr_meta_chunk *)(md + 1); 180 mc += md->ssdi.ssd_chunk_id; 181 182 bc = alloc(sizeof(struct sr_boot_chunk)); 183 bc->sbc_diskinfo = dip; 184 bc->sbc_disk = 0; 185 bc->sbc_part = 'a' + i; 186 187 bc->sbc_mm = 0; 188 189 bc->sbc_chunk_id = md->ssdi.ssd_chunk_id; 190 bc->sbc_ondisk = md->ssd_ondisk; 191 bc->sbc_state = mc->scm_status; 192 193 SLIST_FOREACH(bv, &sr_volumes, sbv_link) { 194 if (bcmp(&md->ssdi.ssd_uuid, &bv->sbv_uuid, 195 sizeof(md->ssdi.ssd_uuid)) == 0) 196 break; 197 } 198 199 if (bv == NULL) { 200 bv = alloc(sizeof(struct sr_boot_volume)); 201 bzero(bv, sizeof(struct sr_boot_volume)); 202 bv->sbv_level = md->ssdi.ssd_level; 203 bv->sbv_volid = md->ssdi.ssd_volid; 204 bv->sbv_chunk_no = md->ssdi.ssd_chunk_no; 205 bv->sbv_flags = md->ssdi.ssd_vol_flags; 206 bv->sbv_size = md->ssdi.ssd_size; 207 bv->sbv_secsize = md->ssdi.ssd_secsize; 208 bv->sbv_data_blkno = md->ssd_data_blkno; 209 bcopy(&md->ssdi.ssd_uuid, &bv->sbv_uuid, 210 sizeof(md->ssdi.ssd_uuid)); 211 SLIST_INIT(&bv->sbv_chunks); 212 SLIST_INIT(&bv->sbv_meta_opt); 213 214 /* Load optional metadata for this volume. */ 215 srprobe_meta_opt_load(md, &bv->sbv_meta_opt); 216 217 /* Maintain volume order. */ 218 bv2 = NULL; 219 SLIST_FOREACH(bv1, &sr_volumes, sbv_link) { 220 if (bv1->sbv_volid > bv->sbv_volid) 221 break; 222 bv2 = bv1; 223 } 224 if (bv2 == NULL) 225 SLIST_INSERT_HEAD(&sr_volumes, bv, 226 sbv_link); 227 else 228 SLIST_INSERT_AFTER(bv2, bv, sbv_link); 229 } 230 231 /* Maintain chunk order. */ 232 bc2 = NULL; 233 SLIST_FOREACH(bc1, &bv->sbv_chunks, sbc_link) { 234 if (bc1->sbc_chunk_id > bc->sbc_chunk_id) 235 break; 236 bc2 = bc1; 237 } 238 if (bc2 == NULL) 239 SLIST_INSERT_HEAD(&bv->sbv_chunks, 240 bc, sbc_link); 241 else 242 SLIST_INSERT_AFTER(bc2, bc, sbc_link); 243 244 bv->sbv_chunks_found++; 245 } 246 } 247 248 /* 249 * Assemble RAID volumes. 250 */ 251 volno = 0; 252 SLIST_FOREACH(bv, &sr_volumes, sbv_link) { 253 254 /* Skip if this is a hotspare "volume". */ 255 if (bv->sbv_level == SR_HOTSPARE_LEVEL && 256 bv->sbv_chunk_no == 1) 257 continue; 258 259 /* Determine current ondisk version. */ 260 bv->sbv_ondisk = 0; 261 SLIST_FOREACH(bc, &bv->sbv_chunks, sbc_link) { 262 if (bc->sbc_ondisk > bv->sbv_ondisk) 263 bv->sbv_ondisk = bc->sbc_ondisk; 264 } 265 SLIST_FOREACH(bc, &bv->sbv_chunks, sbc_link) { 266 if (bc->sbc_ondisk != bv->sbv_ondisk) 267 bc->sbc_state = BIOC_SDOFFLINE; 268 } 269 270 /* XXX - Check for duplicate chunks. */ 271 272 /* 273 * Validate that volume has sufficient chunks for 274 * read-only access. 275 * 276 * XXX - check chunk states. 277 */ 278 bv->sbv_state = BIOC_SVOFFLINE; 279 switch (bv->sbv_level) { 280 case 0: 281 case 'C': 282 case 'c': 283 if (bv->sbv_chunk_no == bv->sbv_chunks_found) 284 bv->sbv_state = BIOC_SVONLINE; 285 break; 286 287 case 1: 288 case 0x1C: 289 if (bv->sbv_chunk_no == bv->sbv_chunks_found) 290 bv->sbv_state = BIOC_SVONLINE; 291 else if (bv->sbv_chunks_found > 0) 292 bv->sbv_state = BIOC_SVDEGRADED; 293 break; 294 } 295 296 bv->sbv_unit = volno++; 297 if (bv->sbv_state != BIOC_SVOFFLINE) 298 printf(" sr%d%s", bv->sbv_unit, 299 bv->sbv_flags & BIOC_SCBOOTABLE ? "*" : ""); 300 } 301 302 explicit_bzero(md, SR_META_SIZE * DEV_BSIZE); 303 free(md, SR_META_SIZE * DEV_BSIZE); 304 } 305 306 int 307 sr_strategy(struct sr_boot_volume *bv, int rw, daddr_t blk, size_t size, 308 void *buf, size_t *rsize) 309 { 310 struct diskinfo *sr_dip, *dip; 311 struct sr_boot_chunk *bc; 312 struct aes_xts_ctx ctx; 313 size_t i, j, nsect; 314 daddr_t blkno; 315 u_char iv[8]; 316 u_char *bp; 317 int err; 318 319 /* We only support read-only softraid. */ 320 if (rw != F_READ) 321 return ENOTSUP; 322 323 /* Partition offset within softraid volume. */ 324 sr_dip = (struct diskinfo *)bv->sbv_diskinfo; 325 blk += DL_SECTOBLK(&sr_dip->disklabel, 326 sr_dip->disklabel.d_partitions[bv->sbv_part - 'a'].p_offset); 327 328 if (bv->sbv_level == 0) { 329 return ENOTSUP; 330 } else if (bv->sbv_level == 1) { 331 332 /* Select first online chunk. */ 333 SLIST_FOREACH(bc, &bv->sbv_chunks, sbc_link) 334 if (bc->sbc_state == BIOC_SDONLINE) 335 break; 336 if (bc == NULL) 337 return EIO; 338 339 dip = (struct diskinfo *)bc->sbc_diskinfo; 340 blk += bv->sbv_data_blkno; 341 342 /* XXX - If I/O failed we should try another chunk... */ 343 return dip->strategy(dip, rw, blk, size, buf, rsize); 344 345 } else if (bv->sbv_level == 'C' || bv->sbv_level == 0x1C) { 346 347 /* Select first online chunk. */ 348 SLIST_FOREACH(bc, &bv->sbv_chunks, sbc_link) 349 if (bc->sbc_state == BIOC_SDONLINE) 350 break; 351 if (bc == NULL) 352 return EIO; 353 354 dip = (struct diskinfo *)bc->sbc_diskinfo; 355 356 /* XXX - select correct key. */ 357 aes_xts_setkey(&ctx, (u_char *)bv->sbv_keys, 64); 358 359 nsect = (size + DEV_BSIZE - 1) / DEV_BSIZE; 360 for (i = 0; i < nsect; i++) { 361 blkno = blk + i; 362 bp = ((u_char *)buf) + i * DEV_BSIZE; 363 err = dip->strategy(dip, rw, bv->sbv_data_blkno + blkno, 364 DEV_BSIZE, bp, NULL); 365 if (err != 0) 366 return err; 367 368 bcopy(&blkno, iv, sizeof(blkno)); 369 aes_xts_reinit(&ctx, iv); 370 for (j = 0; j < DEV_BSIZE; j += AES_XTS_BLOCKSIZE) 371 aes_xts_decrypt(&ctx, bp + j); 372 } 373 if (rsize != NULL) 374 *rsize = nsect * DEV_BSIZE; 375 376 return err; 377 378 } else 379 return ENOTSUP; 380 } 381 382 /* 383 * Returns 0 if the MBR with the provided partition array is a GPT protective 384 * MBR, and returns 1 otherwise. A GPT protective MBR would have one and only 385 * one MBR partition, an EFI partition that either covers the whole disk or as 386 * much of it as is possible with a 32bit size field. 387 * 388 * Taken from kern/subr_disk.c. 389 * 390 * NOTE: MS always uses a size of UINT32_MAX for the EFI partition!** 391 */ 392 static int 393 gpt_chk_mbr(struct dos_partition *dp, u_int64_t dsize) 394 { 395 struct dos_partition *dp2; 396 int efi, found, i; 397 u_int32_t psize; 398 399 found = efi = 0; 400 for (dp2=dp, i=0; i < NDOSPART; i++, dp2++) { 401 if (dp2->dp_typ == DOSPTYP_UNUSED) 402 continue; 403 found++; 404 if (dp2->dp_typ != DOSPTYP_EFI) 405 continue; 406 if (letoh32(dp2->dp_start) != GPTSECTOR) 407 continue; 408 psize = letoh32(dp2->dp_size); 409 if (psize <= (dsize - GPTSECTOR) || psize == UINT32_MAX) 410 efi++; 411 } 412 if (found == 1 && efi == 1) 413 return (0); 414 415 return (1); 416 } 417 418 static uint64_t 419 findopenbsd_gpt(struct sr_boot_volume *bv, const char **err) 420 { 421 struct gpt_header gh; 422 int i, part, found; 423 uint64_t lba; 424 uint32_t orig_csum, new_csum; 425 uint32_t ghsize, ghpartsize, ghpartnum, ghpartspersec; 426 uint32_t gpsectors; 427 const char openbsd_uuid_code[] = GPT_UUID_OPENBSD; 428 struct gpt_partition gp; 429 static struct uuid *openbsd_uuid = NULL, openbsd_uuid_space; 430 u_char *buf; 431 432 /* Prepare OpenBSD UUID */ 433 if (openbsd_uuid == NULL) { 434 /* XXX: should be replaced by uuid_dec_be() */ 435 memcpy(&openbsd_uuid_space, openbsd_uuid_code, 436 sizeof(openbsd_uuid_space)); 437 openbsd_uuid_space.time_low = 438 betoh32(openbsd_uuid_space.time_low); 439 openbsd_uuid_space.time_mid = 440 betoh16(openbsd_uuid_space.time_mid); 441 openbsd_uuid_space.time_hi_and_version = 442 betoh16(openbsd_uuid_space.time_hi_and_version); 443 444 openbsd_uuid = &openbsd_uuid_space; 445 } 446 447 if (bv->sbv_secsize > 4096) { 448 *err = "disk sector > 4096 bytes\n"; 449 return (-1); 450 } 451 buf = alloc(bv->sbv_secsize); 452 if (buf == NULL) { 453 *err = "out of memory\n"; 454 return (-1); 455 } 456 bzero(buf, bv->sbv_secsize); 457 458 /* GPT Header */ 459 lba = GPTSECTOR; 460 sr_strategy(bv, F_READ, lba * (bv->sbv_secsize / DEV_BSIZE), DEV_BSIZE, 461 buf, NULL); 462 memcpy(&gh, buf, sizeof(gh)); 463 464 /* Check signature */ 465 if (letoh64(gh.gh_sig) != GPTSIGNATURE) { 466 *err = "bad GPT signature\n"; 467 free(buf, bv->sbv_secsize); 468 return (-1); 469 } 470 471 if (letoh32(gh.gh_rev) != GPTREVISION) { 472 *err = "bad GPT revision\n"; 473 free(buf, bv->sbv_secsize); 474 return (-1); 475 } 476 477 ghsize = letoh32(gh.gh_size); 478 if (ghsize < GPTMINHDRSIZE || ghsize > sizeof(struct gpt_header)) { 479 *err = "bad GPT header size\n"; 480 free(buf, bv->sbv_secsize); 481 return (-1); 482 } 483 484 /* Check checksum */ 485 orig_csum = gh.gh_csum; 486 gh.gh_csum = 0; 487 new_csum = crc32(0, (unsigned char *)&gh, ghsize); 488 gh.gh_csum = orig_csum; 489 if (letoh32(orig_csum) != new_csum) { 490 *err = "bad GPT header checksum\n"; 491 free(buf, bv->sbv_secsize); 492 return (-1); 493 } 494 495 lba = letoh64(gh.gh_part_lba); 496 ghpartsize = letoh32(gh.gh_part_size); 497 ghpartspersec = bv->sbv_secsize / ghpartsize; 498 ghpartnum = letoh32(gh.gh_part_num); 499 gpsectors = (ghpartnum + ghpartspersec - 1) / ghpartspersec; 500 new_csum = crc32(0L, Z_NULL, 0); 501 found = 0; 502 for (i = 0; i < gpsectors; i++, lba++) { 503 sr_strategy(bv, F_READ, lba * (bv->sbv_secsize / DEV_BSIZE), 504 bv->sbv_secsize, buf, NULL); 505 for (part = 0; part < ghpartspersec; part++) { 506 if (ghpartnum == 0) 507 break; 508 new_csum = crc32(new_csum, buf + part * sizeof(gp), 509 sizeof(gp)); 510 ghpartnum--; 511 if (found) 512 continue; 513 memcpy(&gp, buf + part * sizeof(gp), sizeof(gp)); 514 if (memcmp(&gp.gp_type, openbsd_uuid, 515 sizeof(struct uuid)) == 0) 516 found = 1; 517 } 518 } 519 520 free(buf, bv->sbv_secsize); 521 522 if (new_csum != letoh32(gh.gh_part_csum)) { 523 *err = "bad GPT entries checksum\n"; 524 return (-1); 525 } 526 if (found) 527 return (letoh64(gp.gp_lba_start)); 528 529 return (-1); 530 } 531 532 const char * 533 sr_getdisklabel(struct sr_boot_volume *bv, struct disklabel *label) 534 { 535 struct dos_partition *dp; 536 struct dos_mbr mbr; 537 const char *err = NULL; 538 u_int start = 0; 539 char buf[DEV_BSIZE]; 540 int i; 541 542 /* Check for MBR to determine partition offset. */ 543 bzero(&mbr, sizeof(mbr)); 544 sr_strategy(bv, F_READ, DOSBBSECTOR, sizeof(mbr), &mbr, NULL); 545 if (gpt_chk_mbr(mbr.dmbr_parts, bv->sbv_size / 546 (bv->sbv_secsize / DEV_BSIZE)) == 0) { 547 start = findopenbsd_gpt(bv, &err); 548 if (start == (u_int)-1) { 549 if (err != NULL) 550 return (err); 551 return "no OpenBSD partition\n"; 552 } 553 } else if (mbr.dmbr_sign == DOSMBR_SIGNATURE) { 554 555 /* Search for OpenBSD partition */ 556 for (i = 0; i < NDOSPART; i++) { 557 dp = &mbr.dmbr_parts[i]; 558 if (!dp->dp_size) 559 continue; 560 if (dp->dp_typ == DOSPTYP_OPENBSD) { 561 start = dp->dp_start; 562 break; 563 } 564 } 565 } 566 567 /* Read the disklabel. */ 568 sr_strategy(bv, F_READ, 569 start * (bv->sbv_secsize / DEV_BSIZE) + DOS_LABELSECTOR, 570 sizeof(struct disklabel), buf, NULL); 571 572 #ifdef BIOS_DEBUG 573 printf("sr_getdisklabel: magic %lx\n", 574 ((struct disklabel *)buf)->d_magic); 575 for (i = 0; i < MAXPARTITIONS; i++) 576 printf("part %c: type = %d, size = %d, offset = %d\n", 'a' + i, 577 (int)((struct disklabel *)buf)->d_partitions[i].p_fstype, 578 (int)((struct disklabel *)buf)->d_partitions[i].p_size, 579 (int)((struct disklabel *)buf)->d_partitions[i].p_offset); 580 #endif 581 582 /* Fill in disklabel */ 583 return (getdisklabel(buf, label)); 584 } 585 586 int 587 sropen(struct open_file *f, ...) 588 { 589 struct diskinfo *dip = NULL; 590 struct sr_boot_volume *bv; 591 va_list ap; 592 u_int unit, part; 593 594 va_start(ap, f); 595 unit = va_arg(ap, u_int); 596 part = va_arg(ap, u_int); 597 va_end(ap); 598 599 /* Create a fake diskinfo for this softraid volume. */ 600 SLIST_FOREACH(bv, &sr_volumes, sbv_link) 601 if (bv->sbv_unit == unit) 602 break; 603 if (bv == NULL) { 604 printf("Unknown device: sr%d\n", unit); 605 return EADAPT; 606 } 607 608 if ((bv->sbv_level == 'C' || bv->sbv_level == 0x1C) 609 && bv->sbv_keys == NULL) 610 if (sr_crypto_unlock_volume(bv) != 0) 611 return EPERM; 612 613 if (bv->sbv_diskinfo == NULL) { 614 dip = alloc(sizeof(struct diskinfo)); 615 bzero(dip, sizeof(*dip)); 616 dip->diskio = srdiskio; 617 dip->strategy = srstrategy; 618 bv->sbv_diskinfo = dip; 619 dip->sr_vol = bv; 620 } 621 622 dip = bv->sbv_diskinfo; 623 624 if ((dip->flags & DISKINFO_FLAG_GOODLABEL) == 0) { 625 /* Attempt to read disklabel. */ 626 bv->sbv_part = 'c'; 627 if (sr_getdisklabel(bv, &dip->disklabel)) 628 return ERDLAB; 629 dip->flags |= DISKINFO_FLAG_GOODLABEL; 630 } 631 632 bv->sbv_part = part + 'a'; 633 634 bootdev_dip = dip; 635 f->f_devdata = dip; 636 637 return 0; 638 } 639 640 int 641 srstrategy(void *devdata, int rw, daddr_t blk, size_t size, void *buf, 642 size_t *rsize) 643 { 644 struct diskinfo *dip = (struct diskinfo *)devdata; 645 return sr_strategy(dip->sr_vol, rw, blk, size, buf, rsize); 646 } 647 648 int 649 srdiskio(int rw, struct diskinfo *dip, u_int off, int nsect, void *buf) 650 { 651 return dip->diskio(rw, dip, off, nsect, buf); 652 } 653 654 int 655 srclose(struct open_file *f) 656 { 657 f->f_devdata = NULL; 658 659 return 0; 660 } 661 662 int 663 srioctl(struct open_file *f, u_long cmd, void *data) 664 { 665 return 0; 666 } 667