1 /* $OpenBSD: disksubr.c,v 1.65 2024/12/28 00:00:32 aoyama Exp $ */ 2 /* $NetBSD: disksubr.c,v 1.12 2002/02/19 17:09:44 wiz Exp $ */ 3 4 /* 5 * Copyright (c) 1994, 1995 Gordon W. Ross 6 * Copyright (c) 1994 Theo de Raadt 7 * Copyright (c) 1982, 1986, 1988 Regents of the University of California. 8 * All rights reserved. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the University of 21 * California, Berkeley and its contributors. 22 * 4. Neither the name of the University nor the names of its contributors 23 * may be used to endorse or promote products derived from this software 24 * without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 29 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 36 * SUCH DAMAGE. 37 */ 38 39 #include <sys/param.h> 40 #include <sys/systm.h> 41 #include <sys/buf.h> 42 #include <sys/device.h> 43 #include <sys/disklabel.h> 44 #include <sys/disk.h> 45 46 #include <dev/sun/disklabel.h> 47 48 /* 49 * UniOS disklabel (== ISI disklabel) is very similar to SunOS. 50 * SunOS UniOS/ISI 51 * text 128 128 52 * (pad) 292 294 53 * rpm 2 - 54 * pcyl 2 badchk 2 55 * sparecyl 2 maxblk 4 56 * (pad) 4 dtype 2 57 * interleave 2 ndisk 2 58 * ncyl 2 2 59 * acyl 2 2 60 * ntrack 2 2 61 * nsect 2 2 62 * (pad) 4 bhead 2 63 * - ppart 2 64 * dkpart[8] 64 64 65 * magic 2 2 66 * cksum 2 2 67 * 68 * Magic number value and checksum calculation are identical. Subtle 69 * difference is partition start address; UniOS/ISI maintains sector 70 * numbers while SunOS label has cylinder number. 71 * 72 * It is found that LUNA Mach2.5 has BSD label embedded at offset 64 73 * retaining UniOS/ISI label at the end of label block. LUNA Mach 74 * manipulates BSD disklabel in the same manner as 4.4BSD. It's 75 * uncertain LUNA Mach can create a disklabel on fresh disks since 76 * Mach writedisklabel logic seems to fail when no BSD label is found. 77 * 78 * Kernel handles disklabel in this way; 79 * - searches BSD label at offset 64 80 * - if not found, searches UniOS/ISI label at the end of block 81 * - kernel can distinguish whether it was SunOS label or UniOS/ISI 82 * label and understand both 83 * - kernel writes UniOS/ISI label combined with BSD label to update 84 * the label block 85 */ 86 87 #if LABELSECTOR != 0 88 #error "Default value of LABELSECTOR no longer zero?" 89 #endif 90 91 int disklabel_om_to_bsd(dev_t, struct sun_disklabel *, struct disklabel *); 92 int disklabel_bsd_to_om(struct disklabel *, struct sun_disklabel *); 93 static __inline u_int sun_extended_sum(struct sun_disklabel *, void *); 94 95 /* 96 * Attempt to read a disk label from a device 97 * using the indicated strategy routine. 98 * The label must be partly set up before this: 99 * secpercyl, secsize and anything required for a block i/o read 100 * operation in the driver's strategy/start routines 101 * must be filled in before calling us. 102 */ 103 int 104 readdisklabel(dev_t dev, void (*strat)(struct buf *), 105 struct disklabel *lp, int spoofonly) 106 { 107 struct sun_disklabel *slp; 108 struct buf *bp = NULL; 109 int error; 110 111 if ((error = initdisklabel(lp))) 112 goto done; 113 114 /* get a buffer and initialize it */ 115 bp = geteblk(lp->d_secsize); 116 bp->b_dev = dev; 117 118 if (spoofonly) 119 goto doslabel; 120 121 error = readdisksector(bp, strat, lp, DL_BLKTOSEC(lp, LABELSECTOR)); 122 if (error) 123 goto done; 124 125 slp = (struct sun_disklabel *)bp->b_data; 126 if (slp->sl_magic == SUN_DKMAGIC) { 127 error = disklabel_om_to_bsd(bp->b_dev, slp, lp); 128 goto done; 129 } 130 131 error = checkdisklabel(bp->b_dev, bp->b_data + LABELOFFSET, lp, 0, 132 DL_GETDSIZE(lp)); 133 if (error == 0) 134 goto done; 135 136 doslabel: 137 error = readdoslabel(bp, strat, lp, NULL, spoofonly); 138 if (error == 0) 139 goto done; 140 141 #if defined(CD9660) 142 error = iso_disklabelspoof(dev, strat, lp); 143 if (error == 0) 144 goto done; 145 #endif 146 #if defined(UDF) 147 error = udf_disklabelspoof(dev, strat, lp); 148 if (error == 0) 149 goto done; 150 #endif 151 152 done: 153 if (bp) { 154 bp->b_flags |= B_INVAL; 155 brelse(bp); 156 } 157 disk_change = 1; 158 return (error); 159 } 160 161 /* 162 * Write disk label back to device after modification. 163 */ 164 int 165 writedisklabel(dev_t dev, void (*strat)(struct buf *), struct disklabel *lp) 166 { 167 struct buf *bp = NULL; 168 int error; 169 170 /* get a buffer and initialize it */ 171 bp = geteblk(lp->d_secsize); 172 bp->b_dev = dev; 173 174 error = disklabel_bsd_to_om(lp, (struct sun_disklabel *)bp->b_data); 175 if (error) 176 goto done; 177 178 /* Write out the updated label. */ 179 bp->b_blkno = LABELSECTOR; 180 bp->b_bcount = lp->d_secsize; 181 CLR(bp->b_flags, B_READ | B_WRITE | B_DONE); 182 SET(bp->b_flags, B_BUSY | B_WRITE | B_RAW); 183 (*strat)(bp); 184 error = biowait(bp); 185 186 done: 187 if (bp) { 188 bp->b_flags |= B_INVAL; 189 brelse(bp); 190 } 191 disk_change = 1; 192 return (error); 193 } 194 195 /************************************************************************ 196 * 197 * The rest of this was taken from arch/sparc/scsi/sun_disklabel.c 198 * and then substantially rewritten by Gordon W. Ross 199 * 200 ************************************************************************/ 201 202 /* What partition types to assume for Sun disklabels: */ 203 static const u_char 204 sun_fstypes[16] = { 205 FS_BSDFFS, /* a */ 206 FS_SWAP, /* b */ 207 FS_UNUSED, /* c - whole disk */ 208 FS_BSDFFS, /* d */ 209 FS_BSDFFS, /* e */ 210 FS_BSDFFS, /* f */ 211 FS_BSDFFS, /* g */ 212 FS_BSDFFS, /* h */ 213 FS_BSDFFS, /* i */ 214 FS_BSDFFS, /* j */ 215 FS_BSDFFS, /* k */ 216 FS_BSDFFS, /* l */ 217 FS_BSDFFS, /* m */ 218 FS_BSDFFS, /* n */ 219 FS_BSDFFS, /* o */ 220 FS_BSDFFS /* p */ 221 }; 222 223 /* 224 * Given a struct sun_disklabel, assume it has an extended partition 225 * table and compute the correct value for sl_xpsum. 226 */ 227 static __inline u_int 228 sun_extended_sum(struct sun_disklabel *sl, void *end) 229 { 230 u_int sum, *xp, *ep; 231 232 xp = (u_int *)&sl->sl_xpmag; 233 ep = (u_int *)end; 234 235 sum = 0; 236 for (; xp < ep; xp++) 237 sum += *xp; 238 return (sum); 239 } 240 241 /* 242 * Given a UniOS/ISI disk label, set lp to a BSD disk label. 243 * 244 * The BSD label is cleared out before this is called. 245 */ 246 int 247 disklabel_om_to_bsd(dev_t dev, struct sun_disklabel *sl, struct disklabel *lp) 248 { 249 struct partition *npp; 250 struct sun_dkpart *spp; 251 int i, secpercyl; 252 u_short cksum = 0, *sp1, *sp2; 253 254 /* Verify the XOR check. */ 255 sp1 = (u_short *)sl; 256 sp2 = (u_short *)(sl + 1); 257 while (sp1 < sp2) 258 cksum ^= *sp1++; 259 if (cksum != 0) 260 return (EINVAL); /* UniOS disk label, bad checksum */ 261 262 /* Format conversion. */ 263 lp->d_magic = DISKMAGIC; 264 lp->d_magic2 = DISKMAGIC; 265 memcpy(lp->d_packname, sl->sl_text, sizeof(lp->d_packname)); 266 267 lp->d_secsize = DEV_BSIZE; 268 lp->d_nsectors = sl->sl_nsectors; 269 lp->d_ntracks = sl->sl_ntracks; 270 lp->d_ncylinders = sl->sl_ncylinders; 271 272 secpercyl = sl->sl_nsectors * sl->sl_ntracks; 273 lp->d_secpercyl = secpercyl; 274 /* If unset or initialized as full disk, permit refinement */ 275 if (DL_GETDSIZE(lp) == 0 || DL_GETDSIZE(lp) == MAXDISKSIZE) 276 DL_SETDSIZE(lp, (u_int64_t)secpercyl * sl->sl_ncylinders); 277 lp->d_version = 1; 278 279 memcpy(&lp->d_uid, &sl->sl_uid, sizeof(sl->sl_uid)); 280 281 lp->d_acylinders = sl->sl_acylinders; 282 283 lp->d_npartitions = MAXPARTITIONS; 284 285 for (i = 0; i < 8; i++) { 286 spp = &sl->sl_part[i]; 287 npp = &lp->d_partitions[i]; 288 /* UniOS label uses blkoffset, not cyloffset */ 289 DL_SETPOFFSET(npp, spp->sdkp_cyloffset); 290 DL_SETPSIZE(npp, spp->sdkp_nsectors); 291 if (DL_GETPSIZE(npp) == 0) { 292 npp->p_fstype = FS_UNUSED; 293 } else { 294 npp->p_fstype = sun_fstypes[i]; 295 if (npp->p_fstype == FS_BSDFFS) { 296 /* 297 * The sun label does not store the FFS fields, 298 * so just set them with default values here. 299 */ 300 npp->p_fragblock = 301 DISKLABELV1_FFS_FRAGBLOCK(2048, 8); 302 npp->p_cpg = 16; 303 } 304 } 305 } 306 307 /* 308 * XXX BandAid XXX 309 * UniOS rootfs sits on part c which don't begin at sect 0, 310 * and impossible to mount. Thus, make it usable as part b. 311 * XXX how to setup a swap partition on disks shared with UniOS??? 312 */ 313 if (sl->sl_rpm == 0 && DL_GETPOFFSET(&lp->d_partitions[2]) != 0) { 314 lp->d_partitions[1] = lp->d_partitions[2]; 315 lp->d_partitions[1].p_fstype = FS_BSDFFS; 316 } 317 318 /* Clear "extended" partition info, tentatively */ 319 for (i = 0; i < SUNXPART; i++) { 320 npp = &lp->d_partitions[i+8]; 321 DL_SETPOFFSET(npp, 0); 322 DL_SETPSIZE(npp, 0); 323 npp->p_fstype = FS_UNUSED; 324 } 325 326 /* Check to see if there's an "extended" partition table 327 * SL_XPMAG partitions had checksums up to just before the 328 * (new) sl_types variable, while SL_XPMAGTYP partitions have 329 * checksums up to the just before the (new) sl_xxx1 variable. 330 */ 331 if ((sl->sl_xpmag == SL_XPMAG && 332 sun_extended_sum(sl, &sl->sl_types) == sl->sl_xpsum) || 333 (sl->sl_xpmag == SL_XPMAGTYP && 334 sun_extended_sum(sl, &sl->sl_xxx1) == sl->sl_xpsum)) { 335 /* 336 * There is. Copy over the "extended" partitions. 337 * This code parallels the loop for partitions a-h. 338 */ 339 for (i = 0; i < SUNXPART; i++) { 340 spp = &sl->sl_xpart[i]; 341 npp = &lp->d_partitions[i+8]; 342 DL_SETPOFFSET(npp, spp->sdkp_cyloffset); 343 DL_SETPSIZE(npp, spp->sdkp_nsectors); 344 if (DL_GETPSIZE(npp) == 0) { 345 npp->p_fstype = FS_UNUSED; 346 continue; 347 } 348 npp->p_fstype = sun_fstypes[i+8]; 349 if (npp->p_fstype == FS_BSDFFS) { 350 npp->p_fragblock = 351 DISKLABELV1_FFS_FRAGBLOCK(2048, 8); 352 npp->p_cpg = 16; 353 } 354 } 355 if (sl->sl_xpmag == SL_XPMAGTYP) { 356 for (i = 0; i < MAXPARTITIONS; i++) { 357 npp = &lp->d_partitions[i]; 358 npp->p_fstype = sl->sl_types[i]; 359 npp->p_fragblock = sl->sl_fragblock[i]; 360 npp->p_cpg = sl->sl_cpg[i]; 361 } 362 } 363 } 364 365 lp->d_checksum = 0; 366 lp->d_checksum = dkcksum(lp); 367 return (checkdisklabel(dev, lp, lp, 0, DL_GETDSIZE(lp))); 368 } 369 370 /* 371 * Given a BSD disk label, update the UniOS disklabel 372 * pointed to by sl with the new info. Note that the 373 * UniOS disklabel may have other info we need to keep. 374 */ 375 int 376 disklabel_bsd_to_om(struct disklabel *lp, struct sun_disklabel *sl) 377 { 378 struct partition *npp; 379 struct sun_dkpart *spp; 380 int i, secpercyl; 381 u_short cksum, *sp1, *sp2; 382 383 if (lp->d_secsize != DEV_BSIZE || lp->d_nsectors == 0 || 384 lp->d_ntracks == 0) 385 return (EINVAL); 386 387 /* Format conversion. */ 388 bzero(sl, sizeof(*sl)); 389 memcpy(sl->sl_text, lp->d_packname, sizeof(lp->d_packname)); 390 sl->sl_rpm = 0; /* UniOS compatible */ 391 #if 0 /* leave as was */ 392 sl->sl_pcylinders = lp->d_ncylinders + lp->d_acylinders; /* XXX */ 393 #endif 394 sl->sl_interleave = 1; 395 sl->sl_ncylinders = lp->d_ncylinders; 396 sl->sl_acylinders = lp->d_acylinders; 397 sl->sl_ntracks = lp->d_ntracks; 398 sl->sl_nsectors = lp->d_nsectors; 399 400 memcpy(&sl->sl_uid, &lp->d_uid, sizeof(lp->d_uid)); 401 402 for (i = 0; i < 8; i++) { 403 spp = &sl->sl_part[i]; 404 npp = &lp->d_partitions[i]; 405 spp->sdkp_cyloffset = 0; 406 spp->sdkp_nsectors = 0; 407 if (DL_GETPSIZE(npp)) { 408 spp->sdkp_cyloffset = DL_GETPOFFSET(npp); /* UniOS */ 409 spp->sdkp_nsectors = DL_GETPSIZE(npp); 410 } 411 } 412 sl->sl_magic = SUN_DKMAGIC; 413 414 secpercyl = sl->sl_nsectors * sl->sl_ntracks; 415 for (i = 0; i < SUNXPART; i++) { 416 spp = &sl->sl_xpart[i]; 417 npp = &lp->d_partitions[i+8]; 418 spp->sdkp_cyloffset = 0; 419 spp->sdkp_nsectors = 0; 420 if (DL_GETPSIZE(npp)) { 421 spp->sdkp_cyloffset = DL_GETPOFFSET(npp); 422 spp->sdkp_nsectors = DL_GETPSIZE(npp); 423 } 424 } 425 for (i = 0; i < MAXPARTITIONS; i++) { 426 npp = &lp->d_partitions[i]; 427 sl->sl_types[i] = npp->p_fstype; 428 sl->sl_fragblock[i] = npp->p_fragblock; 429 sl->sl_cpg[i] = npp->p_cpg; 430 } 431 sl->sl_xpmag = SL_XPMAGTYP; 432 sl->sl_xpsum = sun_extended_sum(sl, &sl->sl_xxx1); 433 434 /* Correct the XOR check. */ 435 sp1 = (u_short *)sl; 436 sp2 = (u_short *)(sl + 1); 437 sl->sl_cksum = cksum = 0; 438 while (sp1 < sp2) 439 cksum ^= *sp1++; 440 sl->sl_cksum = cksum; 441 442 return (0); 443 } 444