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