1 /* $NetBSD: disksubr.c,v 1.33 2026/06/11 22:52:09 dbj Exp $ */ 2 3 /* 4 * Copyright (c) 1982, 1986, 1988, 1993 5 * The Regents of the University of California. All rights reserved. 6 * (c) UNIX System Laboratories, Inc. 7 * All or some portions of this file are derived from material licensed 8 * to the University of California by American Telephone and Telegraph 9 * Co. or Unix System Laboratories, Inc. and are reproduced herein with 10 * the permission of UNIX System Laboratories, Inc. 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted provided that the following conditions 14 * are met: 15 * 1. Redistributions of source code must retain the above copyright 16 * notice, this list of conditions and the following disclaimer. 17 * 2. Redistributions in binary form must reproduce the above copyright 18 * notice, this list of conditions and the following disclaimer in the 19 * documentation and/or other materials provided with the distribution. 20 * 3. Neither the name of the University nor the names of its contributors 21 * may be used to endorse or promote products derived from this software 22 * without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 * 36 * @(#)ufs_disksubr.c 8.5 (Berkeley) 1/21/94 37 */ 38 39 #include <sys/cdefs.h> 40 __KERNEL_RCSID(0, "$NetBSD: disksubr.c,v 1.33 2026/06/11 22:52:09 dbj Exp $"); 41 42 #include <sys/param.h> 43 #include <sys/systm.h> 44 #include <sys/buf.h> 45 #define FSTYPENAMES 46 #include <sys/disklabel.h> 47 #include <sys/syslog.h> 48 49 #include <sys/disk.h> 50 51 #include <ufs/ufs/dinode.h> /* XXX for fs.h */ 52 #include <ufs/ffs/fs.h> /* XXX for SBLOCKSIZE */ 53 54 #define b_cylinder b_resid 55 56 static uint16_t nextstep_checksum(unsigned char *, unsigned char *); 57 static const char *parse_nextstep_label(struct next68k_disklabel *, 58 struct disklabel *, struct cpu_disklabel *); 59 static int build_nextstep_label(struct next68k_disklabel *, struct disklabel *); 60 61 static uint16_t 62 nextstep_checksum(unsigned char *buf, unsigned char *limit) 63 { 64 int sum = 0; 65 66 while (buf < limit) { 67 sum += (buf[0] << 8) + buf[1]; 68 buf += 2; 69 } 70 sum += (sum >> 16); 71 return sum & 0xffff; 72 } 73 74 static const char * 75 parse_nextstep_label(struct next68k_disklabel *ondisk, struct disklabel *lp, 76 struct cpu_disklabel *osdep) 77 { 78 int i, t, nbp; 79 uint16_t *checksum; 80 81 if (ondisk->cd_version == NEXT68K_LABEL_CD_V3) { 82 checksum = &ondisk->NEXT68K_LABEL_cd_v3_checksum; 83 } else { 84 checksum = &ondisk->NEXT68K_LABEL_cd_checksum; 85 } 86 if (nextstep_checksum((uint8_t *)ondisk, (uint8_t *)checksum) != 87 *checksum) { 88 return "disk label corrupted"; 89 } 90 91 osdep->od_version = ondisk->cd_version; 92 lp->d_magic = lp->d_magic2 = DISKMAGIC; 93 lp->d_type = DKTYPE_SCSI; 94 lp->d_subtype = 0; 95 if (sizeof(lp->d_typename) > sizeof(ondisk->cd_name)) 96 lp->d_typename[sizeof (ondisk->cd_name)] = '\0'; 97 memcpy(lp->d_typename, ondisk->cd_name, 98 uimin(sizeof (lp->d_typename), sizeof(ondisk->cd_name))); 99 if (sizeof(lp->d_packname) > sizeof(ondisk->cd_label)) 100 lp->d_packname[sizeof (ondisk->cd_label)] = '\0'; 101 memcpy(lp->d_packname, ondisk->cd_label, 102 uimin(sizeof(lp->d_packname), sizeof(ondisk->cd_label))); 103 if (lp->d_secsize == 0) 104 lp->d_secsize = ondisk->cd_secsize; 105 KASSERT(ondisk->cd_secsize >= lp->d_secsize); 106 lp->d_nsectors = ondisk->cd_nsectors; 107 lp->d_ntracks = ondisk->cd_ntracks; 108 lp->d_ncylinders = ondisk->cd_ncylinders; 109 110 lp->d_rpm = ondisk->cd_rpm; 111 lp->d_flags = ondisk->cd_flags; 112 113 lp->d_bbsize = NEXT68K_LABEL_SIZE; 114 lp->d_sbsize = SBLOCKSIZE; 115 116 lp->d_npartitions = nbp = 0; 117 for (i = 0; i < NEXT68K_LABEL_MAXPARTITIONS - 1; i++) { 118 if (ondisk->cd_partitions[i].cp_size > 0) { 119 lp->d_partitions[nbp].p_size = 120 ondisk->cd_partitions[i].cp_size * 121 (ondisk->cd_secsize / lp->d_secsize); 122 lp->d_partitions[nbp].p_offset = 123 (ondisk->cd_front + 124 ondisk->cd_partitions[i].cp_offset) * 125 (ondisk->cd_secsize / lp->d_secsize); 126 lp->d_partitions[nbp].p_fsize = 127 ondisk->cd_partitions[i].cp_fsize; 128 #ifndef FSTYPENAMES 129 lp->d_partitions[nbp].p_fstype = FS_BSDFFS; 130 #else 131 for (t = 0; t < FSMAXTYPES; t++) { 132 if (strncmp(ondisk->cd_partitions[i].cp_type, 133 fstypenames[t], NEXT68K_LABEL_MAXFSTLEN) 134 == 0) 135 break; 136 } 137 if (t == FSMAXTYPES) 138 t = FS_OTHER; 139 lp->d_partitions[nbp].p_fstype = t; 140 #endif 141 if (ondisk->cd_partitions[i].cp_fsize) 142 lp->d_partitions[nbp].p_frag = 143 ondisk->cd_partitions[i].cp_bsize / 144 ondisk->cd_partitions[i].cp_fsize; 145 else 146 lp->d_partitions[nbp].p_frag = 0; 147 lp->d_partitions[nbp].p_cpg = 148 ondisk->cd_partitions[i].cp_cpg; 149 lp->d_npartitions = nbp + 1; 150 } 151 nbp++; 152 if (nbp == RAW_PART) 153 nbp++; 154 if (nbp == MAXPARTITIONS) 155 break; 156 } 157 158 if (lp->d_npartitions <= RAW_PART) 159 lp->d_npartitions = RAW_PART + 1; 160 161 lp->d_checksum = 0; 162 lp->d_checksum = dkcksum(lp); 163 164 return NULL; 165 } 166 167 static int 168 build_nextstep_label(struct next68k_disklabel *ondisk, struct disklabel *lp) 169 { 170 int i, t, nbp; 171 int front_porch = NEXT68K_LABEL_DEFAULTFRONTPORCH; 172 uint16_t *checksum; 173 174 memset(ondisk, 0, sizeof(*ondisk)); 175 176 ondisk->cd_version = NEXT68K_LABEL_CD_V3; 177 /* ondisk->cd_label_blkno = 0; */ 178 /* ondisk->cd_size = 0; */ 179 /* ondisk->cd_tag = 0; */ 180 strncpy(ondisk->cd_type, "fixed_rw_scsi", sizeof(ondisk->cd_type)); 181 ondisk->cd_secsize = lp->d_secsize; 182 /* ondisk->cd_back = 0; */ 183 /* ondisk->cd_ngroups = 0; */ 184 /* ondisk->cd_ag_size = 0; */ 185 /* ondisk->cd_ag_alts = 0; */ 186 /* ondisk->cd_ag_off = 0; */ 187 /* ondisk->kernel */ 188 /* ondisk->hostname */ 189 /* ondisk->rootpartition */ 190 /* ondisk->rwpartition */ 191 KASSERT(ondisk->cd_secsize >= lp->d_secsize); 192 193 if (memcmp(ondisk->cd_name, lp->d_typename, 194 uimin(sizeof(lp->d_typename), sizeof(ondisk->cd_name))) && 195 sizeof (ondisk->cd_name) > sizeof (lp->d_typename)) 196 ondisk->cd_name[sizeof(lp->d_typename)] = '\0'; 197 memcpy(ondisk->cd_name, lp->d_typename, 198 uimin(sizeof(lp->d_typename), sizeof(ondisk->cd_name))); 199 if (memcmp (lp->d_packname, ondisk->cd_label, 200 uimin(sizeof(lp->d_packname), sizeof(ondisk->cd_label))) && 201 sizeof(ondisk->cd_label) > sizeof(lp->d_packname)) 202 ondisk->cd_label[sizeof(lp->d_packname)] = '\0'; 203 memcpy(ondisk->cd_label, lp->d_packname, 204 uimin(sizeof(lp->d_packname), sizeof(ondisk->cd_label))); 205 206 ondisk->cd_nsectors = lp->d_nsectors; 207 ondisk->cd_ntracks = lp->d_ntracks; 208 ondisk->cd_ncylinders = lp->d_ncylinders; 209 210 ondisk->cd_rpm = lp->d_rpm; 211 ondisk->cd_flags = lp->d_flags; 212 213 /* 214 * figure out front porch 215 * try to map partitions which were moved 216 */ 217 for (nbp = 0; nbp < lp->d_npartitions; nbp++) { 218 if (nbp != RAW_PART && lp->d_partitions[nbp].p_offset > 0 && 219 lp->d_partitions[nbp].p_offset < front_porch) 220 front_porch = lp->d_partitions[nbp].p_offset; 221 for (t = 0; t < NEXT68K_LABEL_MAXPARTITIONS; t++) { 222 if (t != (nbp > RAW_PART ? nbp - 1 : nbp) && 223 (lp->d_partitions[nbp].p_size == 224 ondisk->cd_partitions[t].cp_size * 225 (ondisk->cd_secsize / lp->d_secsize)) && 226 (lp->d_partitions[nbp].p_offset == 227 (ondisk->cd_front + 228 ondisk->cd_partitions[t].cp_offset) * 229 (ondisk->cd_secsize / lp->d_secsize)) && 230 ((lp->d_partitions[nbp].p_fstype == FS_OTHER) || 231 (!strncmp (ondisk->cd_partitions[t].cp_type, 232 fstypenames[lp->d_partitions[nbp].p_fstype], 233 NEXT68K_LABEL_MAXFSTLEN)))) { 234 struct next68k_partition tmp; 235 memcpy(&tmp, &ondisk->cd_partitions[t], 236 sizeof(tmp)); 237 memcpy(&ondisk->cd_partitions[t], 238 &ondisk->cd_partitions[nbp > RAW_PART ? 239 nbp - 1 : nbp], 240 sizeof (tmp)); 241 memcpy(&ondisk->cd_partitions[nbp > RAW_PART ? 242 nbp - 1 : nbp], 243 &tmp, sizeof (tmp)); 244 } 245 } 246 } 247 front_porch /= (ondisk->cd_secsize / lp->d_secsize); 248 249 /* 250 * update partitions 251 */ 252 nbp = 0; 253 for (i = 0; i < NEXT68K_LABEL_MAXPARTITIONS; i++) { 254 struct next68k_partition *p = &ondisk->cd_partitions[i]; 255 if (nbp < lp->d_npartitions && lp->d_partitions[nbp].p_size) { 256 p->cp_size = lp->d_partitions[nbp].p_size / 257 (ondisk->cd_secsize / lp->d_secsize); 258 p->cp_offset = (lp->d_partitions[nbp].p_offset / 259 (ondisk->cd_secsize / lp->d_secsize)) - 260 front_porch; 261 p->cp_bsize = lp->d_partitions[nbp].p_frag 262 * lp->d_partitions[nbp].p_fsize; 263 p->cp_fsize = lp->d_partitions[nbp].p_fsize; 264 if (lp->d_partitions[nbp].p_fstype != FS_OTHER) { 265 memset(p->cp_type, 0, NEXT68K_LABEL_MAXFSTLEN); 266 strncpy(p->cp_type, 267 fstypenames[lp->d_partitions[nbp].p_fstype], 268 NEXT68K_LABEL_MAXFSTLEN); 269 } 270 if (p->cp_density < 0) 271 p->cp_density = 4096; /* set some default */ 272 if (p->cp_minfree < 0) 273 p->cp_minfree = 5; /* set some default */ 274 p->cp_cpg = lp->d_partitions[nbp].p_cpg; 275 } else { 276 memset(p, 0, sizeof(*p)); 277 p->cp_size = -1; 278 p->cp_offset = -1; 279 p->cp_bsize = -1; 280 p->cp_fsize = -1; 281 p->cp_density = -1; 282 p->cp_minfree = -1; 283 } 284 nbp++; 285 if (nbp == RAW_PART) 286 nbp++; 287 } 288 289 ondisk->cd_front = front_porch; 290 ondisk->cd_boot_blkno[0] = NEXT68K_LABEL_DEFAULTBOOT0_1 / 291 (ondisk->cd_secsize / lp->d_secsize); 292 ondisk->cd_boot_blkno[1] = NEXT68K_LABEL_DEFAULTBOOT0_2 / 293 (ondisk->cd_secsize / lp->d_secsize); 294 295 if (ondisk->cd_version == NEXT68K_LABEL_CD_V3) { 296 checksum = &ondisk->NEXT68K_LABEL_cd_v3_checksum; 297 } else { 298 checksum = &ondisk->NEXT68K_LABEL_cd_checksum; 299 } 300 *checksum = nextstep_checksum((uint8_t *)ondisk, (uint8_t *)checksum); 301 302 return 0; 303 } 304 305 /* 306 * Attempt to read a disk label from a device using the indicated strategy 307 * routine. The label must be partly set up before this: secpercyl and 308 * anything required in the strategy routine (e.g., sector size) must be 309 * filled in before calling us. Returns null on success and an error 310 * string on failure. 311 */ 312 const char * 313 readdisklabel(dev_t dev, void (*strat)(struct buf *), struct disklabel *lp, 314 struct cpu_disklabel *osdep) 315 { 316 struct buf *bp; 317 struct disklabel *dlp; 318 const char *msg = NULL; 319 int i; 320 321 /* minimal requirements for archetypal disk label */ 322 if (lp->d_secsize == 0) 323 lp->d_secsize = DEV_BSIZE; 324 if (lp->d_secperunit == 0) 325 lp->d_secperunit = 0x1fffffff; 326 lp->d_npartitions = RAW_PART + 1; 327 for (i = 0; i < RAW_PART; i++) { 328 lp->d_partitions[i].p_size = 0; 329 lp->d_partitions[i].p_offset = 0; 330 } 331 if (lp->d_partitions[i].p_size == 0) 332 lp->d_partitions[i].p_size = 0x1fffffff; 333 lp->d_partitions[i].p_offset = 0; 334 335 bp = geteblk(NEXT68K_LABEL_SIZE); 336 bp->b_dev = dev; 337 bp->b_blkno = NEXT68K_LABEL_SECTOR; 338 bp->b_bcount = NEXT68K_LABEL_SIZE; 339 bp->b_flags |= B_READ; 340 bp->b_cylinder = NEXT68K_LABEL_SECTOR / lp->d_secpercyl; 341 (*strat)(bp); 342 343 if (osdep) 344 osdep->od_version = 0; 345 346 if (biowait(bp)) { 347 brelse(bp, 0); 348 return("I/O error"); 349 } 350 dlp = (struct disklabel *) 351 ((char *)bp->b_data + LABELSECTOR * lp->d_secsize + LABELOFFSET); 352 if (dlp->d_magic == DISKMAGIC || dlp->d_magic2 == DISKMAGIC) { 353 /* got a NetBSD disklabel */ 354 if (osdep) 355 osdep->od_version = DISKMAGIC; 356 if (dlp->d_npartitions > MAXPARTITIONS || 357 dkcksum(dlp) != 0) 358 msg = "disk label corrupted"; 359 else { 360 *lp = *dlp; 361 msg = NULL; 362 } 363 brelse(bp, 0); 364 return msg; 365 } 366 if (IS_DISKLABEL((struct next68k_disklabel *)bp->b_data)) { 367 /* got a NeXT disklabel */ 368 msg = parse_nextstep_label( 369 (struct next68k_disklabel *)bp->b_data, lp, osdep); 370 brelse(bp, 0); 371 return msg; 372 } 373 /* 374 * no disklabel at the usual places. Try to locate a NetBSD disklabel 375 * in the first sector. This ensure compatibility with others 376 * big-endian systems, and with next68k when LABELSECTOR was 0. 377 */ 378 msg = "no disk label"; 379 for (dlp = (struct disklabel *)bp->b_data; 380 dlp <= (struct disklabel *)((char *)bp->b_data + 381 DEV_BSIZE - sizeof(*dlp)); 382 dlp = (struct disklabel *)((char *)dlp + sizeof(long))) { 383 if (dlp->d_magic == DISKMAGIC || dlp->d_magic2 == DISKMAGIC) { 384 if (dlp->d_npartitions > MAXPARTITIONS || 385 dkcksum(dlp) != 0) 386 msg = "disk label corrupted"; 387 else { 388 *lp = *dlp; 389 msg = NULL; 390 if (osdep) 391 osdep->od_version = DISKMAGIC; 392 break; 393 } 394 } 395 } 396 brelse(bp, 0); 397 return msg; 398 } 399 400 /* 401 * Write disk label back to device after modification. 402 */ 403 int 404 writedisklabel(dev_t dev, void (*strat)(struct buf *), struct disklabel *lp, 405 struct cpu_disklabel *osdep) 406 { 407 struct buf *bp; 408 #if 0 409 struct disklabel *dlp; 410 #endif 411 int labelpart; 412 int error = 0; 413 414 labelpart = DISKPART(dev); 415 if (lp->d_partitions[labelpart].p_offset != 0) { 416 if (lp->d_partitions[0].p_offset != 0) 417 return EXDEV; /* not quite right */ 418 labelpart = 0; 419 } 420 /* 421 * We always write a NeXT v3 disklabel, and a NetBSD disklabel in 422 * the last sector of the NeXT label area. 423 */ 424 425 bp = geteblk(NEXT68K_LABEL_SIZE); 426 bp->b_dev = MAKEDISKDEV(major(dev), DISKUNIT(dev), labelpart); 427 bp->b_blkno = NEXT68K_LABEL_SECTOR; 428 bp->b_bcount = NEXT68K_LABEL_SIZE; 429 bp->b_flags |= B_WRITE; 430 bp->b_cylinder = NEXT68K_LABEL_SECTOR / lp->d_secpercyl; 431 error = 432 build_nextstep_label((struct next68k_disklabel *)bp->b_data, lp); 433 if (error) 434 goto done; 435 #if 0 436 dlp = (struct disklabel *) 437 ((char *)bp->b_data + LABELSECTOR * lp->d_secsize + LABELOFFSET); 438 *dlp = *lp; 439 #endif 440 (*strat)(bp); 441 error = biowait(bp); 442 done: 443 brelse(bp, 0); 444 return error; 445 } 446