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