1 /* $OpenBSD: softraid.c,v 1.6 2022/11/07 15:56:09 kn Exp $ */ 2 /* 3 * Copyright (c) 2012 Joel Sing <jsing@openbsd.org> 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18 #include <sys/types.h> 19 #include <sys/disklabel.h> 20 #include <sys/dkio.h> 21 #include <sys/ioctl.h> 22 23 #include <dev/biovar.h> 24 25 #include <err.h> 26 #include <fcntl.h> 27 #include <stdio.h> 28 #include <string.h> 29 #include <util.h> 30 31 #include "installboot.h" 32 33 static int sr_volume(int, char *, int *, int *); 34 35 void 36 sr_installboot(int devfd, char *dev) 37 { 38 int vol = -1, ndisks = 0, disk; 39 40 /* Use the normal process if this is not a softraid volume. */ 41 if (!sr_volume(devfd, dev, &vol, &ndisks)) { 42 md_installboot(devfd, dev); 43 return; 44 } 45 46 /* Install boot loader in softraid volume. */ 47 sr_install_bootldr(devfd, dev); 48 49 /* Install boot block on each disk that is part of this volume. */ 50 for (disk = 0; disk < ndisks; disk++) 51 sr_install_bootblk(devfd, vol, disk); 52 } 53 54 int 55 sr_volume(int devfd, char *dev, int *vol, int *disks) 56 { 57 struct bioc_inq bi; 58 struct bioc_vol bv; 59 int i; 60 61 /* 62 * Determine if the given device is a softraid volume. 63 */ 64 65 /* Get volume information. */ 66 memset(&bi, 0, sizeof(bi)); 67 if (ioctl(devfd, BIOCINQ, &bi) == -1) 68 return 0; 69 70 /* XXX - softraid volumes will always have a "softraid0" controller. */ 71 if (strncmp(bi.bi_dev, "softraid0", sizeof("softraid0"))) 72 return 0; 73 74 /* 75 * XXX - this only works with the real disk name (e.g. sd0) - this 76 * should be extracted from the device name, or better yet, fixed in 77 * the softraid ioctl. 78 */ 79 /* Locate specific softraid volume. */ 80 for (i = 0; i < bi.bi_novol; i++) { 81 memset(&bv, 0, sizeof(bv)); 82 bv.bv_volid = i; 83 if (ioctl(devfd, BIOCVOL, &bv) == -1) 84 err(1, "BIOCVOL"); 85 86 if (strncmp(dev, bv.bv_dev, sizeof(bv.bv_dev)) == 0) { 87 *vol = i; 88 *disks = bv.bv_nodisk; 89 break; 90 } 91 } 92 93 if (verbose) 94 fprintf(stderr, "%s: softraid volume with %i disk(s)\n", 95 dev, *disks); 96 97 return 1; 98 } 99 100 void 101 sr_status(struct bio_status *bs) 102 { 103 int i; 104 105 for (i = 0; i < bs->bs_msg_count; i++) 106 warnx("%s", bs->bs_msgs[i].bm_msg); 107 108 if (bs->bs_status == BIO_STATUS_ERROR) { 109 if (bs->bs_msg_count == 0) 110 errx(1, "unknown error"); 111 else 112 exit(1); 113 } 114 } 115 116 int 117 sr_open_chunk(int devfd, int vol, int disk, struct bioc_disk *bd, 118 char **realdev, char *part) 119 { 120 int diskfd; 121 122 /* Get device name for this disk/chunk. */ 123 memset(bd, 0, sizeof(*bd)); 124 bd->bd_volid = vol; 125 bd->bd_diskid = disk; 126 if (ioctl(devfd, BIOCDISK, bd) == -1) 127 err(1, "BIOCDISK"); 128 129 /* Check disk status. */ 130 if (bd->bd_status != BIOC_SDONLINE && 131 bd->bd_status != BIOC_SDREBUILD) { 132 fprintf(stderr, "softraid chunk %u not online - skipping...\n", 133 disk); 134 return -1; 135 } 136 137 /* Keydisks always have a size of zero. */ 138 if (bd->bd_size == 0) { 139 fprintf(stderr, "softraid chunk %u is keydisk - skipping...\n", 140 disk); 141 return -1; 142 } 143 144 if (strlen(bd->bd_vendor) < 1) 145 errx(1, "invalid disk name"); 146 *part = bd->bd_vendor[strlen(bd->bd_vendor) - 1]; 147 if (*part < 'a' || *part >= 'a' + MAXPARTITIONS) 148 errx(1, "invalid partition %c\n", *part); 149 bd->bd_vendor[strlen(bd->bd_vendor) - 1] = '\0'; 150 151 /* Open device. */ 152 if ((diskfd = opendev(bd->bd_vendor, (nowrite ? O_RDONLY : O_RDWR), 153 OPENDEV_PART, realdev)) == -1) 154 err(1, "open: %s", *realdev); 155 156 return diskfd; 157 } 158