1 /* $NetBSD: rdb.c,v 1.2 2010/06/19 08:48:33 kiyohara 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/libsa/stand.h> 35 36 #include "rdb.h" 37 38 39 static u_long 40 rdbchksum(void *bdata) 41 { 42 u_long *blp, cnt, val; 43 44 blp = bdata; 45 cnt = blp[1]; 46 val = 0; 47 48 while (cnt--) 49 val += *blp++; 50 return val; 51 } 52 53 54 static struct adostype 55 getadostype(u_long dostype) 56 { 57 struct adostype adt; 58 u_long t3, b1; 59 60 t3 = dostype & 0xffffff00; 61 b1 = dostype & 0x000000ff; 62 63 adt.fstype = b1; 64 65 switch (t3) { 66 case DOST_NBR: 67 adt.archtype = ADT_NETBSDROOT; 68 return adt; 69 case DOST_NBS: 70 adt.archtype = ADT_NETBSDSWAP; 71 return adt; 72 case DOST_NBU: 73 adt.archtype = ADT_NETBSDUSER; 74 return adt; 75 case DOST_AMIX: 76 adt.archtype = ADT_AMIX; 77 if (b1 == 2) 78 adt.fstype = FS_BSDFFS; 79 else 80 adt.fstype = FS_UNUSED; 81 return adt; 82 case DOST_XXXBSD: 83 if (b1 == 'S') { 84 dostype = DOST_NBS; 85 dostype |= FS_SWAP; 86 } else { 87 if (b1 == 'R') 88 dostype = DOST_NBR; 89 else 90 dostype = DOST_NBU; 91 dostype |= FS_BSDFFS; 92 } 93 return getadostype(dostype); 94 case DOST_EXT2: 95 adt.archtype = ADT_EXT2; 96 adt.fstype = FS_EX2FS; 97 return adt; 98 case DOST_RAID: 99 adt.archtype = ADT_RAID; 100 adt.fstype = FS_RAID; 101 return adt; 102 case DOST_MSD: 103 adt.archtype = ADT_MSD; 104 adt.fstype = FS_MSDOS; 105 return adt; 106 default: 107 adt.archtype = ADT_UNKNOWN; 108 adt.fstype = FS_UNUSED; 109 return adt; 110 } 111 } 112 113 114 /* 115 * Find a valid RDB disklabel. 116 */ 117 int 118 search_rdb_label(struct of_dev *devp, char *buf, struct disklabel *lp) 119 { 120 struct adostype adt; 121 struct rdblock *rbp; 122 struct partblock *pbp; 123 struct disklabel *dlp; 124 struct partition *pp; 125 u_long blk; 126 size_t read; 127 int i; 128 129 /* 130 * Scan the first RDB_MAXBLOCKS of a disk for an RDB block. 131 */ 132 rbp = (struct rdblock *)buf; 133 for (blk = 0; blk < RDB_MAXBLOCKS; blk++) { 134 if (strategy(devp, F_READ, blk, DEV_BSIZE, buf, &read) 135 || read != DEV_BSIZE) 136 return ERDLAB; 137 138 /* check for valid RDB */ 139 if (rbp->id == RDBLOCK_ID && rdbchksum(rbp) == 0) 140 break; 141 142 /* check for native NetBSD label */ 143 dlp = (struct disklabel *)(buf + LABELOFFSET); 144 if (dlp->d_magic == DISKMAGIC && dkcksum(dlp) == 0) { 145 *lp = *dlp; 146 return 0; 147 } 148 } 149 if (blk == RDB_MAXBLOCKS) 150 return ERDLAB; 151 152 /* Found RDB, clear disklabel partitions before reading PART blocks. */ 153 lp->d_npartitions = RAW_PART + 1; 154 for (i = 0; i < MAXPARTITIONS; i++) { 155 lp->d_partitions[i].p_size = 0; 156 lp->d_partitions[i].p_offset = 0; 157 lp->d_partitions[i].p_fstype = 0; 158 } 159 160 /* 161 * Construct a disklabel from RDB. 162 */ 163 lp->d_secsize = rbp->nbytes; 164 lp->d_nsectors = rbp->nsectors; 165 lp->d_ntracks = rbp->nheads; 166 /* be prepared that rbp->ncylinders may be a bogus value */ 167 if (rbp->highcyl == 0) 168 lp->d_ncylinders = rbp->ncylinders; 169 else 170 lp->d_ncylinders = rbp->highcyl + 1; 171 /* also don't trust rbp->secpercyl */ 172 lp->d_secpercyl = (rbp->secpercyl <= lp->d_nsectors * lp->d_ntracks) ? 173 rbp->secpercyl : lp->d_nsectors * lp->d_ntracks; 174 if (lp->d_secpercyl == 0) 175 lp->d_secpercyl = lp->d_nsectors * lp->d_ntracks; 176 177 lp->d_secperunit = lp->d_secpercyl * lp->d_ncylinders; 178 lp->d_acylinders = rbp->ncylinders - (rbp->highcyl - rbp->lowcyl + 1); 179 lp->d_rpm = 3600; 180 lp->d_interleave = rbp->interleave; 181 lp->d_headswitch = lp->d_flags = lp->d_trackskew = lp->d_cylskew = 0; 182 lp->d_trkseek = 0; 183 184 /* raw partition gets the entire disk */ 185 lp->d_partitions[RAW_PART].p_size = rbp->ncylinders * lp->d_secpercyl; 186 187 /* 188 * Now scan for partition blocks. 189 */ 190 pbp = (struct partblock *)buf; 191 for (blk = rbp->partbhead; blk != RDBNULL; blk = pbp->next) { 192 if (strategy(devp, F_READ, blk * (lp->d_secsize / DEV_BSIZE), 193 lp->d_secsize, buf, &read) 194 || read != lp->d_secsize) 195 return ERDLAB; 196 197 /* verify ID and checksum of PART block */ 198 if (pbp->id != PARTBLOCK_ID || rdbchksum(pbp)) 199 return ERDLAB; 200 201 /* environment table in PART block needs at least 11 entries */ 202 if (pbp->e.tabsize < 11) 203 return ERDLAB; 204 205 /* need a table size of 16 for a valid dostype */ 206 if (pbp->e.tabsize < 16) 207 pbp->e.dostype = 0; 208 adt = getadostype(pbp->e.dostype); 209 210 /* determine partition index */ 211 switch (adt.archtype) { 212 case ADT_NETBSDROOT: 213 pp = &lp->d_partitions[0]; 214 if (pp->p_size) 215 continue; 216 break; 217 case ADT_NETBSDSWAP: 218 pp = &lp->d_partitions[1]; 219 if (pp->p_size) 220 continue; 221 break; 222 default: 223 pp = &lp->d_partitions[lp->d_npartitions++]; 224 break; 225 } 226 227 /* sort partitions after RAW_PART by offset */ 228 while ((pp - lp->d_partitions) > RAW_PART + 1) { 229 daddr_t boff; 230 231 boff = pbp->e.lowcyl * pbp->e.secpertrk 232 * pbp->e.numheads 233 * ((pbp->e.sizeblock << 2) / lp->d_secsize); 234 if (boff > (pp - 1)->p_offset) 235 break; 236 *pp = *(pp - 1); /* struct copy */ 237 pp--; 238 } 239 240 /* get partition size, offset, fstype */ 241 pp->p_size = (pbp->e.highcyl - pbp->e.lowcyl + 1) 242 * pbp->e.secpertrk * pbp->e.numheads 243 * ((pbp->e.sizeblock << 2) / lp->d_secsize); 244 pp->p_offset = pbp->e.lowcyl * pbp->e.secpertrk 245 * pbp->e.numheads 246 * ((pbp->e.sizeblock << 2) / lp->d_secsize); 247 pp->p_fstype = adt.fstype; 248 } 249 250 /* 251 * All partitions have been found. The disklabel is valid. 252 */ 253 lp->d_magic = lp->d_magic2 = DISKMAGIC; 254 lp->d_checksum = 0; 255 lp->d_checksum = dkcksum(lp); 256 return 0; 257 } 258