geom_bsd.c revision 103284
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 103284 2002-09-13 11:41:25Z 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/stdint.h> 56#include <sys/errno.h> 57#include <sys/disklabel.h> 58#include <geom/geom.h> 59#include <geom/geom_slice.h> 60 61#define BSD_CLASS_NAME "BSD" 62 63struct g_bsd_softc { 64 off_t labeloffset; 65 struct disklabel ondisk; 66 struct disklabel inram; 67}; 68 69static void 70g_bsd_ledec_partition(u_char *ptr, struct partition *d) 71{ 72 d->p_size = g_dec_le4(ptr + 0); 73 d->p_offset = g_dec_le4(ptr + 4); 74 d->p_fsize = g_dec_le4(ptr + 8); 75 d->p_fstype = ptr[12]; 76 d->p_frag = ptr[13]; 77 d->p_cpg = g_dec_le2(ptr + 14); 78} 79 80static void 81g_bsd_ledec_disklabel(u_char *ptr, struct disklabel *d) 82{ 83 d->d_magic = g_dec_le4(ptr + 0); 84 d->d_type = g_dec_le2(ptr + 4); 85 d->d_subtype = g_dec_le2(ptr + 6); 86 bcopy(ptr + 8, d->d_typename, 16); 87 bcopy(d->d_packname, ptr + 24, 16); 88 d->d_secsize = g_dec_le4(ptr + 40); 89 d->d_nsectors = g_dec_le4(ptr + 44); 90 d->d_ntracks = g_dec_le4(ptr + 48); 91 d->d_ncylinders = g_dec_le4(ptr + 52); 92 d->d_secpercyl = g_dec_le4(ptr + 56); 93 d->d_secperunit = g_dec_le4(ptr + 60); 94 d->d_sparespertrack = g_dec_le2(ptr + 64); 95 d->d_sparespercyl = g_dec_le2(ptr + 66); 96 d->d_acylinders = g_dec_le4(ptr + 68); 97 d->d_rpm = g_dec_le2(ptr + 72); 98 d->d_interleave = g_dec_le2(ptr + 74); 99 d->d_trackskew = g_dec_le2(ptr + 76); 100 d->d_cylskew = g_dec_le2(ptr + 78); 101 d->d_headswitch = g_dec_le4(ptr + 80); 102 d->d_trkseek = g_dec_le4(ptr + 84); 103 d->d_flags = g_dec_le4(ptr + 88); 104 d->d_drivedata[0] = g_dec_le4(ptr + 92); 105 d->d_drivedata[1] = g_dec_le4(ptr + 96); 106 d->d_drivedata[2] = g_dec_le4(ptr + 100); 107 d->d_drivedata[3] = g_dec_le4(ptr + 104); 108 d->d_drivedata[4] = g_dec_le4(ptr + 108); 109 d->d_spare[0] = g_dec_le4(ptr + 112); 110 d->d_spare[1] = g_dec_le4(ptr + 116); 111 d->d_spare[2] = g_dec_le4(ptr + 120); 112 d->d_spare[3] = g_dec_le4(ptr + 124); 113 d->d_spare[4] = g_dec_le4(ptr + 128); 114 d->d_magic2 = g_dec_le4(ptr + 132); 115 d->d_checksum = g_dec_le2(ptr + 136); 116 d->d_npartitions = g_dec_le2(ptr + 138); 117 d->d_bbsize = g_dec_le4(ptr + 140); 118 d->d_sbsize = g_dec_le4(ptr + 144); 119 g_bsd_ledec_partition(ptr + 148, &d->d_partitions[0]); 120 g_bsd_ledec_partition(ptr + 164, &d->d_partitions[1]); 121 g_bsd_ledec_partition(ptr + 180, &d->d_partitions[2]); 122 g_bsd_ledec_partition(ptr + 196, &d->d_partitions[3]); 123 g_bsd_ledec_partition(ptr + 212, &d->d_partitions[4]); 124 g_bsd_ledec_partition(ptr + 228, &d->d_partitions[5]); 125 g_bsd_ledec_partition(ptr + 244, &d->d_partitions[6]); 126 g_bsd_ledec_partition(ptr + 260, &d->d_partitions[7]); 127} 128 129#if 0 130static void 131g_bsd_leenc_partition(u_char *ptr, struct partition *d) 132{ 133 g_enc_le4(ptr + 0, d->p_size); 134 g_enc_le4(ptr + 4, d->p_offset); 135 g_enc_le4(ptr + 8, d->p_fsize); 136 ptr[12] = d->p_fstype; 137 ptr[13] = d->p_frag; 138 g_enc_le2(ptr + 14, d->p_cpg); 139} 140 141static void 142g_bsd_leenc_disklabel(u_char *ptr, struct disklabel *d) 143{ 144 g_enc_le4(ptr + 0, d->d_magic); 145 g_enc_le2(ptr + 4, d->d_type); 146 g_enc_le2(ptr + 6, d->d_subtype); 147 bcopy(d->d_typename, ptr + 8, 16); 148 bcopy(d->d_packname, ptr + 24, 16); 149 g_enc_le4(ptr + 40, d->d_secsize); 150 g_enc_le4(ptr + 44, d->d_nsectors); 151 g_enc_le4(ptr + 48, d->d_ntracks); 152 g_enc_le4(ptr + 52, d->d_ncylinders); 153 g_enc_le4(ptr + 56, d->d_secpercyl); 154 g_enc_le4(ptr + 60, d->d_secperunit); 155 g_enc_le2(ptr + 64, d->d_sparespertrack); 156 g_enc_le2(ptr + 66, d->d_sparespercyl); 157 g_enc_le4(ptr + 68, d->d_acylinders); 158 g_enc_le2(ptr + 72, d->d_rpm); 159 g_enc_le2(ptr + 74, d->d_interleave); 160 g_enc_le2(ptr + 76, d->d_trackskew); 161 g_enc_le2(ptr + 78, d->d_cylskew); 162 g_enc_le4(ptr + 80, d->d_headswitch); 163 g_enc_le4(ptr + 84, d->d_trkseek); 164 g_enc_le4(ptr + 88, d->d_flags); 165 g_enc_le4(ptr + 92, d->d_drivedata[0]); 166 g_enc_le4(ptr + 96, d->d_drivedata[1]); 167 g_enc_le4(ptr + 100, d->d_drivedata[2]); 168 g_enc_le4(ptr + 104, d->d_drivedata[3]); 169 g_enc_le4(ptr + 108, d->d_drivedata[4]); 170 g_enc_le4(ptr + 112, d->d_spare[0]); 171 g_enc_le4(ptr + 116, d->d_spare[1]); 172 g_enc_le4(ptr + 120, d->d_spare[2]); 173 g_enc_le4(ptr + 124, d->d_spare[3]); 174 g_enc_le4(ptr + 128, d->d_spare[4]); 175 g_enc_le4(ptr + 132, d->d_magic2); 176 g_enc_le2(ptr + 136, d->d_checksum); 177 g_enc_le2(ptr + 138, d->d_npartitions); 178 g_enc_le4(ptr + 140, d->d_bbsize); 179 g_enc_le4(ptr + 144, d->d_sbsize); 180 g_bsd_leenc_partition(ptr + 148, &d->d_partitions[0]); 181 g_bsd_leenc_partition(ptr + 164, &d->d_partitions[1]); 182 g_bsd_leenc_partition(ptr + 180, &d->d_partitions[2]); 183 g_bsd_leenc_partition(ptr + 196, &d->d_partitions[3]); 184 g_bsd_leenc_partition(ptr + 212, &d->d_partitions[4]); 185 g_bsd_leenc_partition(ptr + 228, &d->d_partitions[5]); 186 g_bsd_leenc_partition(ptr + 244, &d->d_partitions[6]); 187 g_bsd_leenc_partition(ptr + 260, &d->d_partitions[7]); 188} 189 190#endif 191 192static void 193ondisk2inram(struct g_bsd_softc *sc) 194{ 195 struct partition *ppp; 196 unsigned offset; 197 int i; 198 199 sc->inram = sc->ondisk; 200 offset = sc->inram.d_partitions[RAW_PART].p_offset; 201 for (i = 0; i < 8; i++) { 202 ppp = &sc->inram.d_partitions[i]; 203 if (ppp->p_offset >= offset) 204 ppp->p_offset -= offset; 205 } 206 sc->inram.d_checksum = 0; 207 sc->inram.d_checksum = dkcksum(&sc->inram); 208} 209 210/* 211 * It is rather fortunate that this checksum only covers up to the 212 * actual end of actual data, otherwise the pointer-screwup in 213 * alpha architectures would have been much harder to handle. 214 */ 215static int 216g_bsd_lesum(struct disklabel *dl, u_char *p) 217{ 218 u_char *pe; 219 uint16_t sum; 220 221 pe = p + 148 + 16 * dl->d_npartitions; 222 sum = 0; 223 while (p < pe) { 224 sum ^= g_dec_le2(p); 225 p += 2; 226 } 227 return (sum); 228} 229 230static int 231g_bsd_try(struct g_slicer *gsp, struct g_consumer *cp, int secsize, struct g_bsd_softc *ms, off_t offset) 232{ 233 int error; 234 u_char *buf; 235 struct disklabel *dl; 236 off_t secoff; 237 238 dl = &ms->ondisk; 239 secoff = offset % secsize; 240 buf = g_read_data(cp, offset - secoff, secsize, &error); 241 if (buf == NULL || error != 0) 242 return(ENOENT); 243 g_bsd_ledec_disklabel(buf + secoff, dl); 244 if (dl->d_magic == DISKMAGIC && 245 dl->d_magic2 == DISKMAGIC && 246 g_bsd_lesum(dl, buf + secoff) == 0) 247 error = 0; 248 else 249 error = ENOENT; 250 g_free(buf); 251 if (error == 0) { 252 gsp->frontstuff = 16 * secsize; 253 ms->labeloffset = offset; 254 } 255 return(error); 256} 257 258static int 259g_bsd_start(struct bio *bp) 260{ 261 struct g_geom *gp; 262 struct g_bsd_softc *ms; 263 struct g_slicer *gsp; 264 struct g_ioctl *gio; 265 266 gp = bp->bio_to->geom; 267 gsp = gp->softc; 268 ms = gsp->softc; 269 if (strcmp(bp->bio_attribute, "GEOM::ioctl")) 270 return(0); 271 else if (bp->bio_length != sizeof *gio) 272 return(0); 273 gio = (struct g_ioctl *)bp->bio_data; 274 if (gio->cmd == DIOCGDINFO) { 275 bcopy(&ms->inram, gio->data, sizeof ms->inram); 276 bp->bio_error = 0; 277 g_io_deliver(bp); 278 return (1); 279 } 280 return (0); 281} 282 283static void 284g_bsd_dumpconf(struct sbuf *sb, char *indent, struct g_geom *gp, struct g_consumer *cp __unused, struct g_provider *pp) 285{ 286 struct g_bsd_softc *ms; 287 struct g_slicer *gsp; 288 289 gsp = gp->softc; 290 ms = gsp->softc; 291 if (pp == NULL && cp == NULL) { 292 sbuf_printf(sb, "%s<labeloffset>%jd</labeloffset>\n", 293 indent, (intmax_t)ms->labeloffset); 294 } 295 g_slice_dumpconf(sb, indent, gp, cp, pp); 296} 297 298static struct g_geom * 299g_bsd_taste(struct g_class *mp, struct g_provider *pp, int flags) 300{ 301 struct g_geom *gp; 302 struct g_consumer *cp; 303 struct g_provider *pp2; 304 int error, i, j, npart; 305 struct g_bsd_softc *ms; 306 struct disklabel *dl; 307 u_int secsize; 308 u_int fwsectors, fwheads; 309 off_t mediasize; 310 struct partition *ppp, *ppr; 311 struct g_slicer *gsp; 312 313 g_trace(G_T_TOPOLOGY, "bsd_taste(%s,%s)", mp->name, pp->name); 314 g_topology_assert(); 315 if (flags == G_TF_NORMAL && 316 !strcmp(pp->geom->class->name, BSD_CLASS_NAME)) 317 return (NULL); 318 gp = g_slice_new(mp, 8, pp, &cp, &ms, sizeof *ms, g_bsd_start); 319 if (gp == NULL) 320 return (NULL); 321 gsp = gp->softc; 322 g_topology_unlock(); 323 gp->dumpconf = g_bsd_dumpconf; 324 npart = 0; 325 while (1) { /* a trick to allow us to use break */ 326 error = g_getattr("MBR::type", cp, &i); 327 if (!error && i != 165 && flags == G_TF_NORMAL) 328 break; 329 error = g_getattr("GEOM::sectorsize", cp, &secsize); 330 if (error) { 331 secsize = 512; 332 printf("g_bsd_taste: error %d Sectors are %d bytes\n", 333 error, secsize); 334 } 335 error = g_getattr("GEOM::mediasize", cp, &mediasize); 336 if (error) { 337 mediasize = 0; 338 printf("g_error %d Mediasize is %lld bytes\n", 339 error, (long long)mediasize); 340 } 341 error = g_bsd_try(gsp, cp, secsize, ms, secsize); 342 if (error) 343 error = g_bsd_try(gsp, cp, secsize, ms, 64); 344 if (error) 345 break; 346 dl = &ms->ondisk; 347 if (bootverbose) 348 g_hexdump(dl, sizeof(*dl)); 349 if (dl->d_secsize < secsize) 350 break; 351 if (dl->d_secsize > secsize) 352 secsize = dl->d_secsize; 353 ppr = &dl->d_partitions[2]; 354 for (i = 0; i < 8; i++) { 355 ppp = &dl->d_partitions[i]; 356 if (ppp->p_size == 0) 357 continue; 358 npart++; 359 pp2 = g_slice_addslice(gp, i, 360 ((off_t)(ppp->p_offset - ppr->p_offset)) << 9ULL, 361 ((off_t)ppp->p_size) << 9ULL, 362 "%s%c", pp->name, 'a' + i); 363 g_error_provider(pp2, 0); 364 } 365 ondisk2inram(ms); 366 break; 367 } 368 if (npart == 0 && ( 369 (flags == G_TF_INSIST && mediasize != 0) || 370 (flags == G_TF_TRANSPARENT))) { 371 dl = &ms->ondisk; 372 bzero(dl, sizeof *dl); 373 dl->d_magic = DISKMAGIC; 374 dl->d_magic2 = DISKMAGIC; 375 ppp = &dl->d_partitions[RAW_PART]; 376 ppp->p_offset = 0; 377 ppp->p_size = mediasize / secsize; 378 dl->d_npartitions = MAXPARTITIONS; 379 dl->d_interleave = 1; 380 dl->d_secsize = secsize; 381 dl->d_rpm = 3600; 382 j = sizeof fwsectors; 383 error = g_io_getattr("GEOM::fwsectors", cp, &j, &fwsectors); 384 if (error) 385 dl->d_nsectors = 32; 386 else 387 dl->d_nsectors = fwsectors; 388 error = g_io_getattr("GEOM::fwheads", cp, &j, &fwheads); 389 if (error) 390 dl->d_ntracks = 64; 391 else 392 dl->d_ntracks = fwheads; 393 dl->d_secpercyl = dl->d_nsectors * dl->d_ntracks; 394 dl->d_ncylinders = ppp->p_size / dl->d_secpercyl; 395 dl->d_secperunit = ppp->p_size; 396 dl->d_checksum = 0; 397 dl->d_checksum = dkcksum(dl); 398 ms->inram = ms->ondisk; 399 pp2 = g_slice_addslice(gp, RAW_PART, 400 0, mediasize, "%s%c", pp->name, 'a' + RAW_PART); 401 g_error_provider(pp2, 0); 402 npart = 1; 403 } 404 g_topology_lock(); 405 error = g_access_rel(cp, -1, 0, 0); 406 if (npart > 0) 407 return (gp); 408 g_std_spoiled(cp); 409 return (NULL); 410} 411 412static struct g_class g_bsd_class = { 413 BSD_CLASS_NAME, 414 g_bsd_taste, 415 NULL, 416 G_CLASS_INITIALIZER 417}; 418 419DECLARE_GEOM_CLASS(g_bsd_class, g_bsd); 420