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