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