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