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