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