xref: /illumos-gate/usr/src/cmd/format/label.c (revision d14d7d31f2a70b1e0a9c933607d6627f5718980e)
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 2007 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 /*
29  * This file contains the code relating to label manipulation.
30  */
31 
32 #include "global.h"
33 #include "label.h"
34 #include "misc.h"
35 #include "main.h"
36 #include "partition.h"
37 #include "ctlr_scsi.h"
38 #include <string.h>
39 #include <stdlib.h>
40 #include <memory.h>
41 #include <sys/isa_defs.h>
42 #include <sys/efi_partition.h>
43 #include <sys/vtoc.h>
44 #include <sys/uuid.h>
45 #include <errno.h>
46 #include <devid.h>
47 
48 #if defined(_FIRMWARE_NEEDS_FDISK)
49 #include <sys/dktp/fdisk.h>
50 #include "menu_fdisk.h"
51 #endif		/* defined(_FIRMWARE_NEEDS_FDISK) */
52 
53 #ifndef	WD_NODE
54 #define	WD_NODE		7
55 #endif
56 
57 #ifdef	__STDC__
58 /*
59  * Prototypes for ANSI C compilers
60  */
61 static int	do_geometry_sanity_check(void);
62 static int	vtoc_to_label(struct dk_label *label, struct vtoc *vtoc,
63 		struct dk_geom *geom, struct dk_cinfo *cinfo);
64 extern int	read_vtoc(int, struct vtoc *);
65 extern int	write_vtoc(int, struct vtoc *);
66 static int	vtoc64_to_label(struct efi_info *, struct dk_gpt *);
67 
68 #else	/* __STDC__ */
69 
70 /*
71  * Prototypes for non-ANSI C compilers
72  */
73 static int	do_geometry_sanity_check();
74 static int	vtoc_to_label();
75 extern int	read_vtoc();
76 extern int	write_vtoc();
77 static int	vtoc64_to_label();
78 
79 #endif	/* __STDC__ */
80 
81 /*
82  * This routine checks the given label to see if it is valid.
83  */
84 int
85 checklabel(label)
86 	register struct dk_label *label;
87 {
88 
89 	/*
90 	 * Check the magic number.
91 	 */
92 	if (label->dkl_magic != DKL_MAGIC)
93 		return (0);
94 	/*
95 	 * Check the checksum.
96 	 */
97 	if (checksum(label, CK_CHECKSUM) != 0)
98 		return (0);
99 	return (1);
100 }
101 
102 /*
103  * This routine checks or calculates the label checksum, depending on
104  * the mode it is called in.
105  */
106 int
107 checksum(label, mode)
108 	struct	dk_label *label;
109 	int	mode;
110 {
111 	register short *sp, sum = 0;
112 	register short count = (sizeof (struct dk_label)) / (sizeof (short));
113 
114 	/*
115 	 * If we are generating a checksum, don't include the checksum
116 	 * in the rolling xor.
117 	 */
118 	if (mode == CK_MAKESUM)
119 		count -= 1;
120 	sp = (short *)label;
121 	/*
122 	 * Take the xor of all the half-words in the label.
123 	 */
124 	while (count--) {
125 		sum ^= *sp++;
126 	}
127 	/*
128 	 * If we are checking the checksum, the total will be zero for
129 	 * a correct checksum, so we can just return the sum.
130 	 */
131 	if (mode == CK_CHECKSUM)
132 		return (sum);
133 	/*
134 	 * If we are generating the checksum, fill it in.
135 	 */
136 	else {
137 		label->dkl_cksum = sum;
138 		return (0);
139 	}
140 }
141 
142 /*
143  * This routine is used to extract the id string from the string stored
144  * in a disk label.  The problem is that the string in the label has
145  * the physical characteristics of the drive appended to it.  The approach
146  * is to find the beginning of the physical attributes portion of the string
147  * and truncate it there.
148  */
149 int
150 trim_id(id)
151 	char	*id;
152 {
153 	register char *c;
154 
155 	/*
156 	 * Start at the end of the string.  When we match the word ' cyl',
157 	 * we are at the beginning of the attributes.
158 	 */
159 	for (c = id + strlen(id); c >= id; c--) {
160 		if (strncmp(c, " cyl", strlen(" cyl")) == 0) {
161 			/*
162 			 * Remove any white space.
163 			 */
164 			for (; (((*(c - 1) == ' ') || (*(c - 1) == '\t')) &&
165 				(c >= id)); c--);
166 			break;
167 		}
168 	}
169 	/*
170 	 * If we ran off the beginning of the string, something is wrong.
171 	 */
172 	if (c < id)
173 		return (-1);
174 	/*
175 	 * Truncate the string.
176 	 */
177 	*c = '\0';
178 	return (0);
179 }
180 
181 /*
182  * This routine is used by write_label() to do a quick sanity check on the
183  * supplied geometry. This is not a thorough check.
184  *
185  * The SCSI READ_CAPACITY command is used here to get the capacity of the
186  * disk. But, the available area to store data on a disk is usually less
187  * than this. So, if the specified geometry evaluates to a value which falls
188  * in this margin, then such illegal geometries can slip through the cracks.
189  */
190 static int
191 do_geometry_sanity_check()
192 {
193 	struct scsi_capacity_16	 capacity;
194 
195 	if (uscsi_read_capacity(cur_file, &capacity)) {
196 		err_print("Warning: Unable to get capacity."
197 		    " Cannot check geometry\n");
198 		return (0);	/* Just ignore this problem */
199 	}
200 
201 	if (capacity.sc_capacity < ncyl * nhead * nsect) {
202 		err_print("\nWarning: Current geometry overshoots "
203 		    "actual geometry of disk\n\n");
204 		if (check("Continue labelling disk") != 0)
205 			return (-1);
206 		return (0);	/* Just ignore this problem */
207 	}
208 
209 	return (0);
210 }
211 
212 /*
213  * create a clear EFI partition table when format is used
214  * to convert a SMI label to an EFI lable
215  */
216 int
217 SMI_vtoc_to_EFI(int fd, struct dk_gpt **new_vtoc)
218 {
219 	int i;
220 	struct dk_gpt	*efi;
221 
222 	if (efi_alloc_and_init(fd, EFI_NUMPAR, new_vtoc) != 0) {
223 		err_print("SMI vtoc to EFI failed\n");
224 		return (-1);
225 	}
226 	efi = *new_vtoc;
227 
228 	/*
229 	 * create a clear EFI partition table:
230 	 * s0 takes the whole disk except the primary EFI lable,
231 	 * backup EFI labels, and the reserved partition.
232 	 * s1-s6 are unassigned slices.
233 	 */
234 	efi->efi_parts[0].p_tag = V_USR;
235 	efi->efi_parts[0].p_start = efi->efi_first_u_lba;
236 	efi->efi_parts[0].p_size = efi->efi_last_u_lba - efi->efi_first_u_lba
237 	    - EFI_MIN_RESV_SIZE + 1;
238 
239 	/*
240 	 * s1-s6 are unassigned slices
241 	 */
242 	for (i = 1; i < efi->efi_nparts - 2; i++) {
243 		efi->efi_parts[i].p_tag = V_UNASSIGNED;
244 		efi->efi_parts[i].p_start = 0;
245 		efi->efi_parts[i].p_size = 0;
246 	}
247 
248 	/*
249 	 * the reserved slice
250 	 */
251 	efi->efi_parts[efi->efi_nparts - 1].p_tag = V_RESERVED;
252 	efi->efi_parts[efi->efi_nparts - 1].p_start =
253 	    efi->efi_last_u_lba - EFI_MIN_RESV_SIZE + 1;
254 	efi->efi_parts[efi->efi_nparts - 1].p_size = EFI_MIN_RESV_SIZE;
255 
256 	return (0);
257 }
258 
259 /*
260  * This routine constructs and writes a label on the disk.  It writes both
261  * the primary and backup labels.  It assumes that there is a current
262  * partition map already defined.  It also notifies the SunOS kernel of
263  * the label and partition information it has written on the disk.
264  */
265 int
266 write_label()
267 {
268 	int	error = 0, head, sec;
269 	struct dk_label label;
270 	struct dk_label new_label;
271 	struct vtoc	vtoc;
272 	struct dk_geom	geom;
273 	struct dk_gpt	*vtoc64;
274 	int		nbackups;
275 
276 #if defined(_SUNOS_VTOC_8)
277 	int i;
278 #endif		/* defined(_SUNOS_VTOC_8) */
279 
280 	/*
281 	 * If EFI label, then write it out to disk
282 	 */
283 	if (cur_label == L_TYPE_EFI) {
284 		enter_critical();
285 		vtoc64 = cur_parts->etoc;
286 		err_check(vtoc64);
287 		if (efi_write(cur_file, vtoc64) != 0) {
288 			err_print("Warning: error writing EFI.\n");
289 			error = -1;
290 			}
291 
292 		cur_disk->disk_flags |= DSK_LABEL;
293 		exit_critical();
294 		return (error);
295 	}
296 
297 	/*
298 	 * Fill in a label structure with the geometry information.
299 	 */
300 	(void) memset((char *)&label, 0, sizeof (struct dk_label));
301 	(void) memset((char *)&new_label, 0, sizeof (struct dk_label));
302 	label.dkl_pcyl = pcyl;
303 	label.dkl_ncyl = ncyl;
304 	label.dkl_acyl = acyl;
305 
306 #if defined(_SUNOS_VTOC_16)
307 	label.dkl_bcyl = bcyl;
308 #endif			/* defined(_SUNOC_VTOC_16) */
309 
310 	label.dkl_nhead = nhead;
311 	label.dkl_nsect = nsect;
312 	label.dkl_apc = apc;
313 	label.dkl_intrlv = 1;
314 	label.dkl_rpm = cur_dtype->dtype_rpm;
315 
316 #if defined(_SUNOS_VTOC_8)
317 	/*
318 	 * Also fill in the current partition information.
319 	 */
320 	for (i = 0; i < NDKMAP; i++) {
321 		label.dkl_map[i] = cur_parts->pinfo_map[i];
322 	}
323 #endif			/* defined(_SUNOS_VTOC_8) */
324 
325 	label.dkl_magic = DKL_MAGIC;
326 
327 	/*
328 	 * Fill in the vtoc information
329 	 */
330 	label.dkl_vtoc = cur_parts->vtoc;
331 
332 	/*
333 	 * Use the current label
334 	 */
335 	bcopy(cur_disk->v_volume, label.dkl_vtoc.v_volume, LEN_DKL_VVOL);
336 
337 	/*
338 	 * Put asciilabel in; on x86 it's in the vtoc, not the label.
339 	 */
340 	(void) snprintf(label.dkl_asciilabel, sizeof (label.dkl_asciilabel),
341 	    "%s cyl %d alt %d hd %d sec %d",
342 	    cur_dtype->dtype_asciilabel, ncyl, acyl, nhead, nsect);
343 
344 #if defined(_SUNOS_VTOC_16)
345 	/*
346 	 * Also add in v_sectorsz, as the driver will.  Everyone
347 	 * else is assuming DEV_BSIZE, so we do the same.
348 	 */
349 	label.dkl_vtoc.v_sectorsz = DEV_BSIZE;
350 #endif			/* defined(_SUNOS_VTOC_16) */
351 
352 	/*
353 	 * Generate the correct checksum.
354 	 */
355 	(void) checksum(&label, CK_MAKESUM);
356 	/*
357 	 * Convert the label into a vtoc
358 	 */
359 	if (label_to_vtoc(&vtoc, &label) == -1) {
360 		return (-1);
361 	}
362 	/*
363 	 * Fill in the geometry info.  This is critical that
364 	 * we do this before writing the vtoc.
365 	 */
366 	bzero((caddr_t)&geom, sizeof (struct dk_geom));
367 	geom.dkg_ncyl = ncyl;
368 	geom.dkg_acyl = acyl;
369 
370 #if defined(_SUNOS_VTOC_16)
371 	geom.dkg_bcyl = bcyl;
372 #endif			/* defined(_SUNOS_VTOC_16) */
373 
374 	geom.dkg_nhead = nhead;
375 	geom.dkg_nsect = nsect;
376 	geom.dkg_intrlv = 1;
377 	geom.dkg_apc = apc;
378 	geom.dkg_rpm = cur_dtype->dtype_rpm;
379 	geom.dkg_pcyl = pcyl;
380 
381 	/*
382 	 * Make a quick check to see that the geometry is being
383 	 * written now is not way off from the actual capacity
384 	 * of the disk. This is only an appoximate check and
385 	 * is only for SCSI disks.
386 	 */
387 	if (SCSI && do_geometry_sanity_check() != 0) {
388 		return (-1);
389 	}
390 
391 	/*
392 	 * Lock out interrupts so we do things in sync.
393 	 */
394 	enter_critical();
395 	/*
396 	 * Do the ioctl to tell the kernel the geometry.
397 	 */
398 	if (ioctl(cur_file, DKIOCSGEOM, &geom) == -1) {
399 		err_print("Warning: error setting drive geometry.\n");
400 		error = -1;
401 	}
402 	/*
403 	 * Write the vtoc.  At the time of this writing, our
404 	 * drivers convert the vtoc back to a label, and
405 	 * then write both the primary and backup labels.
406 	 * This is not a requirement, however, as we
407 	 * always use an ioctl to read the vtoc from the
408 	 * driver, so it can do as it likes.
409 	 */
410 	if (write_vtoc(cur_file, &vtoc) != 0) {
411 		err_print("Warning: error writing VTOC.\n");
412 		error = -1;
413 	}
414 
415 	/*
416 	 * Calculate where the backup labels went.  They are always on
417 	 * the last alternate cylinder, but some older drives put them
418 	 * on head 2 instead of the last head.  They are always on the
419 	 * first 5 odd sectors of the appropriate track.
420 	 */
421 	if (cur_ctype->ctype_flags & CF_BLABEL)
422 		head  = 2;
423 	else
424 		head = nhead - 1;
425 	/*
426 	 * Read and verify the backup labels.
427 	 */
428 	nbackups = 0;
429 	for (sec = 1; ((sec < BAD_LISTCNT * 2 + 1) && (sec < nsect));
430 	    sec += 2) {
431 		if ((*cur_ops->op_rdwr)(DIR_READ, cur_file, (diskaddr_t)
432 		    ((chs2bn(ncyl + acyl - 1, head, sec)) + solaris_offset),
433 		    1, (caddr_t)&new_label, F_NORMAL, NULL)) {
434 			err_print("Warning: error reading backup label.\n");
435 			error = -1;
436 		} else {
437 			if (bcmp((char *)&label, (char *)&new_label,
438 			    sizeof (struct dk_label)) == 0) {
439 					nbackups++;
440 			}
441 		}
442 	}
443 	if (nbackups != BAD_LISTCNT) {
444 		err_print("Warning: %s\n", nbackups == 0 ?
445 		    "no backup labels" : "some backup labels incorrect");
446 	}
447 	/*
448 	 * Mark the current disk as labelled and notify the kernel of what
449 	 * has happened.
450 	 */
451 	cur_disk->disk_flags |= DSK_LABEL;
452 
453 	exit_critical();
454 	return (error);
455 }
456 
457 
458 /*
459  * Read the label from the disk.
460  * Do this via the read_vtoc() library routine, then convert it to a label.
461  * We also need a DKIOCGGEOM ioctl to get the disk's geometry.
462  */
463 int
464 read_label(int fd, struct dk_label *label)
465 {
466 	struct vtoc	vtoc;
467 	struct dk_geom	geom;
468 	struct dk_cinfo	dkinfo;
469 
470 	if (read_vtoc(fd, &vtoc) < 0		||
471 	    ioctl(fd, DKIOCGGEOM, &geom) == -1	||
472 	    ioctl(fd, DKIOCINFO, &dkinfo) == -1) {
473 		return (-1);
474 	}
475 
476 	return (vtoc_to_label(label, &vtoc, &geom, &dkinfo));
477 }
478 
479 int
480 get_disk_info_from_devid(int fd, struct efi_info *label)
481 {
482 	ddi_devid_t	devid;
483 	char		*s;
484 	int		n;
485 	char		*vid, *pid;
486 	int		nvid, npid;
487 	struct dk_minfo	minf;
488 	struct dk_cinfo	dkinfo;
489 
490 	if (devid_get(fd, &devid)) {
491 		if (option_msg && diag_msg)
492 			err_print("devid_get failed\n");
493 		return (-1);
494 	}
495 
496 	n = devid_sizeof(devid);
497 	s = (char *)devid;
498 
499 	if (ioctl(fd, DKIOCINFO, &dkinfo) == -1) {
500 		if (option_msg && diag_msg)
501 			err_print("DKIOCINFO failed\n");
502 		return (-1);
503 	}
504 
505 	if (dkinfo.dki_ctype != DKC_DIRECT)
506 		return (-1);
507 
508 	vid = s+12;
509 	if (!(pid = strchr(vid, '=')))
510 		return (-1);
511 	nvid = pid - vid;
512 	pid += 1;
513 	npid = n - nvid - 13;
514 
515 	if (nvid > 9)
516 		nvid = 9;
517 	if (npid > 17) {
518 		pid = pid + npid - 17;
519 		npid = 17;
520 	}
521 
522 	if (ioctl(fd, DKIOCGMEDIAINFO, &minf) == -1) {
523 		devid_free(devid);
524 		return (-1);
525 	}
526 
527 	(void) strlcpy(label->vendor, vid, nvid);
528 	(void) strlcpy(label->product, pid, npid);
529 	(void) strlcpy(label->revision, "0001", 5);
530 	label->capacity = minf.dki_capacity * minf.dki_lbsize / 512;
531 
532 	devid_free(devid);
533 	return (0);
534 }
535 
536 /*
537  * Issue uscsi_inquiry and read_capacity commands to
538  * retrieve the disk's Vendor, Product, Revision and
539  * Capacity information.
540  */
541 int
542 get_disk_info(int fd, struct efi_info *label)
543 {
544 	struct scsi_inquiry	inquiry;
545 	struct scsi_capacity_16	capacity;
546 	struct dk_minfo		minf;
547 
548 	if (!get_disk_info_from_devid(fd, label))
549 		return (0);
550 
551 	if (uscsi_inquiry(fd, (char *)&inquiry, sizeof (inquiry))) {
552 		(void) strlcpy(label->vendor, "Unknown", 8);
553 		(void) strlcpy(label->product, "Unknown", 8);
554 		(void) strlcpy(label->revision, "0001", 5);
555 	} else {
556 		(void) strlcpy(label->vendor, inquiry.inq_vid, 9);
557 		(void) strlcpy(label->product, inquiry.inq_pid, 17);
558 		(void) strlcpy(label->revision, inquiry.inq_revision, 5);
559 	}
560 
561 	if (uscsi_read_capacity(fd, &capacity)) {
562 		if (ioctl(fd, DKIOCGMEDIAINFO, &minf) == -1) {
563 			err_print("Fetch Capacity failed\n");
564 			return (-1);
565 		}
566 		label->capacity = minf.dki_capacity * minf.dki_lbsize / 512;
567 	} else {
568 		label->capacity = capacity.sc_capacity;
569 
570 		/* Since we are counting from zero, add 1 to capacity */
571 		label->capacity++;
572 	}
573 
574 	return (0);
575 }
576 
577 int
578 read_efi_label(int fd, struct efi_info *label)
579 {
580 	struct dk_gpt	*vtoc64;
581 
582 	/* This could fail if there is no label already */
583 	if (efi_alloc_and_read(fd, &vtoc64) < 0) {
584 		return (-1);
585 	}
586 	if (vtoc64_to_label(label, vtoc64) != 0) {
587 		err_print("vtoc64_to_label failed\n");
588 		return (-1);
589 	}
590 	efi_free(vtoc64);
591 	if (get_disk_info(fd, label) != 0) {
592 		return (-1);
593 	}
594 	return (0);
595 }
596 
597 
598 /*
599  * We've read a 64-bit label which has no geometry information.  Use
600  * some heuristics to fake up a geometry that would match the disk in
601  * order to make the rest of format(1M) happy.
602  */
603 static int
604 vtoc64_to_label(struct efi_info *label, struct dk_gpt *vtoc)
605 {
606 	int		i, nparts = 0;
607 	struct dk_gpt	*lmap;
608 
609 	(void) memset((char *)label, 0, sizeof (struct efi_info));
610 
611 	/* XXX do a sanity check here for nparts */
612 	nparts = vtoc->efi_nparts;
613 	lmap = (struct dk_gpt *) calloc(1, (sizeof (struct dk_part) *
614 	    nparts) + sizeof (struct dk_gpt));
615 	if (lmap == NULL) {
616 		err_print("vtoc64_to_label: unable to allocate lmap\n");
617 		fullabort();
618 	}
619 	label->e_parts = lmap;
620 
621 	/*
622 	 * Copy necessary portions
623 	 * XXX Maybe we can use memcpy() ??
624 	 */
625 	lmap->efi_version = vtoc->efi_version;
626 	lmap->efi_nparts = vtoc->efi_nparts;
627 	lmap->efi_part_size = vtoc->efi_part_size;
628 	lmap->efi_lbasize = vtoc->efi_lbasize;
629 	lmap->efi_last_lba = vtoc->efi_last_lba;
630 	lmap->efi_first_u_lba = vtoc->efi_first_u_lba;
631 	lmap->efi_last_u_lba = vtoc->efi_last_u_lba;
632 	lmap->efi_flags = vtoc->efi_flags;
633 	(void) memcpy((uchar_t *)&lmap->efi_disk_uguid,
634 	    (uchar_t *)&vtoc->efi_disk_uguid, sizeof (struct uuid));
635 
636 	for (i = 0; i < nparts; i++) {
637 		lmap->efi_parts[i].p_tag = vtoc->efi_parts[i].p_tag;
638 		lmap->efi_parts[i].p_flag = vtoc->efi_parts[i].p_flag;
639 		lmap->efi_parts[i].p_start = vtoc->efi_parts[i].p_start;
640 		lmap->efi_parts[i].p_size = vtoc->efi_parts[i].p_size;
641 		(void) memcpy((uchar_t *)&lmap->efi_parts[i].p_uguid,
642 		    (uchar_t *)&vtoc->efi_parts[i].p_uguid,
643 		    sizeof (struct uuid));
644 		if (vtoc->efi_parts[i].p_tag == V_RESERVED) {
645 			bcopy(vtoc->efi_parts[i].p_name,
646 			    lmap->efi_parts[i].p_name, LEN_DKL_VVOL);
647 		}
648 	}
649 	return (0);
650 }
651 
652 /*
653  * Convert vtoc/geom to label.
654  */
655 static int
656 vtoc_to_label(struct dk_label *label, struct vtoc *vtoc, struct dk_geom *geom,
657     struct dk_cinfo *cinfo)
658 {
659 #if defined(_SUNOS_VTOC_8)
660 	struct dk_map32		*lmap;
661 #elif defined(_SUNOS_VTOC_16)
662 	struct dkl_partition	*lmap;
663 #else
664 #error No VTOC format defined.
665 #endif			/* defined(_SUNOS_VTOC_8) */
666 
667 	struct partition	*vpart;
668 	long			nblks;
669 	int			i;
670 
671 	(void) memset((char *)label, 0, sizeof (struct dk_label));
672 
673 	/*
674 	 * Sanity-check the vtoc
675 	 */
676 	if (vtoc->v_sanity != VTOC_SANE || vtoc->v_sectorsz != DEV_BSIZE ||
677 	    vtoc->v_nparts != V_NUMPAR) {
678 		return (-1);
679 	}
680 
681 	/*
682 	 * Sanity check of geometry
683 	 */
684 	if (geom->dkg_ncyl == 0 || geom->dkg_nhead == 0 ||
685 	    geom->dkg_nsect == 0) {
686 		return (-1);
687 	}
688 
689 	label->dkl_magic = DKL_MAGIC;
690 
691 	/*
692 	 * Copy necessary portions of the geometry information
693 	 */
694 	label->dkl_rpm = geom->dkg_rpm;
695 	label->dkl_pcyl = geom->dkg_pcyl;
696 	label->dkl_apc = geom->dkg_apc;
697 	label->dkl_intrlv = geom->dkg_intrlv;
698 	label->dkl_ncyl = geom->dkg_ncyl;
699 	label->dkl_acyl = geom->dkg_acyl;
700 
701 #if defined(_SUNOS_VTOC_16)
702 	label->dkl_bcyl = geom->dkg_bcyl;
703 #endif			/* defined(_SUNOS_VTOC_16) */
704 
705 	label->dkl_nhead = geom->dkg_nhead;
706 	label->dkl_nsect = geom->dkg_nsect;
707 
708 #if defined(_SUNOS_VTOC_8)
709 	label->dkl_obs1 = geom->dkg_obs1;
710 	label->dkl_obs2 = geom->dkg_obs2;
711 	label->dkl_obs3 = geom->dkg_obs3;
712 #endif			/* defined(_SUNOS_VTOC_8) */
713 
714 	label->dkl_write_reinstruct = geom->dkg_write_reinstruct;
715 	label->dkl_read_reinstruct = geom->dkg_read_reinstruct;
716 
717 	/*
718 	 * Copy vtoc structure fields into the disk label dk_vtoc
719 	 */
720 	label->dkl_vtoc.v_sanity = vtoc->v_sanity;
721 	label->dkl_vtoc.v_nparts = vtoc->v_nparts;
722 	label->dkl_vtoc.v_version = vtoc->v_version;
723 
724 	(void) memcpy(label->dkl_vtoc.v_volume, vtoc->v_volume,
725 	    LEN_DKL_VVOL);
726 	for (i = 0; i < V_NUMPAR; i++) {
727 		label->dkl_vtoc.v_part[i].p_tag = vtoc->v_part[i].p_tag;
728 		label->dkl_vtoc.v_part[i].p_flag = vtoc->v_part[i].p_flag;
729 	}
730 	(void) memcpy((char *)label->dkl_vtoc.v_bootinfo,
731 	    (char *)vtoc->v_bootinfo, sizeof (vtoc->v_bootinfo));
732 	(void) memcpy((char *)label->dkl_vtoc.v_reserved,
733 	    (char *)vtoc->v_reserved, sizeof (vtoc->v_reserved));
734 	(void) memcpy((char *)label->dkl_vtoc.v_timestamp,
735 	    (char *)vtoc->timestamp, sizeof (vtoc->timestamp));
736 
737 	(void) memcpy(label->dkl_asciilabel, vtoc->v_asciilabel,
738 	    LEN_DKL_ASCII);
739 
740 	/*
741 	 * Note the conversion from starting sector number
742 	 * to starting cylinder number.
743 	 * Return error if division results in a remainder.
744 	 *
745 	 * Note: don't check, if probing virtual disk in Xen
746 	 * for that virtual disk will use fabricated # of headers
747 	 * and sectors per track which may cause the capacity
748 	 * not multiple of # of blocks per cylinder
749 	 */
750 #if defined(_SUNOS_VTOC_8)
751 	lmap = label->dkl_map;
752 
753 #elif defined(_SUNOS_VTOC_16)
754 	lmap = label->dkl_vtoc.v_part;
755 #else
756 #error No VTOC format defined.
757 #endif			/* defined(_SUNOS_VTOC_8) */
758 
759 	vpart = vtoc->v_part;
760 
761 	nblks = (int)label->dkl_nsect * (int)label->dkl_nhead;
762 
763 	for (i = 0; i < NDKMAP; i++, lmap++, vpart++) {
764 		if (cinfo->dki_ctype != DKC_VBD) {
765 			if ((vpart->p_start % nblks) != 0 ||
766 			    (vpart->p_size % nblks) != 0) {
767 				return (-1);
768 			}
769 		}
770 #if defined(_SUNOS_VTOC_8)
771 		lmap->dkl_cylno = vpart->p_start / nblks;
772 		lmap->dkl_nblk = vpart->p_size;
773 
774 #elif defined(_SUNOS_VTOC_16)
775 		lmap->p_start = vpart->p_start;
776 		lmap->p_size = vpart->p_size;
777 #else
778 #error No VTOC format defined.
779 #endif			/* defined(_SUNOS_VTOC_8) */
780 	}
781 
782 	/*
783 	 * Finally, make a checksum
784 	 */
785 	(void) checksum(label, CK_MAKESUM);
786 
787 	return (0);
788 }
789 
790 
791 
792 /*
793  * Extract a vtoc structure out of a valid label
794  */
795 int
796 label_to_vtoc(struct vtoc *vtoc, struct dk_label *label)
797 {
798 #if defined(_SUNOS_VTOC_8)
799 	struct dk_map2		*lpart;
800 	struct dk_map32		*lmap;
801 	long			nblks;
802 
803 #elif defined(_SUNOS_VTOC_16)
804 	struct dkl_partition	*lpart;
805 #else
806 #error No VTOC format defined.
807 #endif				/* defined(_SUNOS_VTOC_8) */
808 
809 	struct partition	*vpart;
810 	int			i;
811 
812 	(void) memset((char *)vtoc, 0, sizeof (struct vtoc));
813 
814 	switch (label->dkl_vtoc.v_version) {
815 	case 0:
816 		/*
817 		 * No valid vtoc information in the label.
818 		 * Construct default p_flags and p_tags.
819 		 */
820 		vpart = vtoc->v_part;
821 		for (i = 0; i < V_NUMPAR; i++, vpart++) {
822 			vpart->p_tag = default_vtoc_map[i].p_tag;
823 			vpart->p_flag = default_vtoc_map[i].p_flag;
824 		}
825 		break;
826 
827 	case V_VERSION:
828 		vpart = vtoc->v_part;
829 		lpart = label->dkl_vtoc.v_part;
830 		for (i = 0; i < V_NUMPAR; i++, vpart++, lpart++) {
831 			vpart->p_tag = lpart->p_tag;
832 			vpart->p_flag = lpart->p_flag;
833 
834 #if defined(_SUNOS_VTOC_16)
835 			vpart->p_start = lpart->p_start;
836 			vpart->p_size = lpart->p_size;
837 #endif	/* defined(_SUNOS_VTOC_16) */
838 		}
839 		(void) memcpy(vtoc->v_volume, label->dkl_vtoc.v_volume,
840 		    LEN_DKL_VVOL);
841 		(void) memcpy((char *)vtoc->v_bootinfo,
842 		    (char *)label->dkl_vtoc.v_bootinfo,
843 		    sizeof (vtoc->v_bootinfo));
844 		(void) memcpy((char *)vtoc->v_reserved,
845 		    (char *)label->dkl_vtoc.v_reserved,
846 		    sizeof (vtoc->v_reserved));
847 		(void) memcpy((char *)vtoc->timestamp,
848 		    (char *)label->dkl_vtoc.v_timestamp,
849 		    sizeof (vtoc->timestamp));
850 		break;
851 
852 	default:
853 		return (-1);
854 	}
855 
856 	/*
857 	 * XXX - this looks wrong to me....
858 	 * why are these values hardwired, rather than returned from
859 	 * the real disk label?
860 	 */
861 	vtoc->v_sanity = VTOC_SANE;
862 	vtoc->v_version = V_VERSION;
863 	vtoc->v_sectorsz = DEV_BSIZE;
864 	vtoc->v_nparts = V_NUMPAR;
865 
866 	(void) memcpy(vtoc->v_asciilabel, label->dkl_asciilabel,
867 	    LEN_DKL_ASCII);
868 
869 #if defined(_SUNOS_VTOC_8)
870 	/*
871 	 * Convert partitioning information.
872 	 * Note the conversion from starting cylinder number
873 	 * to starting sector number.
874 	 */
875 	lmap = label->dkl_map;
876 	vpart = vtoc->v_part;
877 	nblks = label->dkl_nsect * label->dkl_nhead;
878 	for (i = 0; i < V_NUMPAR; i++, vpart++, lmap++) {
879 		vpart->p_start = lmap->dkl_cylno * nblks;
880 		vpart->p_size = lmap->dkl_nblk;
881 	}
882 #endif			/* defined(_SUNOS_VTOC_8) */
883 
884 	return (0);
885 }
886 
887 /*
888  * Input: File descriptor
889  * Output: 1 if disk is >1TB OR has an EFI label, 0 otherwise.
890  */
891 
892 int
893 is_efi_type(int fd)
894 {
895 	struct vtoc vtoc;
896 
897 	if (ioctl(fd, DKIOCGVTOC, &vtoc) == -1) {
898 		if (errno == ENOTSUP) {
899 			return (1);
900 		}
901 	}
902 	return (0);
903 }
904 
905 /* make sure the user specified something reasonable */
906 void
907 err_check(struct dk_gpt *vtoc)
908 {
909 	int			resv_part = -1;
910 	int			i, j;
911 	diskaddr_t		istart, jstart, isize, jsize, endsect;
912 	int			overlap = 0;
913 
914 	/*
915 	 * make sure no partitions overlap
916 	 */
917 	for (i = 0; i < vtoc->efi_nparts; i++) {
918 		/* It can't be unassigned and have an actual size */
919 		if ((vtoc->efi_parts[i].p_tag == V_UNASSIGNED) &&
920 		    (vtoc->efi_parts[i].p_size != 0)) {
921 			(void) fprintf(stderr,
922 "partition %d is \"unassigned\" but has a size of %llu\n", i,
923 			    vtoc->efi_parts[i].p_size);
924 		}
925 		if (vtoc->efi_parts[i].p_tag == V_UNASSIGNED) {
926 			continue;
927 		}
928 		if (vtoc->efi_parts[i].p_tag == V_RESERVED) {
929 			if (resv_part != -1) {
930 				(void) fprintf(stderr,
931 "found duplicate reserved partition at %d\n", i);
932 			}
933 			resv_part = i;
934 			if (vtoc->efi_parts[i].p_size != EFI_MIN_RESV_SIZE)
935 				(void) fprintf(stderr,
936 "Warning: reserved partition size must be %d sectors\n",
937 				    EFI_MIN_RESV_SIZE);
938 		}
939 		if ((vtoc->efi_parts[i].p_start < vtoc->efi_first_u_lba) ||
940 		    (vtoc->efi_parts[i].p_start > vtoc->efi_last_u_lba)) {
941 			(void) fprintf(stderr,
942 			    "Partition %d starts at %llu\n",
943 			    i,
944 			    vtoc->efi_parts[i].p_start);
945 			(void) fprintf(stderr,
946 			    "It must be between %llu and %llu.\n",
947 			    vtoc->efi_first_u_lba,
948 			    vtoc->efi_last_u_lba);
949 		}
950 		if ((vtoc->efi_parts[i].p_start +
951 		    vtoc->efi_parts[i].p_size <
952 		    vtoc->efi_first_u_lba) ||
953 		    (vtoc->efi_parts[i].p_start +
954 		    vtoc->efi_parts[i].p_size >
955 		    vtoc->efi_last_u_lba + 1)) {
956 			(void) fprintf(stderr,
957 			    "Partition %d ends at %llu\n",
958 			    i,
959 			    vtoc->efi_parts[i].p_start +
960 			    vtoc->efi_parts[i].p_size);
961 			(void) fprintf(stderr,
962 			    "It must be between %llu and %llu.\n",
963 			    vtoc->efi_first_u_lba,
964 			    vtoc->efi_last_u_lba);
965 		}
966 
967 		for (j = 0; j < vtoc->efi_nparts; j++) {
968 			isize = vtoc->efi_parts[i].p_size;
969 			jsize = vtoc->efi_parts[j].p_size;
970 			istart = vtoc->efi_parts[i].p_start;
971 			jstart = vtoc->efi_parts[j].p_start;
972 			if ((i != j) && (isize != 0) && (jsize != 0)) {
973 				endsect = jstart + jsize -1;
974 				if ((jstart <= istart) &&
975 				    (istart <= endsect)) {
976 					if (!overlap) {
977 					(void) fprintf(stderr,
978 "label error: EFI Labels do not support overlapping partitions\n");
979 					}
980 					(void) fprintf(stderr,
981 "Partition %d overlaps partition %d.\n", i, j);
982 					overlap = 1;
983 				}
984 			}
985 		}
986 	}
987 	/* make sure there is a reserved partition */
988 	if (resv_part == -1) {
989 		(void) fprintf(stderr,
990 		    "no reserved partition found\n");
991 	}
992 }
993 
994 #ifdef	FOR_DEBUGGING_ONLY
995 int
996 dump_label(label)
997 	struct dk_label	*label;
998 {
999 	int		i;
1000 
1001 	fmt_print("%s\n", label->dkl_asciilabel);
1002 
1003 	fmt_print("version:  %d\n", label->dkl_vtoc.v_version);
1004 	fmt_print("volume:   ");
1005 	for (i = 0; i < LEN_DKL_VVOL; i++) {
1006 		if (label->dkl_vtoc.v_volume[i] == 0)
1007 			break;
1008 		fmt_print("%c", label->dkl_vtoc.v_volume[i]);
1009 	}
1010 	fmt_print("\n");
1011 	fmt_print("v_nparts: %d\n", label->dkl_vtoc.v_nparts);
1012 	fmt_print("v_sanity: %lx\n", label->dkl_vtoc.v_sanity);
1013 
1014 #if defined(_SUNOS_VTOC_8)
1015 	fmt_print("rpm:      %d\n", label->dkl_rpm);
1016 	fmt_print("pcyl:     %d\n", label->dkl_pcyl);
1017 	fmt_print("apc:      %d\n", label->dkl_apc);
1018 	fmt_print("obs1:     %d\n", label->dkl_obs1);
1019 	fmt_print("obs2:     %d\n", label->dkl_obs2);
1020 	fmt_print("intrlv:   %d\n", label->dkl_intrlv);
1021 	fmt_print("ncyl:     %d\n", label->dkl_ncyl);
1022 	fmt_print("acyl:     %d\n", label->dkl_acyl);
1023 	fmt_print("nhead:    %d\n", label->dkl_nhead);
1024 	fmt_print("nsect:    %d\n", label->dkl_nsect);
1025 	fmt_print("obs3:     %d\n", label->dkl_obs3);
1026 	fmt_print("obs4:     %d\n", label->dkl_obs4);
1027 
1028 #elif defined(_SUNOS_VTOC_16)
1029 	fmt_print("rpm:      %d\n", label->dkl_rpm);
1030 	fmt_print("pcyl:     %d\n", label->dkl_pcyl);
1031 	fmt_print("apc:      %d\n", label->dkl_apc);
1032 	fmt_print("intrlv:   %d\n", label->dkl_intrlv);
1033 	fmt_print("ncyl:     %d\n", label->dkl_ncyl);
1034 	fmt_print("acyl:     %d\n", label->dkl_acyl);
1035 	fmt_print("nhead:    %d\n", label->dkl_nhead);
1036 	fmt_print("nsect:    %d\n", label->dkl_nsect);
1037 	fmt_print("bcyl:     %d\n", label->dkl_bcyl);
1038 	fmt_print("skew:     %d\n", label->dkl_skew);
1039 #else
1040 #error No VTOC format defined.
1041 #endif				/* defined(_SUNOS_VTOC_8) */
1042 	fmt_print("magic:    %0x\n", label->dkl_magic);
1043 	fmt_print("cksum:    %0x\n", label->dkl_cksum);
1044 
1045 	for (i = 0; i < NDKMAP; i++) {
1046 
1047 #if defined(_SUNOS_VTOC_8)
1048 		fmt_print("%c:        cyl=%d, blocks=%d", i+'a',
1049 			label->dkl_map[i].dkl_cylno,
1050 			label->dkl_map[i].dkl_nblk);
1051 
1052 #elif defined(_SUNOS_VTOC_16)
1053 		fmt_print("%c:        start=%d, blocks=%d", i+'a',
1054 		    label->dkl_vtoc.v_part[i].p_start,
1055 		    label->dkl_vtoc.v_part[i].p_size);
1056 #else
1057 #error No VTOC format defined.
1058 #endif				/* defined(_SUNOS_VTOC_8) */
1059 
1060 		fmt_print(",  tag=%d,  flag=%d",
1061 			label->dkl_vtoc.v_part[i].p_tag,
1062 			label->dkl_vtoc.v_part[i].p_flag);
1063 		fmt_print("\n");
1064 	}
1065 
1066 	fmt_print("read_reinstruct:  %d\n", label->dkl_read_reinstruct);
1067 	fmt_print("write_reinstruct: %d\n", label->dkl_write_reinstruct);
1068 
1069 	fmt_print("bootinfo: ");
1070 	for (i = 0; i < 3; i++) {
1071 		fmt_print("0x%x ", label->dkl_vtoc.v_bootinfo[i]);
1072 	}
1073 	fmt_print("\n");
1074 
1075 	fmt_print("reserved: ");
1076 	for (i = 0; i < 10; i++) {
1077 		if ((i % 4) == 3)
1078 			fmt_print("\n");
1079 		fmt_print("0x%x ", label->dkl_vtoc.v_reserved[i]);
1080 	}
1081 	fmt_print("\n");
1082 
1083 	fmt_print("timestamp:\n");
1084 	for (i = 0; i < NDKMAP; i++) {
1085 		if ((i % 4) == 3)
1086 			fmt_print("\n");
1087 		fmt_print("0x%x ", label->dkl_vtoc.v_timestamp[i]);
1088 	}
1089 	fmt_print("\n");
1090 
1091 	fmt_print("pad:\n");
1092 	dump("", label->dkl_pad, LEN_DKL_PAD, HEX_ONLY);
1093 
1094 	fmt_print("\n\n");
1095 }
1096 #endif	/* FOR_DEBUGGING_ONLY */
1097