1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 /* 30 * This file contains functions to implement automatic configuration 31 * of scsi disks. 32 */ 33 #include "global.h" 34 35 #include <fcntl.h> 36 #include <stdlib.h> 37 #include <string.h> 38 #include <strings.h> 39 #include <stdlib.h> 40 #include <ctype.h> 41 42 #include "misc.h" 43 #include "param.h" 44 #include "ctlr_scsi.h" 45 #include "auto_sense.h" 46 #include "partition.h" 47 #include "label.h" 48 #include "startup.h" 49 #include "analyze.h" 50 #include "io.h" 51 #include "hardware_structs.h" 52 #include "menu_fdisk.h" 53 54 55 #define DISK_NAME_MAX 256 56 57 extern int nctypes; 58 extern struct ctlr_type ctlr_types[]; 59 60 61 /* 62 * Marker for free hog partition 63 */ 64 #define HOG (-1) 65 66 67 68 /* 69 * Default partition tables 70 * 71 * Disk capacity root swap usr 72 * ------------- ---- ---- --- 73 * 0mb to 64mb 0 0 remainder 74 * 64mb to 180mb 16mb 16mb remainder 75 * 180mb to 280mb 16mb 32mb remainder 76 * 280mb to 380mb 24mb 32mb remainder 77 * 380mb to 600mb 32mb 32mb remainder 78 * 600mb to 1gb 32mb 64mb remainder 79 * 1gb to 2gb 64mb 128mb remainder 80 * 2gb on up 128mb 128mb remainder 81 */ 82 struct part_table { 83 int partitions[NDKMAP]; 84 }; 85 86 static struct part_table part_table_64mb = { 87 { 0, 0, 0, 0, 0, 0, HOG, 0} 88 }; 89 90 static struct part_table part_table_180mb = { 91 { 16, 16, 0, 0, 0, 0, HOG, 0} 92 }; 93 94 static struct part_table part_table_280mb = { 95 { 16, 32, 0, 0, 0, 0, HOG, 0} 96 }; 97 98 static struct part_table part_table_380mb = { 99 { 24, 32, 0, 0, 0, 0, HOG, 0} 100 }; 101 102 static struct part_table part_table_600mb = { 103 { 32, 32, 0, 0, 0, 0, HOG, 0} 104 }; 105 106 static struct part_table part_table_1gb = { 107 { 32, 64, 0, 0, 0, 0, HOG, 0} 108 }; 109 110 static struct part_table part_table_2gb = { 111 { 64, 128, 0, 0, 0, 0, HOG, 0} 112 }; 113 114 static struct part_table part_table_infinity = { 115 { 128, 128, 0, 0, 0, 0, HOG, 0} 116 }; 117 118 119 static struct default_partitions { 120 long min_capacity; 121 long max_capacity; 122 struct part_table *part_table; 123 } default_partitions[] = { 124 { 0, 64, &part_table_64mb }, /* 0 to 64 mb */ 125 { 64, 180, &part_table_180mb }, /* 64 to 180 mb */ 126 { 180, 280, &part_table_280mb }, /* 180 to 280 mb */ 127 { 280, 380, &part_table_380mb }, /* 280 to 380 mb */ 128 { 380, 600, &part_table_600mb }, /* 380 to 600 mb */ 129 { 600, 1024, &part_table_1gb }, /* 600 to 1 gb */ 130 { 1024, 2048, &part_table_2gb }, /* 1 to 2 gb */ 131 { 2048, INFINITY, &part_table_infinity }, /* 2 gb on up */ 132 }; 133 134 #define DEFAULT_PARTITION_TABLE_SIZE \ 135 (sizeof (default_partitions) / sizeof (struct default_partitions)) 136 137 /* 138 * msgs for check() 139 */ 140 #define FORMAT_MSG "Auto configuration via format.dat" 141 #define GENERIC_MSG "Auto configuration via generic SCSI-2" 142 143 /* 144 * Disks on symbios(Hardwire raid controller) return a fixed number 145 * of heads(64)/cylinders(64) and adjust the cylinders depending 146 * capacity of the configured lun. 147 * In such a case we get number of physical cylinders < 3 which 148 * is the minimum required by solaris(2 reserved + 1 data cylinders). 149 * Hence try to adjust the cylinders by reducing the "nsect/nhead". 150 * 151 */ 152 /* 153 * assuming a minimum of 32 block cylinders. 154 */ 155 #define MINIMUM_NO_HEADS 2 156 #define MINIMUM_NO_SECTORS 16 157 158 #define MINIMUM_NO_CYLINDERS 128 159 160 #if defined(_SUNOS_VTOC_8) 161 162 /* These are 16-bit fields */ 163 #define MAXIMUM_NO_HEADS 65535 164 #define MAXIMUM_NO_SECTORS 65535 165 #define MAXIMUM_NO_CYLINDERS 65535 166 167 #endif /* defined(_SUNOS_VTOC_8) */ 168 169 /* 170 * minimum number of cylinders required by Solaris. 171 */ 172 #define SUN_MIN_CYL 3 173 174 175 176 /* 177 * ANSI prototypes for local static functions 178 */ 179 static struct disk_type *generic_disk_sense( 180 int fd, 181 int can_prompt, 182 struct dk_label *label, 183 struct scsi_inquiry *inquiry, 184 struct scsi_capacity_16 *capacity, 185 char *disk_name); 186 static int use_existing_disk_type( 187 int fd, 188 int can_prompt, 189 struct dk_label *label, 190 struct scsi_inquiry *inquiry, 191 struct disk_type *disk_type, 192 struct scsi_capacity_16 *capacity); 193 int build_default_partition(struct dk_label *label, 194 int ctrl_type); 195 static struct disk_type *find_scsi_disk_type( 196 char *disk_name, 197 struct dk_label *label); 198 static struct disk_type *find_scsi_disk_by_name( 199 char *disk_name); 200 static struct ctlr_type *find_scsi_ctlr_type(void); 201 static struct ctlr_info *find_scsi_ctlr_info( 202 struct dk_cinfo *dkinfo); 203 static struct disk_type *new_scsi_disk_type( 204 int fd, 205 char *disk_name, 206 struct dk_label *label); 207 static struct disk_info *find_scsi_disk_info( 208 struct dk_cinfo *dkinfo); 209 210 static struct disk_type *new_direct_disk_type(int fd, char *disk_name, 211 struct dk_label *label); 212 213 static struct disk_info *find_direct_disk_info(struct dk_cinfo *dkinfo); 214 static int efi_ioctl(int fd, int cmd, dk_efi_t *dk_ioc); 215 static int auto_label_init(struct dk_label *label); 216 static struct ctlr_info *find_direct_ctlr_info(struct dk_cinfo *dkinfo); 217 static struct disk_info *find_direct_disk_info(struct dk_cinfo *dkinfo); 218 219 static char *get_sun_disk_name( 220 char *disk_name, 221 struct scsi_inquiry *inquiry); 222 static char *get_generic_disk_name( 223 char *disk_name, 224 struct scsi_inquiry *inquiry); 225 static int force_blocksize(int fd); 226 static int raw_format(int fd); 227 static char *strcopy( 228 char *dst, 229 char *src, 230 int n); 231 static int adjust_disk_geometry(int capacity, int *cyl, 232 int *nsect, int *nhead); 233 #if defined(_SUNOS_VTOC_8) 234 static int square_box( 235 int capacity, 236 int *dim1, int lim1, 237 int *dim2, int lim2, 238 int *dim3, int lim3); 239 #endif /* defined(_SUNOS_VTOC_8) */ 240 241 242 /* 243 * We need to get information necessary to construct a *new* efi 244 * label type 245 */ 246 struct disk_type * 247 auto_efi_sense(int fd, struct efi_info *label) 248 { 249 250 struct dk_gpt *vtoc; 251 int i; 252 253 struct disk_type *disk, *dp; 254 struct disk_info *disk_info; 255 struct ctlr_info *ctlr; 256 struct dk_cinfo dkinfo; 257 struct partition_info *part; 258 259 /* 260 * get vendor, product, revision and capacity info. 261 */ 262 if (get_disk_info(fd, label) == -1) { 263 return ((struct disk_type *)NULL); 264 } 265 /* 266 * Now build the default partition table 267 */ 268 if (efi_alloc_and_init(fd, EFI_NUMPAR, &vtoc) != 0) { 269 err_print("efi_alloc_and_init failed. \n"); 270 return ((struct disk_type *)NULL); 271 } 272 273 label->e_parts = vtoc; 274 275 for (i = 0; i < min(vtoc->efi_nparts, V_NUMPAR); i++) { 276 vtoc->efi_parts[i].p_tag = default_vtoc_map[i].p_tag; 277 vtoc->efi_parts[i].p_flag = default_vtoc_map[i].p_flag; 278 vtoc->efi_parts[i].p_start = 0; 279 vtoc->efi_parts[i].p_size = 0; 280 } 281 /* 282 * Make constants first 283 * and variable partitions later 284 */ 285 286 /* root partition - s0 128 MB */ 287 vtoc->efi_parts[0].p_start = 34; 288 vtoc->efi_parts[0].p_size = 262144; 289 290 /* partition - s1 128 MB */ 291 vtoc->efi_parts[1].p_start = 262178; 292 vtoc->efi_parts[1].p_size = 262144; 293 294 /* partition -s2 is NOT the Backup disk */ 295 vtoc->efi_parts[2].p_tag = V_UNASSIGNED; 296 297 /* partition -s6 /usr partition - HOG */ 298 vtoc->efi_parts[6].p_start = 524322; 299 vtoc->efi_parts[6].p_size = vtoc->efi_last_u_lba - 524322 300 - (1024 * 16); 301 302 /* efi reserved partition - s9 16K */ 303 vtoc->efi_parts[8].p_start = vtoc->efi_last_u_lba - (1024 * 16); 304 vtoc->efi_parts[8].p_size = (1024 * 16); 305 vtoc->efi_parts[8].p_tag = V_RESERVED; 306 /* 307 * Now stick all of it into the disk_type struct 308 */ 309 310 if (ioctl(fd, DKIOCINFO, &dkinfo) == -1) { 311 if (option_msg && diag_msg) { 312 err_print("DKIOCINFO failed\n"); 313 } 314 return (NULL); 315 } 316 ctlr = find_scsi_ctlr_info(&dkinfo); 317 disk = (struct disk_type *)zalloc(sizeof (struct disk_type)); 318 disk_info = find_scsi_disk_info(&dkinfo); 319 assert(disk_info->disk_ctlr == ctlr); 320 dp = ctlr->ctlr_ctype->ctype_dlist; 321 if (dp == NULL) { 322 ctlr->ctlr_ctype->ctype_dlist = dp; 323 } else { 324 while (dp->dtype_next != NULL) { 325 dp = dp->dtype_next; 326 } 327 dp->dtype_next = disk; 328 } 329 disk->dtype_next = NULL; 330 331 (void) strlcpy(disk->vendor, label->vendor, 332 sizeof (disk->vendor)); 333 (void) strlcpy(disk->product, label->product, 334 sizeof (disk->product)); 335 (void) strlcpy(disk->revision, label->revision, 336 sizeof (disk->revision)); 337 disk->capacity = label->capacity; 338 339 part = (struct partition_info *) 340 zalloc(sizeof (struct partition_info)); 341 disk->dtype_plist = part; 342 343 part->pinfo_name = alloc_string("default"); 344 part->pinfo_next = NULL; 345 part->etoc = vtoc; 346 347 bzero(disk_info->v_volume, LEN_DKL_VVOL); 348 disk_info->disk_parts = part; 349 return (disk); 350 } 351 352 static int 353 efi_ioctl(int fd, int cmd, dk_efi_t *dk_ioc) 354 { 355 void *data = dk_ioc->dki_data; 356 int error; 357 358 dk_ioc->dki_data_64 = (uint64_t)(uintptr_t)data; 359 error = ioctl(fd, cmd, (void *)dk_ioc); 360 dk_ioc->dki_data = data; 361 362 return (error); 363 } 364 365 static struct ctlr_info * 366 find_direct_ctlr_info( 367 struct dk_cinfo *dkinfo) 368 { 369 struct ctlr_info *ctlr; 370 371 if (dkinfo->dki_ctype != DKC_DIRECT) 372 return (NULL); 373 374 for (ctlr = ctlr_list; ctlr != NULL; ctlr = ctlr->ctlr_next) { 375 if (ctlr->ctlr_addr == dkinfo->dki_addr && 376 ctlr->ctlr_space == dkinfo->dki_space && 377 ctlr->ctlr_ctype->ctype_ctype == DKC_DIRECT) { 378 return (ctlr); 379 } 380 } 381 382 impossible("no DIRECT controller info"); 383 /*NOTREACHED*/ 384 } 385 386 static struct disk_info * 387 find_direct_disk_info( 388 struct dk_cinfo *dkinfo) 389 { 390 struct disk_info *disk; 391 struct dk_cinfo *dp; 392 393 for (disk = disk_list; disk != NULL; disk = disk->disk_next) { 394 assert(dkinfo->dki_ctype == DKC_DIRECT); 395 dp = &disk->disk_dkinfo; 396 if (dp->dki_ctype == dkinfo->dki_ctype && 397 dp->dki_cnum == dkinfo->dki_cnum && 398 dp->dki_unit == dkinfo->dki_unit && 399 strcmp(dp->dki_dname, dkinfo->dki_dname) == 0) { 400 return (disk); 401 } 402 } 403 404 impossible("No DIRECT disk info instance\n"); 405 /*NOTREACHED*/ 406 } 407 408 /* 409 * To convert EFI to SMI labels, we need to get label geometry. 410 * Unfortunately at this time there is no good way to do so. 411 * DKIOCGGEOM will fail if disk is EFI labeled. So we hack around 412 * it and clear EFI label, do a DKIOCGGEOM and put the EFI label 413 * back on disk. 414 * This routine gets the label geometry and initializes the label 415 * It uses cur_file as opened device. 416 * returns 0 if succeeds or -1 if failed. 417 */ 418 static int 419 auto_label_init(struct dk_label *label) 420 { 421 dk_efi_t dk_ioc; 422 dk_efi_t dk_ioc_back; 423 efi_gpt_t *data = NULL; 424 efi_gpt_t *databack = NULL; 425 struct dk_geom disk_geom; 426 struct dk_minfo disk_info; 427 efi_gpt_t *backsigp; 428 int fd = cur_file; 429 int rval = -1; 430 int efisize = EFI_LABEL_SIZE * 2; 431 int success = 0; 432 uint64_t sig; 433 uint64_t backsig; 434 435 if ((data = calloc(efisize, 1)) == NULL) { 436 err_print("auto_label_init: calloc failed\n"); 437 goto auto_label_init_out; 438 } 439 440 dk_ioc.dki_data = data; 441 dk_ioc.dki_lba = 1; 442 dk_ioc.dki_length = efisize; 443 444 if (efi_ioctl(fd, DKIOCGETEFI, &dk_ioc) != 0) { 445 err_print("auto_label_init: GETEFI failed\n"); 446 goto auto_label_init_out; 447 } 448 449 if ((databack = calloc(efisize, 1)) == NULL) { 450 err_print("auto_label_init calloc2 failed"); 451 goto auto_label_init_out; 452 } 453 454 /* get the LBA size and capacity */ 455 if (ioctl(fd, DKIOCGMEDIAINFO, (caddr_t)&disk_info) == -1) { 456 err_print("auto_label_init: dkiocgmediainfo failed\n"); 457 goto auto_label_init_out; 458 } 459 460 if (disk_info.dki_lbsize == 0) { 461 if (option_msg && diag_msg) { 462 err_print("auto_lbal_init: assuming 512 byte" 463 "block size"); 464 } 465 disk_info.dki_lbsize = DEV_BSIZE; 466 } 467 468 if (disk_info.dki_lbsize != DEV_BSIZE) { 469 err_print("auto_label_init: lbasize is not 512\n"); 470 goto auto_label_init_out; 471 } 472 473 dk_ioc_back.dki_data = databack; 474 475 /* 476 * back up efi label goes to capacity - 1, we are reading an extra block 477 * before the back up label. 478 */ 479 dk_ioc_back.dki_lba = disk_info.dki_capacity - 1 - 1; 480 dk_ioc_back.dki_length = efisize; 481 482 if (efi_ioctl(fd, DKIOCGETEFI, &dk_ioc_back) != 0) { 483 err_print("auto_label_init: GETEFI backup failed\n"); 484 goto auto_label_init_out; 485 } 486 487 sig = dk_ioc.dki_data->efi_gpt_Signature; 488 dk_ioc.dki_data->efi_gpt_Signature = 0x0; 489 490 enter_critical(); 491 492 if (efi_ioctl(fd, DKIOCSETEFI, &dk_ioc) == -1) { 493 err_print("auto_label_init: SETEFI failed\n"); 494 exit_critical(); 495 goto auto_label_init_out; 496 } 497 498 backsigp = (efi_gpt_t *)((uintptr_t)dk_ioc_back.dki_data + DEV_BSIZE); 499 500 backsig = backsigp->efi_gpt_Signature; 501 502 backsigp->efi_gpt_Signature = 0; 503 504 if (efi_ioctl(fd, DKIOCSETEFI, &dk_ioc_back) == -1) { 505 err_print("auto_label_init: SETEFI backup failed\n"); 506 } 507 508 if (ioctl(cur_file, DKIOCGGEOM, &disk_geom) != 0) 509 err_print("auto_label_init: GGEOM failed\n"); 510 else 511 success = 1; 512 513 dk_ioc.dki_data->efi_gpt_Signature = sig; 514 backsigp->efi_gpt_Signature = backsig; 515 516 if (efi_ioctl(cur_file, DKIOCSETEFI, &dk_ioc_back) == -1) { 517 err_print("auto_label_init: SETEFI revert backup failed\n"); 518 success = 0; 519 } 520 521 if (efi_ioctl(cur_file, DKIOCSETEFI, &dk_ioc) == -1) { 522 err_print("auto_label_init: SETEFI revert failed\n"); 523 success = 0; 524 } 525 526 exit_critical(); 527 528 if (success == 0) 529 goto auto_label_init_out; 530 531 ncyl = disk_geom.dkg_ncyl; 532 acyl = disk_geom.dkg_acyl; 533 nhead = disk_geom.dkg_nhead; 534 nsect = disk_geom.dkg_nsect; 535 pcyl = ncyl + acyl; 536 537 label->dkl_pcyl = pcyl; 538 label->dkl_ncyl = ncyl; 539 label->dkl_acyl = acyl; 540 label->dkl_nhead = nhead; 541 label->dkl_nsect = nsect; 542 label->dkl_apc = 0; 543 label->dkl_intrlv = 1; 544 label->dkl_rpm = disk_geom.dkg_rpm; 545 546 label->dkl_magic = DKL_MAGIC; 547 548 (void) snprintf(label->dkl_asciilabel, sizeof (label->dkl_asciilabel), 549 "%s cyl %d alt %d hd %d sec %d", 550 "DEFAULT", ncyl, acyl, nhead, nsect); 551 552 rval = 0; 553 #if defined(_FIRMWARE_NEEDS_FDISK) 554 (void) auto_solaris_part(label); 555 ncyl = label->dkl_ncyl; 556 557 #endif /* defined(_FIRMWARE_NEEDS_FDISK) */ 558 559 if (!build_default_partition(label, DKC_DIRECT)) { 560 rval = -1; 561 } 562 563 (void) checksum(label, CK_MAKESUM); 564 565 566 auto_label_init_out: 567 if (data) 568 free(data); 569 if (databack) 570 free(databack); 571 572 return (rval); 573 } 574 575 static struct disk_type * 576 new_direct_disk_type( 577 int fd, 578 char *disk_name, 579 struct dk_label *label) 580 { 581 struct disk_type *dp; 582 struct disk_type *disk; 583 struct ctlr_info *ctlr; 584 struct dk_cinfo dkinfo; 585 struct partition_info *part = NULL; 586 struct partition_info *pt; 587 struct disk_info *disk_info; 588 int i; 589 590 /* 591 * Get the disk controller info for this disk 592 */ 593 if (ioctl(fd, DKIOCINFO, &dkinfo) == -1) { 594 if (option_msg && diag_msg) { 595 err_print("DKIOCINFO failed\n"); 596 } 597 return (NULL); 598 } 599 600 /* 601 * Find the ctlr_info for this disk. 602 */ 603 ctlr = find_direct_ctlr_info(&dkinfo); 604 605 /* 606 * Allocate a new disk type for the direct controller. 607 */ 608 disk = (struct disk_type *)zalloc(sizeof (struct disk_type)); 609 610 /* 611 * Find the disk_info instance for this disk. 612 */ 613 disk_info = find_direct_disk_info(&dkinfo); 614 615 /* 616 * The controller and the disk should match. 617 */ 618 assert(disk_info->disk_ctlr == ctlr); 619 620 /* 621 * Link the disk into the list of disks 622 */ 623 dp = ctlr->ctlr_ctype->ctype_dlist; 624 if (dp == NULL) { 625 ctlr->ctlr_ctype->ctype_dlist = dp; 626 } else { 627 while (dp->dtype_next != NULL) { 628 dp = dp->dtype_next; 629 } 630 dp->dtype_next = disk; 631 } 632 disk->dtype_next = NULL; 633 634 /* 635 * Allocate and initialize the disk name. 636 */ 637 disk->dtype_asciilabel = alloc_string(disk_name); 638 639 /* 640 * Initialize disk geometry info 641 */ 642 disk->dtype_pcyl = label->dkl_pcyl; 643 disk->dtype_ncyl = label->dkl_ncyl; 644 disk->dtype_acyl = label->dkl_acyl; 645 disk->dtype_nhead = label->dkl_nhead; 646 disk->dtype_nsect = label->dkl_nsect; 647 disk->dtype_rpm = label->dkl_rpm; 648 649 part = (struct partition_info *) 650 zalloc(sizeof (struct partition_info)); 651 pt = disk->dtype_plist; 652 if (pt == NULL) { 653 disk->dtype_plist = part; 654 } else { 655 while (pt->pinfo_next != NULL) { 656 pt = pt->pinfo_next; 657 } 658 pt->pinfo_next = part; 659 } 660 661 part->pinfo_next = NULL; 662 663 /* 664 * Set up the partition name 665 */ 666 part->pinfo_name = alloc_string("default"); 667 668 /* 669 * Fill in the partition info from the label 670 */ 671 for (i = 0; i < NDKMAP; i++) { 672 673 #if defined(_SUNOS_VTOC_8) 674 part->pinfo_map[i] = label->dkl_map[i]; 675 676 #elif defined(_SUNOS_VTOC_16) 677 part->pinfo_map[i].dkl_cylno = 678 label->dkl_vtoc.v_part[i].p_start / 679 ((int)(disk->dtype_nhead * 680 disk->dtype_nsect - apc)); 681 part->pinfo_map[i].dkl_nblk = 682 label->dkl_vtoc.v_part[i].p_size; 683 #else 684 #error No VTOC format defined. 685 #endif /* defined(_SUNOS_VTOC_8) */ 686 } 687 688 /* 689 * Use the VTOC if valid, or install a default 690 */ 691 if (label->dkl_vtoc.v_version == V_VERSION) { 692 (void) memcpy(disk_info->v_volume, label->dkl_vtoc.v_volume, 693 LEN_DKL_VVOL); 694 part->vtoc = label->dkl_vtoc; 695 } else { 696 (void) memset(disk_info->v_volume, 0, LEN_DKL_VVOL); 697 set_vtoc_defaults(part); 698 } 699 700 /* 701 * Link the disk to the partition map 702 */ 703 disk_info->disk_parts = part; 704 705 return (disk); 706 } 707 708 /* 709 * Get a disk type that has label info. This is used to convert 710 * EFI label to SMI label 711 */ 712 struct disk_type * 713 auto_direct_get_geom_label(int fd, struct dk_label *label) 714 { 715 struct disk_type *disk_type; 716 717 if (auto_label_init(label) != 0) { 718 err_print("auto_direct_get_geom_label: failed to get label" 719 "geometry"); 720 return (NULL); 721 } else { 722 disk_type = new_direct_disk_type(fd, "DEFAULT", label); 723 return (disk_type); 724 } 725 } 726 727 728 /* 729 * Auto-sense a scsi disk configuration, ie get the information 730 * necessary to construct a label. We have two different 731 * ways to auto-sense a scsi disk: 732 * - format.dat override, via inquiry name 733 * - generic scsi, via standard mode sense and inquiry 734 * Depending on how and when we are called, and/or 735 * change geometry and reformat. 736 */ 737 struct disk_type * 738 auto_sense( 739 int fd, 740 int can_prompt, 741 struct dk_label *label) 742 { 743 struct scsi_inquiry inquiry; 744 struct scsi_capacity_16 capacity; 745 struct disk_type *disk_type; 746 char disk_name[DISK_NAME_MAX]; 747 int force_format_dat = 0; 748 int force_generic = 0; 749 u_ioparam_t ioparam; 750 int deflt; 751 752 /* 753 * First, if expert mode, find out if the user 754 * wants to override any of the standard methods. 755 */ 756 if (can_prompt && expert_mode) { 757 deflt = 1; 758 ioparam.io_charlist = confirm_list; 759 if (input(FIO_MSTR, FORMAT_MSG, '?', &ioparam, 760 &deflt, DATA_INPUT) == 0) { 761 force_format_dat = 1; 762 } else if (input(FIO_MSTR, GENERIC_MSG, '?', &ioparam, 763 &deflt, DATA_INPUT) == 0) { 764 force_generic = 1; 765 } 766 } 767 768 /* 769 * Get the Inquiry data. If this fails, there's 770 * no hope for this disk, so give up. 771 */ 772 if (uscsi_inquiry(fd, (char *)&inquiry, sizeof (inquiry))) { 773 return ((struct disk_type *)NULL); 774 } 775 if (option_msg && diag_msg) { 776 err_print("Product id: "); 777 print_buf(inquiry.inq_pid, sizeof (inquiry.inq_pid)); 778 err_print("\n"); 779 } 780 781 /* 782 * Get the Read Capacity 783 */ 784 if (uscsi_read_capacity(fd, &capacity)) { 785 return ((struct disk_type *)NULL); 786 } 787 if (option_msg && diag_msg) { 788 err_print("blocks: %llu (0x%llx)\n", 789 capacity.sc_capacity, capacity.sc_capacity); 790 err_print("blksize: %u\n", capacity.sc_lbasize); 791 } 792 793 /* 794 * Extract the disk name for the format.dat override 795 */ 796 (void) get_sun_disk_name(disk_name, &inquiry); 797 if (option_msg && diag_msg) { 798 err_print("disk name: `%s`\n", disk_name); 799 } 800 801 /* 802 * Figure out which method we use for auto sense. 803 * If a particular method fails, we fall back to 804 * the next possibility. 805 */ 806 807 if (force_generic) { 808 return (generic_disk_sense(fd, can_prompt, label, 809 &inquiry, &capacity, disk_name)); 810 } 811 812 /* 813 * Try for an existing format.dat first 814 */ 815 if ((disk_type = find_scsi_disk_by_name(disk_name)) != NULL) { 816 if (use_existing_disk_type(fd, can_prompt, label, 817 &inquiry, disk_type, &capacity)) { 818 return (disk_type); 819 } 820 if (force_format_dat) { 821 return (NULL); 822 } 823 } 824 825 /* 826 * Otherwise, try using generic SCSI-2 sense and inquiry. 827 */ 828 829 return (generic_disk_sense(fd, can_prompt, label, 830 &inquiry, &capacity, disk_name)); 831 } 832 833 834 835 /*ARGSUSED*/ 836 static struct disk_type * 837 generic_disk_sense( 838 int fd, 839 int can_prompt, 840 struct dk_label *label, 841 struct scsi_inquiry *inquiry, 842 struct scsi_capacity_16 *capacity, 843 char *disk_name) 844 { 845 struct disk_type *disk; 846 int pcyl; 847 int ncyl; 848 int acyl; 849 int nhead; 850 int nsect; 851 int rpm; 852 long nblocks; 853 union { 854 struct mode_format page3; 855 uchar_t buf3[MAX_MODE_SENSE_SIZE]; 856 } u_page3; 857 union { 858 struct mode_geometry page4; 859 uchar_t buf4[MAX_MODE_SENSE_SIZE]; 860 } u_page4; 861 struct scsi_capacity_16 new_capacity; 862 struct mode_format *page3 = &u_page3.page3; 863 struct mode_geometry *page4 = &u_page4.page4; 864 struct scsi_ms_header header; 865 866 /* 867 * If the name of this disk appears to be "SUN", use it, 868 * otherwise construct a name out of the generic 869 * Inquiry info. If it turns out that we already 870 * have a SUN disk type of this name that differs 871 * in geometry, we will revert to the generic name 872 * anyway. 873 */ 874 if (memcmp(disk_name, "SUN", strlen("SUN")) != 0) { 875 (void) get_generic_disk_name(disk_name, inquiry); 876 } 877 878 /* 879 * If the device's block size is not 512, we have to 880 * change block size, reformat, and then sense the 881 * geometry. To do this, we must be able to prompt 882 * the user. 883 */ 884 if (capacity->sc_lbasize != DEV_BSIZE) { 885 if (!can_prompt) { 886 return (NULL); 887 } 888 if (force_blocksize(fd)) { 889 goto err; 890 } 891 892 /* 893 * Get the capacity again, since this has changed 894 */ 895 if (uscsi_read_capacity(fd, &new_capacity)) { 896 goto err; 897 } 898 if (option_msg && diag_msg) { 899 err_print("blocks: %llu (0x%llx)\n", 900 new_capacity.sc_capacity, 901 new_capacity.sc_capacity); 902 err_print("blksize: %u\n", new_capacity.sc_lbasize); 903 } 904 capacity = &new_capacity; 905 if (capacity->sc_lbasize != DEV_BSIZE) { 906 goto err; 907 } 908 } 909 910 /* 911 * Get current Page 3 - Format Parameters page 912 */ 913 if (uscsi_mode_sense(fd, DAD_MODE_FORMAT, MODE_SENSE_PC_CURRENT, 914 (caddr_t)&u_page3, MAX_MODE_SENSE_SIZE, &header)) { 915 goto err; 916 } 917 918 /* 919 * Get current Page 4 - Drive Geometry page 920 */ 921 if (uscsi_mode_sense(fd, DAD_MODE_GEOMETRY, MODE_SENSE_PC_CURRENT, 922 (caddr_t)&u_page4, MAX_MODE_SENSE_SIZE, &header)) { 923 goto err; 924 } 925 926 /* 927 * Correct for byte order if necessary 928 */ 929 page4->rpm = BE_16(page4->rpm); 930 page4->step_rate = BE_16(page4->step_rate); 931 page3->tracks_per_zone = BE_16(page3->tracks_per_zone); 932 page3->alt_sect_zone = BE_16(page3->alt_sect_zone); 933 page3->alt_tracks_zone = BE_16(page3->alt_tracks_zone); 934 page3->alt_tracks_vol = BE_16(page3->alt_tracks_vol); 935 page3->sect_track = BE_16(page3->sect_track); 936 page3->data_bytes_sect = BE_16(page3->data_bytes_sect); 937 page3->interleave = BE_16(page3->interleave); 938 page3->track_skew = BE_16(page3->track_skew); 939 page3->cylinder_skew = BE_16(page3->cylinder_skew); 940 941 942 /* 943 * Construct a new label out of the sense data, 944 * Inquiry and Capacity. 945 */ 946 pcyl = (page4->cyl_ub << 16) + (page4->cyl_mb << 8) + page4->cyl_lb; 947 nhead = page4->heads; 948 nsect = page3->sect_track; 949 rpm = page4->rpm; 950 951 /* 952 * If the number of physical cylinders reported is less 953 * the SUN_MIN_CYL(3) then try to adjust the geometry so that 954 * we have atleast SUN_MIN_CYL cylinders. 955 */ 956 if (pcyl < SUN_MIN_CYL) { 957 if (adjust_disk_geometry((int)(capacity->sc_capacity + 1), 958 &pcyl, &nhead, &nsect)) { 959 goto err; 960 } 961 } 962 963 /* 964 * The sd driver reserves 2 cylinders the backup disk label and 965 * the deviceid. Set the number of data cylinders to pcyl-acyl. 966 */ 967 acyl = DK_ACYL; 968 ncyl = pcyl - acyl; 969 970 if (option_msg && diag_msg) { 971 err_print("Geometry:\n"); 972 err_print(" pcyl: %d\n", pcyl); 973 err_print(" ncyl: %d\n", ncyl); 974 err_print(" heads: %d\n", nhead); 975 err_print(" nsects: %d\n", nsect); 976 err_print(" acyl: %d\n", acyl); 977 978 #if defined(_SUNOS_VTOC_16) 979 err_print(" bcyl: %d\n", bcyl); 980 #endif /* defined(_SUNOS_VTOC_16) */ 981 982 err_print(" rpm: %d\n", rpm); 983 } 984 985 /* 986 * Some drives report 0 for page4->rpm, adjust it to AVG_RPM, 3600. 987 */ 988 if (rpm < MIN_RPM || rpm > MAX_RPM) { 989 err_print("Mode sense page(4) reports rpm value as %d," 990 " adjusting it to %d\n", rpm, AVG_RPM); 991 rpm = AVG_RPM; 992 } 993 994 /* 995 * Get the number of blocks from Read Capacity data. Note that 996 * the logical block address range from 0 to capacity->sc_capacity. 997 */ 998 nblocks = (long)(capacity->sc_capacity + 1); 999 1000 /* 1001 * Some drives report 0 for nsect (page 3, byte 10 and 11) if they 1002 * have variable number of sectors per track. So adjust nsect. 1003 * Also the value is defined as vendor specific, hence check if 1004 * it is in a tolerable range. The values (32 and 4 below) are 1005 * chosen so that this change below does not generate a different 1006 * geometry for currently supported sun disks. 1007 */ 1008 if ((nsect <= 0) || 1009 (pcyl * nhead * nsect) < (nblocks - nblocks/32) || 1010 (pcyl * nhead * nsect) > (nblocks + nblocks/4)) { 1011 err_print("Mode sense page(3) reports nsect value as %d, " 1012 "adjusting it to %ld\n", nsect, nblocks / (pcyl * nhead)); 1013 nsect = nblocks / (pcyl * nhead); 1014 } 1015 1016 /* 1017 * Some drives report their physical geometry such that 1018 * it is greater than the actual capacity. Adjust the 1019 * geometry to allow for this, so we don't run off 1020 * the end of the disk. 1021 */ 1022 if ((pcyl * nhead * nsect) > nblocks) { 1023 int p = pcyl; 1024 if (option_msg && diag_msg) { 1025 err_print("Computed capacity (%ld) exceeds actual " 1026 "disk capacity (%ld)\n", 1027 (long)(pcyl * nhead * nsect), nblocks); 1028 } 1029 do { 1030 pcyl--; 1031 } while ((pcyl * nhead * nsect) > nblocks); 1032 1033 if (can_prompt && expert_mode && !option_f) { 1034 /* 1035 * Try to adjust nsect instead of pcyl to see if we 1036 * can optimize. For compatability reasons do this 1037 * only in expert mode (refer to bug 1144812). 1038 */ 1039 int n = nsect; 1040 do { 1041 n--; 1042 } while ((p * nhead * n) > nblocks); 1043 if ((p * nhead * n) > (pcyl * nhead * nsect)) { 1044 u_ioparam_t ioparam; 1045 int deflt = 1; 1046 /* 1047 * Ask the user for a choice here. 1048 */ 1049 ioparam.io_bounds.lower = 1; 1050 ioparam.io_bounds.upper = 2; 1051 err_print("1. Capacity = %d, with pcyl = %d " 1052 "nhead = %d nsect = %d\n", 1053 (pcyl * nhead * nsect), 1054 pcyl, nhead, nsect); 1055 err_print("2. Capacity = %d, with pcyl = %d " 1056 "nhead = %d nsect = %d\n", 1057 (p * nhead * n), 1058 p, nhead, n); 1059 if (input(FIO_INT, "Select one of the above " 1060 "choices ", ':', &ioparam, 1061 &deflt, DATA_INPUT) == 2) { 1062 pcyl = p; 1063 nsect = n; 1064 } 1065 } 1066 } 1067 } 1068 1069 #if defined(_SUNOS_VTOC_8) 1070 /* 1071 * Finally, we need to make sure we don't overflow any of the 1072 * fields in our disk label. To do this we need to `square 1073 * the box' so to speak. We will lose bits here. 1074 */ 1075 1076 if ((pcyl > MAXIMUM_NO_CYLINDERS && 1077 ((nsect > MAXIMUM_NO_SECTORS) || 1078 (nhead > MAXIMUM_NO_HEADS))) || 1079 ((nsect > MAXIMUM_NO_SECTORS) && 1080 (nhead > MAXIMUM_NO_HEADS))) { 1081 err_print("This disk is too big to label. " 1082 " You will lose some blocks.\n"); 1083 } 1084 if ((pcyl > MAXIMUM_NO_CYLINDERS) || 1085 (nsect > MAXIMUM_NO_SECTORS) || 1086 (nhead > MAXIMUM_NO_HEADS)) { 1087 u_ioparam_t ioparam; 1088 int order; 1089 char msg[256]; 1090 1091 order = ((ncyl > nhead)<<2) | 1092 ((ncyl > nsect)<<1) | 1093 (nhead > nsect); 1094 switch (order) { 1095 case 0x7: /* ncyl > nhead > nsect */ 1096 nblocks = 1097 square_box(nblocks, 1098 &pcyl, MAXIMUM_NO_CYLINDERS, 1099 &nhead, MAXIMUM_NO_HEADS, 1100 &nsect, MAXIMUM_NO_SECTORS); 1101 break; 1102 case 0x6: /* ncyl > nsect > nhead */ 1103 nblocks = 1104 square_box(nblocks, 1105 &pcyl, MAXIMUM_NO_CYLINDERS, 1106 &nsect, MAXIMUM_NO_SECTORS, 1107 &nhead, MAXIMUM_NO_HEADS); 1108 break; 1109 case 0x4: /* nsect > ncyl > nhead */ 1110 nblocks = 1111 square_box(nblocks, 1112 &nsect, MAXIMUM_NO_SECTORS, 1113 &pcyl, MAXIMUM_NO_CYLINDERS, 1114 &nhead, MAXIMUM_NO_HEADS); 1115 break; 1116 case 0x0: /* nsect > nhead > ncyl */ 1117 nblocks = 1118 square_box(nblocks, 1119 &nsect, MAXIMUM_NO_SECTORS, 1120 &nhead, MAXIMUM_NO_HEADS, 1121 &pcyl, MAXIMUM_NO_CYLINDERS); 1122 break; 1123 case 0x3: /* nhead > ncyl > nsect */ 1124 nblocks = 1125 square_box(nblocks, 1126 &nhead, MAXIMUM_NO_HEADS, 1127 &pcyl, MAXIMUM_NO_CYLINDERS, 1128 &nsect, MAXIMUM_NO_SECTORS); 1129 break; 1130 case 0x1: /* nhead > nsect > ncyl */ 1131 nblocks = 1132 square_box(nblocks, 1133 &nhead, MAXIMUM_NO_HEADS, 1134 &nsect, MAXIMUM_NO_SECTORS, 1135 &pcyl, MAXIMUM_NO_CYLINDERS); 1136 break; 1137 default: 1138 /* How did we get here? */ 1139 impossible("label overflow adjustment"); 1140 1141 /* Do something useful */ 1142 nblocks = 1143 square_box(nblocks, 1144 &nhead, MAXIMUM_NO_HEADS, 1145 &nsect, MAXIMUM_NO_SECTORS, 1146 &pcyl, MAXIMUM_NO_CYLINDERS); 1147 break; 1148 } 1149 if (option_msg && diag_msg && 1150 (capacity->sc_capacity + 1 != nblocks)) { 1151 err_print("After adjusting geometry you lost" 1152 " %llu of %lld blocks.\n", 1153 (capacity->sc_capacity + 1 - nblocks), 1154 capacity->sc_capacity + 1); 1155 } 1156 while (can_prompt && expert_mode && !option_f) { 1157 int deflt = 1; 1158 1159 /* 1160 * Allow user to modify this by hand if desired. 1161 */ 1162 (void) sprintf(msg, 1163 "\nGeometry: %d heads, %d sectors %d " 1164 " cylinders result in %d out of %lld blocks.\n" 1165 "Do you want to modify the device geometry", 1166 nhead, nsect, pcyl, 1167 (int)nblocks, capacity->sc_capacity + 1); 1168 1169 ioparam.io_charlist = confirm_list; 1170 if (input(FIO_MSTR, msg, '?', &ioparam, 1171 &deflt, DATA_INPUT) != 0) 1172 break; 1173 1174 ioparam.io_bounds.lower = MINIMUM_NO_HEADS; 1175 ioparam.io_bounds.upper = MAXIMUM_NO_HEADS; 1176 nhead = input(FIO_INT, "Number of heads", ':', 1177 &ioparam, &nhead, DATA_INPUT); 1178 ioparam.io_bounds.lower = MINIMUM_NO_SECTORS; 1179 ioparam.io_bounds.upper = MAXIMUM_NO_SECTORS; 1180 nsect = input(FIO_INT, 1181 "Number of sectors per track", 1182 ':', &ioparam, &nsect, DATA_INPUT); 1183 ioparam.io_bounds.lower = SUN_MIN_CYL; 1184 ioparam.io_bounds.upper = MAXIMUM_NO_CYLINDERS; 1185 pcyl = input(FIO_INT, "Number of cylinders", 1186 ':', &ioparam, &pcyl, DATA_INPUT); 1187 nblocks = nhead * nsect * pcyl; 1188 if (nblocks > capacity->sc_capacity + 1) { 1189 err_print("Warning: %ld blocks exceeds " 1190 "disk capacity of %lld blocks\n", 1191 nblocks, 1192 capacity->sc_capacity + 1); 1193 } 1194 } 1195 } 1196 #endif /* defined(_SUNOS_VTOC_8) */ 1197 1198 ncyl = pcyl - acyl; 1199 1200 if (option_msg && diag_msg) { 1201 err_print("\nGeometry after adjusting for capacity:\n"); 1202 err_print(" pcyl: %d\n", pcyl); 1203 err_print(" ncyl: %d\n", ncyl); 1204 err_print(" heads: %d\n", nhead); 1205 err_print(" nsects: %d\n", nsect); 1206 err_print(" acyl: %d\n", acyl); 1207 err_print(" rpm: %d\n", rpm); 1208 } 1209 1210 (void) memset((char *)label, 0, sizeof (struct dk_label)); 1211 1212 label->dkl_magic = DKL_MAGIC; 1213 1214 (void) snprintf(label->dkl_asciilabel, sizeof (label->dkl_asciilabel), 1215 "%s cyl %d alt %d hd %d sec %d", 1216 disk_name, ncyl, acyl, nhead, nsect); 1217 1218 label->dkl_pcyl = pcyl; 1219 label->dkl_ncyl = ncyl; 1220 label->dkl_acyl = acyl; 1221 label->dkl_nhead = nhead; 1222 label->dkl_nsect = nsect; 1223 label->dkl_apc = 0; 1224 label->dkl_intrlv = 1; 1225 label->dkl_rpm = rpm; 1226 1227 #if defined(_FIRMWARE_NEEDS_FDISK) 1228 (void) auto_solaris_part(label); 1229 ncyl = label->dkl_ncyl; 1230 #endif /* defined(_FIRMWARE_NEEDS_FDISK) */ 1231 1232 1233 if (!build_default_partition(label, DKC_SCSI_CCS)) { 1234 goto err; 1235 } 1236 1237 (void) checksum(label, CK_MAKESUM); 1238 1239 /* 1240 * Find an existing disk type defined for this disk. 1241 * For this to work, both the name and geometry must 1242 * match. If there is no such type, but there already 1243 * is a disk defined with that name, but with a different 1244 * geometry, construct a new generic disk name out of 1245 * the inquiry information. Whatever name we're 1246 * finally using, if there's no such disk type defined, 1247 * build a new disk definition. 1248 */ 1249 if ((disk = find_scsi_disk_type(disk_name, label)) == NULL) { 1250 if (find_scsi_disk_by_name(disk_name) != NULL) { 1251 char old_name[DISK_NAME_MAX]; 1252 (void) strcpy(old_name, disk_name); 1253 (void) get_generic_disk_name(disk_name, 1254 inquiry); 1255 if (option_msg && diag_msg) { 1256 err_print( 1257 "Changing disk type name from '%s' to '%s'\n", old_name, disk_name); 1258 } 1259 (void) snprintf(label->dkl_asciilabel, 1260 sizeof (label->dkl_asciilabel), 1261 "%s cyl %d alt %d hd %d sec %d", 1262 disk_name, ncyl, acyl, nhead, nsect); 1263 (void) checksum(label, CK_MAKESUM); 1264 disk = find_scsi_disk_type(disk_name, label); 1265 } 1266 if (disk == NULL) { 1267 disk = new_scsi_disk_type(fd, disk_name, label); 1268 if (disk == NULL) 1269 goto err; 1270 } 1271 } 1272 1273 return (disk); 1274 1275 err: 1276 if (option_msg && diag_msg) { 1277 err_print( 1278 "Configuration via generic SCSI-2 information failed\n"); 1279 } 1280 return (NULL); 1281 } 1282 1283 1284 /*ARGSUSED*/ 1285 static int 1286 use_existing_disk_type( 1287 int fd, 1288 int can_prompt, 1289 struct dk_label *label, 1290 struct scsi_inquiry *inquiry, 1291 struct disk_type *disk_type, 1292 struct scsi_capacity_16 *capacity) 1293 { 1294 struct scsi_capacity_16 new_capacity; 1295 int pcyl; 1296 int acyl; 1297 int nhead; 1298 int nsect; 1299 int rpm; 1300 1301 /* 1302 * If the device's block size is not 512, we have to 1303 * change block size, reformat, and then sense the 1304 * geometry. To do this, we must be able to prompt 1305 * the user. 1306 */ 1307 if (capacity->sc_lbasize != DEV_BSIZE) { 1308 if (!can_prompt) { 1309 return (0); 1310 } 1311 if (force_blocksize(fd)) { 1312 goto err; 1313 } 1314 1315 /* 1316 * Get the capacity again, since this has changed 1317 */ 1318 if (uscsi_read_capacity(fd, &new_capacity)) { 1319 goto err; 1320 } 1321 1322 if (option_msg && diag_msg) { 1323 err_print("blocks: %llu (0x%llx)\n", 1324 new_capacity.sc_capacity, 1325 new_capacity.sc_capacity); 1326 err_print("blksize: %u\n", new_capacity.sc_lbasize); 1327 } 1328 1329 capacity = &new_capacity; 1330 if (capacity->sc_lbasize != DEV_BSIZE) { 1331 goto err; 1332 } 1333 } 1334 1335 /* 1336 * Construct a new label out of the format.dat 1337 */ 1338 pcyl = disk_type->dtype_pcyl; 1339 acyl = disk_type->dtype_acyl; 1340 ncyl = disk_type->dtype_ncyl; 1341 nhead = disk_type->dtype_nhead; 1342 nsect = disk_type->dtype_nsect; 1343 rpm = disk_type->dtype_rpm; 1344 1345 if (option_msg && diag_msg) { 1346 err_print("Format.dat geometry:\n"); 1347 err_print(" pcyl: %d\n", pcyl); 1348 err_print(" heads: %d\n", nhead); 1349 err_print(" nsects: %d\n", nsect); 1350 err_print(" acyl: %d\n", acyl); 1351 err_print(" rpm: %d\n", rpm); 1352 } 1353 1354 (void) memset((char *)label, 0, sizeof (struct dk_label)); 1355 1356 label->dkl_magic = DKL_MAGIC; 1357 1358 (void) snprintf(label->dkl_asciilabel, sizeof (label->dkl_asciilabel), 1359 "%s cyl %d alt %d hd %d sec %d", 1360 disk_type->dtype_asciilabel, 1361 ncyl, acyl, nhead, nsect); 1362 1363 label->dkl_pcyl = pcyl; 1364 label->dkl_ncyl = ncyl; 1365 label->dkl_acyl = acyl; 1366 label->dkl_nhead = nhead; 1367 label->dkl_nsect = nsect; 1368 label->dkl_apc = 0; 1369 label->dkl_intrlv = 1; 1370 label->dkl_rpm = rpm; 1371 1372 if (!build_default_partition(label, DKC_SCSI_CCS)) { 1373 goto err; 1374 } 1375 1376 (void) checksum(label, CK_MAKESUM); 1377 return (1); 1378 1379 err: 1380 if (option_msg && diag_msg) { 1381 err_print( 1382 "Configuration via format.dat geometry failed\n"); 1383 } 1384 return (0); 1385 } 1386 1387 int 1388 build_default_partition( 1389 struct dk_label *label, 1390 int ctrl_type) 1391 { 1392 int i; 1393 int ncyls[NDKMAP]; 1394 int nblks; 1395 int cyl; 1396 struct dk_vtoc *vtoc; 1397 struct part_table *pt; 1398 struct default_partitions *dpt; 1399 long capacity; 1400 int freecyls; 1401 int blks_per_cyl; 1402 int ncyl; 1403 1404 #ifdef lint 1405 ctrl_type = ctrl_type; 1406 #endif 1407 1408 /* 1409 * Install a default vtoc 1410 */ 1411 vtoc = &label->dkl_vtoc; 1412 vtoc->v_version = V_VERSION; 1413 vtoc->v_nparts = NDKMAP; 1414 vtoc->v_sanity = VTOC_SANE; 1415 1416 for (i = 0; i < NDKMAP; i++) { 1417 vtoc->v_part[i].p_tag = default_vtoc_map[i].p_tag; 1418 vtoc->v_part[i].p_flag = default_vtoc_map[i].p_flag; 1419 } 1420 1421 /* 1422 * Find a partition that matches this disk. Capacity 1423 * is in integral number of megabytes. 1424 */ 1425 capacity = (long)(label->dkl_ncyl * label->dkl_nhead * 1426 label->dkl_nsect) / (long)((1024 * 1024) / DEV_BSIZE); 1427 dpt = default_partitions; 1428 for (i = 0; i < DEFAULT_PARTITION_TABLE_SIZE; i++, dpt++) { 1429 if (capacity >= dpt->min_capacity && 1430 capacity < dpt->max_capacity) { 1431 break; 1432 } 1433 } 1434 if (i == DEFAULT_PARTITION_TABLE_SIZE) { 1435 if (option_msg && diag_msg) { 1436 err_print("No matching default partition (%ld)\n", 1437 capacity); 1438 } 1439 return (0); 1440 } 1441 pt = dpt->part_table; 1442 1443 /* 1444 * Go through default partition table, finding fixed 1445 * sized entries. 1446 */ 1447 freecyls = label->dkl_ncyl; 1448 blks_per_cyl = label->dkl_nhead * label->dkl_nsect; 1449 for (i = 0; i < NDKMAP; i++) { 1450 if (pt->partitions[i] == HOG || pt->partitions[i] == 0) { 1451 ncyls[i] = 0; 1452 } else { 1453 /* 1454 * Calculate number of cylinders necessary 1455 * for specified size, rounding up to 1456 * the next greatest integral number of 1457 * cylinders. Always give what they 1458 * asked or more, never less. 1459 */ 1460 nblks = pt->partitions[i] * ((1024*1024)/DEV_BSIZE); 1461 nblks += (blks_per_cyl - 1); 1462 ncyls[i] = nblks / blks_per_cyl; 1463 freecyls -= ncyls[i]; 1464 } 1465 } 1466 1467 if (freecyls < 0) { 1468 if (option_msg && diag_msg) { 1469 for (i = 0; i < NDKMAP; i++) { 1470 if (ncyls[i] == 0) 1471 continue; 1472 err_print("Partition %d: %d cyls\n", 1473 i, ncyls[i]); 1474 } 1475 err_print("Free cylinders exhausted (%d)\n", 1476 freecyls); 1477 } 1478 return (0); 1479 } 1480 #if defined(i386) 1481 /* 1482 * Set the default boot partition to 1 cylinder 1483 */ 1484 ncyls[8] = 1; 1485 freecyls -= 1; 1486 1487 /* 1488 * If current disk type is not a SCSI disk, 1489 * set the default alternates partition to 2 cylinders 1490 */ 1491 if (ctrl_type != DKC_SCSI_CCS) { 1492 ncyls[9] = 2; 1493 freecyls -= 2; 1494 } 1495 #endif /* defined(i386) */ 1496 1497 /* 1498 * Set the free hog partition to whatever space remains. 1499 * It's an error to have more than one HOG partition, 1500 * but we don't verify that here. 1501 */ 1502 for (i = 0; i < NDKMAP; i++) { 1503 if (pt->partitions[i] == HOG) { 1504 assert(ncyls[i] == 0); 1505 ncyls[i] = freecyls; 1506 break; 1507 } 1508 } 1509 1510 /* 1511 * Error checking 1512 */ 1513 ncyl = 0; 1514 for (i = 0; i < NDKMAP; i++) { 1515 ncyl += ncyls[i]; 1516 } 1517 assert(ncyl == (label->dkl_ncyl)); 1518 1519 /* 1520 * Finally, install the partition in the label. 1521 */ 1522 cyl = 0; 1523 1524 #if defined(_SUNOS_VTOC_16) 1525 for (i = NDKMAP/2; i < NDKMAP; i++) { 1526 if (i == 2 || ncyls[i] == 0) 1527 continue; 1528 label->dkl_vtoc.v_part[i].p_start = cyl * blks_per_cyl; 1529 label->dkl_vtoc.v_part[i].p_size = ncyls[i] * blks_per_cyl; 1530 cyl += ncyls[i]; 1531 } 1532 for (i = 0; i < NDKMAP/2; i++) { 1533 1534 #elif defined(_SUNOS_VTOC_8) 1535 for (i = 0; i < NDKMAP; i++) { 1536 1537 #else 1538 #error No VTOC format defined. 1539 #endif /* defined(_SUNOS_VTOC_16) */ 1540 1541 if (i == 2 || ncyls[i] == 0) { 1542 #if defined(_SUNOS_VTOC_8) 1543 if (i != 2) { 1544 label->dkl_map[i].dkl_cylno = 0; 1545 label->dkl_map[i].dkl_nblk = 0; 1546 } 1547 #endif 1548 continue; 1549 } 1550 #if defined(_SUNOS_VTOC_8) 1551 label->dkl_map[i].dkl_cylno = cyl; 1552 label->dkl_map[i].dkl_nblk = ncyls[i] * blks_per_cyl; 1553 #elif defined(_SUNOS_VTOC_16) 1554 label->dkl_vtoc.v_part[i].p_start = cyl * blks_per_cyl; 1555 label->dkl_vtoc.v_part[i].p_size = ncyls[i] * blks_per_cyl; 1556 1557 #else 1558 #error No VTOC format defined. 1559 #endif /* defined(_SUNOS_VTOC_8) */ 1560 1561 cyl += ncyls[i]; 1562 } 1563 1564 /* 1565 * Set the whole disk partition 1566 */ 1567 #if defined(_SUNOS_VTOC_8) 1568 label->dkl_map[2].dkl_cylno = 0; 1569 label->dkl_map[2].dkl_nblk = 1570 label->dkl_ncyl * label->dkl_nhead * label->dkl_nsect; 1571 1572 #elif defined(_SUNOS_VTOC_16) 1573 label->dkl_vtoc.v_part[2].p_start = 0; 1574 label->dkl_vtoc.v_part[2].p_size = 1575 (label->dkl_ncyl + label->dkl_acyl) * label->dkl_nhead * 1576 label->dkl_nsect; 1577 #else 1578 #error No VTOC format defined. 1579 #endif /* defined(_SUNOS_VTOC_8) */ 1580 1581 1582 if (option_msg && diag_msg) { 1583 float scaled; 1584 err_print("\n"); 1585 for (i = 0; i < NDKMAP; i++) { 1586 #if defined(_SUNOS_VTOC_8) 1587 if (label->dkl_map[i].dkl_nblk == 0) 1588 1589 #elif defined(_SUNOS_VTOC_16) 1590 if (label->dkl_vtoc.v_part[i].p_size == 0) 1591 1592 #else 1593 #error No VTOC format defined. 1594 #endif /* defined(_SUNOS_VTOC_8) */ 1595 1596 continue; 1597 err_print("Partition %d: ", i); 1598 #if defined(_SUNOS_VTOC_8) 1599 scaled = bn2mb(label->dkl_map[i].dkl_nblk); 1600 1601 #elif defined(_SUNOS_VTOC_16) 1602 1603 scaled = bn2mb(label->dkl_vtoc.v_part[i].p_size); 1604 #else 1605 #error No VTOC format defined. 1606 #endif /* defined(_SUNOS_VTOC_8) */ 1607 1608 if (scaled > 1024.0) { 1609 err_print("%6.2fGB ", scaled/1024.0); 1610 } else { 1611 err_print("%6.2fMB ", scaled); 1612 } 1613 err_print(" %6d cylinders\n", 1614 #if defined(_SUNOS_VTOC_8) 1615 label->dkl_map[i].dkl_nblk/blks_per_cyl); 1616 1617 #elif defined(_SUNOS_VTOC_16) 1618 label->dkl_vtoc.v_part[i].p_size/blks_per_cyl); 1619 1620 #else 1621 #error No VTOC format defined. 1622 #endif /* defined(_SUNOS_VTOC_8) */ 1623 1624 } 1625 err_print("\n"); 1626 } 1627 1628 return (1); 1629 } 1630 1631 1632 1633 /* 1634 * Find an existing scsi disk definition by this name, 1635 * if possible. 1636 */ 1637 static struct disk_type * 1638 find_scsi_disk_type( 1639 char *disk_name, 1640 struct dk_label *label) 1641 { 1642 struct ctlr_type *ctlr; 1643 struct disk_type *dp; 1644 1645 ctlr = find_scsi_ctlr_type(); 1646 for (dp = ctlr->ctype_dlist; dp != NULL; dp = dp->dtype_next) { 1647 if (dp->dtype_asciilabel) { 1648 if ((strcmp(dp->dtype_asciilabel, disk_name) == 0) && 1649 dp->dtype_pcyl == label->dkl_pcyl && 1650 dp->dtype_ncyl == label->dkl_ncyl && 1651 dp->dtype_acyl == label->dkl_acyl && 1652 dp->dtype_nhead == label->dkl_nhead && 1653 dp->dtype_nsect == label->dkl_nsect) { 1654 return (dp); 1655 } 1656 } 1657 } 1658 1659 return ((struct disk_type *)NULL); 1660 } 1661 1662 1663 /* 1664 * Find an existing scsi disk definition by this name, 1665 * if possible. 1666 */ 1667 static struct disk_type * 1668 find_scsi_disk_by_name( 1669 char *disk_name) 1670 { 1671 struct ctlr_type *ctlr; 1672 struct disk_type *dp; 1673 1674 ctlr = find_scsi_ctlr_type(); 1675 for (dp = ctlr->ctype_dlist; dp != NULL; dp = dp->dtype_next) { 1676 if (dp->dtype_asciilabel) { 1677 if ((strcmp(dp->dtype_asciilabel, disk_name) == 0)) { 1678 return (dp); 1679 } 1680 } 1681 } 1682 1683 return ((struct disk_type *)NULL); 1684 } 1685 1686 1687 /* 1688 * Return a pointer to the ctlr_type structure for SCSI 1689 * disks. This list is built into the program, so there's 1690 * no chance of not being able to find it, unless someone 1691 * totally mangles the code. 1692 */ 1693 static struct ctlr_type * 1694 find_scsi_ctlr_type() 1695 { 1696 struct mctlr_list *mlp; 1697 1698 mlp = controlp; 1699 1700 while (mlp != NULL) { 1701 if (mlp->ctlr_type->ctype_ctype == DKC_SCSI_CCS) { 1702 return (mlp->ctlr_type); 1703 } 1704 mlp = mlp->next; 1705 } 1706 1707 impossible("no SCSI controller type"); 1708 1709 return ((struct ctlr_type *)NULL); 1710 } 1711 1712 1713 1714 /* 1715 * Return a pointer to the scsi ctlr_info structure. This 1716 * structure is allocated the first time format sees a 1717 * disk on this controller, so it must be present. 1718 */ 1719 static struct ctlr_info * 1720 find_scsi_ctlr_info( 1721 struct dk_cinfo *dkinfo) 1722 { 1723 struct ctlr_info *ctlr; 1724 1725 if (dkinfo->dki_ctype != DKC_SCSI_CCS) { 1726 return (NULL); 1727 } 1728 1729 for (ctlr = ctlr_list; ctlr != NULL; ctlr = ctlr->ctlr_next) { 1730 if (ctlr->ctlr_addr == dkinfo->dki_addr && 1731 ctlr->ctlr_space == dkinfo->dki_space && 1732 ctlr->ctlr_ctype->ctype_ctype == 1733 DKC_SCSI_CCS) { 1734 return (ctlr); 1735 } 1736 } 1737 1738 impossible("no SCSI controller info"); 1739 1740 return ((struct ctlr_info *)NULL); 1741 } 1742 1743 1744 1745 static struct disk_type * 1746 new_scsi_disk_type( 1747 int fd, 1748 char *disk_name, 1749 struct dk_label *label) 1750 { 1751 struct disk_type *dp; 1752 struct disk_type *disk; 1753 struct ctlr_info *ctlr; 1754 struct dk_cinfo dkinfo; 1755 struct partition_info *part; 1756 struct partition_info *pt; 1757 struct disk_info *disk_info; 1758 int i; 1759 1760 /* 1761 * Get the disk controller info for this disk 1762 */ 1763 if (ioctl(fd, DKIOCINFO, &dkinfo) == -1) { 1764 if (option_msg && diag_msg) { 1765 err_print("DKIOCINFO failed\n"); 1766 } 1767 return (NULL); 1768 } 1769 1770 /* 1771 * Find the ctlr_info for this disk. 1772 */ 1773 ctlr = find_scsi_ctlr_info(&dkinfo); 1774 1775 /* 1776 * Allocate a new disk type for the SCSI controller. 1777 */ 1778 disk = (struct disk_type *)zalloc(sizeof (struct disk_type)); 1779 1780 /* 1781 * Find the disk_info instance for this disk. 1782 */ 1783 disk_info = find_scsi_disk_info(&dkinfo); 1784 1785 /* 1786 * The controller and the disk should match. 1787 */ 1788 assert(disk_info->disk_ctlr == ctlr); 1789 1790 /* 1791 * Link the disk into the list of disks 1792 */ 1793 dp = ctlr->ctlr_ctype->ctype_dlist; 1794 if (dp == NULL) { 1795 ctlr->ctlr_ctype->ctype_dlist = dp; 1796 } else { 1797 while (dp->dtype_next != NULL) { 1798 dp = dp->dtype_next; 1799 } 1800 dp->dtype_next = disk; 1801 } 1802 disk->dtype_next = NULL; 1803 1804 /* 1805 * Allocate and initialize the disk name. 1806 */ 1807 disk->dtype_asciilabel = alloc_string(disk_name); 1808 1809 /* 1810 * Initialize disk geometry info 1811 */ 1812 disk->dtype_pcyl = label->dkl_pcyl; 1813 disk->dtype_ncyl = label->dkl_ncyl; 1814 disk->dtype_acyl = label->dkl_acyl; 1815 disk->dtype_nhead = label->dkl_nhead; 1816 disk->dtype_nsect = label->dkl_nsect; 1817 disk->dtype_rpm = label->dkl_rpm; 1818 1819 /* 1820 * Attempt to match the partition map in the label 1821 * with a know partition for this disk type. 1822 */ 1823 for (part = disk->dtype_plist; part; part = part->pinfo_next) { 1824 if (parts_match(label, part)) { 1825 break; 1826 } 1827 } 1828 1829 /* 1830 * If no match was made, we need to create a partition 1831 * map for this disk. 1832 */ 1833 if (part == NULL) { 1834 part = (struct partition_info *) 1835 zalloc(sizeof (struct partition_info)); 1836 pt = disk->dtype_plist; 1837 if (pt == NULL) { 1838 disk->dtype_plist = part; 1839 } else { 1840 while (pt->pinfo_next != NULL) { 1841 pt = pt->pinfo_next; 1842 } 1843 pt->pinfo_next = part; 1844 } 1845 part->pinfo_next = NULL; 1846 1847 /* 1848 * Set up the partition name 1849 */ 1850 part->pinfo_name = alloc_string("default"); 1851 1852 /* 1853 * Fill in the partition info from the label 1854 */ 1855 for (i = 0; i < NDKMAP; i++) { 1856 1857 #if defined(_SUNOS_VTOC_8) 1858 part->pinfo_map[i] = label->dkl_map[i]; 1859 1860 #elif defined(_SUNOS_VTOC_16) 1861 part->pinfo_map[i].dkl_cylno = 1862 label->dkl_vtoc.v_part[i].p_start / 1863 ((int)(disk->dtype_nhead * 1864 disk->dtype_nsect - apc)); 1865 part->pinfo_map[i].dkl_nblk = 1866 label->dkl_vtoc.v_part[i].p_size; 1867 #else 1868 #error No VTOC format defined. 1869 #endif /* defined(_SUNOS_VTOC_8) */ 1870 1871 } 1872 } 1873 1874 1875 /* 1876 * Use the VTOC if valid, or install a default 1877 */ 1878 if (label->dkl_vtoc.v_version == V_VERSION) { 1879 (void) memcpy(disk_info->v_volume, label->dkl_vtoc.v_volume, 1880 LEN_DKL_VVOL); 1881 part->vtoc = label->dkl_vtoc; 1882 } else { 1883 (void) memset(disk_info->v_volume, 0, LEN_DKL_VVOL); 1884 set_vtoc_defaults(part); 1885 } 1886 1887 /* 1888 * Link the disk to the partition map 1889 */ 1890 disk_info->disk_parts = part; 1891 1892 return (disk); 1893 } 1894 1895 1896 static struct disk_info * 1897 find_scsi_disk_info( 1898 struct dk_cinfo *dkinfo) 1899 { 1900 struct disk_info *disk; 1901 struct dk_cinfo *dp; 1902 1903 for (disk = disk_list; disk != NULL; disk = disk->disk_next) { 1904 assert(dkinfo->dki_ctype == DKC_SCSI_CCS); 1905 dp = &disk->disk_dkinfo; 1906 if (dp->dki_ctype == dkinfo->dki_ctype && 1907 dp->dki_cnum == dkinfo->dki_cnum && 1908 dp->dki_unit == dkinfo->dki_unit && 1909 strcmp(dp->dki_dname, dkinfo->dki_dname) == 0) { 1910 return (disk); 1911 } 1912 } 1913 1914 impossible("No SCSI disk info instance\n"); 1915 1916 return ((struct disk_info *)NULL); 1917 } 1918 1919 1920 static char * 1921 get_sun_disk_name( 1922 char *disk_name, 1923 struct scsi_inquiry *inquiry) 1924 { 1925 /* 1926 * Extract the sun name of the disk 1927 */ 1928 (void) memset(disk_name, 0, DISK_NAME_MAX); 1929 (void) memcpy(disk_name, (char *)&inquiry->inq_pid[9], 7); 1930 1931 return (disk_name); 1932 } 1933 1934 1935 static char * 1936 get_generic_disk_name( 1937 char *disk_name, 1938 struct scsi_inquiry *inquiry) 1939 { 1940 char *p; 1941 1942 (void) memset(disk_name, 0, DISK_NAME_MAX); 1943 p = strcopy(disk_name, inquiry->inq_vid, 1944 sizeof (inquiry->inq_vid)); 1945 *p++ = '-'; 1946 p = strcopy(p, inquiry->inq_pid, sizeof (inquiry->inq_pid)); 1947 *p++ = '-'; 1948 p = strcopy(p, inquiry->inq_revision, 1949 sizeof (inquiry->inq_revision)); 1950 1951 return (disk_name); 1952 } 1953 1954 1955 1956 static int 1957 force_blocksize( 1958 int fd) 1959 { 1960 union { 1961 struct mode_format page3; 1962 uchar_t buf3[MAX_MODE_SENSE_SIZE]; 1963 } u_page3; 1964 struct mode_format *page3 = &u_page3.page3; 1965 struct scsi_ms_header header; 1966 1967 if (check("\ 1968 Must reformat device to 512-byte blocksize. Continue") == 0) { 1969 1970 /* 1971 * Get current Page 3 - Format Parameters page 1972 */ 1973 if (uscsi_mode_sense(fd, DAD_MODE_FORMAT, 1974 MODE_SENSE_PC_CURRENT, (caddr_t)&u_page3, 1975 MAX_MODE_SENSE_SIZE, &header)) { 1976 goto err; 1977 } 1978 1979 /* 1980 * Make our changes to the geometry 1981 */ 1982 header.mode_header.length = 0; 1983 header.mode_header.device_specific = 0; 1984 page3->mode_page.ps = 0; 1985 page3->data_bytes_sect = DEV_BSIZE; 1986 1987 /* 1988 * make sure that logical block size is of 1989 * DEV_BSIZE. 1990 */ 1991 header.block_descriptor.blksize_hi = (DEV_BSIZE >> 16); 1992 header.block_descriptor.blksize_mid = (DEV_BSIZE >> 8); 1993 header.block_descriptor.blksize_lo = (char)(DEV_BSIZE); 1994 /* 1995 * Select current Page 3 - Format Parameters page 1996 */ 1997 if (uscsi_mode_select(fd, DAD_MODE_FORMAT, 1998 MODE_SELECT_PF, (caddr_t)&u_page3, 1999 MODESENSE_PAGE_LEN(&u_page3), &header)) { 2000 goto err; 2001 } 2002 2003 /* 2004 * Now reformat the device 2005 */ 2006 if (raw_format(fd)) { 2007 goto err; 2008 } 2009 return (0); 2010 } 2011 2012 err: 2013 if (option_msg && diag_msg) { 2014 err_print( 2015 "Reformat device to 512-byte blocksize failed\n"); 2016 } 2017 return (1); 2018 } 2019 2020 static int 2021 raw_format( 2022 int fd) 2023 { 2024 union scsi_cdb cdb; 2025 struct uscsi_cmd ucmd; 2026 struct scsi_defect_hdr defect_hdr; 2027 2028 (void) memset((char *)&ucmd, 0, sizeof (ucmd)); 2029 (void) memset((char *)&cdb, 0, sizeof (union scsi_cdb)); 2030 (void) memset((char *)&defect_hdr, 0, sizeof (defect_hdr)); 2031 cdb.scc_cmd = SCMD_FORMAT; 2032 ucmd.uscsi_cdb = (caddr_t)&cdb; 2033 ucmd.uscsi_cdblen = CDB_GROUP0; 2034 ucmd.uscsi_bufaddr = (caddr_t)&defect_hdr; 2035 ucmd.uscsi_buflen = sizeof (defect_hdr); 2036 cdb.cdb_opaque[1] = FPB_DATA; 2037 2038 /* 2039 * Issue the format ioctl 2040 */ 2041 fmt_print("Formatting...\n"); 2042 (void) fflush(stdout); 2043 if (uscsi_cmd(fd, &ucmd, 2044 (option_msg && diag_msg) ? F_NORMAL : F_SILENT)) { 2045 return (1); 2046 } 2047 return (0); 2048 } 2049 2050 /* 2051 * Copy a string of characters from src to dst, for at 2052 * most n bytes. Strip all leading and trailing spaces, 2053 * and stop if there are any non-printable characters. 2054 * Return ptr to the next character to be filled. 2055 */ 2056 static char * 2057 strcopy( 2058 char *dst, 2059 char *src, 2060 int n) 2061 { 2062 int i; 2063 2064 while (*src == ' ' && n > 0) { 2065 src++; 2066 n--; 2067 } 2068 2069 for (i = 0; n-- > 0 && isascii(*src) && isprint(*src); src++) { 2070 if (*src == ' ') { 2071 i++; 2072 } else { 2073 while (i-- > 0) 2074 *dst++ = ' '; 2075 *dst++ = *src; 2076 } 2077 } 2078 2079 *dst = 0; 2080 return (dst); 2081 } 2082 2083 /* 2084 * adjust disk geometry. 2085 * This is used when disk reports a disk geometry page having 2086 * no of physical cylinders is < 3 which is the minimum required 2087 * by Solaris (2 for storing labels and at least one as a data 2088 * cylinder ) 2089 */ 2090 int 2091 adjust_disk_geometry(int capacity, int *cyl, int *nhead, int *nsect) 2092 { 2093 int lcyl = *cyl; 2094 int lnhead = *nhead; 2095 int lnsect = *nsect; 2096 2097 assert(lcyl < SUN_MIN_CYL); 2098 2099 /* 2100 * reduce nsect by 2 for each iteration and re-calculate 2101 * the number of cylinders. 2102 */ 2103 while (lnsect > MINIMUM_NO_SECTORS && 2104 lcyl < MINIMUM_NO_CYLINDERS) { 2105 /* 2106 * make sure that we do not go below MINIMUM_NO_SECTORS. 2107 */ 2108 lnsect = max(MINIMUM_NO_SECTORS, lnsect / 2); 2109 lcyl = (capacity) / (lnhead * lnsect); 2110 } 2111 /* 2112 * If the geometry still does not satisfy 2113 * MINIMUM_NO_CYLINDERS then try to reduce the 2114 * no of heads. 2115 */ 2116 while (lnhead > MINIMUM_NO_HEADS && 2117 (lcyl < MINIMUM_NO_CYLINDERS)) { 2118 lnhead = max(MINIMUM_NO_HEADS, lnhead / 2); 2119 lcyl = (capacity) / (lnhead * lnsect); 2120 } 2121 /* 2122 * now we should have atleast SUN_MIN_CYL cylinders. 2123 * If we still do not get SUN_MIN_CYL with MINIMUM_NO_HEADS 2124 * and MINIMUM_NO_HEADS then return error. 2125 */ 2126 if (lcyl < SUN_MIN_CYL) 2127 return (1); 2128 else { 2129 *cyl = lcyl; 2130 *nhead = lnhead; 2131 *nsect = lnsect; 2132 return (0); 2133 } 2134 } 2135 2136 #if defined(_SUNOS_VTOC_8) 2137 /* 2138 * Reduce the size of one dimention below a specified 2139 * limit with a minimum loss of volume. Dimenstions are 2140 * assumed to be passed in form the largest value (the one 2141 * that needs to be reduced) to the smallest value. The 2142 * values will be twiddled until they are all less than or 2143 * equal to their limit. Returns the number in the new geometry. 2144 */ 2145 static int 2146 square_box( 2147 int capacity, 2148 int *dim1, int lim1, 2149 int *dim2, int lim2, 2150 int *dim3, int lim3) 2151 { 2152 int i; 2153 2154 /* 2155 * Although the routine should work with any ordering of 2156 * parameters, it's most efficient if they are passed in 2157 * in decreasing magnitude. 2158 */ 2159 assert(*dim1 >= *dim2); 2160 assert(*dim2 >= *dim3); 2161 2162 /* 2163 * This is done in a very arbitrary manner. We could try to 2164 * find better values but I can't come up with a method that 2165 * would run in a reasonable amount of time. That could take 2166 * approximately 65535 * 65535 iterations of a dozen flops each 2167 * or well over 4G flops. 2168 * 2169 * First: 2170 * 2171 * Let's see how far we can go with bitshifts w/o losing 2172 * any blocks. 2173 */ 2174 2175 for (i = 0; (((*dim1)>>i)&1) == 0 && ((*dim1)>>i) > lim1; i++); 2176 if (i) { 2177 *dim1 = ((*dim1)>>i); 2178 *dim3 = ((*dim3)<<i); 2179 } 2180 2181 if (((*dim1) > lim1) || ((*dim2) > lim2) || ((*dim3) > lim3)) { 2182 double d[4]; 2183 2184 /* 2185 * Second: 2186 * 2187 * Set the highest value at its limit then calculate errors, 2188 * adjusting the 2nd highest value (we get better resolution 2189 * that way). 2190 */ 2191 d[1] = lim1; 2192 d[3] = *dim3; 2193 d[2] = (double)capacity/(d[1]*d[3]); 2194 2195 /* 2196 * If we overflowed the middle term, set it to its limit and 2197 * chose a new low term. 2198 */ 2199 if (d[2] > lim2) { 2200 d[2] = lim2; 2201 d[3] = (double)capacity/(d[1]*d[2]); 2202 } 2203 /* 2204 * Convert to integers. 2205 */ 2206 *dim1 = (int)d[1]; 2207 *dim2 = (int)d[2]; 2208 *dim3 = (int)d[3]; 2209 } 2210 /* 2211 * Fixup any other possible problems. 2212 * If this happens, we need a new disklabel format. 2213 */ 2214 if (*dim1 > lim1) *dim1 = lim1; 2215 if (*dim2 > lim2) *dim2 = lim2; 2216 if (*dim3 > lim3) *dim3 = lim3; 2217 return (*dim1 * *dim2 * *dim3); 2218 } 2219 #endif /* defined(_SUNOS_VTOC_8) */ 2220