1 /* $NetBSD: disksubr.c,v 1.23 2002/03/05 09:40:40 simonb Exp $ */ 2 3 /* 4 * Copyright (c) 1995 Dale Rahn. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by Dale Rahn. 18 * 4. The name of the author may not be used to endorse or promote products 19 * derived from this software without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 #include <sys/param.h> 34 #include <sys/systm.h> 35 #include <sys/buf.h> 36 #include <sys/device.h> 37 #define FSTYPENAMES 38 #include <sys/disklabel.h> 39 #include <sys/disk.h> 40 41 #include <dev/scsipi/scsi_all.h> 42 #include <dev/scsipi/scsipi_all.h> 43 #include <dev/scsipi/scsiconf.h> 44 45 #include <machine/autoconf.h> 46 47 #ifdef DEBUG 48 int disksubr_debug = 0; 49 #endif 50 51 static void bsdtocpulabel __P((struct disklabel *lp, 52 struct cpu_disklabel *clp)); 53 static void cputobsdlabel __P((struct disklabel *lp, 54 struct cpu_disklabel *clp)); 55 56 #ifdef DEBUG 57 static void printlp __P((struct disklabel *lp, char *str)); 58 static void printclp __P((struct cpu_disklabel *clp, char *str)); 59 #endif 60 61 62 /* 63 * Attempt to read a disk label from a device 64 * using the indicated strategy routine. 65 * The label must be partly set up before this: 66 * secpercyl and anything required in the strategy routine 67 * (e.g., sector size) must be filled in before calling us. 68 * Returns null on success and an error string on failure. 69 */ 70 char * 71 readdisklabel(dev, strat, lp, clp) 72 dev_t dev; 73 void (*strat)(struct buf *); 74 struct disklabel *lp; 75 struct cpu_disklabel *clp; 76 { 77 struct buf *bp; 78 char *msg = NULL; 79 80 /* obtain buffer to probe drive with */ 81 bp = geteblk((int)lp->d_secsize); 82 83 /* request no partition relocation by driver on I/O operations */ 84 bp->b_dev = dev; 85 bp->b_blkno = 0; /* contained in block 0 */ 86 bp->b_bcount = lp->d_secsize; 87 bp->b_flags |= B_READ; 88 bp->b_cylinder = 0; /* contained in block 0 */ 89 (*strat)(bp); 90 91 if (biowait(bp)) { 92 msg = "cpu_disklabel read error\n"; 93 } else { 94 memcpy(clp, bp->b_data, sizeof (struct cpu_disklabel)); 95 } 96 97 brelse(bp); 98 99 if (msg || clp->magic1 != DISKMAGIC || clp->magic2 != DISKMAGIC) { 100 return (msg); 101 } 102 103 cputobsdlabel(lp, clp); 104 #ifdef DEBUG 105 if(disksubr_debug > 0) { 106 printlp(lp, "readdisklabel:bsd label"); 107 printclp(clp, "readdisklabel:cpu label"); 108 } 109 #endif 110 return (msg); 111 } 112 113 /* 114 * Check new disk label for sensibility 115 * before setting it. 116 */ 117 int 118 setdisklabel(olp, nlp, openmask, clp) 119 struct disklabel *olp, *nlp; 120 u_long openmask; 121 struct cpu_disklabel *clp; 122 { 123 int i; 124 struct partition *opp, *npp; 125 126 #ifdef DEBUG 127 if(disksubr_debug > 0) { 128 printlp(nlp, "setdisklabel:new disklabel"); 129 printlp(olp, "setdisklabel:old disklabel"); 130 printclp(clp, "setdisklabel:cpu disklabel"); 131 } 132 #endif 133 134 135 /* sanity clause */ 136 if (nlp->d_secpercyl == 0 || nlp->d_secsize == 0 || 137 (nlp->d_secsize % DEV_BSIZE) != 0) 138 return (EINVAL); 139 140 /* special case to allow disklabel to be invalidated */ 141 if (nlp->d_magic == 0xffffffff) { 142 *olp = *nlp; 143 return (0); 144 } 145 146 if (nlp->d_magic != DISKMAGIC || nlp->d_magic2 != DISKMAGIC || 147 dkcksum(nlp) != 0) 148 return (EINVAL); 149 150 while ((i = ffs(openmask)) != 0) { 151 i--; 152 openmask &= ~(1 << i); 153 if (nlp->d_npartitions <= i) 154 return (EBUSY); 155 opp = &olp->d_partitions[i]; 156 npp = &nlp->d_partitions[i]; 157 if (npp->p_offset != opp->p_offset || npp->p_size < opp->p_size) 158 return (EBUSY); 159 /* 160 * Copy internally-set partition information 161 * if new label doesn't include it. XXX 162 */ 163 if (npp->p_fstype == FS_UNUSED && opp->p_fstype != FS_UNUSED) { 164 npp->p_fstype = opp->p_fstype; 165 npp->p_fsize = opp->p_fsize; 166 npp->p_frag = opp->p_frag; 167 npp->p_cpg = opp->p_cpg; 168 } 169 } 170 171 nlp->d_checksum = 0; 172 nlp->d_checksum = dkcksum(nlp); 173 *olp = *nlp; 174 #ifdef DEBUG 175 if(disksubr_debug > 0) { 176 printlp(olp, "setdisklabel:old->new disklabel"); 177 } 178 #endif 179 return (0); 180 } 181 182 /* 183 * Write disk label back to device after modification. 184 */ 185 int 186 writedisklabel(dev, strat, lp, clp) 187 dev_t dev; 188 void (*strat)(struct buf *); 189 struct disklabel *lp; 190 struct cpu_disklabel *clp; 191 { 192 struct buf *bp; 193 int error; 194 195 #ifdef DEBUG 196 if(disksubr_debug > 0) { 197 printlp(lp, "writedisklabel: bsd label"); 198 } 199 #endif 200 201 /* obtain buffer to read initial cpu_disklabel, for bootloader size :-) */ 202 bp = geteblk((int)lp->d_secsize); 203 204 /* request no partition relocation by driver on I/O operations */ 205 bp->b_dev = dev; 206 bp->b_blkno = 0; /* contained in block 0 */ 207 bp->b_bcount = lp->d_secsize; 208 bp->b_flags |= B_READ; 209 bp->b_cylinder = 0; /* contained in block 0 */ 210 (*strat)(bp); 211 212 if ( (error = biowait(bp)) != 0 ) { 213 /* nothing */ 214 } else { 215 memcpy(clp, bp->b_data, sizeof(struct cpu_disklabel)); 216 } 217 218 brelse(bp); 219 220 if (error) { 221 return (error); 222 } 223 224 bsdtocpulabel(lp, clp); 225 226 #ifdef DEBUG 227 if (disksubr_debug > 0) { 228 printclp(clp, "writedisklabel: cpu label"); 229 } 230 #endif 231 232 if (lp->d_magic == DISKMAGIC && lp->d_magic2 == DISKMAGIC && 233 dkcksum(lp) == 0) { 234 /* obtain buffer to scrozz drive with */ 235 bp = geteblk((int)lp->d_secsize); 236 237 memcpy(bp->b_data, clp, sizeof(struct cpu_disklabel)); 238 239 /* request no partition relocation by driver on I/O operations */ 240 bp->b_dev = dev; 241 bp->b_blkno = 0; /* contained in block 0 */ 242 bp->b_bcount = lp->d_secsize; 243 bp->b_flags |= B_WRITE; 244 bp->b_cylinder = 0; /* contained in block 0 */ 245 (*strat)(bp); 246 247 error = biowait(bp); 248 249 brelse(bp); 250 } 251 return (error); 252 } 253 254 255 int 256 bounds_check_with_label(bp, lp, wlabel) 257 struct buf *bp; 258 struct disklabel *lp; 259 int wlabel; 260 { 261 struct partition *p = lp->d_partitions + DISKPART(bp->b_dev); 262 int maxsz = p->p_size; 263 int sz = (bp->b_bcount + DEV_BSIZE - 1) >> DEV_BSHIFT; 264 265 /* overwriting disk label ? */ 266 /* XXX should also protect bootstrap in first 8K */ 267 /* XXX this assumes everything <=LABELSECTOR is label! */ 268 /* (but since LABELSECTOR is zero, this is ok) */ 269 if (bp->b_blkno + p->p_offset <= LABELSECTOR && 270 (bp->b_flags & B_READ) == 0 && wlabel == 0) { 271 bp->b_error = EROFS; 272 goto bad; 273 } 274 275 /* beyond partition? */ 276 if (bp->b_blkno < 0 || bp->b_blkno + sz > maxsz) { 277 /* if exactly at end of disk, return an EOF */ 278 if (bp->b_blkno == maxsz) { 279 bp->b_resid = bp->b_bcount; 280 return(0); 281 } 282 /* or truncate if part of it fits */ 283 sz = maxsz - bp->b_blkno; 284 if (sz <= 0) { 285 bp->b_error = EINVAL; 286 goto bad; 287 } 288 bp->b_bcount = sz << DEV_BSHIFT; 289 } 290 291 /* calculate cylinder for disksort to order transfers with */ 292 bp->b_cylinder = (bp->b_blkno + p->p_offset) / lp->d_secpercyl; 293 return(1); 294 295 bad: 296 bp->b_flags |= B_ERROR; 297 return(-1); 298 } 299 300 301 static void 302 bsdtocpulabel(lp, clp) 303 struct disklabel *lp; 304 struct cpu_disklabel *clp; 305 { 306 int i; 307 308 clp->magic1 = lp->d_magic; 309 clp->type = lp->d_type; 310 clp->subtype = lp->d_subtype; 311 strncpy(clp->vid_vd, lp->d_typename, 16); 312 strncpy(clp->packname, lp->d_packname, 16); 313 clp->cfg_psm = lp->d_secsize; 314 clp->cfg_spt = lp->d_nsectors; 315 clp->cfg_trk = lp->d_ncylinders; /* trk is really num of cyl! */ 316 clp->cfg_hds = lp->d_ntracks; 317 318 clp->secpercyl = lp->d_secpercyl; 319 clp->secperunit = lp->d_secperunit; 320 clp->sparespertrack = lp->d_sparespertrack; 321 clp->sparespercyl = lp->d_sparespercyl; 322 clp->acylinders = lp->d_acylinders; 323 clp->rpm = lp->d_rpm; 324 325 clp->cfg_ilv = lp->d_interleave; 326 clp->cfg_sof = lp->d_trackskew; 327 clp->cylskew = lp->d_cylskew; 328 clp->headswitch = lp->d_headswitch; 329 330 /* this silly table is for winchester drives */ 331 if (lp->d_trkseek < 6) { 332 clp->cfg_ssr = 0; 333 } else if (lp->d_trkseek < 10) { 334 clp->cfg_ssr = 1; 335 } else if (lp->d_trkseek < 15) { 336 clp->cfg_ssr = 2; 337 } else if (lp->d_trkseek < 20) { 338 clp->cfg_ssr = 3; 339 } else { 340 clp->cfg_ssr = 4; 341 } 342 343 clp->flags = lp->d_flags; 344 for (i = 0; i < NDDATA; i++) 345 clp->drivedata[i] = lp->d_drivedata[i]; 346 for (i = 0; i < NSPARE; i++) 347 clp->spare[i] = lp->d_spare[i]; 348 349 clp->magic2 = lp->d_magic2; 350 clp->checksum = lp->d_checksum; 351 clp->partitions = lp->d_npartitions; 352 clp->bbsize = lp->d_bbsize; 353 clp->sbsize = lp->d_sbsize; 354 clp->checksum = lp->d_checksum; 355 /* note: assume at least 4 partitions */ 356 memcpy(clp->vid_4, &lp->d_partitions[0], sizeof(struct partition) * 4); 357 memset(clp->cfg_4, 0, sizeof(struct partition) * 12); 358 memcpy(clp->cfg_4, &lp->d_partitions[4], sizeof(struct partition) 359 * ((MAXPARTITIONS < 16) ? (MAXPARTITIONS - 4) : 12)); 360 361 /* 362 * here are the parts of the cpu_disklabel the kernel must init. 363 * see disklabel.h for more details 364 * [note: this used to be handled by 'wrtvid'] 365 */ 366 memcpy(clp->vid_id, VID_ID, sizeof(clp->vid_id)); 367 clp->vid_oss = VID_OSS; 368 clp->vid_osl = VID_OSL; 369 clp->vid_osa_u = VID_OSAU; 370 clp->vid_osa_l = VID_OSAL; 371 clp->vid_cas = VID_CAS; 372 clp->vid_cal = VID_CAL; 373 memcpy(clp->vid_mot, VID_MOT, sizeof(clp->vid_mot)); 374 clp->cfg_rec = CFG_REC; 375 clp->cfg_psm = CFG_PSM; 376 } 377 378 static void 379 cputobsdlabel(lp, clp) 380 struct disklabel *lp; 381 struct cpu_disklabel *clp; 382 { 383 int i; 384 385 lp->d_magic = clp->magic1; 386 lp->d_type = clp->type; 387 lp->d_subtype = clp->subtype; 388 strncpy(lp->d_typename, clp->vid_vd, 16); 389 strncpy(lp->d_packname, clp->packname, 16); 390 lp->d_secsize = clp->cfg_psm; 391 lp->d_nsectors = clp->cfg_spt; 392 lp->d_ncylinders = clp->cfg_trk; /* trk is really num of cyl! */ 393 lp->d_ntracks = clp->cfg_hds; 394 395 lp->d_secpercyl = clp->secpercyl; 396 lp->d_secperunit = clp->secperunit; 397 lp->d_secpercyl = clp->secpercyl; 398 lp->d_secperunit = clp->secperunit; 399 lp->d_sparespertrack = clp->sparespertrack; 400 lp->d_sparespercyl = clp->sparespercyl; 401 lp->d_acylinders = clp->acylinders; 402 lp->d_rpm = clp->rpm; 403 lp->d_interleave = clp->cfg_ilv; 404 lp->d_trackskew = clp->cfg_sof; 405 lp->d_cylskew = clp->cylskew; 406 lp->d_headswitch = clp->headswitch; 407 408 /* this silly table is for winchester drives */ 409 switch (clp->cfg_ssr) { 410 case 0: 411 lp->d_trkseek = 0; 412 break; 413 case 1: 414 lp->d_trkseek = 6; 415 break; 416 case 2: 417 lp->d_trkseek = 10; 418 break; 419 case 3: 420 lp->d_trkseek = 15; 421 break; 422 case 4: 423 lp->d_trkseek = 20; 424 break; 425 default: 426 lp->d_trkseek = 0; 427 } 428 lp->d_flags = clp->flags; 429 for (i = 0; i < NDDATA; i++) 430 lp->d_drivedata[i] = clp->drivedata[i]; 431 for (i = 0; i < NSPARE; i++) 432 lp->d_spare[i] = clp->spare[i]; 433 434 lp->d_magic2 = clp->magic2; 435 lp->d_checksum = clp->checksum; 436 lp->d_npartitions = clp->partitions; 437 lp->d_bbsize = clp->bbsize; 438 lp->d_sbsize = clp->sbsize; 439 /* note: assume at least 4 partitions */ 440 memcpy(&lp->d_partitions[0], clp->vid_4, sizeof(struct partition) * 4); 441 memcpy(&lp->d_partitions[4], clp->cfg_4, sizeof(struct partition) 442 * ((MAXPARTITIONS < 16) ? (MAXPARTITIONS - 4) : 12)); 443 lp->d_checksum = 0; 444 lp->d_checksum = dkcksum(lp); 445 #if DEBUG 446 if (disksubr_debug > 0) { 447 printlp(lp, "translated label read from disk\n"); 448 } 449 #endif 450 } 451 452 #ifdef DEBUG 453 static void 454 printlp(lp, str) 455 struct disklabel *lp; 456 char *str; 457 { 458 int i; 459 460 printf("%s\n", str); 461 printf("magic1 %x\n", lp->d_magic); 462 printf("magic2 %x\n", lp->d_magic2); 463 printf("typename %s\n", lp->d_typename); 464 printf("secsize %x nsect %x ntrack %x ncylinders %x\n", 465 lp->d_secsize, lp->d_nsectors, lp->d_ntracks, lp->d_ncylinders); 466 printf("Num partitions %x\n", lp->d_npartitions); 467 for (i = 0; i < lp->d_npartitions; i++) { 468 struct partition *part = &lp->d_partitions[i]; 469 const char *fstyp = fstypenames[part->p_fstype]; 470 471 printf("%c: size %10x offset %10x type %7s frag %5x cpg %3x\n", 472 'a' + i, part->p_size, part->p_offset, fstyp, 473 part->p_frag, part->p_cpg); 474 } 475 } 476 477 static void 478 printclp(clp, str) 479 struct cpu_disklabel *clp; 480 char *str; 481 { 482 int max, i; 483 484 printf("%s\n", str); 485 printf("magic1 %lx\n", clp->magic1); 486 printf("magic2 %lx\n", clp->magic2); 487 printf("typename %s\n", clp->vid_vd); 488 printf("secsize %x nsect %x ntrack %x ncylinders %x\n", 489 clp->cfg_psm, clp->cfg_spt, clp->cfg_hds, clp->cfg_trk); 490 printf("Num partitions %x\n", clp->partitions); 491 max = clp->partitions < 16 ? clp->partitions : 16; 492 for (i = 0; i < max; i++) { 493 struct partition *part; 494 const char *fstyp; 495 496 if (i < 4) { 497 part = (void *)&clp->vid_4[0]; 498 part = &part[i]; 499 } else { 500 part = (void *)&clp->cfg_4[0]; 501 part = &part[i-4]; 502 } 503 504 fstyp = fstypenames[part->p_fstype]; 505 506 printf("%c: size %10x offset %10x type %7s frag %5x cpg %3x\n", 507 'a' + i, part->p_size, part->p_offset, fstyp, 508 part->p_frag, part->p_cpg); 509 } 510 } 511 #endif 512