1 /* $NetBSD: disksubr.c,v 1.29 2009/10/26 19:16:56 cegger Exp $ */ 2 3 /* 4 * Copyright (c) 1982, 1986, 1988 Regents of the University of California. 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. Neither the name of the University nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 * 31 * Credits: 32 * This file was based mostly on the i386/disksubr.c file: 33 * @(#)ufs_disksubr.c 7.16 (Berkeley) 5/4/91 34 * The functions: disklabel_sun_to_bsd, disklabel_bsd_to_sun 35 * were originally taken from arch/sparc/scsi/sun_disklabel.c 36 * (which was written by Theo de Raadt) and then substantially 37 * rewritten by Gordon W. Ross. 38 */ 39 40 /* 41 * Copyright (c) 1994 Theo de Raadt. All rights reserved. 42 * 43 * Redistribution and use in source and binary forms, with or without 44 * modification, are permitted provided that the following conditions 45 * are met: 46 * 1. Redistributions of source code must retain the above copyright 47 * notice, this list of conditions and the following disclaimer. 48 * 2. Redistributions in binary form must reproduce the above copyright 49 * notice, this list of conditions and the following disclaimer in the 50 * documentation and/or other materials provided with the distribution. 51 * 52 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 53 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 54 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 55 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 56 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 57 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 58 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 59 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 60 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 61 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 62 * 63 */ 64 65 /* 66 * Copyright (c) 1994, 1995 Gordon W. Ross 67 * 68 * Redistribution and use in source and binary forms, with or without 69 * modification, are permitted provided that the following conditions 70 * are met: 71 * 1. Redistributions of source code must retain the above copyright 72 * notice, this list of conditions and the following disclaimer. 73 * 2. Redistributions in binary form must reproduce the above copyright 74 * notice, this list of conditions and the following disclaimer in the 75 * documentation and/or other materials provided with the distribution. 76 * 3. All advertising materials mentioning features or use of this software 77 * must display the following acknowledgement: 78 * This product includes software developed by the University of 79 * California, Berkeley and its contributors. 80 * 4. Neither the name of the University nor the names of its contributors 81 * may be used to endorse or promote products derived from this software 82 * without specific prior written permission. 83 * 84 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 85 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 86 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 87 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 88 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 89 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 90 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 91 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 92 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 93 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 94 * SUCH DAMAGE. 95 * 96 * Credits: 97 * This file was based mostly on the i386/disksubr.c file: 98 * @(#)ufs_disksubr.c 7.16 (Berkeley) 5/4/91 99 * The functions: disklabel_sun_to_bsd, disklabel_bsd_to_sun 100 * were originally taken from arch/sparc/scsi/sun_disklabel.c 101 * (which was written by Theo de Raadt) and then substantially 102 * rewritten by Gordon W. Ross. 103 */ 104 105 #include <sys/cdefs.h> 106 __KERNEL_RCSID(0, "$NetBSD: disksubr.c,v 1.29 2009/10/26 19:16:56 cegger Exp $"); 107 108 #include <sys/param.h> 109 #include <sys/systm.h> 110 #include <sys/buf.h> 111 #include <sys/device.h> 112 #include <sys/disklabel.h> 113 #include <sys/disk.h> 114 #include <sys/dkbad.h> 115 116 #include <dev/sun/disklabel.h> 117 118 /* 119 * UniOS disklabel (== ISI disklabel) is very similar to SunOS. 120 * SunOS UniOS/ISI 121 * text 128 128 122 * (pad) 292 294 123 * rpm 2 - 124 * pcyl 2 badchk 2 125 * sparecyl 2 maxblk 4 126 * (pad) 4 dtype 2 127 * interleave 2 ndisk 2 128 * ncyl 2 2 129 * acyl 2 2 130 * ntrack 2 2 131 * nsect 2 2 132 * (pad) 4 bhead 2 133 * - ppart 2 134 * dkpart[8] 64 64 135 * magic 2 2 136 * cksum 2 2 137 * 138 * Magic number value and checksum calculation are identical. Subtle 139 * difference is partition start address; UniOS/ISI maintains sector 140 * numbers while SunOS label has cylinder number. 141 * 142 * It is found that LUNA Mach2.5 has BSD label embedded at offset 64 143 * retaining UniOS/ISI label at the end of label block. LUNA Mach 144 * manipulates BSD disklabel in the same manner as 4.4BSD. It's 145 * uncertain LUNA Mach can create a disklabel on fresh disks since 146 * Mach writedisklabel logic seems to fail when no BSD label is found. 147 * 148 * Kernel handles disklabel in this way; 149 * - searchs BSD label at offset 64 150 * - if not found, searchs UniOS/ISI label at the end of block 151 * - kernel can distinguish whether it was SunOS label or UniOS/ISI 152 * label and understand both 153 * - kernel writes UniOS/ISI label combined with BSD label to update 154 * the label block 155 */ 156 157 #if LABELSECTOR != 0 158 #error "Default value of LABELSECTOR no longer zero?" 159 #endif 160 161 static const char *disklabel_om_to_bsd(char *, struct disklabel *); 162 static int disklabel_bsd_to_om(struct disklabel *, char *); 163 164 /* 165 * Attempt to read a disk label from a device 166 * using the indicated strategy routine. 167 * The label must be partly set up before this: 168 * secpercyl, secsize and anything required for a block i/o read 169 * operation in the driver's strategy/start routines 170 * must be filled in before calling us. 171 * 172 * Return buffer for use in signalling errors if requested. 173 * 174 * Returns null on success and an error string on failure. 175 */ 176 const char * 177 readdisklabel(dev_t dev, void (*strat)(struct buf *), struct disklabel *lp, struct cpu_disklabel *clp) 178 { 179 struct buf *bp; 180 struct disklabel *dlp; 181 struct sun_disklabel *slp; 182 int error; 183 184 /* minimal requirements for archtypal disk label */ 185 if (lp->d_secperunit == 0) 186 lp->d_secperunit = 0x1fffffff; 187 lp->d_npartitions = 1; 188 if (lp->d_partitions[0].p_size == 0) 189 lp->d_partitions[0].p_size = 0x1fffffff; 190 lp->d_partitions[0].p_offset = 0; 191 192 /* obtain buffer to probe drive with */ 193 bp = geteblk((int)lp->d_secsize); 194 195 /* next, dig out disk label */ 196 bp->b_dev = dev; 197 bp->b_blkno = LABELSECTOR; 198 bp->b_cylinder = 0; 199 bp->b_bcount = lp->d_secsize; 200 bp->b_flags |= B_READ; 201 (*strat)(bp); 202 203 /* if successful, locate disk label within block and validate */ 204 error = biowait(bp); 205 if (!error) { 206 /* Save the whole block in case it has info we need. */ 207 memcpy(clp->cd_block, bp->b_data, sizeof(clp->cd_block)); 208 } 209 brelse(bp, 0); 210 if (error) 211 return ("disk label read error"); 212 213 /* Check for a NetBSD disk label first. */ 214 dlp = (struct disklabel *)(clp->cd_block + LABELOFFSET); 215 if (dlp->d_magic == DISKMAGIC && dlp->d_magic2 == DISKMAGIC) { 216 if (dkcksum(dlp) == 0) { 217 *lp = *dlp; /* struct assignment */ 218 return (NULL); 219 } 220 printf("NetBSD disk label corrupted"); 221 } 222 223 /* Check for a UniOS/ISI disk label. */ 224 slp = (struct sun_disklabel *)clp->cd_block; 225 if (slp->sl_magic == SUN_DKMAGIC) { 226 return (disklabel_om_to_bsd(clp->cd_block, lp)); 227 } 228 229 memset(clp->cd_block, 0, sizeof(clp->cd_block)); 230 return ("no disk label"); 231 } 232 233 /* 234 * Check new disk label for sensibility 235 * before setting it. 236 */ 237 int 238 setdisklabel(struct disklabel *olp, struct disklabel *nlp, u_long openmask, struct cpu_disklabel *clp) 239 { 240 struct partition *opp, *npp; 241 int i; 242 243 /* sanity clause */ 244 if ((nlp->d_secpercyl == 0) || (nlp->d_secsize == 0) || 245 (nlp->d_secsize % DEV_BSIZE) != 0) 246 return (EINVAL); 247 248 /* special case to allow disklabel to be invalidated */ 249 if (nlp->d_magic == 0xffffffff) { 250 *olp = *nlp; 251 return (0); 252 } 253 254 if (nlp->d_magic != DISKMAGIC || 255 nlp->d_magic2 != DISKMAGIC || 256 dkcksum(nlp) != 0) 257 return (EINVAL); 258 259 while (openmask != 0) { 260 i = ffs(openmask) - 1; 261 openmask &= ~(1 << i); 262 if (nlp->d_npartitions <= i) 263 return (EBUSY); 264 opp = &olp->d_partitions[i]; 265 npp = &nlp->d_partitions[i]; 266 if (npp->p_offset != opp->p_offset || 267 npp->p_size < opp->p_size) 268 return (EBUSY); 269 } 270 271 /* We did not modify the new label, so the checksum is OK. */ 272 *olp = *nlp; 273 return (0); 274 } 275 276 277 /* 278 * Write disk label back to device after modification. 279 * Current label is already in clp->cd_block[] 280 */ 281 int 282 writedisklabel(dev_t dev, void (*strat)(struct buf *), struct disklabel *lp, struct cpu_disklabel *clp) 283 { 284 struct buf *bp; 285 struct disklabel *dlp; 286 int error; 287 288 /* implant NetBSD disklabel at LABELOFFSET. */ 289 dlp = (struct disklabel *)(clp->cd_block + LABELOFFSET); 290 *dlp = *lp; /* struct assignment */ 291 292 error = disklabel_bsd_to_om(lp, clp->cd_block); 293 if (error) 294 return (error); 295 296 /* Get a buffer and copy the new label into it. */ 297 bp = geteblk((int)lp->d_secsize); 298 memcpy(bp->b_data, clp->cd_block, sizeof(clp->cd_block)); 299 300 /* Write out the updated label. */ 301 bp->b_dev = dev; 302 bp->b_blkno = LABELSECTOR; 303 bp->b_cylinder = 0; 304 bp->b_bcount = lp->d_secsize; 305 bp->b_flags |= B_WRITE; 306 (*strat)(bp); 307 error = biowait(bp); 308 brelse(bp, 0); 309 310 return (error); 311 } 312 313 /************************************************************************ 314 * 315 * The rest of this was taken from arch/sparc/scsi/sun_disklabel.c 316 * and then substantially rewritten by Gordon W. Ross 317 * 318 ************************************************************************/ 319 320 /* What partition types to assume for Sun disklabels: */ 321 static u_char 322 sun_fstypes[8] = { 323 FS_BSDFFS, /* a */ 324 FS_SWAP, /* b */ 325 FS_OTHER, /* c - whole disk */ 326 FS_BSDFFS, /* d */ 327 FS_BSDFFS, /* e */ 328 FS_BSDFFS, /* f */ 329 FS_BSDFFS, /* g */ 330 FS_BSDFFS, /* h */ 331 }; 332 333 /* 334 * Given a UniOS/ISI disk label, set lp to a BSD disk label. 335 * Returns NULL on success, else an error string. 336 * 337 * The BSD label is cleared out before this is called. 338 */ 339 static const char * 340 disklabel_om_to_bsd(char *cp, struct disklabel *lp) 341 { 342 struct sun_disklabel *sl; 343 struct partition *npp; 344 struct sun_dkpart *spp; 345 int i, secpercyl; 346 u_short cksum, *sp1, *sp2; 347 348 sl = (struct sun_disklabel *)cp; 349 350 /* Verify the XOR check. */ 351 sp1 = (u_short *)sl; 352 sp2 = (u_short *)(sl + 1); 353 cksum = 0; 354 while (sp1 < sp2) 355 cksum ^= *sp1++; 356 if (cksum != 0) 357 return ("UniOS disk label, bad checksum"); 358 359 memset((void *)lp, 0, sizeof(struct disklabel)); 360 /* Format conversion. */ 361 lp->d_magic = DISKMAGIC; 362 lp->d_magic2 = DISKMAGIC; 363 memcpy(lp->d_packname, sl->sl_text, sizeof(lp->d_packname)); 364 365 lp->d_type = DTYPE_SCSI; 366 lp->d_secsize = 512; 367 lp->d_nsectors = sl->sl_nsectors; 368 lp->d_ntracks = sl->sl_ntracks; 369 lp->d_ncylinders = sl->sl_ncylinders; 370 371 secpercyl = sl->sl_nsectors * sl->sl_ntracks; 372 lp->d_secpercyl = secpercyl; 373 lp->d_secperunit = secpercyl * sl->sl_ncylinders; 374 375 lp->d_sparespercyl = 0; /* no way to know */ 376 lp->d_acylinders = sl->sl_acylinders; 377 lp->d_rpm = sl->sl_rpm; /* UniOS - (empty) */ 378 lp->d_interleave = sl->sl_interleave; /* UniOS - ndisk */ 379 380 if (sl->sl_rpm == 0) { 381 /* UniOS label has blkoffset, not cyloffset */ 382 secpercyl = 1; 383 } 384 385 lp->d_npartitions = 8; 386 /* These are as defined in <ufs/ffs/fs.h> */ 387 lp->d_bbsize = 8192; /* XXX */ 388 lp->d_sbsize = 8192; /* XXX */ 389 for (i = 0; i < 8; i++) { 390 spp = &sl->sl_part[i]; 391 npp = &lp->d_partitions[i]; 392 npp->p_offset = spp->sdkp_cyloffset * secpercyl; 393 npp->p_size = spp->sdkp_nsectors; 394 if (npp->p_size == 0) 395 npp->p_fstype = FS_UNUSED; 396 else { 397 /* Partition has non-zero size. Set type, etc. */ 398 npp->p_fstype = sun_fstypes[i]; 399 400 /* 401 * The sun label does not store the FFS fields, 402 * so just set them with default values here. 403 * XXX: This keeps newfs from trying to rewrite 404 * XXX: the disk label in the most common case. 405 * XXX: (Should remove that code from newfs...) 406 */ 407 if (npp->p_fstype == FS_BSDFFS) { 408 npp->p_fsize = 1024; 409 npp->p_frag = 8; 410 npp->p_cpg = 16; 411 } 412 } 413 } 414 415 /* 416 * XXX BandAid XXX 417 * UniOS rootfs sits on part c which don't begin at sect 0, 418 * and impossible to mount. Thus, make it usable as part b. 419 */ 420 if (sl->sl_rpm == 0 && lp->d_partitions[2].p_offset != 0) { 421 lp->d_partitions[1] = lp->d_partitions[2]; 422 lp->d_partitions[1].p_fstype = FS_BSDFFS; 423 } 424 425 lp->d_checksum = dkcksum(lp); 426 427 return (NULL); 428 } 429 430 /* 431 * Given a BSD disk label, update the UniOS disklabel 432 * pointed to by cp with the new info. Note that the 433 * UniOS disklabel may have other info we need to keep. 434 * Returns zero or error code. 435 */ 436 static int 437 disklabel_bsd_to_om(struct disklabel *lp, char *cp) 438 { 439 struct sun_disklabel *sl; 440 struct partition *npp; 441 struct sun_dkpart *spp; 442 int i; 443 u_short cksum, *sp1, *sp2; 444 445 if (lp->d_secsize != 512) 446 return (EINVAL); 447 448 sl = (struct sun_disklabel *)cp; 449 450 /* Format conversion. */ 451 memcpy(sl->sl_text, lp->d_packname, sizeof(lp->d_packname)); 452 sl->sl_rpm = 0; /* UniOS */ 453 #if 0 /* leave as was */ 454 sl->sl_pcyl = lp->d_ncylinders + lp->d_acylinders; /* XXX */ 455 sl->sl_sparespercyl = lp->d_sparespercyl; 456 #endif 457 sl->sl_interleave = lp->d_interleave; 458 sl->sl_ncylinders = lp->d_ncylinders; 459 sl->sl_acylinders = lp->d_acylinders; 460 sl->sl_ntracks = lp->d_ntracks; 461 sl->sl_nsectors = lp->d_nsectors; 462 463 for (i = 0; i < 8; i++) { 464 spp = &sl->sl_part[i]; 465 npp = &lp->d_partitions[i]; 466 467 spp->sdkp_cyloffset = npp->p_offset; /* UniOS */ 468 spp->sdkp_nsectors = npp->p_size; 469 } 470 sl->sl_magic = SUN_DKMAGIC; 471 472 /* Correct the XOR check. */ 473 sp1 = (u_short *)sl; 474 sp2 = (u_short *)(sl + 1); 475 sl->sl_cksum = cksum = 0; 476 while (sp1 < sp2) 477 cksum ^= *sp1++; 478 sl->sl_cksum = cksum; 479 480 return (0); 481 } 482