geom_bsd.c revision 103009
1/*- 2 * Copyright (c) 2002 Poul-Henning Kamp 3 * Copyright (c) 2002 Networks Associates Technology, Inc. 4 * All rights reserved. 5 * 6 * This software was developed for the FreeBSD Project by Poul-Henning Kamp 7 * and NAI Labs, the Security Research Division of Network Associates, Inc. 8 * under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the 9 * DARPA CHATS research program. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 3. The names of the authors may not be used to endorse or promote 20 * products derived from this software without specific prior written 21 * permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 * 35 * $FreeBSD: head/sys/geom/geom_bsd.c 103009 2002-09-06 08:50:28Z phk $ 36 */ 37 38 39#include <sys/param.h> 40#ifndef _KERNEL 41#include <stdio.h> 42#include <string.h> 43#include <stdlib.h> 44#include <signal.h> 45#include <err.h> 46#else 47#include <sys/systm.h> 48#include <sys/kernel.h> 49#include <sys/conf.h> 50#include <sys/bio.h> 51#include <sys/malloc.h> 52#include <sys/lock.h> 53#include <sys/mutex.h> 54#endif 55#include <sys/errno.h> 56#include <sys/disklabel.h> 57#include <geom/geom.h> 58#include <geom/geom_slice.h> 59 60#define BSD_CLASS_NAME "BSD" 61 62struct g_bsd_softc { 63 off_t labeloffset; 64 struct disklabel ondisk; 65 struct disklabel inram; 66}; 67 68static void 69g_bsd_ledec_partition(u_char *ptr, struct partition *d) 70{ 71 d->p_size = g_dec_le4(ptr + 0); 72 d->p_offset = g_dec_le4(ptr + 4); 73 d->p_fsize = g_dec_le4(ptr + 8); 74 d->p_fstype = ptr[12]; 75 d->p_frag = ptr[13]; 76 d->p_cpg = g_dec_le2(ptr + 14); 77} 78 79static void 80g_bsd_ledec_disklabel(u_char *ptr, struct disklabel *d) 81{ 82 d->d_magic = g_dec_le4(ptr + 0); 83 d->d_type = g_dec_le2(ptr + 4); 84 d->d_subtype = g_dec_le2(ptr + 6); 85 bcopy(ptr + 8, d->d_typename, 16); 86 bcopy(d->d_packname, ptr + 24, 16); 87 d->d_secsize = g_dec_le4(ptr + 40); 88 d->d_nsectors = g_dec_le4(ptr + 44); 89 d->d_ntracks = g_dec_le4(ptr + 48); 90 d->d_ncylinders = g_dec_le4(ptr + 52); 91 d->d_secpercyl = g_dec_le4(ptr + 56); 92 d->d_secperunit = g_dec_le4(ptr + 60); 93 d->d_sparespertrack = g_dec_le2(ptr + 64); 94 d->d_sparespercyl = g_dec_le2(ptr + 66); 95 d->d_acylinders = g_dec_le4(ptr + 68); 96 d->d_rpm = g_dec_le2(ptr + 72); 97 d->d_interleave = g_dec_le2(ptr + 74); 98 d->d_trackskew = g_dec_le2(ptr + 76); 99 d->d_cylskew = g_dec_le2(ptr + 78); 100 d->d_headswitch = g_dec_le4(ptr + 80); 101 d->d_trkseek = g_dec_le4(ptr + 84); 102 d->d_flags = g_dec_le4(ptr + 88); 103 d->d_drivedata[0] = g_dec_le4(ptr + 92); 104 d->d_drivedata[1] = g_dec_le4(ptr + 96); 105 d->d_drivedata[2] = g_dec_le4(ptr + 100); 106 d->d_drivedata[3] = g_dec_le4(ptr + 104); 107 d->d_drivedata[4] = g_dec_le4(ptr + 108); 108 d->d_spare[0] = g_dec_le4(ptr + 112); 109 d->d_spare[1] = g_dec_le4(ptr + 116); 110 d->d_spare[2] = g_dec_le4(ptr + 120); 111 d->d_spare[3] = g_dec_le4(ptr + 124); 112 d->d_spare[4] = g_dec_le4(ptr + 128); 113 d->d_magic2 = g_dec_le4(ptr + 132); 114 d->d_checksum = g_dec_le2(ptr + 136); 115 d->d_npartitions = g_dec_le2(ptr + 138); 116 d->d_bbsize = g_dec_le4(ptr + 140); 117 d->d_sbsize = g_dec_le4(ptr + 144); 118 g_bsd_ledec_partition(ptr + 148, &d->d_partitions[0]); 119 g_bsd_ledec_partition(ptr + 164, &d->d_partitions[1]); 120 g_bsd_ledec_partition(ptr + 180, &d->d_partitions[2]); 121 g_bsd_ledec_partition(ptr + 196, &d->d_partitions[3]); 122 g_bsd_ledec_partition(ptr + 212, &d->d_partitions[4]); 123 g_bsd_ledec_partition(ptr + 228, &d->d_partitions[5]); 124 g_bsd_ledec_partition(ptr + 244, &d->d_partitions[6]); 125 g_bsd_ledec_partition(ptr + 260, &d->d_partitions[7]); 126} 127 128#if 0 129static void 130g_bsd_leenc_partition(u_char *ptr, struct partition *d) 131{ 132 g_enc_le4(ptr + 0, d->p_size); 133 g_enc_le4(ptr + 4, d->p_offset); 134 g_enc_le4(ptr + 8, d->p_fsize); 135 ptr[12] = d->p_fstype; 136 ptr[13] = d->p_frag; 137 g_enc_le2(ptr + 14, d->p_cpg); 138} 139 140static void 141g_bsd_leenc_disklabel(u_char *ptr, struct disklabel *d) 142{ 143 g_enc_le4(ptr + 0, d->d_magic); 144 g_enc_le2(ptr + 4, d->d_type); 145 g_enc_le2(ptr + 6, d->d_subtype); 146 bcopy(d->d_typename, ptr + 8, 16); 147 bcopy(d->d_packname, ptr + 24, 16); 148 g_enc_le4(ptr + 40, d->d_secsize); 149 g_enc_le4(ptr + 44, d->d_nsectors); 150 g_enc_le4(ptr + 48, d->d_ntracks); 151 g_enc_le4(ptr + 52, d->d_ncylinders); 152 g_enc_le4(ptr + 56, d->d_secpercyl); 153 g_enc_le4(ptr + 60, d->d_secperunit); 154 g_enc_le2(ptr + 64, d->d_sparespertrack); 155 g_enc_le2(ptr + 66, d->d_sparespercyl); 156 g_enc_le4(ptr + 68, d->d_acylinders); 157 g_enc_le2(ptr + 72, d->d_rpm); 158 g_enc_le2(ptr + 74, d->d_interleave); 159 g_enc_le2(ptr + 76, d->d_trackskew); 160 g_enc_le2(ptr + 78, d->d_cylskew); 161 g_enc_le4(ptr + 80, d->d_headswitch); 162 g_enc_le4(ptr + 84, d->d_trkseek); 163 g_enc_le4(ptr + 88, d->d_flags); 164 g_enc_le4(ptr + 92, d->d_drivedata[0]); 165 g_enc_le4(ptr + 96, d->d_drivedata[1]); 166 g_enc_le4(ptr + 100, d->d_drivedata[2]); 167 g_enc_le4(ptr + 104, d->d_drivedata[3]); 168 g_enc_le4(ptr + 108, d->d_drivedata[4]); 169 g_enc_le4(ptr + 112, d->d_spare[0]); 170 g_enc_le4(ptr + 116, d->d_spare[1]); 171 g_enc_le4(ptr + 120, d->d_spare[2]); 172 g_enc_le4(ptr + 124, d->d_spare[3]); 173 g_enc_le4(ptr + 128, d->d_spare[4]); 174 g_enc_le4(ptr + 132, d->d_magic2); 175 g_enc_le2(ptr + 136, d->d_checksum); 176 g_enc_le2(ptr + 138, d->d_npartitions); 177 g_enc_le4(ptr + 140, d->d_bbsize); 178 g_enc_le4(ptr + 144, d->d_sbsize); 179 g_bsd_leenc_partition(ptr + 148, &d->d_partitions[0]); 180 g_bsd_leenc_partition(ptr + 164, &d->d_partitions[1]); 181 g_bsd_leenc_partition(ptr + 180, &d->d_partitions[2]); 182 g_bsd_leenc_partition(ptr + 196, &d->d_partitions[3]); 183 g_bsd_leenc_partition(ptr + 212, &d->d_partitions[4]); 184 g_bsd_leenc_partition(ptr + 228, &d->d_partitions[5]); 185 g_bsd_leenc_partition(ptr + 244, &d->d_partitions[6]); 186 g_bsd_leenc_partition(ptr + 260, &d->d_partitions[7]); 187} 188 189#endif 190 191static void 192ondisk2inram(struct g_bsd_softc *sc) 193{ 194 struct partition *ppp; 195 unsigned offset; 196 int i; 197 198 sc->inram = sc->ondisk; 199 offset = sc->inram.d_partitions[RAW_PART].p_offset; 200 for (i = 0; i < 8; i++) { 201 ppp = &sc->inram.d_partitions[i]; 202 if (ppp->p_offset >= offset) 203 ppp->p_offset -= offset; 204 } 205 sc->inram.d_checksum = 0; 206 sc->inram.d_checksum = dkcksum(&sc->inram); 207} 208 209/* 210 * It is rather fortunate that this checksum only covers up to the 211 * actual end of actual data, otherwise the pointer-screwup in 212 * alpha architectures would have been much harder to handle. 213 */ 214static int 215g_bsd_lesum(struct disklabel *dl, u_char *p) 216{ 217 u_char *pe; 218 uint16_t sum; 219 220 pe = p + 148 + 16 * dl->d_npartitions; 221 sum = 0; 222 while (p < pe) { 223 sum ^= g_dec_le2(p); 224 p += 2; 225 } 226 return (sum); 227} 228 229static int 230g_bsd_try(struct g_slicer *gsp, struct g_consumer *cp, int secsize, struct g_bsd_softc *ms, off_t offset) 231{ 232 int error; 233 u_char *buf; 234 struct disklabel *dl; 235 off_t secoff; 236 237 dl = &ms->ondisk; 238 secoff = offset % secsize; 239 buf = g_read_data(cp, offset - secoff, secsize, &error); 240 if (buf == NULL || error != 0) 241 return(ENOENT); 242 g_bsd_ledec_disklabel(buf + secoff, dl); 243 if (dl->d_magic == DISKMAGIC && 244 dl->d_magic2 == DISKMAGIC && 245 g_bsd_lesum(dl, buf + secoff) == 0) 246 error = 0; 247 else 248 error = ENOENT; 249 g_free(buf); 250 if (error == 0) { 251 gsp->frontstuff = 16 * secsize; 252 ms->labeloffset = offset; 253 } 254 return(error); 255} 256 257static int 258g_bsd_start(struct bio *bp) 259{ 260 struct g_geom *gp; 261 struct g_bsd_softc *ms; 262 struct g_slicer *gsp; 263 struct g_ioctl *gio; 264 265 gp = bp->bio_to->geom; 266 gsp = gp->softc; 267 ms = gsp->softc; 268 if (strcmp(bp->bio_attribute, "GEOM::ioctl")) 269 return(0); 270 else if (bp->bio_length != sizeof *gio) 271 return(0); 272 gio = (struct g_ioctl *)bp->bio_data; 273 if (gio->cmd == DIOCGDINFO) { 274 bcopy(&ms->inram, gio->data, sizeof ms->inram); 275 bp->bio_error = 0; 276 g_io_deliver(bp); 277 return (1); 278 } 279 return (0); 280} 281 282static void 283g_bsd_dumpconf(struct sbuf *sb, char *indent, struct g_geom *gp, struct g_consumer *cp __unused, struct g_provider *pp) 284{ 285 struct g_bsd_softc *ms; 286 struct g_slicer *gsp; 287 288 gsp = gp->softc; 289 ms = gsp->softc; 290 if (pp == NULL && cp == NULL) { 291 sbuf_printf(sb, "%s<labeloffset>%lld</labeloffset>\n", 292 indent, ms->labeloffset); 293 } 294 g_slice_dumpconf(sb, indent, gp, cp, pp); 295} 296 297static struct g_geom * 298g_bsd_taste(struct g_class *mp, struct g_provider *pp, int flags) 299{ 300 struct g_geom *gp; 301 struct g_consumer *cp; 302 struct g_provider *pp2; 303 int error, i, j, npart; 304 struct g_bsd_softc *ms; 305 struct disklabel *dl; 306 u_int secsize; 307 u_int fwsectors, fwheads; 308 off_t mediasize; 309 struct partition *ppp, *ppr; 310 struct g_slicer *gsp; 311 312 g_trace(G_T_TOPOLOGY, "bsd_taste(%s,%s)", mp->name, pp->name); 313 g_topology_assert(); 314 if (flags == G_TF_NORMAL && 315 !strcmp(pp->geom->class->name, BSD_CLASS_NAME)) 316 return (NULL); 317 gp = g_slice_new(mp, 8, pp, &cp, &ms, sizeof *ms, g_bsd_start); 318 if (gp == NULL) 319 return (NULL); 320 gsp = gp->softc; 321 g_topology_unlock(); 322 gp->dumpconf = g_bsd_dumpconf; 323 npart = 0; 324 while (1) { /* a trick to allow us to use break */ 325 error = g_getattr("MBR::type", cp, &i); 326 if (!error && i != 165 && flags == G_TF_NORMAL) 327 break; 328 error = g_getattr("GEOM::sectorsize", cp, &secsize); 329 if (error) { 330 secsize = 512; 331 printf("g_bsd_taste: error %d Sectors are %d bytes\n", 332 error, secsize); 333 } 334 error = g_getattr("GEOM::mediasize", cp, &mediasize); 335 if (error) { 336 mediasize = 0; 337 printf("g_error %d Mediasize is %lld bytes\n", 338 error, (long long)mediasize); 339 } 340 error = g_bsd_try(gsp, cp, secsize, ms, secsize); 341 if (error) 342 error = g_bsd_try(gsp, cp, secsize, ms, 64); 343 if (error) 344 break; 345 dl = &ms->ondisk; 346 if (bootverbose) 347 g_hexdump(dl, sizeof(*dl)); 348 if (dl->d_secsize < secsize) 349 break; 350 if (dl->d_secsize > secsize) 351 secsize = dl->d_secsize; 352 ppr = &dl->d_partitions[2]; 353 for (i = 0; i < 8; i++) { 354 ppp = &dl->d_partitions[i]; 355 if (ppp->p_size == 0) 356 continue; 357 npart++; 358 pp2 = g_slice_addslice(gp, i, 359 ((off_t)(ppp->p_offset - ppr->p_offset)) << 9ULL, 360 ((off_t)ppp->p_size) << 9ULL, 361 "%s%c", pp->name, 'a' + i); 362 g_error_provider(pp2, 0); 363 } 364 ondisk2inram(ms); 365 break; 366 } 367 if (npart == 0 && ( 368 (flags == G_TF_INSIST && mediasize != 0) || 369 (flags == G_TF_TRANSPARENT))) { 370 dl = &ms->ondisk; 371 bzero(dl, sizeof *dl); 372 dl->d_magic = DISKMAGIC; 373 dl->d_magic2 = DISKMAGIC; 374 ppp = &dl->d_partitions[RAW_PART]; 375 ppp->p_offset = 0; 376 ppp->p_size = mediasize / secsize; 377 dl->d_npartitions = MAXPARTITIONS; 378 dl->d_interleave = 1; 379 dl->d_secsize = secsize; 380 dl->d_rpm = 3600; 381 j = sizeof fwsectors; 382 error = g_io_getattr("GEOM::fwsectors", cp, &j, &fwsectors); 383 if (error) 384 dl->d_nsectors = 32; 385 else 386 dl->d_nsectors = fwsectors; 387 error = g_io_getattr("GEOM::fwheads", cp, &j, &fwheads); 388 if (error) 389 dl->d_ntracks = 64; 390 else 391 dl->d_ntracks = fwheads; 392 dl->d_secpercyl = dl->d_nsectors * dl->d_ntracks; 393 dl->d_ncylinders = ppp->p_size / dl->d_secpercyl; 394 dl->d_secperunit = ppp->p_size; 395 dl->d_checksum = 0; 396 dl->d_checksum = dkcksum(dl); 397 ms->inram = ms->ondisk; 398 pp2 = g_slice_addslice(gp, RAW_PART, 399 0, mediasize, "%s%c", pp->name, 'a' + RAW_PART); 400 g_error_provider(pp2, 0); 401 npart = 1; 402 } 403 g_topology_lock(); 404 error = g_access_rel(cp, -1, 0, 0); 405 if (npart > 0) 406 return (gp); 407 g_std_spoiled(cp); 408 return (NULL); 409} 410 411static struct g_class g_bsd_class = { 412 BSD_CLASS_NAME, 413 g_bsd_taste, 414 NULL, 415 G_CLASS_INITIALIZER 416}; 417 418DECLARE_GEOM_CLASS(g_bsd_class, g_bsd); 419