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