xref: /openbsd-src/sys/arch/sparc64/stand/ofwboot/softraid_sparc64.c (revision 5655a256dbe5dc1bd6b61d3678a678d3d6925e55)
1*5655a256Skrw /*	$OpenBSD: softraid_sparc64.c,v 1.8 2023/06/03 21:37:53 krw Exp $	*/
265f4a3c7Sjsing 
365f4a3c7Sjsing /*
465f4a3c7Sjsing  * Copyright (c) 2012 Joel Sing <jsing@openbsd.org>
565f4a3c7Sjsing  *
665f4a3c7Sjsing  * Permission to use, copy, modify, and distribute this software for any
765f4a3c7Sjsing  * purpose with or without fee is hereby granted, provided that the above
865f4a3c7Sjsing  * copyright notice and this permission notice appear in all copies.
965f4a3c7Sjsing  *
1065f4a3c7Sjsing  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1165f4a3c7Sjsing  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1265f4a3c7Sjsing  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1365f4a3c7Sjsing  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1465f4a3c7Sjsing  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1565f4a3c7Sjsing  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1665f4a3c7Sjsing  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1765f4a3c7Sjsing  */
1865f4a3c7Sjsing 
1965f4a3c7Sjsing #include <sys/param.h>
2065f4a3c7Sjsing #include <sys/queue.h>
2165f4a3c7Sjsing #include <sys/disklabel.h>
2265f4a3c7Sjsing #include <sys/reboot.h>
2365f4a3c7Sjsing 
2465f4a3c7Sjsing #include <dev/biovar.h>
2565f4a3c7Sjsing #include <dev/softraidvar.h>
2665f4a3c7Sjsing 
2765f4a3c7Sjsing #include <lib/libsa/stand.h>
2865f4a3c7Sjsing #include <lib/libsa/aes_xts.h>
29822493b2Sjsing #include <lib/libsa/softraid.h>
3065f4a3c7Sjsing 
3165f4a3c7Sjsing #include "disk.h"
326c45f45cSclaudio #include "openfirm.h"
3365f4a3c7Sjsing #include "ofdev.h"
3465f4a3c7Sjsing #include "softraid_sparc64.h"
3565f4a3c7Sjsing 
3665f4a3c7Sjsing void
srprobe_meta_opt_load(struct sr_metadata * sm,struct sr_meta_opt_head * som)3765f4a3c7Sjsing srprobe_meta_opt_load(struct sr_metadata *sm, struct sr_meta_opt_head *som)
3865f4a3c7Sjsing {
3965f4a3c7Sjsing 	struct sr_meta_opt_hdr	*omh;
4065f4a3c7Sjsing 	struct sr_meta_opt_item *omi;
4165f4a3c7Sjsing #if 0
4265f4a3c7Sjsing 	u_int8_t checksum[MD5_DIGEST_LENGTH];
4365f4a3c7Sjsing #endif
4465f4a3c7Sjsing 	int			i;
4565f4a3c7Sjsing 
4665f4a3c7Sjsing 	/* Process optional metadata. */
4765f4a3c7Sjsing 	omh = (struct sr_meta_opt_hdr *)((u_int8_t *)(sm + 1) +
4865f4a3c7Sjsing 	    sizeof(struct sr_meta_chunk) * sm->ssdi.ssd_chunk_no);
4965f4a3c7Sjsing 	for (i = 0; i < sm->ssdi.ssd_opt_no; i++) {
5065f4a3c7Sjsing 
5165f4a3c7Sjsing #ifdef DEBUG
5265f4a3c7Sjsing 		printf("Found optional metadata of type %u, length %u\n",
5365f4a3c7Sjsing 		    omh->som_type, omh->som_length);
5465f4a3c7Sjsing #endif
5565f4a3c7Sjsing 
5665f4a3c7Sjsing 		/* Unsupported old fixed length optional metadata. */
5765f4a3c7Sjsing 		if (omh->som_length == 0) {
5865f4a3c7Sjsing 			omh = (struct sr_meta_opt_hdr *)((void *)omh +
5965f4a3c7Sjsing 			    SR_OLD_META_OPT_SIZE);
6065f4a3c7Sjsing 			continue;
6165f4a3c7Sjsing 		}
6265f4a3c7Sjsing 
6365f4a3c7Sjsing 		/* Load variable length optional metadata. */
6465f4a3c7Sjsing 		omi = alloc(sizeof(struct sr_meta_opt_item));
6565f4a3c7Sjsing 		bzero(omi, sizeof(struct sr_meta_opt_item));
6665f4a3c7Sjsing 		SLIST_INSERT_HEAD(som, omi, omi_link);
6765f4a3c7Sjsing 		omi->omi_som = alloc(omh->som_length);
6865f4a3c7Sjsing 		bzero(omi->omi_som, omh->som_length);
6965f4a3c7Sjsing 		bcopy(omh, omi->omi_som, omh->som_length);
7065f4a3c7Sjsing 
7165f4a3c7Sjsing #if 0
7265f4a3c7Sjsing 		/* XXX - Validate checksum. */
7365f4a3c7Sjsing 		bcopy(&omi->omi_som->som_checksum, &checksum,
7465f4a3c7Sjsing 		    MD5_DIGEST_LENGTH);
7565f4a3c7Sjsing 		bzero(&omi->omi_som->som_checksum, MD5_DIGEST_LENGTH);
7665f4a3c7Sjsing 		sr_checksum(sc, omi->omi_som,
7765f4a3c7Sjsing 		    &omi->omi_som->som_checksum, omh->som_length);
7865f4a3c7Sjsing 		if (bcmp(&checksum, &omi->omi_som->som_checksum,
7965f4a3c7Sjsing 		    sizeof(checksum)))
8065f4a3c7Sjsing 			panic("%s: invalid optional metadata checksum",
8165f4a3c7Sjsing 			    DEVNAME(sc));
8265f4a3c7Sjsing #endif
8365f4a3c7Sjsing 
8465f4a3c7Sjsing 		omh = (struct sr_meta_opt_hdr *)((void *)omh +
8565f4a3c7Sjsing 		    omh->som_length);
8665f4a3c7Sjsing 	}
8765f4a3c7Sjsing }
8865f4a3c7Sjsing 
8965f4a3c7Sjsing void
srprobe_keydisk_load(struct sr_metadata * sm)9065f4a3c7Sjsing srprobe_keydisk_load(struct sr_metadata *sm)
9165f4a3c7Sjsing {
9265f4a3c7Sjsing 	struct sr_meta_opt_hdr	*omh;
9365f4a3c7Sjsing 	struct sr_meta_keydisk	*skm;
9465f4a3c7Sjsing 	struct sr_boot_keydisk	*kd;
9565f4a3c7Sjsing 	int i;
9665f4a3c7Sjsing 
9765f4a3c7Sjsing 	/* Process optional metadata. */
9865f4a3c7Sjsing 	omh = (struct sr_meta_opt_hdr *)((u_int8_t *)(sm + 1) +
9965f4a3c7Sjsing 	    sizeof(struct sr_meta_chunk) * sm->ssdi.ssd_chunk_no);
10065f4a3c7Sjsing 	for (i = 0; i < sm->ssdi.ssd_opt_no; i++) {
10165f4a3c7Sjsing 
10265f4a3c7Sjsing 		/* Unsupported old fixed length optional metadata. */
10365f4a3c7Sjsing 		if (omh->som_length == 0) {
10465f4a3c7Sjsing 			omh = (struct sr_meta_opt_hdr *)((void *)omh +
10565f4a3c7Sjsing 			    SR_OLD_META_OPT_SIZE);
10665f4a3c7Sjsing 			continue;
10765f4a3c7Sjsing 		}
10865f4a3c7Sjsing 
10965f4a3c7Sjsing 		if (omh->som_type != SR_OPT_KEYDISK) {
11065f4a3c7Sjsing 			omh = (struct sr_meta_opt_hdr *)((void *)omh +
11165f4a3c7Sjsing 			    omh->som_length);
11265f4a3c7Sjsing 			continue;
11365f4a3c7Sjsing 		}
11465f4a3c7Sjsing 
11565f4a3c7Sjsing 		kd = alloc(sizeof(struct sr_boot_keydisk));
11665f4a3c7Sjsing 		bcopy(&sm->ssdi.ssd_uuid, &kd->kd_uuid, sizeof(kd->kd_uuid));
11765f4a3c7Sjsing 		skm = (struct sr_meta_keydisk*)omh;
11865f4a3c7Sjsing 		bcopy(&skm->skm_maskkey, &kd->kd_key, sizeof(kd->kd_key));
11965f4a3c7Sjsing 		SLIST_INSERT_HEAD(&sr_keydisks, kd, kd_link);
12065f4a3c7Sjsing 	}
12165f4a3c7Sjsing }
12265f4a3c7Sjsing 
12365f4a3c7Sjsing void
srprobe(void)12465f4a3c7Sjsing srprobe(void)
12565f4a3c7Sjsing {
12665f4a3c7Sjsing 	struct sr_boot_volume *bv, *bv1, *bv2;
12765f4a3c7Sjsing 	struct sr_boot_chunk *bc, *bc1, *bc2;
12865f4a3c7Sjsing 	struct sr_meta_chunk *mc;
12965f4a3c7Sjsing 	struct sr_metadata *md;
13065f4a3c7Sjsing 	struct diskinfo *dip;
13165f4a3c7Sjsing 	struct partition *pp;
13265f4a3c7Sjsing 	struct of_dev ofdev;
13365f4a3c7Sjsing 	size_t read;
13465f4a3c7Sjsing 	int i, error, diskno, volno, ihandle;
13565f4a3c7Sjsing 	dev_t bsd_dev;
13665f4a3c7Sjsing 
13765f4a3c7Sjsing 	/* Probe for softraid volumes. */
13865f4a3c7Sjsing 	SLIST_INIT(&sr_volumes);
13965f4a3c7Sjsing 	SLIST_INIT(&sr_keydisks);
14065f4a3c7Sjsing 
14165f4a3c7Sjsing 	md = alloc(SR_META_SIZE * DEV_BSIZE);
14265f4a3c7Sjsing 	diskno = 0;
14365f4a3c7Sjsing 	ihandle = -1;
14465f4a3c7Sjsing 	TAILQ_FOREACH(dip, &disklist, list) {
14565f4a3c7Sjsing 		ihandle = OF_open(dip->path);
14665f4a3c7Sjsing 		if (ihandle == -1)
14765f4a3c7Sjsing 			continue;
14865f4a3c7Sjsing 		bzero(&ofdev, sizeof(ofdev));
14965f4a3c7Sjsing 		ofdev.handle = ihandle;
15065f4a3c7Sjsing 		ofdev.type = OFDEV_DISK;
15165f4a3c7Sjsing 		ofdev.bsize = DEV_BSIZE;
15265f4a3c7Sjsing 		for (i = 0; i < MAXPARTITIONS; i++) {
15365f4a3c7Sjsing 			pp = &dip->disklabel.d_partitions[i];
15465f4a3c7Sjsing 			if (pp->p_fstype != FS_RAID || pp->p_size == 0)
15565f4a3c7Sjsing 				continue;
15665f4a3c7Sjsing 
15765f4a3c7Sjsing 			/* Read softraid metadata. */
15865f4a3c7Sjsing 			bzero(md, SR_META_SIZE * DEV_BSIZE);
15965f4a3c7Sjsing 			ofdev.partoff = DL_SECTOBLK(&dip->disklabel,
16065f4a3c7Sjsing 			    DL_GETPOFFSET(pp));
16165f4a3c7Sjsing 			error = strategy(&ofdev, F_READ, SR_META_OFFSET,
16265f4a3c7Sjsing 			    SR_META_SIZE * DEV_BSIZE, md, &read);
16365f4a3c7Sjsing 			if (error || read != SR_META_SIZE * DEV_BSIZE)
16465f4a3c7Sjsing 				continue;
16565f4a3c7Sjsing 
16665f4a3c7Sjsing 			/* Is this valid softraid metadata? */
16765f4a3c7Sjsing 			if (md->ssdi.ssd_magic != SR_MAGIC)
16865f4a3c7Sjsing 				continue;
16965f4a3c7Sjsing 
17065f4a3c7Sjsing 			/* XXX - validate checksum. */
17165f4a3c7Sjsing 
17265f4a3c7Sjsing 			/* Handle key disks separately... */
17365f4a3c7Sjsing 			if (md->ssdi.ssd_level == SR_KEYDISK_LEVEL) {
17465f4a3c7Sjsing 				srprobe_keydisk_load(md);
17565f4a3c7Sjsing 				continue;
17665f4a3c7Sjsing 			}
17765f4a3c7Sjsing 
17865f4a3c7Sjsing 			/* Locate chunk-specific metadata for this chunk. */
17965f4a3c7Sjsing 			mc = (struct sr_meta_chunk *)(md + 1);
18065f4a3c7Sjsing 			mc += md->ssdi.ssd_chunk_id;
18165f4a3c7Sjsing 
18265f4a3c7Sjsing 			bc = alloc(sizeof(struct sr_boot_chunk));
18365f4a3c7Sjsing 			bc->sbc_diskinfo = dip;
18465f4a3c7Sjsing 			bc->sbc_disk = diskno++;
18565f4a3c7Sjsing 			bc->sbc_part = 'a' + i;
18665f4a3c7Sjsing 
18765f4a3c7Sjsing 			bsd_dev = MAKEBOOTDEV(
18865f4a3c7Sjsing 			    dip->disklabel.d_type == DTYPE_SCSI ? 4 : 0,
18965f4a3c7Sjsing 			    0, 0, diskno, RAW_PART);
19065f4a3c7Sjsing 			bc->sbc_mm = MAKEBOOTDEV(B_TYPE(bsd_dev),
19165f4a3c7Sjsing 			    B_ADAPTOR(bsd_dev), B_CONTROLLER(bsd_dev),
19265f4a3c7Sjsing 			    B_UNIT(bsd_dev), bc->sbc_part - 'a');
19365f4a3c7Sjsing 
19465f4a3c7Sjsing 			bc->sbc_chunk_id = md->ssdi.ssd_chunk_id;
19565f4a3c7Sjsing 			bc->sbc_ondisk = md->ssd_ondisk;
19665f4a3c7Sjsing 			bc->sbc_state = mc->scm_status;
19765f4a3c7Sjsing 
19865f4a3c7Sjsing 			SLIST_FOREACH(bv, &sr_volumes, sbv_link) {
19965f4a3c7Sjsing 				if (bcmp(&md->ssdi.ssd_uuid, &bv->sbv_uuid,
20065f4a3c7Sjsing 				    sizeof(md->ssdi.ssd_uuid)) == 0)
20165f4a3c7Sjsing 					break;
20265f4a3c7Sjsing 			}
20365f4a3c7Sjsing 
20465f4a3c7Sjsing 			if (bv == NULL) {
20565f4a3c7Sjsing 				bv = alloc(sizeof(struct sr_boot_volume));
20665f4a3c7Sjsing 				bzero(bv, sizeof(struct sr_boot_volume));
20765f4a3c7Sjsing 				bv->sbv_level = md->ssdi.ssd_level;
20865f4a3c7Sjsing 				bv->sbv_volid = md->ssdi.ssd_volid;
20965f4a3c7Sjsing 				bv->sbv_chunk_no = md->ssdi.ssd_chunk_no;
21065f4a3c7Sjsing 				bv->sbv_flags = md->ssdi.ssd_vol_flags;
21165f4a3c7Sjsing 				bv->sbv_size = md->ssdi.ssd_size;
21265f4a3c7Sjsing 				bv->sbv_data_blkno = md->ssd_data_blkno;
21365f4a3c7Sjsing 				bcopy(&md->ssdi.ssd_uuid, &bv->sbv_uuid,
21465f4a3c7Sjsing 				    sizeof(md->ssdi.ssd_uuid));
21565f4a3c7Sjsing 				SLIST_INIT(&bv->sbv_chunks);
21665f4a3c7Sjsing 				SLIST_INIT(&bv->sbv_meta_opt);
21765f4a3c7Sjsing 
21865f4a3c7Sjsing 				/* Load optional metadata for this volume. */
21965f4a3c7Sjsing 				srprobe_meta_opt_load(md, &bv->sbv_meta_opt);
22065f4a3c7Sjsing 
22165f4a3c7Sjsing 				/* Maintain volume order. */
22265f4a3c7Sjsing 				bv2 = NULL;
22365f4a3c7Sjsing 				SLIST_FOREACH(bv1, &sr_volumes, sbv_link) {
22465f4a3c7Sjsing 					if (bv1->sbv_volid > bv->sbv_volid)
22565f4a3c7Sjsing 						break;
22665f4a3c7Sjsing 					bv2 = bv1;
22765f4a3c7Sjsing 				}
22865f4a3c7Sjsing 				if (bv2 == NULL)
22965f4a3c7Sjsing 					SLIST_INSERT_HEAD(&sr_volumes, bv,
23065f4a3c7Sjsing 					    sbv_link);
23165f4a3c7Sjsing 				else
23265f4a3c7Sjsing 					SLIST_INSERT_AFTER(bv2, bv, sbv_link);
23365f4a3c7Sjsing 			}
23465f4a3c7Sjsing 
23565f4a3c7Sjsing 			/* Maintain chunk order. */
23665f4a3c7Sjsing 			bc2 = NULL;
23765f4a3c7Sjsing 			SLIST_FOREACH(bc1, &bv->sbv_chunks, sbc_link) {
23865f4a3c7Sjsing 				if (bc1->sbc_chunk_id > bc->sbc_chunk_id)
23965f4a3c7Sjsing 					break;
24065f4a3c7Sjsing 				bc2 = bc1;
24165f4a3c7Sjsing 			}
24265f4a3c7Sjsing 			if (bc2 == NULL)
24365f4a3c7Sjsing 				SLIST_INSERT_HEAD(&bv->sbv_chunks,
24465f4a3c7Sjsing 				    bc, sbc_link);
24565f4a3c7Sjsing 			else
24665f4a3c7Sjsing 				SLIST_INSERT_AFTER(bc2, bc, sbc_link);
24765f4a3c7Sjsing 
24865f4a3c7Sjsing 			bv->sbv_chunks_found++;
24965f4a3c7Sjsing 		}
25065f4a3c7Sjsing 		OF_close(ihandle);
25165f4a3c7Sjsing 	}
25265f4a3c7Sjsing 
25365f4a3c7Sjsing 	/*
25465f4a3c7Sjsing 	 * Assemble RAID volumes.
25565f4a3c7Sjsing 	 */
25665f4a3c7Sjsing 	volno = 0;
25765f4a3c7Sjsing 	SLIST_FOREACH(bv, &sr_volumes, sbv_link) {
25865f4a3c7Sjsing 
25965f4a3c7Sjsing 		/* Skip if this is a hotspare "volume". */
26065f4a3c7Sjsing 		if (bv->sbv_level == SR_HOTSPARE_LEVEL &&
26165f4a3c7Sjsing 		    bv->sbv_chunk_no == 1)
26265f4a3c7Sjsing 			continue;
26365f4a3c7Sjsing 
26465f4a3c7Sjsing 		/* Determine current ondisk version. */
26565f4a3c7Sjsing 		bv->sbv_ondisk = 0;
26665f4a3c7Sjsing 		SLIST_FOREACH(bc, &bv->sbv_chunks, sbc_link) {
26765f4a3c7Sjsing 			if (bc->sbc_ondisk > bv->sbv_ondisk)
26865f4a3c7Sjsing 				bv->sbv_ondisk = bc->sbc_ondisk;
26965f4a3c7Sjsing 		}
27065f4a3c7Sjsing 		SLIST_FOREACH(bc, &bv->sbv_chunks, sbc_link) {
27165f4a3c7Sjsing 			if (bc->sbc_ondisk != bv->sbv_ondisk)
27265f4a3c7Sjsing 				bc->sbc_state = BIOC_SDOFFLINE;
27365f4a3c7Sjsing 		}
27465f4a3c7Sjsing 
27565f4a3c7Sjsing 		/* XXX - Check for duplicate chunks. */
27665f4a3c7Sjsing 
27765f4a3c7Sjsing 		/*
27865f4a3c7Sjsing 		 * Validate that volume has sufficient chunks for
27965f4a3c7Sjsing 		 * read-only access.
28065f4a3c7Sjsing 		 *
28165f4a3c7Sjsing 		 * XXX - check chunk states.
28265f4a3c7Sjsing 		 */
28365f4a3c7Sjsing 		bv->sbv_state = BIOC_SVOFFLINE;
28465f4a3c7Sjsing 		switch (bv->sbv_level) {
28565f4a3c7Sjsing 		case 0:
28665f4a3c7Sjsing 		case 'C':
28765f4a3c7Sjsing 		case 'c':
28865f4a3c7Sjsing 			if (bv->sbv_chunk_no == bv->sbv_chunks_found)
28965f4a3c7Sjsing 				bv->sbv_state = BIOC_SVONLINE;
29065f4a3c7Sjsing 			break;
29165f4a3c7Sjsing 
29265f4a3c7Sjsing 		case 1:
293172b98bfSkn 		case 0x1C:
29465f4a3c7Sjsing 			if (bv->sbv_chunk_no == bv->sbv_chunks_found)
29565f4a3c7Sjsing 				bv->sbv_state = BIOC_SVONLINE;
29665f4a3c7Sjsing 			else if (bv->sbv_chunks_found > 0)
29765f4a3c7Sjsing 				bv->sbv_state = BIOC_SVDEGRADED;
29865f4a3c7Sjsing 			break;
29965f4a3c7Sjsing 		}
30065f4a3c7Sjsing 
30165f4a3c7Sjsing 		bv->sbv_unit = volno++;
30265f4a3c7Sjsing 		if (bv->sbv_state != BIOC_SVOFFLINE)
30365f4a3c7Sjsing 			printf("sr%d%s\n", bv->sbv_unit,
30465f4a3c7Sjsing 			    bv->sbv_flags & BIOC_SCBOOTABLE ? "*" : "");
30565f4a3c7Sjsing 	}
30665f4a3c7Sjsing 
30765f4a3c7Sjsing 	explicit_bzero(md, SR_META_SIZE * DEV_BSIZE);
30865f4a3c7Sjsing 	free(md, SR_META_SIZE * DEV_BSIZE);
30965f4a3c7Sjsing }
31065f4a3c7Sjsing 
311a45f661fSstsp struct sr_boot_chunk *
sr_vol_boot_chunk(struct sr_boot_volume * bv)312a45f661fSstsp sr_vol_boot_chunk(struct sr_boot_volume *bv)
313a45f661fSstsp {
314a45f661fSstsp 	struct sr_boot_chunk *bc = NULL;
315a45f661fSstsp 
316172b98bfSkn 	if (bv->sbv_level == 1 || bv->sbv_level == 'C' ||
317172b98bfSkn 	    bv->sbv_level == 0x1C) {
318a45f661fSstsp 		/* Select first online chunk. */
319a45f661fSstsp 		SLIST_FOREACH(bc, &bv->sbv_chunks, sbc_link)
320a45f661fSstsp 			if (bc->sbc_state == BIOC_SDONLINE)
321a45f661fSstsp 				break;
322a45f661fSstsp 	}
323a45f661fSstsp 
324a45f661fSstsp 	return bc;
325a45f661fSstsp }
326a45f661fSstsp 
327a45f661fSstsp 
32865f4a3c7Sjsing int
sr_strategy(struct sr_boot_volume * bv,int sr_handle,int rw,daddr_t blk,size_t size,void * buf,size_t * rsize)3293e58d19eSkrw sr_strategy(struct sr_boot_volume *bv, int sr_handle, int rw, daddr_t blk,
330a45f661fSstsp     size_t size, void *buf, size_t *rsize)
33165f4a3c7Sjsing {
33265f4a3c7Sjsing 	struct diskinfo *sr_dip, *dip;
33365f4a3c7Sjsing 	struct partition *pp;
33465f4a3c7Sjsing 	struct sr_boot_chunk *bc;
33565f4a3c7Sjsing 	struct aes_xts_ctx ctx;
33665f4a3c7Sjsing 	struct of_dev ofdev;
33765f4a3c7Sjsing 	size_t i, j, nsect;
33865f4a3c7Sjsing 	daddr_t blkno;
33965f4a3c7Sjsing 	u_char iv[8];
34065f4a3c7Sjsing 	u_char *bp;
34165f4a3c7Sjsing 	int err;
34265f4a3c7Sjsing 
34365f4a3c7Sjsing 	/* We only support read-only softraid. */
34465f4a3c7Sjsing 	if (rw != F_READ)
34565f4a3c7Sjsing 		return ENOTSUP;
34665f4a3c7Sjsing 
34765f4a3c7Sjsing 	/* Partition offset within softraid volume. */
34865f4a3c7Sjsing 	sr_dip = (struct diskinfo *)bv->sbv_diskinfo;
34965f4a3c7Sjsing 	blk +=
35065f4a3c7Sjsing 	    DL_GETPOFFSET(&sr_dip->disklabel.d_partitions[bv->sbv_part - 'a']);
35165f4a3c7Sjsing 
352a45f661fSstsp 	bc = sr_vol_boot_chunk(bv);
353a45f661fSstsp 	if (bc == NULL)
354a45f661fSstsp 		return ENXIO;
355a45f661fSstsp 
356a45f661fSstsp 	dip = (struct diskinfo *)bc->sbc_diskinfo;
357a45f661fSstsp 	pp = &dip->disklabel.d_partitions[bc->sbc_part - 'a'];
358a45f661fSstsp 	bzero(&ofdev, sizeof(ofdev));
359a45f661fSstsp 	ofdev.handle = sr_handle;
360a45f661fSstsp 	ofdev.type = OFDEV_DISK;
361a45f661fSstsp 	ofdev.bsize = DEV_BSIZE;
362a45f661fSstsp 	ofdev.partoff = DL_GETPOFFSET(pp);
363a45f661fSstsp 
36465f4a3c7Sjsing 	if (bv->sbv_level == 0) {
36565f4a3c7Sjsing 		return ENOTSUP;
36665f4a3c7Sjsing 	} else if (bv->sbv_level == 1) {
36765f4a3c7Sjsing 		blk += bv->sbv_data_blkno;
36865f4a3c7Sjsing 
36965f4a3c7Sjsing 		/* XXX - If I/O failed we should try another chunk... */
37065f4a3c7Sjsing 		err = strategy(&ofdev, rw, blk, size, buf, rsize);
37165f4a3c7Sjsing 		return err;
37265f4a3c7Sjsing 
373172b98bfSkn 	} else if (bv->sbv_level == 'C' || bv->sbv_level == 0x1C) {
37465f4a3c7Sjsing 		/* XXX - select correct key. */
37565f4a3c7Sjsing 		aes_xts_setkey(&ctx, (u_char *)bv->sbv_keys, 64);
37665f4a3c7Sjsing 
37765f4a3c7Sjsing 		nsect = (size + DEV_BSIZE - 1) / DEV_BSIZE;
37865f4a3c7Sjsing 		for (i = 0; i < nsect; i++) {
37965f4a3c7Sjsing 			blkno = blk + i;
38065f4a3c7Sjsing 			bp = ((u_char *)buf) + i * DEV_BSIZE;
38165f4a3c7Sjsing 
38265f4a3c7Sjsing 			err = strategy(&ofdev, rw,
38365f4a3c7Sjsing 			    bv->sbv_data_blkno + blkno,
38465f4a3c7Sjsing 			    DEV_BSIZE, bp, rsize);
38565f4a3c7Sjsing 			if (err != 0 || *rsize != DEV_BSIZE) {
38665f4a3c7Sjsing 				printf("Read from crypto volume failed "
38765f4a3c7Sjsing 				    "(read %d bytes): %s\n", *rsize,
38865f4a3c7Sjsing 				    strerror(err));
38965f4a3c7Sjsing 				return err;
39065f4a3c7Sjsing 			}
39165f4a3c7Sjsing 			bcopy(&blkno, iv, sizeof(blkno));
39265f4a3c7Sjsing 			aes_xts_reinit(&ctx, iv);
39365f4a3c7Sjsing 			for (j = 0; j < DEV_BSIZE; j += AES_XTS_BLOCKSIZE)
39465f4a3c7Sjsing 				aes_xts_decrypt(&ctx, bp + j);
39565f4a3c7Sjsing 		}
39665f4a3c7Sjsing 		*rsize = nsect * DEV_BSIZE;
39765f4a3c7Sjsing 		return err;
39865f4a3c7Sjsing 
39965f4a3c7Sjsing 	} else
40065f4a3c7Sjsing 		return ENOTSUP;
40165f4a3c7Sjsing }
40265f4a3c7Sjsing 
40365f4a3c7Sjsing const char *
sr_getdisklabel(struct sr_boot_volume * bv,struct disklabel * label)40465f4a3c7Sjsing sr_getdisklabel(struct sr_boot_volume *bv, struct disklabel *label)
40565f4a3c7Sjsing {
40665f4a3c7Sjsing 	struct of_dev ofdev;
40765f4a3c7Sjsing #ifdef DEBUG
40865f4a3c7Sjsing 	int i;
40965f4a3c7Sjsing #endif
41065f4a3c7Sjsing 
41165f4a3c7Sjsing 	bzero(&ofdev, sizeof ofdev);
41265f4a3c7Sjsing 	ofdev.type = OFDEV_SOFTRAID;
41365f4a3c7Sjsing 
41465f4a3c7Sjsing 	if (load_disklabel(&ofdev, label))
41565f4a3c7Sjsing 		return ("Could not read disklabel from softraid");
41665f4a3c7Sjsing #ifdef DEBUG
41765f4a3c7Sjsing 	printf("sr_getdisklabel: magic %lx\n", label->d_magic);
41865f4a3c7Sjsing 	for (i = 0; i < MAXPARTITIONS; i++)
41965f4a3c7Sjsing 		printf("part %c: type = %d, size = %d, offset = %d\n", 'a' + i,
42065f4a3c7Sjsing 		    (int)label->d_partitions[i].p_fstype,
42165f4a3c7Sjsing 		    (int)label->d_partitions[i].p_size,
42265f4a3c7Sjsing 		    (int)label->d_partitions[i].p_offset);
42365f4a3c7Sjsing #endif
42465f4a3c7Sjsing 
42565f4a3c7Sjsing 	return (NULL);
42665f4a3c7Sjsing }
427