6645 sgsmsg relies on undefined behaviour of loop-scoped variables
[unleashed.git] / usr / src / cmd / format / auto_sense.c
blob5ea76569cab1feeae6ab5098a7247e9424d4a22d
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
22 * Copyright (c) 2011 Gary Mills
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.
30 * This file contains functions to implement automatic configuration
31 * of scsi disks.
33 #include "global.h"
35 #include <fcntl.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #include <strings.h>
39 #include <stdlib.h>
40 #include <ctype.h>
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"
55 #define DISK_NAME_MAX 256
57 extern int nctypes;
58 extern struct ctlr_type ctlr_types[];
62 * Marker for free hog partition
64 #define HOG (-1)
69 * Default partition tables
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
82 struct part_table {
83 int partitions[NDKMAP];
86 static struct part_table part_table_64mb = {
87 { 0, 0, 0, 0, 0, 0, HOG, 0}
90 static struct part_table part_table_180mb = {
91 { 16, 16, 0, 0, 0, 0, HOG, 0}
94 static struct part_table part_table_280mb = {
95 { 16, 32, 0, 0, 0, 0, HOG, 0}
98 static struct part_table part_table_380mb = {
99 { 24, 32, 0, 0, 0, 0, HOG, 0}
102 static struct part_table part_table_600mb = {
103 { 32, 32, 0, 0, 0, 0, HOG, 0}
106 static struct part_table part_table_1gb = {
107 { 32, 64, 0, 0, 0, 0, HOG, 0}
110 static struct part_table part_table_2gb = {
111 { 64, 128, 0, 0, 0, 0, HOG, 0}
114 static struct part_table part_table_infinity = {
115 { 128, 128, 0, 0, 0, 0, HOG, 0}
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 */
134 #define DEFAULT_PARTITION_TABLE_SIZE \
135 (sizeof (default_partitions) / sizeof (struct default_partitions))
138 * msgs for check()
140 #define FORMAT_MSG "Auto configuration via format.dat"
141 #define GENERIC_MSG "Auto configuration via generic SCSI-2"
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".
153 * assuming a minimum of 32 block cylinders.
155 #define MINIMUM_NO_HEADS 2
156 #define MINIMUM_NO_SECTORS 16
158 #define MINIMUM_NO_CYLINDERS 128
160 #if defined(_SUNOS_VTOC_8)
162 /* These are 16-bit fields */
163 #define MAXIMUM_NO_HEADS 65535
164 #define MAXIMUM_NO_SECTORS 65535
165 #define MAXIMUM_NO_CYLINDERS 65535
167 #endif /* defined(_SUNOS_VTOC_8) */
170 * minimum number of cylinders required by Solaris.
172 #define SUN_MIN_CYL 3
177 * ANSI prototypes for local static functions
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);
210 static struct disk_type *new_direct_disk_type(int fd, char *disk_name,
211 struct dk_label *label);
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);
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) */
245 * We need to get information necessary to construct a *new* efi
246 * label type
248 struct disk_type *
249 auto_efi_sense(int fd, struct efi_info *label)
252 struct dk_gpt *vtoc;
253 int i;
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;
261 if (ioctl(fd, DKIOCINFO, &dkinfo) == -1) {
262 if (option_msg && diag_msg) {
263 err_print("DKIOCINFO failed\n");
265 return (NULL);
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);
279 * get vendor, product, revision and capacity info.
281 if (get_disk_info(fd, label, disk_info) == -1) {
282 return ((struct disk_type *)NULL);
285 * Now build the default partition table
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);
292 label->e_parts = vtoc;
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.
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;
305 * S1-S6 are unassigned slices.
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;
314 * The reserved slice
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;
322 * Now stick all of it into the disk_type struct
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;
334 dp->dtype_next = disk;
336 disk->dtype_next = NULL;
338 disk->vendor = strdup(label->vendor);
339 disk->product = strdup(label->product);
340 disk->revision = strdup(label->revision);
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);
352 disk->capacity = label->capacity;
354 part = (struct partition_info *)
355 zalloc(sizeof (struct partition_info));
356 disk->dtype_plist = part;
358 part->pinfo_name = alloc_string("default");
359 part->pinfo_next = NULL;
360 part->etoc = vtoc;
362 bzero(disk_info->v_volume, LEN_DKL_VVOL);
363 disk_info->disk_parts = part;
364 return (disk);
367 static int
368 efi_ioctl(int fd, int cmd, dk_efi_t *dk_ioc)
370 void *data = dk_ioc->dki_data;
371 int error;
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;
377 return (error);
380 static struct ctlr_type *
381 find_direct_ctlr_type()
383 struct mctlr_list *mlp;
385 mlp = controlp;
387 while (mlp != NULL) {
388 if (mlp->ctlr_type->ctype_ctype == DKC_DIRECT) {
389 return (mlp->ctlr_type);
391 mlp = mlp->next;
394 impossible("no DIRECT controller type");
396 return ((struct ctlr_type *)NULL);
399 static struct ctlr_type *
400 find_vbd_ctlr_type()
402 struct mctlr_list *mlp;
404 mlp = controlp;
406 while (mlp != NULL) {
407 if (mlp->ctlr_type->ctype_ctype == DKC_VBD) {
408 return (mlp->ctlr_type);
410 mlp = mlp->next;
413 impossible("no VBD controller type");
415 return ((struct ctlr_type *)NULL);
418 static struct ctlr_info *
419 find_direct_ctlr_info(
420 struct dk_cinfo *dkinfo)
422 struct ctlr_info *ctlr;
424 if (dkinfo->dki_ctype != DKC_DIRECT)
425 return (NULL);
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);
435 impossible("no DIRECT controller info");
436 /*NOTREACHED*/
439 static struct ctlr_info *
440 find_vbd_ctlr_info(
441 struct dk_cinfo *dkinfo)
443 struct ctlr_info *ctlr;
445 if (dkinfo->dki_ctype != DKC_VBD)
446 return (NULL);
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);
456 impossible("no VBD controller info");
457 /*NOTREACHED*/
460 static struct disk_info *
461 find_direct_disk_info(
462 struct dk_cinfo *dkinfo)
464 struct disk_info *disk;
465 struct dk_cinfo *dp;
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);
478 impossible("No DIRECT disk info instance\n");
479 /*NOTREACHED*/
482 static struct disk_info *
483 find_vbd_disk_info(
484 struct dk_cinfo *dkinfo)
486 struct disk_info *disk;
487 struct dk_cinfo *dp;
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);
500 impossible("No VBD disk info instance\n");
501 /*NOTREACHED*/
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.
514 static int
515 auto_label_init(struct dk_label *label)
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;
531 if ((data = calloc(efisize, 1)) == NULL) {
532 err_print("auto_label_init: calloc failed\n");
533 goto auto_label_init_out;
536 dk_ioc.dki_data = data;
537 dk_ioc.dki_lba = 1;
538 dk_ioc.dki_length = efisize;
540 if (efi_ioctl(fd, DKIOCGETEFI, &dk_ioc) != 0) {
541 err_print("auto_label_init: GETEFI failed\n");
542 goto auto_label_init_out;
545 if ((databack = calloc(efisize, 1)) == NULL) {
546 err_print("auto_label_init calloc2 failed");
547 goto auto_label_init_out;
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;
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");
561 disk_info.dki_lbsize = DEV_BSIZE;
564 dk_ioc_back.dki_data = databack;
567 * back up efi label goes to capacity - 1, we are reading an extra block
568 * before the back up label.
570 dk_ioc_back.dki_lba = disk_info.dki_capacity - 1 - 1;
571 dk_ioc_back.dki_length = efisize;
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;
578 sig = dk_ioc.dki_data->efi_gpt_Signature;
579 dk_ioc.dki_data->efi_gpt_Signature = 0x0;
581 enter_critical();
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;
589 backsigp = (efi_gpt_t *)((uintptr_t)dk_ioc_back.dki_data + cur_blksz);
591 backsig = backsigp->efi_gpt_Signature;
593 backsigp->efi_gpt_Signature = 0;
595 if (efi_ioctl(fd, DKIOCSETEFI, &dk_ioc_back) == -1) {
596 err_print("auto_label_init: SETEFI backup failed\n");
599 if (ioctl(cur_file, DKIOCGGEOM, &disk_geom) != 0)
600 err_print("auto_label_init: GGEOM failed\n");
601 else
602 success = 1;
604 dk_ioc.dki_data->efi_gpt_Signature = sig;
605 backsigp->efi_gpt_Signature = backsig;
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;
612 if (efi_ioctl(cur_file, DKIOCSETEFI, &dk_ioc) == -1) {
613 err_print("auto_label_init: SETEFI revert failed\n");
614 success = 0;
617 exit_critical();
619 if (success == 0)
620 goto auto_label_init_out;
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;
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;
637 label->dkl_magic = DKL_MAGIC;
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);
643 rval = 0;
644 #if defined(_FIRMWARE_NEEDS_FDISK)
645 (void) auto_solaris_part(label);
646 ncyl = label->dkl_ncyl;
648 #endif /* defined(_FIRMWARE_NEEDS_FDISK) */
650 if (!build_default_partition(label, DKC_DIRECT)) {
651 rval = -1;
654 (void) checksum(label, CK_MAKESUM);
657 auto_label_init_out:
658 if (data)
659 free(data);
660 if (databack)
661 free(databack);
663 return (rval);
666 static struct disk_type *
667 new_direct_disk_type(
668 int fd,
669 char *disk_name,
670 struct dk_label *label)
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;
682 * Get the disk controller info for this disk
684 if (ioctl(fd, DKIOCINFO, &dkinfo) == -1) {
685 if (option_msg && diag_msg) {
686 err_print("DKIOCINFO failed\n");
688 return (NULL);
692 * Find the ctlr_info for this disk.
694 ctlr = find_direct_ctlr_info(&dkinfo);
697 * Allocate a new disk type for the direct controller.
699 disk = (struct disk_type *)zalloc(sizeof (struct disk_type));
702 * Find the disk_info instance for this disk.
704 disk_info = find_direct_disk_info(&dkinfo);
707 * The controller and the disk should match.
709 assert(disk_info->disk_ctlr == ctlr);
712 * Link the disk into the list of disks
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;
721 dp->dtype_next = disk;
723 disk->dtype_next = NULL;
726 * Allocate and initialize the disk name.
728 disk->dtype_asciilabel = alloc_string(disk_name);
731 * Initialize disk geometry info
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;
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;
749 pt->pinfo_next = part;
752 part->pinfo_next = NULL;
755 * Set up the partition name
757 part->pinfo_name = alloc_string("default");
760 * Fill in the partition info from the label
762 for (i = 0; i < NDKMAP; i++) {
764 #if defined(_SUNOS_VTOC_8)
765 part->pinfo_map[i] = label->dkl_map[i];
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) */
780 * Use the VTOC if valid, or install a default
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);
792 * Link the disk to the partition map
794 disk_info->disk_parts = part;
796 return (disk);
800 * Get a disk type that has label info. This is used to convert
801 * EFI label to SMI label
803 struct disk_type *
804 auto_direct_get_geom_label(int fd, struct dk_label *label)
806 struct disk_type *disk_type;
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);
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.
827 struct disk_type *
828 auto_sense(
829 int fd,
830 int can_prompt,
831 struct dk_label *label)
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;
844 * First, if expert mode, find out if the user
845 * wants to override any of the standard methods.
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;
860 * Get the Inquiry data. If this fails, there's
861 * no hope for this disk, so give up.
863 if (uscsi_inquiry(fd, (char *)&inquiry, sizeof (inquiry))) {
864 return ((struct disk_type *)NULL);
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");
873 * Get the Read Capacity
875 if (uscsi_read_capacity(fd, &capacity)) {
876 return ((struct disk_type *)NULL);
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.
887 if ((capacity.sc_capacity == 0) ||
888 (capacity.sc_capacity == UINT_MAX64)) {
889 if (option_msg && diag_msg) {
890 err_print("Invalid capacity\n");
892 return ((struct disk_type *)NULL);
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);
901 * Extract the disk name for the format.dat override
903 (void) get_sun_disk_name(disk_name, &inquiry);
904 if (option_msg && diag_msg) {
905 err_print("disk name: `%s`\n", disk_name);
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);
914 free(buf);
917 * Figure out which method we use for auto sense.
918 * If a particular method fails, we fall back to
919 * the next possibility.
922 if (force_generic) {
923 return (generic_disk_sense(fd, can_prompt, label,
924 &inquiry, &capacity, disk_name));
928 * Try for an existing format.dat first
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);
935 if (force_format_dat) {
936 return (NULL);
941 * Otherwise, try using generic SCSI-2 sense and inquiry.
944 return (generic_disk_sense(fd, can_prompt, label,
945 &inquiry, &capacity, disk_name));
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)
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;
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.
990 if (memcmp(disk_name, "SUN", strlen("SUN")) != 0) {
991 (void) get_generic_disk_name(disk_name, inquiry);
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.
999 tblocks = (capacity->sc_capacity + 1);
1000 if (tblocks > UINT32_MAX)
1001 nblocks = UINT32_MAX;
1002 else
1003 nblocks = tblocks;
1006 * Get current Page 3 - Format Parameters page
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;
1014 * Get current Page 4 - Drive Geometry page
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;
1021 if (setdefault != 1) {
1022 /* The inquiry of mode page 3 & page 4 are successful */
1024 * Correct for byte order if necessary
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);
1040 * Construct a new label out of the sense data,
1041 * Inquiry and Capacity.
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.
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;
1057 rpm = page4->rpm;
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.
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;
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.
1080 if ((setdefault == 1) || (capacity->sc_lbasize != DEV_BSIZE)) {
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.
1086 compute_chs_values(tblocks, nblocks, &pcyl, &nhead, &nsect);
1090 * The sd driver reserves 2 cylinders the backup disk label and
1091 * the deviceid. Set the number of data cylinders to pcyl-acyl.
1093 acyl = DK_ACYL;
1094 ncyl = pcyl - acyl;
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);
1104 #if defined(_SUNOS_VTOC_16)
1105 err_print(" bcyl: %u\n", bcyl);
1106 #endif /* defined(_SUNOS_VTOC_16) */
1108 err_print(" rpm: %d\n", rpm);
1109 err_print(" nblocks: %llu\n", nblocks);
1113 * Some drives do not support page4 or report 0 for page4->rpm,
1114 * adjust it to AVG_RPM, 3600.
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;
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.
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);
1154 #if defined(_SUNOS_VTOC_16)
1155 err_print(" bcyl: %u\n", bcyl);
1156 #endif
1158 err_print(" rpm: %d\n", rpm);
1159 err_print(" nblocks: %llu\n", nblocks);
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.
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);
1177 do {
1178 pcyl--;
1179 } while (((diskaddr_t)pcyl * nhead * nsect) > nblocks);
1181 if (can_prompt && expert_mode && !option_f) {
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).
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;
1196 * Ask the user for a choice here.
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;
1218 #if defined(_SUNOS_VTOC_8)
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.
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");
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];
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");
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;
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);
1305 while (can_prompt && expert_mode && !option_f) {
1306 int deflt = 1;
1309 * Allow user to modify this by hand if desired.
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);
1318 ioparam.io_charlist = confirm_list;
1319 if (input(FIO_MSTR, msg, '?', &ioparam,
1320 &deflt, DATA_INPUT) != 0)
1321 break;
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);
1345 #endif /* defined(_SUNOS_VTOC_8) */
1347 ncyl = pcyl - acyl;
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);
1359 (void) memset((char *)label, 0, sizeof (struct dk_label));
1361 label->dkl_magic = DKL_MAGIC;
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);
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;
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) */
1383 if (!build_default_partition(label, DKC_SCSI_CCS)) {
1384 goto err;
1387 (void) checksum(label, CK_MAKESUM);
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.
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);
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);
1416 if (disk == NULL) {
1417 disk = new_scsi_disk_type(fd, disk_name, label);
1418 if (disk == NULL)
1419 goto err;
1423 return (disk);
1425 err:
1426 if (option_msg && diag_msg) {
1427 err_print(
1428 "Configuration via generic SCSI-2 information failed\n");
1430 return (NULL);
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)
1444 int pcyl;
1445 int acyl;
1446 int nhead;
1447 int nsect;
1448 int rpm;
1451 * Construct a new label out of the format.dat
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;
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);
1469 (void) memset((char *)label, 0, sizeof (struct dk_label));
1471 label->dkl_magic = DKL_MAGIC;
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);
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;
1487 if (!build_default_partition(label, DKC_SCSI_CCS)) {
1488 goto err;
1491 (void) checksum(label, CK_MAKESUM);
1492 return (1);
1494 err:
1495 if (option_msg && diag_msg) {
1496 err_print(
1497 "Configuration via format.dat geometry failed\n");
1499 return (0);
1503 build_default_partition(
1504 struct dk_label *label,
1505 int ctrl_type)
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;
1519 #ifdef lint
1520 ctrl_type = ctrl_type;
1521 #endif
1524 * Install a default vtoc
1526 vtoc = &label->dkl_vtoc;
1527 vtoc->v_version = V_VERSION;
1528 vtoc->v_nparts = NDKMAP;
1529 vtoc->v_sanity = VTOC_SANE;
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;
1537 * Find a partition that matches this disk. Capacity
1538 * is in integral number of megabytes.
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;
1549 if (i == DEFAULT_PARTITION_TABLE_SIZE) {
1550 if (option_msg && diag_msg) {
1551 err_print("No matching default partition (%llu)\n",
1552 capacity);
1554 return (0);
1556 pt = dpt->part_table;
1559 * Go through default partition table, finding fixed
1560 * sized entries.
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 {
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.
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];
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]);
1590 err_print("Free cylinders exhausted (%d)\n",
1591 freecyls);
1593 return (0);
1595 #if defined(i386)
1597 * Set the default boot partition to 1 cylinder
1599 ncyls[8] = 1;
1600 freecyls -= 1;
1603 * If current disk type is not a SCSI disk,
1604 * set the default alternates partition to 2 cylinders
1606 if (ctrl_type != DKC_SCSI_CCS) {
1607 ncyls[9] = 2;
1608 freecyls -= 2;
1610 #endif /* defined(i386) */
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.
1617 for (i = 0; i < NDKMAP; i++) {
1618 if (pt->partitions[i] == HOG) {
1619 assert(ncyls[i] == 0);
1620 ncyls[i] = freecyls;
1621 break;
1626 * Error checking
1628 ncyl = 0;
1629 for (i = 0; i < NDKMAP; i++) {
1630 ncyl += ncyls[i];
1632 assert(ncyl == (label->dkl_ncyl));
1635 * Finally, install the partition in the label.
1637 cyl = 0;
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];
1647 for (i = 0; i < NDKMAP/2; i++) {
1649 #elif defined(_SUNOS_VTOC_8)
1650 for (i = 0; i < NDKMAP; i++) {
1652 #else
1653 #error No VTOC format defined.
1654 #endif /* defined(_SUNOS_VTOC_16) */
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;
1662 #endif
1663 continue;
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;
1672 #else
1673 #error No VTOC format defined.
1674 #endif /* defined(_SUNOS_VTOC_8) */
1676 cyl += ncyls[i];
1680 * Set the whole disk partition
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;
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) */
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)
1704 #elif defined(_SUNOS_VTOC_16)
1705 if (label->dkl_vtoc.v_part[i].p_size == 0)
1707 #else
1708 #error No VTOC format defined.
1709 #endif /* defined(_SUNOS_VTOC_8) */
1711 continue;
1712 err_print("Partition %d: ", i);
1713 #if defined(_SUNOS_VTOC_8)
1714 scaled = bn2mb(label->dkl_map[i].dkl_nblk);
1716 #elif defined(_SUNOS_VTOC_16)
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) */
1723 if (scaled > 1024.0) {
1724 err_print("%6.2fGB ", scaled/1024.0);
1725 } else {
1726 err_print("%6.2fMB ", scaled);
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) */
1739 err_print("\n");
1742 return (1);
1748 * Find an existing scsi disk definition by this name,
1749 * if possible.
1751 static struct disk_type *
1752 find_scsi_disk_type(
1753 char *disk_name,
1754 struct dk_label *label)
1756 struct ctlr_type *ctlr;
1757 struct disk_type *dp;
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);
1773 return ((struct disk_type *)NULL);
1778 * Find an existing scsi disk definition by this name,
1779 * if possible.
1781 static struct disk_type *
1782 find_scsi_disk_by_name(
1783 char *disk_name)
1785 struct ctlr_type *ctlr;
1786 struct disk_type *dp;
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);
1797 return ((struct disk_type *)NULL);
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.
1807 static struct ctlr_type *
1808 find_scsi_ctlr_type()
1810 struct mctlr_list *mlp;
1812 mlp = controlp;
1814 while (mlp != NULL) {
1815 if (mlp->ctlr_type->ctype_ctype == DKC_SCSI_CCS) {
1816 return (mlp->ctlr_type);
1818 mlp = mlp->next;
1821 impossible("no SCSI controller type");
1823 return ((struct ctlr_type *)NULL);
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.
1833 static struct ctlr_info *
1834 find_scsi_ctlr_info(
1835 struct dk_cinfo *dkinfo)
1837 struct ctlr_info *ctlr;
1839 if (dkinfo->dki_ctype != DKC_SCSI_CCS) {
1840 return (NULL);
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);
1851 impossible("no SCSI controller info");
1853 return ((struct ctlr_info *)NULL);
1858 static struct disk_type *
1859 new_scsi_disk_type(
1860 int fd,
1861 char *disk_name,
1862 struct dk_label *label)
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;
1874 * Get the disk controller info for this disk
1876 if (ioctl(fd, DKIOCINFO, &dkinfo) == -1) {
1877 if (option_msg && diag_msg) {
1878 err_print("DKIOCINFO failed\n");
1880 return (NULL);
1884 * Find the ctlr_info for this disk.
1886 ctlr = find_scsi_ctlr_info(&dkinfo);
1889 * Allocate a new disk type for the SCSI controller.
1891 disk = (struct disk_type *)zalloc(sizeof (struct disk_type));
1894 * Find the disk_info instance for this disk.
1896 disk_info = find_scsi_disk_info(&dkinfo);
1899 * The controller and the disk should match.
1901 assert(disk_info->disk_ctlr == ctlr);
1904 * Link the disk into the list of disks
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;
1913 dp->dtype_next = disk;
1915 disk->dtype_next = NULL;
1918 * Allocate and initialize the disk name.
1920 disk->dtype_asciilabel = alloc_string(disk_name);
1923 * Initialize disk geometry info
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;
1933 * Attempt to match the partition map in the label
1934 * with a know partition for this disk type.
1936 for (part = disk->dtype_plist; part; part = part->pinfo_next) {
1937 if (parts_match(label, part)) {
1938 break;
1943 * If no match was made, we need to create a partition
1944 * map for this disk.
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;
1956 pt->pinfo_next = part;
1958 part->pinfo_next = NULL;
1961 * Set up the partition name
1963 part->pinfo_name = alloc_string("default");
1966 * Fill in the partition info from the label
1968 for (i = 0; i < NDKMAP; i++) {
1970 #if defined(_SUNOS_VTOC_8)
1971 part->pinfo_map[i] = label->dkl_map[i];
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) */
1989 * Use the VTOC if valid, or install a default
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);
2001 * Link the disk to the partition map
2003 disk_info->disk_parts = part;
2005 return (disk);
2010 * Delete a disk type from disk type list.
2013 delete_disk_type(
2014 struct disk_type *disk_type)
2016 struct ctlr_type *ctlr;
2017 struct disk_type *dp, *disk;
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);
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);
2055 return (-1);
2060 static struct disk_info *
2061 find_scsi_disk_info(
2062 struct dk_cinfo *dkinfo)
2064 struct disk_info *disk;
2065 struct dk_cinfo *dp;
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);
2078 impossible("No SCSI disk info instance\n");
2080 return ((struct disk_info *)NULL);
2084 static char *
2085 get_sun_disk_name(
2086 char *disk_name,
2087 struct scsi_inquiry *inquiry)
2090 * Extract the sun name of the disk
2092 (void) memset(disk_name, 0, DISK_NAME_MAX);
2093 (void) memcpy(disk_name, (char *)&inquiry->inq_pid[9], 7);
2095 return (disk_name);
2099 char *
2100 get_generic_disk_name(
2101 char *disk_name,
2102 struct scsi_inquiry *inquiry)
2104 char *p;
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));
2115 return (disk_name);
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.
2124 static char *
2125 strcopy(
2126 char *dst,
2127 char *src,
2128 int n)
2130 int i;
2132 while (*src == ' ' && n > 0) {
2133 src++;
2134 n--;
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;
2147 *dst = 0;
2148 return (dst);
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 )
2159 adjust_disk_geometry(diskaddr_t capacity, uint_t *cyl, uint_t *nhead,
2160 uint_t *nsect)
2162 uint_t lcyl = *cyl;
2163 uint_t lnhead = *nhead;
2164 uint_t lnsect = *nsect;
2166 assert(lcyl < SUN_MIN_CYL);
2169 * reduce nsect by 2 for each iteration and re-calculate
2170 * the number of cylinders.
2172 while (lnsect > MINIMUM_NO_SECTORS &&
2173 lcyl < MINIMUM_NO_CYLINDERS) {
2175 * make sure that we do not go below MINIMUM_NO_SECTORS.
2177 lnsect = max(MINIMUM_NO_SECTORS, lnsect / 2);
2178 lcyl = (capacity) / (lnhead * lnsect);
2181 * If the geometry still does not satisfy
2182 * MINIMUM_NO_CYLINDERS then try to reduce the
2183 * no of heads.
2185 while (lnhead > MINIMUM_NO_HEADS &&
2186 lcyl < MINIMUM_NO_CYLINDERS) {
2187 lnhead = max(MINIMUM_NO_HEADS, lnhead / 2);
2188 lcyl = (capacity) / (lnhead * lnsect);
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.
2195 if (lcyl < SUN_MIN_CYL)
2196 return (1);
2197 else {
2198 *cyl = lcyl;
2199 *nhead = lnhead;
2200 *nsect = lnsect;
2201 return (0);
2205 #if defined(_SUNOS_VTOC_8)
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.
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)
2221 uint_t i;
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.
2228 assert(*dim1 >= *dim2);
2229 assert(*dim2 >= *dim3);
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.
2238 * First:
2240 * Let's see how far we can go with bitshifts w/o losing
2241 * any blocks.
2244 for (i = 0; (((*dim1)>>i)&1) == 0 && ((*dim1)>>i) > lim1; i++)
2246 if (i) {
2247 *dim1 = ((*dim1)>>i);
2248 *dim3 = ((*dim3)<<i);
2251 if (((*dim1) > lim1) || ((*dim2) > lim2) || ((*dim3) > lim3)) {
2252 double d[4];
2255 * Second:
2257 * Set the highest value at its limit then calculate errors,
2258 * adjusting the 2nd highest value (we get better resolution
2259 * that way).
2261 d[1] = lim1;
2262 d[3] = *dim3;
2263 d[2] = (double)capacity/(d[1]*d[3]);
2266 * If we overflowed the middle term, set it to its limit and
2267 * chose a new low term.
2269 if (d[2] > lim2) {
2270 d[2] = lim2;
2271 d[3] = (double)capacity/(d[1]*d[2]);
2274 * Convert to integers.
2276 *dim1 = (int)d[1];
2277 *dim2 = (int)d[2];
2278 *dim3 = (int)d[3];
2281 * Fixup any other possible problems.
2282 * If this happens, we need a new disklabel format.
2284 if (*dim1 > lim1) *dim1 = lim1;
2285 if (*dim2 > lim2) *dim2 = lim2;
2286 if (*dim3 > lim3) *dim3 = lim3;
2287 return (*dim1 * *dim2 * *dim3);
2289 #endif /* defined(_SUNOS_VTOC_8) */
2292 * Calculate CHS values based on the capacity data.
2294 * NOTE: This function is same as cmlb_convert_geomerty() function in
2295 * cmlb kernel module.
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)
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;
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.
2328 * The following table (in order) illustrates some end result
2329 * calculations:
2331 * Maximum number of blocks nhead nsect
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 * ...
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;
2352 /* make nsect be smallest multiple of 63 */
2353 *nsectp = ((total_capacity +
2354 (UINT16_MAX * 255 * 63) - 1) /
2355 (UINT16_MAX * 255 * 63)) * 63;
2357 if (*nsectp == 0)
2358 *nsectp = (UINT16_MAX / 63) * 63;
2361 if (usable_capacity < total_capacity)
2362 *pcylp = usable_capacity / ((*nheadp) * (*nsectp));
2363 else
2364 *pcylp = total_capacity / ((*nheadp) * (*nsectp));