1 /* $NetBSD: disksubr.c,v 1.9 2002/07/11 16:03:15 christos 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. All advertising materials mentioning features or use of this software 21 * must display the following acknowledgement: 22 * This product includes software developed by the University of 23 * California, Berkeley and its contributors. 24 * 4. Neither the name of the University nor the names of its contributors 25 * may be used to endorse or promote products derived from this software 26 * without specific prior written permission. 27 * 28 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 29 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 30 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 31 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 32 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 33 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 34 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 35 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 36 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 37 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 38 * SUCH DAMAGE. 39 * 40 * @(#)ufs_disksubr.c 8.5 (Berkeley) 1/21/94 41 */ 42 43 #include <sys/param.h> 44 #include <sys/systm.h> 45 #include <sys/buf.h> 46 #define FSTYPENAMES 47 #include <sys/disklabel.h> 48 #include <sys/syslog.h> 49 50 #include <sys/disk.h> 51 52 #include <ufs/ufs/dinode.h> /* XXX for fs.h */ 53 #include <ufs/ffs/fs.h> /* XXX for SBSIZE */ 54 55 #define b_cylinder b_resid 56 57 static unsigned short nextstep_checksum __P((unsigned char *, 58 unsigned char *)); 59 static char * parse_nextstep_label __P((struct nextstep_disklabel *, 60 struct disklabel *, struct cpu_disklabel *)); 61 static int build_nextstep_label __P((struct nextstep_disklabel *, 62 struct disklabel *, struct cpu_disklabel *)); 63 64 static unsigned short 65 nextstep_checksum(buf, limit) 66 unsigned char *buf; 67 unsigned char *limit; 68 { 69 int sum = 0; 70 71 while (buf < limit) { 72 sum += (buf[0] << 8) + buf[1]; 73 buf += 2; 74 } 75 sum += (sum >> 16); 76 return (sum & 0xffff); 77 } 78 79 static char * 80 parse_nextstep_label(ondisk, lp, osdep) 81 struct nextstep_disklabel *ondisk; 82 struct disklabel *lp; 83 struct cpu_disklabel *osdep; 84 { 85 int i, t, nbp; 86 unsigned short *checksum; 87 88 if (ondisk->cd_version == CD_V3) { 89 checksum = &ondisk->cd_v3_checksum; 90 } else { 91 checksum = &ondisk->cd_checksum; 92 } 93 if (nextstep_checksum ((unsigned char *)ondisk, 94 (unsigned char *)checksum) != *checksum) { 95 return ("disk label corrupted"); 96 } 97 98 osdep->od_version = ondisk->cd_version; 99 lp->d_magic = lp->d_magic2 = DISKMAGIC; 100 lp->d_type = DTYPE_SCSI; 101 lp->d_subtype = 0; 102 if (sizeof (lp->d_typename) > sizeof (ondisk->cd_name)) 103 lp->d_typename[sizeof (ondisk->cd_name)] = '\0'; 104 memcpy (lp->d_typename, ondisk->cd_name, 105 min (sizeof (lp->d_typename), sizeof (ondisk->cd_name))); 106 if (sizeof (lp->d_packname) > sizeof (ondisk->cd_label)) 107 lp->d_packname[sizeof (ondisk->cd_label)] = '\0'; 108 memcpy (lp->d_packname, ondisk->cd_label, 109 min (sizeof (lp->d_packname), sizeof (ondisk->cd_label))); 110 if (lp->d_secsize == 0) 111 lp->d_secsize = ondisk->cd_secsize; 112 KASSERT(ondisk->cd_secsize >= lp->d_secsize); 113 lp->d_nsectors = ondisk->cd_nsectors; 114 lp->d_ntracks = ondisk->cd_ntracks; 115 lp->d_ncylinders = ondisk->cd_ncylinders; 116 117 lp->d_rpm = ondisk->cd_rpm; 118 lp->d_flags = ondisk->cd_flags; 119 120 lp->d_bbsize = LABELSIZE; 121 lp->d_sbsize = SBSIZE; 122 123 lp->d_npartitions = nbp = 0; 124 for (i = 0; i < CPUMAXPARTITIONS - 1; i++) { 125 if (ondisk->cd_partitions[i].cp_size > 0) { 126 lp->d_partitions[nbp].p_size = 127 ondisk->cd_partitions[i].cp_size * 128 (ondisk->cd_secsize / lp->d_secsize); 129 lp->d_partitions[nbp].p_offset = 130 (ondisk->cd_front + 131 ondisk->cd_partitions[i].cp_offset) * 132 (ondisk->cd_secsize / lp->d_secsize); 133 lp->d_partitions[nbp].p_fsize = 134 ondisk->cd_partitions[i].cp_fsize; 135 #ifndef FSTYPENAMES 136 lp->d_partitions[nbp].p_fstype = 137 FS_BSDFFS; 138 #else 139 for (t = 0; t < FSMAXTYPES; t++) { 140 if (!strncmp (ondisk->cd_partitions[i].cp_type, 141 fstypenames[t], MAXFSTLEN)) 142 break; 143 } 144 if (t == FSMAXTYPES) 145 t = FS_OTHER; 146 lp->d_partitions[nbp].p_fstype = t; 147 #endif 148 if (ondisk->cd_partitions[i].cp_fsize) 149 lp->d_partitions[nbp].p_frag = 150 ondisk->cd_partitions[i].cp_bsize / 151 ondisk->cd_partitions[i].cp_fsize; 152 else 153 lp->d_partitions[nbp].p_frag = 0; 154 lp->d_partitions[nbp].p_cpg = 155 ondisk->cd_partitions[i].cp_cpg; 156 lp->d_npartitions = nbp + 1; 157 } 158 nbp++; 159 if (nbp == RAW_PART) 160 nbp++; 161 if (nbp == MAXPARTITIONS) 162 break; 163 } 164 165 if (lp->d_npartitions <= RAW_PART) 166 lp->d_npartitions = RAW_PART + 1; 167 168 lp->d_checksum = 0; 169 lp->d_checksum = dkcksum(lp); 170 171 return (NULL); 172 } 173 174 static int 175 build_nextstep_label(ondisk, lp, osdep) 176 struct nextstep_disklabel *ondisk; 177 struct disklabel *lp; 178 struct cpu_disklabel *osdep; 179 { 180 int i, t, nbp; 181 int front_porch = DEFAULTFRONTPORCH; 182 unsigned short *checksum; 183 184 if (osdep->od_version == 0) { 185 osdep->od_version = CD_V3; 186 187 memset (ondisk, 0, sizeof (ondisk)); 188 189 /* ondisk->cd_label_blkno = 0; */ 190 /* ondisk->cd_size = 0; */ 191 /* ondisk->cd_tag = 0; */ 192 strncpy (ondisk->cd_type, "fixed_rw_scsi", sizeof (ondisk->cd_type)); 193 ondisk->cd_secsize = lp->d_secsize; 194 /* ondisk->cd_back = 0; */ 195 /* ondisk->cd_ngroups = 0; */ 196 /* ondisk->cd_ag_size = 0; */ 197 /* ondisk->cd_ag_alts = 0; */ 198 /* ondisk->cd_ag_off = 0; */ 199 /* ondisk->kernel */ 200 /* ondisk->hostname */ 201 /* ondisk->rootpartition */ 202 /* ondisk->rwpartition */ 203 } 204 KASSERT(ondisk->cd_secsize >= lp->d_secsize); 205 206 ondisk->cd_version = osdep->od_version; 207 if (memcmp (ondisk->cd_name, lp->d_typename, 208 min (sizeof (lp->d_typename), sizeof (ondisk->cd_name))) && 209 sizeof (ondisk->cd_name) > sizeof (lp->d_typename)) 210 ondisk->cd_name[sizeof (lp->d_typename)] = '\0'; 211 memcpy (ondisk->cd_name, lp->d_typename, 212 min (sizeof (lp->d_typename), sizeof (ondisk->cd_name))); 213 if (memcmp (lp->d_packname, ondisk->cd_label, 214 min (sizeof (lp->d_packname), sizeof (ondisk->cd_label))) && 215 sizeof (ondisk->cd_label) > sizeof (lp->d_packname)) 216 ondisk->cd_label[sizeof (lp->d_packname)] = '\0'; 217 memcpy (ondisk->cd_label, lp->d_packname, 218 min (sizeof (lp->d_packname), sizeof (ondisk->cd_label))); 219 220 ondisk->cd_nsectors = lp->d_nsectors; 221 ondisk->cd_ntracks = lp->d_ntracks; 222 ondisk->cd_ncylinders = lp->d_ncylinders; 223 224 ondisk->cd_rpm = lp->d_rpm; 225 ondisk->cd_flags = lp->d_flags; 226 227 /* 228 * figure out front porch 229 * try to map partitions which were moved 230 */ 231 for (nbp = 0; nbp < lp->d_npartitions; nbp++) { 232 if (nbp != RAW_PART && lp->d_partitions[nbp].p_offset > 0 && 233 lp->d_partitions[nbp].p_offset < front_porch) 234 front_porch = lp->d_partitions[nbp].p_offset; 235 for (t = 0; t < CPUMAXPARTITIONS; t++) { 236 if (t != (nbp > RAW_PART ? nbp-1 : nbp) && 237 (lp->d_partitions[nbp].p_size == 238 ondisk->cd_partitions[t].cp_size * 239 (ondisk->cd_secsize / lp->d_secsize)) && 240 (lp->d_partitions[nbp].p_offset == 241 (ondisk->cd_front + 242 ondisk->cd_partitions[t].cp_offset) * 243 (ondisk->cd_secsize / lp->d_secsize)) && 244 ((lp->d_partitions[nbp].p_fstype == FS_OTHER) || 245 (!strncmp (ondisk->cd_partitions[t].cp_type, 246 fstypenames[lp->d_partitions[nbp].p_fstype], MAXFSTLEN)))) 247 { 248 struct cpu_partition tmp; 249 memcpy (&tmp, &ondisk->cd_partitions[t], sizeof (tmp)); 250 memcpy (&ondisk->cd_partitions[t], &ondisk->cd_partitions[nbp > RAW_PART ? nbp-1 : nbp], sizeof (tmp)); 251 memcpy (&ondisk->cd_partitions[nbp > RAW_PART ? nbp-1 : nbp], &tmp, sizeof (tmp)); 252 } 253 } 254 } 255 front_porch /= (ondisk->cd_secsize / lp->d_secsize); 256 257 /* 258 * update partitions 259 */ 260 nbp = 0; 261 for (i = 0; i < CPUMAXPARTITIONS; i++) { 262 struct cpu_partition *p = &ondisk->cd_partitions[i]; 263 if (nbp < lp->d_npartitions && lp->d_partitions[nbp].p_size) { 264 p->cp_size = lp->d_partitions[nbp].p_size / 265 (ondisk->cd_secsize / lp->d_secsize); 266 p->cp_offset = (lp->d_partitions[nbp].p_offset / 267 (ondisk->cd_secsize / lp->d_secsize)) - 268 front_porch; 269 p->cp_bsize = lp->d_partitions[nbp].p_frag 270 * lp->d_partitions[nbp].p_fsize; 271 p->cp_fsize = lp->d_partitions[nbp].p_fsize; 272 if (lp->d_partitions[nbp].p_fstype != FS_OTHER) { 273 memset (p->cp_type, 0, MAXFSTLEN); 274 strncpy (p->cp_type, 275 fstypenames[lp->d_partitions[nbp].p_fstype], MAXFSTLEN); 276 } 277 if (p->cp_density < 0) 278 p->cp_density = 4096; /* set some default */ 279 if (p->cp_minfree < 0) 280 p->cp_minfree = 5; /* set some default */ 281 p->cp_cpg = lp->d_partitions[nbp].p_cpg; 282 } else { 283 memset (p, 0, sizeof(p)); 284 p->cp_size = -1; 285 p->cp_offset = -1; 286 p->cp_bsize = -1; 287 p->cp_fsize = -1; 288 p->cp_density = -1; 289 p->cp_minfree = -1; 290 } 291 nbp++; 292 if (nbp == RAW_PART) 293 nbp++; 294 } 295 296 ondisk->cd_front = front_porch; 297 ondisk->cd_boot_blkno[0] = DEFAULTBOOT0_1 / 298 (ondisk->cd_secsize / lp->d_secsize); 299 ondisk->cd_boot_blkno[1] = DEFAULTBOOT0_2 / 300 (ondisk->cd_secsize / lp->d_secsize); 301 302 if (ondisk->cd_version == CD_V3) { 303 checksum = &ondisk->cd_v3_checksum; 304 } else { 305 checksum = &ondisk->cd_checksum; 306 } 307 *checksum = nextstep_checksum ((unsigned char *)ondisk, 308 (unsigned char *)checksum); 309 310 return 0; 311 } 312 313 /* 314 * Attempt to read a disk label from a device using the indicated strategy 315 * routine. The label must be partly set up before this: secpercyl and 316 * anything required in the strategy routine (e.g., sector size) must be 317 * filled in before calling us. Returns null on success and an error 318 * string on failure. 319 */ 320 char * 321 readdisklabel(dev, strat, lp, osdep) 322 dev_t dev; 323 void (*strat) __P((struct buf *)); 324 struct disklabel *lp; 325 struct cpu_disklabel *osdep; 326 { 327 struct buf *bp; 328 struct disklabel *dlp; 329 char *msg = NULL; 330 int i; 331 332 /* minimal requirements for archtypal disk label */ 333 if (lp->d_secsize == 0) 334 lp->d_secsize = DEV_BSIZE; 335 if (lp->d_secperunit == 0) 336 lp->d_secperunit = 0x1fffffff; 337 lp->d_npartitions = RAW_PART + 1; 338 for (i = 0; i < RAW_PART; i++) { 339 lp->d_partitions[i].p_size = 0; 340 lp->d_partitions[i].p_offset = 0; 341 } 342 if (lp->d_partitions[i].p_size == 0) 343 lp->d_partitions[i].p_size = 0x1fffffff; 344 lp->d_partitions[i].p_offset = 0; 345 346 bp = geteblk(LABELSIZE); 347 bp->b_dev = dev; 348 bp->b_blkno = LABELSECTOR; 349 bp->b_bcount = LABELSIZE; 350 bp->b_flags |= B_READ; 351 bp->b_cylinder = LABELSECTOR / lp->d_secpercyl; 352 (*strat)(bp); 353 354 if (osdep) 355 osdep->od_version = 0; 356 357 if (biowait(bp)) 358 msg = "I/O error"; 359 else if (IS_DISKLABEL ((struct nextstep_disklabel *)bp->b_data)) 360 msg = parse_nextstep_label 361 ((struct nextstep_disklabel *)bp->b_data, lp, osdep); 362 else { 363 if (osdep && 364 ((struct disklabel *)bp->b_data)->d_magic == DISKMAGIC) 365 osdep->od_version = DISKMAGIC; 366 for (dlp = (struct disklabel *)bp->b_data; 367 dlp <= (struct disklabel *)((char *)bp->b_data + 368 DEV_BSIZE - sizeof(*dlp)); 369 dlp = (struct disklabel *)((char *)dlp + sizeof(long))) { 370 if (dlp->d_magic != DISKMAGIC || dlp->d_magic2 != DISKMAGIC) { 371 if (msg == NULL) 372 msg = "no disk label"; 373 } else if (dlp->d_npartitions > MAXPARTITIONS || 374 dkcksum(dlp) != 0) 375 msg = "disk label corrupted"; 376 else { 377 *lp = *dlp; 378 msg = NULL; 379 if (osdep) 380 osdep->od_version = DISKMAGIC; 381 break; 382 } 383 } 384 } 385 brelse(bp); 386 return (msg); 387 } 388 389 /* 390 * Check new disk label for sensibility before setting it. 391 */ 392 int 393 setdisklabel(olp, nlp, openmask, osdep) 394 struct disklabel *olp, *nlp; 395 u_long openmask; 396 struct cpu_disklabel *osdep; 397 { 398 int i; 399 struct partition *opp, *npp; 400 401 if (nlp->d_magic != DISKMAGIC || nlp->d_magic2 != DISKMAGIC || 402 dkcksum(nlp) != 0) 403 return (EINVAL); 404 while ((i = ffs(openmask)) != 0) { 405 i--; 406 openmask &= ~(1 << i); 407 if (nlp->d_npartitions <= i) 408 return (EBUSY); 409 opp = &olp->d_partitions[i]; 410 npp = &nlp->d_partitions[i]; 411 if (npp->p_offset != opp->p_offset || npp->p_size < opp->p_size) 412 return (EBUSY); 413 /* 414 * Copy internally-set partition information 415 * if new label doesn't include it. XXX 416 */ 417 if (npp->p_fstype == FS_UNUSED && opp->p_fstype != FS_UNUSED) { 418 npp->p_fstype = opp->p_fstype; 419 npp->p_fsize = opp->p_fsize; 420 npp->p_frag = opp->p_frag; 421 npp->p_cpg = opp->p_cpg; 422 } 423 } 424 nlp->d_checksum = 0; 425 nlp->d_checksum = dkcksum(nlp); 426 *olp = *nlp; 427 return (0); 428 } 429 430 /* 431 * Write disk label back to device after modification. 432 */ 433 int 434 writedisklabel(dev, strat, lp, osdep) 435 dev_t dev; 436 void (*strat) __P((struct buf *)); 437 struct disklabel *lp; 438 struct cpu_disklabel *osdep; 439 { 440 struct buf *bp; 441 struct disklabel *dlp; 442 int labelpart; 443 int error = 0; 444 445 labelpart = DISKPART(dev); 446 if (lp->d_partitions[labelpart].p_offset != 0) { 447 if (lp->d_partitions[0].p_offset != 0) 448 return (EXDEV); /* not quite right */ 449 labelpart = 0; 450 } 451 if (osdep->od_version != DISKMAGIC) { 452 bp = geteblk(LABELSIZE); 453 bp->b_dev = MAKEDISKDEV(major(dev), DISKUNIT(dev), labelpart); 454 bp->b_blkno = LABELSECTOR; 455 bp->b_bcount = LABELSIZE; 456 bp->b_flags |= B_READ; 457 bp->b_cylinder = LABELSECTOR / lp->d_secpercyl; 458 (*strat)(bp); 459 error = biowait(bp); 460 if (error) 461 goto done; 462 error = build_nextstep_label 463 ((struct nextstep_disklabel *)bp->b_data, lp, osdep); 464 if (error) 465 goto done; 466 bp->b_flags &= ~(B_READ|B_DONE); 467 bp->b_flags |= B_WRITE; 468 (*strat)(bp); 469 error = biowait(bp); 470 } else { 471 bp = geteblk((int)lp->d_secsize); 472 bp->b_dev = MAKEDISKDEV(major(dev), DISKUNIT(dev), labelpart); 473 bp->b_blkno = LABELSECTOR; 474 bp->b_bcount = lp->d_secsize; 475 bp->b_flags |= B_READ; 476 (*strat)(bp); 477 if ((error = biowait(bp))) 478 goto done; 479 for (dlp = (struct disklabel *)bp->b_data; 480 dlp <= (struct disklabel *) 481 ((char *)bp->b_data + lp->d_secsize - sizeof(*dlp)); 482 dlp = (struct disklabel *)((char *)dlp + sizeof(long))) { 483 if (dlp->d_magic == DISKMAGIC && dlp->d_magic2 == DISKMAGIC && 484 dkcksum(dlp) == 0) { 485 *dlp = *lp; 486 bp->b_flags &= ~(B_READ|B_DONE); 487 bp->b_flags |= B_WRITE; 488 (*strat)(bp); 489 error = biowait(bp); 490 goto done; 491 } 492 } 493 error = ESRCH; 494 } 495 done: 496 brelse(bp); 497 return (error); 498 } 499 500 /* 501 * Determine the size of the transfer, and make sure it is 502 * within the boundaries of the partition. Adjust transfer 503 * if needed, and signal errors or early completion. 504 */ 505 int 506 bounds_check_with_label(bp, lp, wlabel) 507 struct buf *bp; 508 struct disklabel *lp; 509 int wlabel; 510 { 511 struct partition *p = &lp->d_partitions[DISKPART(bp->b_dev)]; 512 int labelsect = lp->d_partitions[0].p_offset; 513 int maxsz = p->p_size; 514 int sz = (bp->b_bcount + DEV_BSIZE - 1) >> DEV_BSHIFT; 515 516 /* Overwriting disk label? */ 517 if (bp->b_blkno + p->p_offset <= LABELSECTOR + labelsect && 518 (bp->b_flags & B_READ) == 0 && !wlabel) { 519 bp->b_error = EROFS; 520 goto bad; 521 } 522 523 /* beyond partition? */ 524 if (bp->b_blkno < 0 || bp->b_blkno + sz > maxsz) { 525 if (bp->b_blkno == maxsz) { 526 /* If exactly at end of disk, return EOF. */ 527 bp->b_resid = bp->b_bcount; 528 return (0); 529 } 530 /* ...or truncate if part of it fits */ 531 sz = maxsz - bp->b_blkno; 532 if (sz <= 0) { 533 bp->b_error = EINVAL; 534 goto bad; 535 } 536 bp->b_bcount = sz << DEV_BSHIFT; 537 } 538 539 /* calculate cylinder for disksort to order transfers with */ 540 bp->b_resid = (bp->b_blkno + p->p_offset) / lp->d_secpercyl; 541 return (1); 542 543 bad: 544 bp->b_flags |= B_ERROR; 545 return (-1); 546 } 547