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