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