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