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