1 /* $OpenBSD: softraid_riscv64.c,v 1.2 2021/06/02 22:44:27 krw 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 if (bv->sbv_chunk_no == bv->sbv_chunks_found) 289 bv->sbv_state = BIOC_SVONLINE; 290 else if (bv->sbv_chunks_found > 0) 291 bv->sbv_state = BIOC_SVDEGRADED; 292 break; 293 } 294 295 bv->sbv_unit = volno++; 296 if (bv->sbv_state != BIOC_SVOFFLINE) 297 printf(" sr%d%s", bv->sbv_unit, 298 bv->sbv_flags & BIOC_SCBOOTABLE ? "*" : ""); 299 } 300 301 explicit_bzero(md, SR_META_SIZE * DEV_BSIZE); 302 free(md, SR_META_SIZE * DEV_BSIZE); 303 } 304 305 int 306 sr_strategy(struct sr_boot_volume *bv, int rw, daddr_t blk, size_t size, 307 void *buf, size_t *rsize) 308 { 309 struct diskinfo *sr_dip, *dip; 310 struct sr_boot_chunk *bc; 311 struct aes_xts_ctx ctx; 312 size_t i, j, nsect; 313 daddr_t blkno; 314 u_char iv[8]; 315 u_char *bp; 316 int err; 317 318 /* We only support read-only softraid. */ 319 if (rw != F_READ) 320 return ENOTSUP; 321 322 /* Partition offset within softraid volume. */ 323 sr_dip = (struct diskinfo *)bv->sbv_diskinfo; 324 blk += DL_SECTOBLK(&sr_dip->disklabel, 325 sr_dip->disklabel.d_partitions[bv->sbv_part - 'a'].p_offset); 326 327 if (bv->sbv_level == 0) { 328 return ENOTSUP; 329 } else if (bv->sbv_level == 1) { 330 331 /* Select first online chunk. */ 332 SLIST_FOREACH(bc, &bv->sbv_chunks, sbc_link) 333 if (bc->sbc_state == BIOC_SDONLINE) 334 break; 335 if (bc == NULL) 336 return EIO; 337 338 dip = (struct diskinfo *)bc->sbc_diskinfo; 339 blk += bv->sbv_data_blkno; 340 341 /* XXX - If I/O failed we should try another chunk... */ 342 return dip->strategy(dip, rw, blk, size, buf, rsize); 343 344 } else if (bv->sbv_level == 'C') { 345 346 /* Select first online chunk. */ 347 SLIST_FOREACH(bc, &bv->sbv_chunks, sbc_link) 348 if (bc->sbc_state == BIOC_SDONLINE) 349 break; 350 if (bc == NULL) 351 return EIO; 352 353 dip = (struct diskinfo *)bc->sbc_diskinfo; 354 355 /* XXX - select correct key. */ 356 aes_xts_setkey(&ctx, (u_char *)bv->sbv_keys, 64); 357 358 nsect = (size + DEV_BSIZE - 1) / DEV_BSIZE; 359 for (i = 0; i < nsect; i++) { 360 blkno = blk + i; 361 bp = ((u_char *)buf) + i * DEV_BSIZE; 362 err = dip->strategy(dip, rw, bv->sbv_data_blkno + blkno, 363 DEV_BSIZE, bp, NULL); 364 if (err != 0) 365 return err; 366 367 bcopy(&blkno, iv, sizeof(blkno)); 368 aes_xts_reinit(&ctx, iv); 369 for (j = 0; j < DEV_BSIZE; j += AES_XTS_BLOCKSIZE) 370 aes_xts_decrypt(&ctx, bp + j); 371 } 372 if (rsize != NULL) 373 *rsize = nsect * DEV_BSIZE; 374 375 return err; 376 377 } else 378 return ENOTSUP; 379 } 380 381 /* 382 * Returns 0 if the MBR with the provided partition array is a GPT protective 383 * MBR, and returns 1 otherwise. A GPT protective MBR would have one and only 384 * one MBR partition, an EFI partition that either covers the whole disk or as 385 * much of it as is possible with a 32bit size field. 386 * 387 * Taken from kern/subr_disk.c. 388 * 389 * NOTE: MS always uses a size of UINT32_MAX for the EFI partition!** 390 */ 391 static int 392 gpt_chk_mbr(struct dos_partition *dp, u_int64_t dsize) 393 { 394 struct dos_partition *dp2; 395 int efi, found, i; 396 u_int32_t psize; 397 398 found = efi = 0; 399 for (dp2=dp, i=0; i < NDOSPART; i++, dp2++) { 400 if (dp2->dp_typ == DOSPTYP_UNUSED) 401 continue; 402 found++; 403 if (dp2->dp_typ != DOSPTYP_EFI) 404 continue; 405 if (letoh32(dp2->dp_start) != GPTSECTOR) 406 continue; 407 psize = letoh32(dp2->dp_size); 408 if (psize <= (dsize - GPTSECTOR) || psize == UINT32_MAX) 409 efi++; 410 } 411 if (found == 1 && efi == 1) 412 return (0); 413 414 return (1); 415 } 416 417 static uint64_t 418 findopenbsd_gpt(struct sr_boot_volume *bv, const char **err) 419 { 420 struct gpt_header gh; 421 int i, part, found; 422 uint64_t lba; 423 uint32_t orig_csum, new_csum; 424 uint32_t ghsize, ghpartsize, ghpartnum, ghpartspersec; 425 uint32_t gpsectors; 426 const char openbsd_uuid_code[] = GPT_UUID_OPENBSD; 427 struct gpt_partition gp; 428 static struct uuid *openbsd_uuid = NULL, openbsd_uuid_space; 429 u_char *buf; 430 431 /* Prepare OpenBSD UUID */ 432 if (openbsd_uuid == NULL) { 433 /* XXX: should be replaced by uuid_dec_be() */ 434 memcpy(&openbsd_uuid_space, openbsd_uuid_code, 435 sizeof(openbsd_uuid_space)); 436 openbsd_uuid_space.time_low = 437 betoh32(openbsd_uuid_space.time_low); 438 openbsd_uuid_space.time_mid = 439 betoh16(openbsd_uuid_space.time_mid); 440 openbsd_uuid_space.time_hi_and_version = 441 betoh16(openbsd_uuid_space.time_hi_and_version); 442 443 openbsd_uuid = &openbsd_uuid_space; 444 } 445 446 if (bv->sbv_secsize > 4096) { 447 *err = "disk sector > 4096 bytes\n"; 448 return (-1); 449 } 450 buf = alloc(bv->sbv_secsize); 451 if (buf == NULL) { 452 *err = "out of memory\n"; 453 return (-1); 454 } 455 bzero(buf, bv->sbv_secsize); 456 457 /* GPT Header */ 458 lba = GPTSECTOR; 459 sr_strategy(bv, F_READ, lba * (bv->sbv_secsize / DEV_BSIZE), DEV_BSIZE, 460 buf, NULL); 461 memcpy(&gh, buf, sizeof(gh)); 462 463 /* Check signature */ 464 if (letoh64(gh.gh_sig) != GPTSIGNATURE) { 465 *err = "bad GPT signature\n"; 466 free(buf, bv->sbv_secsize); 467 return (-1); 468 } 469 470 if (letoh32(gh.gh_rev) != GPTREVISION) { 471 *err = "bad GPT revision\n"; 472 free(buf, bv->sbv_secsize); 473 return (-1); 474 } 475 476 ghsize = letoh32(gh.gh_size); 477 if (ghsize < GPTMINHDRSIZE || ghsize > sizeof(struct gpt_header)) { 478 *err = "bad GPT header size\n"; 479 free(buf, bv->sbv_secsize); 480 return (-1); 481 } 482 483 /* Check checksum */ 484 orig_csum = gh.gh_csum; 485 gh.gh_csum = 0; 486 new_csum = crc32(0, (unsigned char *)&gh, ghsize); 487 gh.gh_csum = orig_csum; 488 if (letoh32(orig_csum) != new_csum) { 489 *err = "bad GPT header checksum\n"; 490 free(buf, bv->sbv_secsize); 491 return (-1); 492 } 493 494 lba = letoh64(gh.gh_part_lba); 495 ghpartsize = letoh32(gh.gh_part_size); 496 ghpartspersec = bv->sbv_secsize / ghpartsize; 497 ghpartnum = letoh32(gh.gh_part_num); 498 gpsectors = (ghpartnum + ghpartspersec - 1) / ghpartspersec; 499 new_csum = crc32(0L, Z_NULL, 0); 500 found = 0; 501 for (i = 0; i < gpsectors; i++, lba++) { 502 sr_strategy(bv, F_READ, lba * (bv->sbv_secsize / DEV_BSIZE), 503 bv->sbv_secsize, buf, NULL); 504 for (part = 0; part < ghpartspersec; part++) { 505 if (ghpartnum == 0) 506 break; 507 new_csum = crc32(new_csum, buf + part * sizeof(gp), 508 sizeof(gp)); 509 ghpartnum--; 510 if (found) 511 continue; 512 memcpy(&gp, buf + part * sizeof(gp), sizeof(gp)); 513 if (memcmp(&gp.gp_type, openbsd_uuid, 514 sizeof(struct uuid)) == 0) 515 found = 1; 516 } 517 } 518 519 free(buf, bv->sbv_secsize); 520 521 if (new_csum != letoh32(gh.gh_part_csum)) { 522 *err = "bad GPT entries checksum\n"; 523 return (-1); 524 } 525 if (found) 526 return (letoh64(gp.gp_lba_start)); 527 528 return (-1); 529 } 530 531 const char * 532 sr_getdisklabel(struct sr_boot_volume *bv, struct disklabel *label) 533 { 534 struct dos_partition *dp; 535 struct dos_mbr mbr; 536 const char *err = NULL; 537 u_int start = 0; 538 char buf[DEV_BSIZE]; 539 int i; 540 541 /* Check for MBR to determine partition offset. */ 542 bzero(&mbr, sizeof(mbr)); 543 sr_strategy(bv, F_READ, DOSBBSECTOR, sizeof(mbr), &mbr, NULL); 544 if (gpt_chk_mbr(mbr.dmbr_parts, bv->sbv_size / 545 (bv->sbv_secsize / DEV_BSIZE)) == 0) { 546 start = findopenbsd_gpt(bv, &err); 547 if (start == (u_int)-1) { 548 if (err != NULL) 549 return (err); 550 return "no OpenBSD partition\n"; 551 } 552 } else if (mbr.dmbr_sign == DOSMBR_SIGNATURE) { 553 554 /* Search for OpenBSD partition */ 555 for (i = 0; i < NDOSPART; i++) { 556 dp = &mbr.dmbr_parts[i]; 557 if (!dp->dp_size) 558 continue; 559 if (dp->dp_typ == DOSPTYP_OPENBSD) { 560 start = dp->dp_start; 561 break; 562 } 563 } 564 } 565 566 /* Read the disklabel. */ 567 sr_strategy(bv, F_READ, 568 start * (bv->sbv_secsize / DEV_BSIZE) + DOS_LABELSECTOR, 569 sizeof(struct disklabel), buf, NULL); 570 571 #ifdef BIOS_DEBUG 572 printf("sr_getdisklabel: magic %lx\n", 573 ((struct disklabel *)buf)->d_magic); 574 for (i = 0; i < MAXPARTITIONS; i++) 575 printf("part %c: type = %d, size = %d, offset = %d\n", 'a' + i, 576 (int)((struct disklabel *)buf)->d_partitions[i].p_fstype, 577 (int)((struct disklabel *)buf)->d_partitions[i].p_size, 578 (int)((struct disklabel *)buf)->d_partitions[i].p_offset); 579 #endif 580 581 /* Fill in disklabel */ 582 return (getdisklabel(buf, label)); 583 } 584 585 int 586 sropen(struct open_file *f, ...) 587 { 588 struct diskinfo *dip = NULL; 589 struct sr_boot_volume *bv; 590 va_list ap; 591 u_int unit, part; 592 593 va_start(ap, f); 594 unit = va_arg(ap, u_int); 595 part = va_arg(ap, u_int); 596 va_end(ap); 597 598 /* Create a fake diskinfo for this softraid volume. */ 599 SLIST_FOREACH(bv, &sr_volumes, sbv_link) 600 if (bv->sbv_unit == unit) 601 break; 602 if (bv == NULL) { 603 printf("Unknown device: sr%d\n", unit); 604 return EADAPT; 605 } 606 607 if (bv->sbv_level == 'C' && bv->sbv_keys == NULL) 608 if (sr_crypto_unlock_volume(bv) != 0) 609 return EPERM; 610 611 if (bv->sbv_diskinfo == NULL) { 612 dip = alloc(sizeof(struct diskinfo)); 613 bzero(dip, sizeof(*dip)); 614 dip->diskio = srdiskio; 615 dip->strategy = srstrategy; 616 bv->sbv_diskinfo = dip; 617 dip->sr_vol = bv; 618 } 619 620 dip = bv->sbv_diskinfo; 621 622 if ((dip->flags & DISKINFO_FLAG_GOODLABEL) == 0) { 623 /* Attempt to read disklabel. */ 624 bv->sbv_part = 'c'; 625 if (sr_getdisklabel(bv, &dip->disklabel)) 626 return ERDLAB; 627 dip->flags |= DISKINFO_FLAG_GOODLABEL; 628 } 629 630 bv->sbv_part = part + 'a'; 631 632 bootdev_dip = dip; 633 f->f_devdata = dip; 634 635 return 0; 636 } 637 638 int 639 srstrategy(void *devdata, int rw, daddr_t blk, size_t size, void *buf, 640 size_t *rsize) 641 { 642 struct diskinfo *dip = (struct diskinfo *)devdata; 643 return sr_strategy(dip->sr_vol, rw, blk, size, buf, rsize); 644 } 645 646 int 647 srdiskio(int rw, struct diskinfo *dip, u_int off, int nsect, void *buf) 648 { 649 return dip->diskio(rw, dip, off, nsect, buf); 650 } 651 652 int 653 srclose(struct open_file *f) 654 { 655 f->f_devdata = NULL; 656 657 return 0; 658 } 659 660 int 661 srioctl(struct open_file *f, u_long cmd, void *data) 662 { 663 return 0; 664 } 665