1 /* $NetBSD: disksubr.c,v 1.19 2026/07/03 21:36:27 thorpej 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 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 * SUCH DAMAGE. 29 */ 30 31 /* 32 * Copyright (c) 1994, 1995 Gordon W. Ross 33 * Copyright (c) 1994 Theo de Raadt 34 * All rights reserved. 35 * 36 * Redistribution and use in source and binary forms, with or without 37 * modification, are permitted provided that the following conditions 38 * are met: 39 * 1. Redistributions of source code must retain the above copyright 40 * notice, this list of conditions and the following disclaimer. 41 * 2. Redistributions in binary form must reproduce the above copyright 42 * notice, this list of conditions and the following disclaimer in the 43 * documentation and/or other materials provided with the distribution. 44 * 45 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 46 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 47 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 48 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 49 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 50 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 51 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 52 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 53 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 54 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 55 */ 56 57 #include <sys/cdefs.h> 58 __KERNEL_RCSID(0, "$NetBSD: disksubr.c,v 1.19 2026/07/03 21:36:27 thorpej Exp $"); 59 60 #include <sys/param.h> 61 #include <sys/systm.h> 62 #include <sys/buf.h> 63 #include <sys/ioccom.h> 64 #include <sys/device.h> 65 #include <sys/disklabel.h> 66 #include <sys/disk.h> 67 68 #include <dev/sun/disklabel.h> 69 70 #if LABELSECTOR != 0 71 #error "Default value of LABELSECTOR no longer zero?" 72 #endif 73 74 static const char *disklabel_sun_to_bsd(char *, struct disklabel *); 75 static int disklabel_bsd_to_sun(struct disklabel *, char *); 76 77 /* 78 * Attempt to read a disk label from a device 79 * using the indicated strategy routine. 80 * The label must be partly set up before this: 81 * secpercyl, secsize and anything required for a block i/o read 82 * operation in the driver's strategy/start routines 83 * must be filled in before calling us. 84 * 85 * Return buffer for use in signalling errors if requested. 86 * 87 * Returns null on success and an error string on failure. 88 */ 89 const char * 90 readdisklabel(dev_t dev, void (*strat)(struct buf *), struct disklabel *lp, struct cpu_disklabel *clp) 91 { 92 struct buf *bp; 93 struct disklabel *dlp; 94 struct sun_disklabel *slp; 95 int error; 96 97 /* minimal requirements for archetypal disk label */ 98 if (lp->d_secperunit == 0) 99 lp->d_secperunit = 0x1fffffff; 100 if (lp->d_npartitions == 0) { 101 lp->d_npartitions = RAW_PART + 1; 102 if (lp->d_partitions[RAW_PART].p_size == 0) 103 lp->d_partitions[RAW_PART].p_size = 0x1fffffff; 104 lp->d_partitions[RAW_PART].p_offset = 0; 105 } 106 if (lp->d_secsize == 0) 107 return ("sector size 0"); 108 109 /* obtain buffer to probe drive with */ 110 bp = geteblk((int)lp->d_secsize); 111 112 /* next, dig out disk label */ 113 bp->b_dev = dev; 114 bp->b_blkno = LABELSECTOR; 115 bp->b_cylinder = 0; 116 bp->b_bcount = lp->d_secsize; 117 bp->b_flags |= B_READ; 118 (*strat)(bp); 119 120 /* if successful, locate disk label within block and validate */ 121 error = biowait(bp); 122 if (error == 0) { 123 /* Save the whole block in case it has info we need. */ 124 memcpy(clp->cd_block, bp->b_data, sizeof(clp->cd_block)); 125 } 126 brelse(bp, 0); 127 if (error) 128 return ("disk label read error"); 129 130 /* Check for a NetBSD disk label at LABELOFFSET */ 131 dlp = (struct disklabel *) (clp->cd_block + LABELOFFSET); 132 if (dlp->d_magic == DISKMAGIC) { 133 if (dkcksum(dlp)) 134 return ("NetBSD disk label corrupted"); 135 *lp = *dlp; 136 return (NULL); 137 } 138 139 /* Check for a Sun disk label (for PROM compatibility). */ 140 slp = (struct sun_disklabel *) clp->cd_block; 141 if (slp->sl_magic == SUN_DKMAGIC) 142 return (disklabel_sun_to_bsd(clp->cd_block, lp)); 143 144 /* 145 * Check for a NetBSD disk label somewhere in LABELSECTOR 146 * (compat with others big-endian boxes) 147 */ 148 for (dlp = (struct disklabel *)clp->cd_block; 149 dlp <= (struct disklabel *)((char *)clp->cd_block + 150 DEV_BSIZE - sizeof(*dlp)); 151 dlp = (struct disklabel *)((char *)dlp + sizeof(long))) { 152 if (dlp->d_magic != DISKMAGIC || dlp->d_magic2 != DISKMAGIC) { 153 continue; 154 } 155 if (dlp->d_npartitions > MAXPARTITIONS || dkcksum(dlp) != 0) 156 return("NetBSD disk label corrupted"); 157 else { 158 *lp = *dlp; 159 return(NULL); 160 } 161 } 162 163 memset(clp->cd_block, 0, sizeof(clp->cd_block)); 164 return NULL; 165 } 166 167 /* 168 * Write disk label back to device after modification. 169 * Current label is already in clp->cd_block[] 170 */ 171 int 172 writedisklabel(dev_t dev, void (*strat)(struct buf *), struct disklabel *lp, struct cpu_disklabel *clp) 173 { 174 struct buf *bp; 175 int error; 176 struct disklabel *dlp; 177 struct sun_disklabel *slp; 178 179 /* 180 * Embed native label in a piece of wasteland. 181 */ 182 if (sizeof(struct disklabel) > sizeof slp->sl_bsdlabel) 183 return EFBIG; 184 185 slp = (struct sun_disklabel *)clp->cd_block; 186 memset(slp->sl_bsdlabel, 0, sizeof(slp->sl_bsdlabel)); 187 dlp = (struct disklabel *)slp->sl_bsdlabel; 188 *dlp = *lp; 189 190 /* Build a SunOS compatible label around the native label */ 191 error = disklabel_bsd_to_sun(lp, clp->cd_block); 192 if (error) 193 return (error); 194 195 /* Get a buffer and copy the new label into it. */ 196 bp = geteblk((int)lp->d_secsize); 197 memcpy(bp->b_data, clp->cd_block, sizeof(clp->cd_block)); 198 199 /* Write out the updated label. */ 200 bp->b_dev = dev; 201 bp->b_blkno = LABELSECTOR; 202 bp->b_cylinder = 0; 203 bp->b_bcount = lp->d_secsize; 204 bp->b_flags |= B_WRITE; 205 (*strat)(bp); 206 error = biowait(bp); 207 brelse(bp, 0); 208 209 return (error); 210 } 211 212 /************************************************************************ 213 * 214 * The rest of this was taken from arch/sparc/scsi/sun_disklabel.c 215 * and then substantially rewritten by Gordon W. Ross 216 * 217 ************************************************************************/ 218 219 /* What partition types to assume for Sun disklabels: */ 220 static u_char 221 sun_fstypes[8] = { 222 FS_BSDFFS, /* a */ 223 FS_SWAP, /* b */ 224 FS_OTHER, /* c - whole disk */ 225 FS_BSDFFS, /* d */ 226 FS_BSDFFS, /* e */ 227 FS_BSDFFS, /* f */ 228 FS_BSDFFS, /* g */ 229 FS_BSDFFS, /* h */ 230 }; 231 232 /* 233 * Given a SunOS disk label, set lp to a BSD disk label. 234 * Returns NULL on success, else an error string. 235 * 236 * The BSD label is cleared out before this is called. 237 */ 238 static const char * 239 disklabel_sun_to_bsd(char *cp, struct disklabel *lp) 240 { 241 struct sun_disklabel *sl; 242 struct partition *npp; 243 struct sun_dkpart *spp; 244 int i, secpercyl; 245 unsigned int secpblck; 246 u_short cksum, *sp1, *sp2; 247 248 sl = (struct sun_disklabel *)cp; 249 250 /* Verify the XOR check. */ 251 sp1 = (u_short *)sl; 252 sp2 = (u_short *)(sl + 1); 253 cksum = 0; 254 while (sp1 < sp2) 255 cksum ^= *sp1++; 256 if (cksum != 0) 257 return("SunOS disk label, bad checksum"); 258 259 /* Format conversion. */ 260 lp->d_magic = DISKMAGIC; 261 lp->d_magic2 = DISKMAGIC; 262 memcpy(lp->d_packname, sl->sl_text, sizeof(lp->d_packname)); 263 264 secpblck = lp->d_secsize / 512; 265 if (secpblck == 0) secpblck = 1; /* can't happen */ 266 lp->d_secsize = 512; 267 lp->d_nsectors = sl->sl_nsectors; 268 lp->d_ntracks = sl->sl_ntracks; 269 lp->d_ncylinders = sl->sl_ncylinders; 270 271 secpercyl = sl->sl_nsectors * sl->sl_ntracks; 272 lp->d_secpercyl = secpercyl; 273 lp->d_secperunit = secpercyl * sl->sl_ncylinders; 274 275 lp->d_sparespercyl = sl->sl_sparespercyl; 276 lp->d_acylinders = sl->sl_acylinders; 277 lp->d_rpm = sl->sl_rpm; 278 lp->d_interleave = sl->sl_interleave; 279 280 lp->d_npartitions = 8; 281 /* These are as defined in <ufs/ffs/fs.h> */ 282 lp->d_bbsize = 8192; /* XXX */ 283 lp->d_sbsize = 8192; /* XXX */ 284 285 for (i = 0; i < 8; i++) { 286 spp = &sl->sl_part[i]; 287 npp = &lp->d_partitions[i]; 288 289 if (npp->p_fstype == FS_ISO9660 290 && spp->sdkp_cyloffset * secpercyl == npp->p_offset*secpblck 291 && spp->sdkp_nsectors <= npp->p_size*secpblck 292 && npp->p_size > 0 && spp->sdkp_nsectors > 0) { 293 /* 294 * This happens for example on sunlabel'd hybrid 295 * (ffs + ISO9660) CDs, like our install CDs. 296 * The cd driver has initialized a valid ISO9660 297 * partition (including session parameters), so 298 * we better not overwrite it. 299 */ 300 npp->p_offset *= secpblck; 301 npp->p_size = spp->sdkp_nsectors; 302 npp->p_cdsession *= secpblck; 303 continue; 304 } 305 npp->p_offset = spp->sdkp_cyloffset * secpercyl; 306 npp->p_size = spp->sdkp_nsectors; 307 if (npp->p_size == 0) { 308 npp->p_fstype = FS_UNUSED; 309 } else { 310 npp->p_fstype = sun_fstypes[i]; 311 if (npp->p_fstype == FS_BSDFFS) { 312 /* 313 * The sun label does not store the FFS fields, 314 * so just set them with default values here. 315 */ 316 npp->p_fsize = 1024; 317 npp->p_frag = 8; 318 npp->p_cpg = 16; 319 } 320 } 321 } 322 323 lp->d_checksum = 0; 324 lp->d_checksum = dkcksum(lp); 325 return (NULL); 326 } 327 328 /* 329 * Given a BSD disk label, update the Sun disklabel 330 * pointed to by cp with the new info. Note that the 331 * Sun disklabel may have other info we need to keep. 332 * Returns zero or error code. 333 */ 334 static int 335 disklabel_bsd_to_sun(struct disklabel *lp, char *cp) 336 { 337 struct sun_disklabel *sl; 338 struct partition *npp; 339 struct sun_dkpart *spp; 340 int i, secpercyl; 341 u_short cksum, *sp1, *sp2; 342 343 if (lp->d_secsize != 512) 344 return (EINVAL); 345 346 sl = (struct sun_disklabel *)cp; 347 348 /* 349 * Format conversion. 350 */ 351 memcpy(sl->sl_text, lp->d_packname, sizeof(lp->d_packname)); 352 sl->sl_rpm = lp->d_rpm; 353 sl->sl_pcylinders = lp->d_ncylinders + lp->d_acylinders; /* XXX */ 354 sl->sl_sparespercyl = lp->d_sparespercyl; 355 sl->sl_interleave = lp->d_interleave; 356 sl->sl_ncylinders = lp->d_ncylinders; 357 sl->sl_acylinders = lp->d_acylinders; 358 sl->sl_ntracks = lp->d_ntracks; 359 sl->sl_nsectors = lp->d_nsectors; 360 361 secpercyl = sl->sl_nsectors * sl->sl_ntracks; 362 for (i = 0; i < 8; i++) { 363 spp = &sl->sl_part[i]; 364 npp = &lp->d_partitions[i]; 365 366 /* 367 * SunOS partitions must start on a cylinder boundary. 368 * Note this restriction is forced upon NetBSD/sparc 369 * labels too, since we want to keep both labels 370 * synchronised. 371 */ 372 if (npp->p_offset % secpercyl) 373 return (EINVAL); 374 spp->sdkp_cyloffset = npp->p_offset / secpercyl; 375 spp->sdkp_nsectors = npp->p_size; 376 } 377 sl->sl_magic = SUN_DKMAGIC; 378 379 /* Compute the XOR check. */ 380 sp1 = (u_short *)sl; 381 sp2 = (u_short *)(sl + 1); 382 sl->sl_cksum = cksum = 0; 383 while (sp1 < sp2) 384 cksum ^= *sp1++; 385 sl->sl_cksum = cksum; 386 387 return (0); 388 } 389