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