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