1 /* $OpenBSD: softraid_arm64.c,v 1.4 2022/08/15 13:13:41 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_arm64.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
srprobe_meta_opt_load(struct sr_metadata * sm,struct sr_meta_opt_head * som)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
srprobe_keydisk_load(struct sr_metadata * sm)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
srprobe(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
sr_strategy(struct sr_boot_volume * bv,int rw,daddr_t blk,size_t size,void * buf,size_t * rsize)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
gpt_chk_mbr(struct dos_partition * dp,u_int64_t dsize)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
findopenbsd_gpt(struct sr_boot_volume * bv,const char ** err)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 *
sr_getdisklabel(struct sr_boot_volume * bv,struct disklabel * label)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
sropen(struct open_file * f,...)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
srstrategy(void * devdata,int rw,daddr_t blk,size_t size,void * buf,size_t * rsize)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
srdiskio(int rw,struct diskinfo * dip,u_int off,int nsect,void * buf)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
srclose(struct open_file * f)655 srclose(struct open_file *f)
656 {
657 f->f_devdata = NULL;
658
659 return 0;
660 }
661
662 int
srioctl(struct open_file * f,u_long cmd,void * data)663 srioctl(struct open_file *f, u_long cmd, void *data)
664 {
665 return 0;
666 }
667