1 /* $NetBSD: disksubr.c,v 1.36 2026/06/21 10:28:08 andvar 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.36 2026/06/21 10:28:08 andvar 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 115 #include <dev/sun/disklabel.h> 116 117 /* 118 * UniOS disklabel (== ISI disklabel) is very similar to SunOS. 119 * SunOS UniOS/ISI 120 * text 128 128 121 * (pad) 292 294 122 * rpm 2 - 123 * pcyl 2 badchk 2 124 * sparecyl 2 maxblk 4 125 * (pad) 4 dtype 2 126 * interleave 2 ndisk 2 127 * ncyl 2 2 128 * acyl 2 2 129 * ntrack 2 2 130 * nsect 2 2 131 * (pad) 4 bhead 2 132 * - ppart 2 133 * dkpart[8] 64 64 134 * magic 2 2 135 * cksum 2 2 136 * 137 * Magic number value and checksum calculation are identical. Subtle 138 * difference is partition start address; UniOS/ISI maintains sector 139 * numbers while SunOS label has cylinder number. 140 * 141 * It is found that LUNA Mach2.5 has BSD label embedded at offset 64 142 * retaining UniOS/ISI label at the end of label block. LUNA Mach 143 * manipulates BSD disklabel in the same manner as 4.4BSD. It's 144 * uncertain LUNA Mach can create a disklabel on fresh disks since 145 * Mach writedisklabel logic seems to fail when no BSD label is found. 146 * 147 * Kernel handles disklabel in this way; 148 * - searches BSD label at offset 64 149 * - if not found, searches UniOS/ISI label at the end of block 150 * - kernel can distinguish whether it was SunOS label or UniOS/ISI 151 * label and understand both 152 * - kernel writes UniOS/ISI label combined with BSD label to update 153 * the label block 154 */ 155 156 #if LABELSECTOR != 0 157 #error "Default value of LABELSECTOR no longer zero?" 158 #endif 159 160 static const char *disklabel_om_to_bsd(char *, struct disklabel *); 161 static int disklabel_bsd_to_om(struct disklabel *, char *); 162 163 /* 164 * Attempt to read a disk label from a device 165 * using the indicated strategy routine. 166 * The label must be partly set up before this: 167 * secpercyl, secsize and anything required for a block i/o read 168 * operation in the driver's strategy/start routines 169 * must be filled in before calling us. 170 * 171 * Return buffer for use in signalling errors if requested. 172 * 173 * Returns null on success and an error string on failure. 174 */ 175 const char * 176 readdisklabel(dev_t dev, void (*strat)(struct buf *), struct disklabel *lp, struct cpu_disklabel *clp) 177 { 178 struct buf *bp; 179 struct disklabel *dlp; 180 struct sun_disklabel *slp; 181 int error; 182 int i; 183 184 /* minimal requirements for archetypal disk label */ 185 if (lp->d_secperunit == 0) 186 lp->d_secperunit = 0x1fffffff; 187 if (lp->d_npartitions < RAW_PART + 1) 188 lp->d_npartitions = RAW_PART + 1; 189 for (i = 0; i < RAW_PART; i++) { 190 lp->d_partitions[i].p_size = 0; 191 lp->d_partitions[i].p_offset = 0; 192 } 193 if (lp->d_partitions[RAW_PART].p_size == 0) 194 lp->d_partitions[RAW_PART].p_size = lp->d_secperunit; 195 lp->d_partitions[RAW_PART].p_offset = 0; 196 197 /* obtain buffer to probe drive with */ 198 bp = geteblk((int)lp->d_secsize); 199 200 /* next, dig out disk label */ 201 bp->b_dev = dev; 202 bp->b_blkno = LABELSECTOR; 203 bp->b_cylinder = 0; 204 bp->b_bcount = lp->d_secsize; 205 bp->b_flags |= B_READ; 206 (*strat)(bp); 207 208 /* if successful, locate disk label within block and validate */ 209 error = biowait(bp); 210 if (!error) { 211 /* Save the whole block in case it has info we need. */ 212 memcpy(clp->cd_block, bp->b_data, sizeof(clp->cd_block)); 213 } 214 brelse(bp, 0); 215 if (error) 216 return ("disk label read error"); 217 218 /* Check for a NetBSD disk label first. */ 219 dlp = (struct disklabel *)(clp->cd_block + LABELOFFSET); 220 if (dlp->d_magic == DISKMAGIC && dlp->d_magic2 == DISKMAGIC) { 221 if (dkcksum(dlp) == 0) { 222 *lp = *dlp; /* struct assignment */ 223 return (NULL); 224 } 225 printf("NetBSD disk label corrupted"); 226 } 227 228 /* Check for a UniOS/ISI disk label. */ 229 slp = (struct sun_disklabel *)clp->cd_block; 230 if (slp->sl_magic == SUN_DKMAGIC) { 231 return (disklabel_om_to_bsd(clp->cd_block, lp)); 232 } 233 234 memset(clp->cd_block, 0, sizeof(clp->cd_block)); 235 return ("no disk label"); 236 } 237 238 /* 239 * Write disk label back to device after modification. 240 * Current label is already in clp->cd_block[] 241 */ 242 int 243 writedisklabel(dev_t dev, void (*strat)(struct buf *), struct disklabel *lp, struct cpu_disklabel *clp) 244 { 245 struct buf *bp; 246 struct disklabel *dlp; 247 int error; 248 249 /* implant NetBSD disklabel at LABELOFFSET. */ 250 dlp = (struct disklabel *)(clp->cd_block + LABELOFFSET); 251 *dlp = *lp; /* struct assignment */ 252 253 error = disklabel_bsd_to_om(lp, clp->cd_block); 254 if (error) 255 return (error); 256 257 /* Get a buffer and copy the new label into it. */ 258 bp = geteblk((int)lp->d_secsize); 259 memcpy(bp->b_data, clp->cd_block, sizeof(clp->cd_block)); 260 261 /* Write out the updated label. */ 262 bp->b_dev = dev; 263 bp->b_blkno = LABELSECTOR; 264 bp->b_cylinder = 0; 265 bp->b_bcount = lp->d_secsize; 266 bp->b_flags |= B_WRITE; 267 (*strat)(bp); 268 error = biowait(bp); 269 brelse(bp, 0); 270 271 return (error); 272 } 273 274 /************************************************************************ 275 * 276 * The rest of this was taken from arch/sparc/scsi/sun_disklabel.c 277 * and then substantially rewritten by Gordon W. Ross 278 * 279 ************************************************************************/ 280 281 /* What partition types to assume for Sun disklabels: */ 282 static u_char 283 sun_fstypes[8] = { 284 FS_BSDFFS, /* a */ 285 FS_SWAP, /* b */ 286 FS_OTHER, /* c - whole disk */ 287 FS_BSDFFS, /* d */ 288 FS_BSDFFS, /* e */ 289 FS_BSDFFS, /* f */ 290 FS_BSDFFS, /* g */ 291 FS_BSDFFS, /* h */ 292 }; 293 294 /* 295 * Given a UniOS/ISI disk label, set lp to a BSD disk label. 296 * Returns NULL on success, else an error string. 297 * 298 * The BSD label is cleared out before this is called. 299 */ 300 static const char * 301 disklabel_om_to_bsd(char *cp, struct disklabel *lp) 302 { 303 struct sun_disklabel *sl; 304 struct partition *npp; 305 struct sun_dkpart *spp; 306 int i, secpercyl; 307 u_short cksum, *sp1, *sp2; 308 309 sl = (struct sun_disklabel *)cp; 310 311 /* Verify the XOR check. */ 312 sp1 = (u_short *)sl; 313 sp2 = (u_short *)(sl + 1); 314 cksum = 0; 315 while (sp1 < sp2) 316 cksum ^= *sp1++; 317 if (cksum != 0) 318 return ("UniOS disk label, bad checksum"); 319 320 memset((void *)lp, 0, sizeof(struct disklabel)); 321 /* Format conversion. */ 322 lp->d_magic = DISKMAGIC; 323 lp->d_magic2 = DISKMAGIC; 324 memcpy(lp->d_packname, sl->sl_text, sizeof(lp->d_packname)); 325 326 lp->d_type = DKTYPE_SCSI; 327 lp->d_secsize = 512; 328 lp->d_nsectors = sl->sl_nsectors; 329 lp->d_ntracks = sl->sl_ntracks; 330 lp->d_ncylinders = sl->sl_ncylinders; 331 332 secpercyl = sl->sl_nsectors * sl->sl_ntracks; 333 lp->d_secpercyl = secpercyl; 334 lp->d_secperunit = secpercyl * sl->sl_ncylinders; 335 336 lp->d_sparespercyl = 0; /* no way to know */ 337 lp->d_acylinders = sl->sl_acylinders; 338 lp->d_rpm = sl->sl_rpm; /* UniOS - (empty) */ 339 lp->d_interleave = sl->sl_interleave; /* UniOS - ndisk */ 340 341 if (sl->sl_rpm == 0) { 342 /* UniOS label has blkoffset, not cyloffset */ 343 secpercyl = 1; 344 } 345 346 lp->d_npartitions = 8; 347 /* These are as defined in <ufs/ffs/fs.h> */ 348 lp->d_bbsize = 8192; /* XXX */ 349 lp->d_sbsize = 8192; /* XXX */ 350 for (i = 0; i < 8; i++) { 351 spp = &sl->sl_part[i]; 352 npp = &lp->d_partitions[i]; 353 npp->p_offset = spp->sdkp_cyloffset * secpercyl; 354 npp->p_size = spp->sdkp_nsectors; 355 if (npp->p_size == 0) 356 npp->p_fstype = FS_UNUSED; 357 else { 358 /* Partition has non-zero size. Set type, etc. */ 359 npp->p_fstype = sun_fstypes[i]; 360 361 /* 362 * The sun label does not store the FFS fields, 363 * so just set them with default values here. 364 * XXX: This keeps newfs from trying to rewrite 365 * XXX: the disk label in the most common case. 366 * XXX: (Should remove that code from newfs...) 367 */ 368 if (npp->p_fstype == FS_BSDFFS) { 369 npp->p_fsize = 1024; 370 npp->p_frag = 8; 371 npp->p_cpg = 16; 372 } 373 } 374 } 375 376 /* 377 * XXX BandAid XXX 378 * UniOS rootfs sits on part c which don't begin at sect 0, 379 * and impossible to mount. Thus, make it usable as part b. 380 */ 381 if (sl->sl_rpm == 0 && lp->d_partitions[2].p_offset != 0) { 382 lp->d_partitions[1] = lp->d_partitions[2]; 383 lp->d_partitions[1].p_fstype = FS_BSDFFS; 384 } 385 386 lp->d_checksum = dkcksum(lp); 387 388 return (NULL); 389 } 390 391 /* 392 * Given a BSD disk label, update the UniOS disklabel 393 * pointed to by cp with the new info. Note that the 394 * UniOS disklabel may have other info we need to keep. 395 * Returns zero or error code. 396 */ 397 static int 398 disklabel_bsd_to_om(struct disklabel *lp, char *cp) 399 { 400 struct sun_disklabel *sl; 401 struct partition *npp; 402 struct sun_dkpart *spp; 403 int i; 404 u_short cksum, *sp1, *sp2; 405 406 if (lp->d_secsize != 512) 407 return (EINVAL); 408 409 sl = (struct sun_disklabel *)cp; 410 411 /* Format conversion. */ 412 memcpy(sl->sl_text, lp->d_packname, sizeof(lp->d_packname)); 413 sl->sl_rpm = 0; /* UniOS */ 414 #if 0 /* leave as was */ 415 sl->sl_pcyl = lp->d_ncylinders + lp->d_acylinders; /* XXX */ 416 sl->sl_sparespercyl = lp->d_sparespercyl; 417 #endif 418 sl->sl_interleave = lp->d_interleave; 419 sl->sl_ncylinders = lp->d_ncylinders; 420 sl->sl_acylinders = lp->d_acylinders; 421 sl->sl_ntracks = lp->d_ntracks; 422 sl->sl_nsectors = lp->d_nsectors; 423 424 for (i = 0; i < 8; i++) { 425 spp = &sl->sl_part[i]; 426 npp = &lp->d_partitions[i]; 427 428 spp->sdkp_cyloffset = npp->p_offset; /* UniOS */ 429 spp->sdkp_nsectors = npp->p_size; 430 } 431 sl->sl_magic = SUN_DKMAGIC; 432 433 /* Correct the XOR check. */ 434 sp1 = (u_short *)sl; 435 sp2 = (u_short *)(sl + 1); 436 sl->sl_cksum = cksum = 0; 437 while (sp1 < sp2) 438 cksum ^= *sp1++; 439 sl->sl_cksum = cksum; 440 441 return (0); 442 } 443