xref: /openbsd-src/usr.sbin/installboot/softraid.c (revision 6dfaf0dfc1ad2a0831bbce5417be20f1b1ef9b0d)
1*6dfaf0dfSkn /*	$OpenBSD: softraid.c,v 1.9 2022/11/14 13:39:37 kn Exp $	*/
2a7036d21Sjsing /*
3a7036d21Sjsing  * Copyright (c) 2012 Joel Sing <jsing@openbsd.org>
4a7036d21Sjsing  *
5a7036d21Sjsing  * Permission to use, copy, modify, and distribute this software for any
6a7036d21Sjsing  * purpose with or without fee is hereby granted, provided that the above
7a7036d21Sjsing  * copyright notice and this permission notice appear in all copies.
8a7036d21Sjsing  *
9a7036d21Sjsing  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10a7036d21Sjsing  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11a7036d21Sjsing  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12a7036d21Sjsing  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13a7036d21Sjsing  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14a7036d21Sjsing  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15a7036d21Sjsing  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16a7036d21Sjsing  */
17a7036d21Sjsing 
18092d8916Skn #include <sys/types.h>
19092d8916Skn #include <sys/disklabel.h>
20a7036d21Sjsing #include <sys/dkio.h>
21a7036d21Sjsing #include <sys/ioctl.h>
22a7036d21Sjsing 
23a7036d21Sjsing #include <dev/biovar.h>
24a7036d21Sjsing 
25a7036d21Sjsing #include <err.h>
26092d8916Skn #include <fcntl.h>
27a7036d21Sjsing #include <stdio.h>
28a7036d21Sjsing #include <string.h>
2926ce53eaSkn #include <unistd.h>
30092d8916Skn #include <util.h>
31a7036d21Sjsing 
32a7036d21Sjsing #include "installboot.h"
33a7036d21Sjsing 
34a7036d21Sjsing static int sr_volume(int, char *, int *, int *);
35a7036d21Sjsing 
3626ce53eaSkn static void
sr_prepare_chunk(int devfd,int vol,int disk)3726ce53eaSkn sr_prepare_chunk(int devfd, int vol, int disk)
3826ce53eaSkn {
3926ce53eaSkn 	struct bioc_disk bd;
4026ce53eaSkn 	char *realdev;
4126ce53eaSkn 	char part;
4226ce53eaSkn 	int diskfd;
4326ce53eaSkn 
4426ce53eaSkn 	diskfd = sr_open_chunk(devfd, vol, disk, &bd, &realdev, &part);
4526ce53eaSkn 	if (diskfd == -1)
4626ce53eaSkn 		return;
4726ce53eaSkn 
4826ce53eaSkn 	/* Prepare file system on device. */
4926ce53eaSkn 	md_prepareboot(diskfd, realdev);
5026ce53eaSkn 
5126ce53eaSkn 	close(diskfd);
5226ce53eaSkn }
5326ce53eaSkn 
5426ce53eaSkn void
sr_prepareboot(int devfd,char * dev)5526ce53eaSkn sr_prepareboot(int devfd, char *dev)
5626ce53eaSkn {
5726ce53eaSkn 	int vol = -1, ndisks = 0, disk;
5826ce53eaSkn 
5926ce53eaSkn 	/* Use the normal process if this is not a softraid volume. */
6026ce53eaSkn 	if (!sr_volume(devfd, dev, &vol, &ndisks)) {
6126ce53eaSkn 		md_prepareboot(devfd, dev);
6226ce53eaSkn 		return;
6326ce53eaSkn 	}
6426ce53eaSkn 
6526ce53eaSkn 	/* Prepare file system on each disk that is part of this volume. */
6626ce53eaSkn 	for (disk = 0; disk < ndisks; disk++)
6726ce53eaSkn 		sr_prepare_chunk(devfd, vol, disk);
6826ce53eaSkn }
6926ce53eaSkn 
70a7036d21Sjsing void
sr_installboot(int devfd,char * dev)71a7036d21Sjsing sr_installboot(int devfd, char *dev)
72a7036d21Sjsing {
73a7036d21Sjsing 	int	vol = -1, ndisks = 0, disk;
74a7036d21Sjsing 
75a7036d21Sjsing 	/* Use the normal process if this is not a softraid volume. */
76a7036d21Sjsing 	if (!sr_volume(devfd, dev, &vol, &ndisks)) {
77a7036d21Sjsing 		md_installboot(devfd, dev);
78a7036d21Sjsing 		return;
79a7036d21Sjsing 	}
80a7036d21Sjsing 
81a7036d21Sjsing 	/* Install boot loader in softraid volume. */
82a7036d21Sjsing 	sr_install_bootldr(devfd, dev);
83a7036d21Sjsing 
84a7036d21Sjsing 	/* Install boot block on each disk that is part of this volume. */
85a7036d21Sjsing 	for (disk = 0; disk < ndisks; disk++)
86a7036d21Sjsing 		sr_install_bootblk(devfd, vol, disk);
87a7036d21Sjsing }
88a7036d21Sjsing 
89a7036d21Sjsing int
sr_volume(int devfd,char * dev,int * vol,int * disks)90a7036d21Sjsing sr_volume(int devfd, char *dev, int *vol, int *disks)
91a7036d21Sjsing {
92a7036d21Sjsing 	struct	bioc_inq bi;
93a7036d21Sjsing 	struct	bioc_vol bv;
94808c6500Sjsing 	int	i;
95a7036d21Sjsing 
96a7036d21Sjsing 	/*
97a7036d21Sjsing 	 * Determine if the given device is a softraid volume.
98a7036d21Sjsing 	 */
99a7036d21Sjsing 
100a7036d21Sjsing 	/* Get volume information. */
101a7036d21Sjsing 	memset(&bi, 0, sizeof(bi));
102808c6500Sjsing 	if (ioctl(devfd, BIOCINQ, &bi) == -1)
103a7036d21Sjsing 		return 0;
104a7036d21Sjsing 
105a7036d21Sjsing 	/* XXX - softraid volumes will always have a "softraid0" controller. */
106a7036d21Sjsing 	if (strncmp(bi.bi_dev, "softraid0", sizeof("softraid0")))
107a7036d21Sjsing 		return 0;
108a7036d21Sjsing 
109a7036d21Sjsing 	/*
110a7036d21Sjsing 	 * XXX - this only works with the real disk name (e.g. sd0) - this
111a7036d21Sjsing 	 * should be extracted from the device name, or better yet, fixed in
112a7036d21Sjsing 	 * the softraid ioctl.
113a7036d21Sjsing 	 */
114a7036d21Sjsing 	/* Locate specific softraid volume. */
115a7036d21Sjsing 	for (i = 0; i < bi.bi_novol; i++) {
116a7036d21Sjsing 		memset(&bv, 0, sizeof(bv));
117a7036d21Sjsing 		bv.bv_volid = i;
118808c6500Sjsing 		if (ioctl(devfd, BIOCVOL, &bv) == -1)
119a7036d21Sjsing 			err(1, "BIOCVOL");
120a7036d21Sjsing 
121a7036d21Sjsing 		if (strncmp(dev, bv.bv_dev, sizeof(bv.bv_dev)) == 0) {
122a7036d21Sjsing 			*vol = i;
123a7036d21Sjsing 			*disks = bv.bv_nodisk;
124a7036d21Sjsing 			break;
125a7036d21Sjsing 		}
126a7036d21Sjsing 	}
127a7036d21Sjsing 
128a7036d21Sjsing 	if (verbose)
129a7036d21Sjsing 		fprintf(stderr, "%s: softraid volume with %i disk(s)\n",
130a7036d21Sjsing 		    dev, *disks);
131a7036d21Sjsing 
132a7036d21Sjsing 	return 1;
133a7036d21Sjsing }
1349de342e3Skn 
1359de342e3Skn void
sr_status(struct bio_status * bs)1369de342e3Skn sr_status(struct bio_status *bs)
1379de342e3Skn {
1389de342e3Skn 	int	i;
1399de342e3Skn 
1409de342e3Skn 	for (i = 0; i < bs->bs_msg_count; i++)
1419de342e3Skn 		warnx("%s", bs->bs_msgs[i].bm_msg);
1429de342e3Skn 
1439de342e3Skn 	if (bs->bs_status == BIO_STATUS_ERROR) {
1449de342e3Skn 		if (bs->bs_msg_count == 0)
1459de342e3Skn 			errx(1, "unknown error");
1469de342e3Skn 		else
1479de342e3Skn 			exit(1);
1489de342e3Skn 	}
1499de342e3Skn }
150092d8916Skn 
151092d8916Skn int
sr_open_chunk(int devfd,int vol,int disk,struct bioc_disk * bd,char ** realdev,char * part)152092d8916Skn sr_open_chunk(int devfd, int vol, int disk, struct bioc_disk *bd,
153092d8916Skn     char **realdev, char *part)
154092d8916Skn {
155092d8916Skn 	int diskfd;
156092d8916Skn 
157092d8916Skn 	/* Get device name for this disk/chunk. */
158092d8916Skn 	memset(bd, 0, sizeof(*bd));
159092d8916Skn 	bd->bd_volid = vol;
160092d8916Skn 	bd->bd_diskid = disk;
161092d8916Skn 	if (ioctl(devfd, BIOCDISK, bd) == -1)
162092d8916Skn 		err(1, "BIOCDISK");
163092d8916Skn 
164092d8916Skn 	/* Check disk status. */
165092d8916Skn 	if (bd->bd_status != BIOC_SDONLINE &&
166092d8916Skn 	    bd->bd_status != BIOC_SDREBUILD) {
167092d8916Skn 		fprintf(stderr, "softraid chunk %u not online - skipping...\n",
168092d8916Skn 		    disk);
169092d8916Skn 		return -1;
170092d8916Skn 	}
171092d8916Skn 
172*6dfaf0dfSkn 	/* Keydisks always have a size of zero. */
173*6dfaf0dfSkn 	if (bd->bd_size == 0)
174*6dfaf0dfSkn 		return -1;
175*6dfaf0dfSkn 
176092d8916Skn 	if (strlen(bd->bd_vendor) < 1)
177092d8916Skn 		errx(1, "invalid disk name");
178092d8916Skn 	*part = bd->bd_vendor[strlen(bd->bd_vendor) - 1];
179092d8916Skn 	if (*part < 'a' || *part >= 'a' + MAXPARTITIONS)
180092d8916Skn 		errx(1, "invalid partition %c\n", *part);
181092d8916Skn 	bd->bd_vendor[strlen(bd->bd_vendor) - 1] = '\0';
182092d8916Skn 
183092d8916Skn 	/* Open device. */
184092d8916Skn 	if ((diskfd = opendev(bd->bd_vendor, (nowrite ? O_RDONLY : O_RDWR),
185092d8916Skn 	    OPENDEV_PART, realdev)) == -1)
186092d8916Skn 		err(1, "open: %s", *realdev);
187092d8916Skn 
188092d8916Skn 	return diskfd;
189092d8916Skn }
190