1 /* $NetBSD: rdb.c,v 1.3 2021/05/17 20:21:05 mrg Exp $ */ 2 3 /*- 4 * Copyright (c) 2009 Frank Wille. 5 * All rights reserved. 6 * 7 * Written by Frank Wille for The NetBSD Project. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 19 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 20 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 21 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 22 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 * POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 #include <sys/param.h> 32 #include <sys/disklabel_rdb.h> 33 34 #include <lib/libkern/libkern.h> 35 #include <lib/libsa/stand.h> 36 37 #include "rdb.h" 38 39 40 static u_long 41 rdbchksum(void *bdata) 42 { 43 u_long *blp, cnt, val; 44 45 blp = bdata; 46 cnt = blp[1]; 47 val = 0; 48 49 while (cnt--) 50 val += *blp++; 51 return val; 52 } 53 54 55 static struct adostype 56 getadostype(u_long dostype) 57 { 58 struct adostype adt; 59 u_long t3, b1; 60 61 t3 = dostype & 0xffffff00; 62 b1 = dostype & 0x000000ff; 63 64 adt.fstype = b1; 65 66 switch (t3) { 67 case DOST_NBR: 68 adt.archtype = ADT_NETBSDROOT; 69 return adt; 70 case DOST_NBS: 71 adt.archtype = ADT_NETBSDSWAP; 72 return adt; 73 case DOST_NBU: 74 adt.archtype = ADT_NETBSDUSER; 75 return adt; 76 case DOST_AMIX: 77 adt.archtype = ADT_AMIX; 78 if (b1 == 2) 79 adt.fstype = FS_BSDFFS; 80 else 81 adt.fstype = FS_UNUSED; 82 return adt; 83 case DOST_XXXBSD: 84 if (b1 == 'S') { 85 dostype = DOST_NBS; 86 dostype |= FS_SWAP; 87 } else { 88 if (b1 == 'R') 89 dostype = DOST_NBR; 90 else 91 dostype = DOST_NBU; 92 dostype |= FS_BSDFFS; 93 } 94 return getadostype(dostype); 95 case DOST_EXT2: 96 adt.archtype = ADT_EXT2; 97 adt.fstype = FS_EX2FS; 98 return adt; 99 case DOST_RAID: 100 adt.archtype = ADT_RAID; 101 adt.fstype = FS_RAID; 102 return adt; 103 case DOST_MSD: 104 adt.archtype = ADT_MSD; 105 adt.fstype = FS_MSDOS; 106 return adt; 107 default: 108 adt.archtype = ADT_UNKNOWN; 109 adt.fstype = FS_UNUSED; 110 return adt; 111 } 112 } 113 114 115 /* 116 * Find a valid RDB disklabel. 117 */ 118 int 119 search_rdb_label(struct of_dev *devp, char *buf, struct disklabel *lp) 120 { 121 struct adostype adt; 122 struct rdblock *rbp; 123 struct partblock *pbp; 124 struct disklabel *dlp; 125 struct partition *pp; 126 u_long blk; 127 size_t read; 128 int i; 129 130 /* 131 * Scan the first RDB_MAXBLOCKS of a disk for an RDB block. 132 */ 133 rbp = (struct rdblock *)buf; 134 for (blk = 0; blk < RDB_MAXBLOCKS; blk++) { 135 if (strategy(devp, F_READ, blk, DEV_BSIZE, buf, &read) 136 || read != DEV_BSIZE) 137 return ERDLAB; 138 139 /* check for valid RDB */ 140 if (rbp->id == RDBLOCK_ID && rdbchksum(rbp) == 0) 141 break; 142 143 /* check for native NetBSD label */ 144 dlp = (struct disklabel *)(buf + LABELOFFSET); 145 if (dlp->d_magic == DISKMAGIC && dkcksum(dlp) == 0) { 146 *lp = *dlp; 147 return 0; 148 } 149 } 150 if (blk == RDB_MAXBLOCKS) 151 return ERDLAB; 152 153 /* Found RDB, clear disklabel partitions before reading PART blocks. */ 154 lp->d_npartitions = RAW_PART + 1; 155 for (i = 0; i < MAXPARTITIONS; i++) { 156 lp->d_partitions[i].p_size = 0; 157 lp->d_partitions[i].p_offset = 0; 158 lp->d_partitions[i].p_fstype = 0; 159 } 160 161 /* 162 * Construct a disklabel from RDB. 163 */ 164 lp->d_secsize = rbp->nbytes; 165 lp->d_nsectors = rbp->nsectors; 166 lp->d_ntracks = rbp->nheads; 167 /* be prepared that rbp->ncylinders may be a bogus value */ 168 if (rbp->highcyl == 0) 169 lp->d_ncylinders = rbp->ncylinders; 170 else 171 lp->d_ncylinders = rbp->highcyl + 1; 172 /* also don't trust rbp->secpercyl */ 173 lp->d_secpercyl = (rbp->secpercyl <= lp->d_nsectors * lp->d_ntracks) ? 174 rbp->secpercyl : lp->d_nsectors * lp->d_ntracks; 175 if (lp->d_secpercyl == 0) 176 lp->d_secpercyl = lp->d_nsectors * lp->d_ntracks; 177 178 lp->d_secperunit = lp->d_secpercyl * lp->d_ncylinders; 179 lp->d_acylinders = rbp->ncylinders - (rbp->highcyl - rbp->lowcyl + 1); 180 lp->d_rpm = 3600; 181 lp->d_interleave = rbp->interleave; 182 lp->d_headswitch = lp->d_flags = lp->d_trackskew = lp->d_cylskew = 0; 183 lp->d_trkseek = 0; 184 185 /* raw partition gets the entire disk */ 186 lp->d_partitions[RAW_PART].p_size = rbp->ncylinders * lp->d_secpercyl; 187 188 /* 189 * Now scan for partition blocks. 190 */ 191 pbp = (struct partblock *)buf; 192 for (blk = rbp->partbhead; blk != RDBNULL; blk = pbp->next) { 193 if (strategy(devp, F_READ, blk * (lp->d_secsize / DEV_BSIZE), 194 lp->d_secsize, buf, &read) 195 || read != lp->d_secsize) 196 return ERDLAB; 197 198 /* verify ID and checksum of PART block */ 199 if (pbp->id != PARTBLOCK_ID || rdbchksum(pbp)) 200 return ERDLAB; 201 202 /* environment table in PART block needs at least 11 entries */ 203 if (pbp->e.tabsize < 11) 204 return ERDLAB; 205 206 /* need a table size of 16 for a valid dostype */ 207 if (pbp->e.tabsize < 16) 208 pbp->e.dostype = 0; 209 adt = getadostype(pbp->e.dostype); 210 211 /* determine partition index */ 212 switch (adt.archtype) { 213 case ADT_NETBSDROOT: 214 pp = &lp->d_partitions[0]; 215 if (pp->p_size) 216 continue; 217 break; 218 case ADT_NETBSDSWAP: 219 pp = &lp->d_partitions[1]; 220 if (pp->p_size) 221 continue; 222 break; 223 default: 224 pp = &lp->d_partitions[lp->d_npartitions++]; 225 break; 226 } 227 228 /* sort partitions after RAW_PART by offset */ 229 while ((pp - lp->d_partitions) > RAW_PART + 1) { 230 daddr_t boff; 231 232 boff = pbp->e.lowcyl * pbp->e.secpertrk 233 * pbp->e.numheads 234 * ((pbp->e.sizeblock << 2) / lp->d_secsize); 235 if (boff > (pp - 1)->p_offset) 236 break; 237 *pp = *(pp - 1); /* struct copy */ 238 pp--; 239 } 240 241 /* get partition size, offset, fstype */ 242 pp->p_size = (pbp->e.highcyl - pbp->e.lowcyl + 1) 243 * pbp->e.secpertrk * pbp->e.numheads 244 * ((pbp->e.sizeblock << 2) / lp->d_secsize); 245 pp->p_offset = pbp->e.lowcyl * pbp->e.secpertrk 246 * pbp->e.numheads 247 * ((pbp->e.sizeblock << 2) / lp->d_secsize); 248 pp->p_fstype = adt.fstype; 249 } 250 251 /* 252 * All partitions have been found. The disklabel is valid. 253 */ 254 lp->d_magic = lp->d_magic2 = DISKMAGIC; 255 lp->d_checksum = 0; 256 lp->d_checksum = dkcksum(lp); 257 return 0; 258 } 259