xref: /illumos-gate/usr/src/cmd/format/label.c (revision 4bc0a2ef)
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 #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);
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  * expand the internal 32-bit SMI VTOC into the 64-bit EFI version
215  * for writing it out to the disk
216  */
217 int
218 SMI_vtoc_to_EFI(int fd, struct dk_gpt **new_vtoc, struct vtoc *old_vtoc)
219 {
220 	int i, j;
221 	int vtoc_part_count = 0;
222 	int highest_assigned_part = 0;
223 	int last_par = 0;
224 	int compact = 0;
225 	struct dk_gpt	*vtoc;
226 	struct vtoc	old_vtoc_copy;
227 	diskaddr_t	start, size;
228 
229 	if (efi_alloc_and_init(fd, EFI_NUMPAR, new_vtoc) != 0) {
230 	    err_print("SMI vtoc to EFI failed\n");
231 	    return (-1);
232 	}
233 	vtoc = *new_vtoc;
234 	old_vtoc_copy = *old_vtoc;
235 
236 	/*
237 	 * Prepare old VTOC table for transfer by ensuring the
238 	 * tags are set correctly.  Also collect information
239 	 * about the old VTOC table including the number of
240 	 * valid VTOC partitions and the highest VTOC partition
241 	 * in use.  An EFI label provides fewer partitions, so
242 	 * it is possible that the VTOC partitions cannot all be
243 	 * transferred.
244 	 */
245 	for (i = 0; i < V_NUMPAR; i++) {
246 		/*
247 		 * we may be carrying around old tags from the
248 		 * default partition table.  If the partition
249 		 * is really unassigned, set the tag correctly
250 		 */
251 		if ((old_vtoc->v_part[i].p_start == 0) &&
252 		    (old_vtoc->v_part[i].p_size == 0))
253 			old_vtoc->v_part[i].p_tag = V_UNASSIGNED;
254 		/*
255 		 * Likewise, if the partition is not empty, don't
256 		 * write it out as "unassigned."
257 		 */
258 		if ((old_vtoc->v_part[i].p_size != 0) &&
259 		    (old_vtoc->v_part[i].p_tag == V_UNASSIGNED))
260 			old_vtoc->v_part[i].p_tag = V_ROOT;
261 		if (old_vtoc->v_part[i].p_tag != V_BACKUP &&
262 		    old_vtoc->v_part[i].p_tag != V_UNASSIGNED &&
263 		    old_vtoc->v_part[i].p_start < vtoc->efi_first_u_lba) {
264 			old_vtoc->v_part[i].p_start = vtoc->efi_first_u_lba;
265 			old_vtoc->v_part[i].p_size -= vtoc->efi_first_u_lba;
266 		}
267 
268 		if (old_vtoc->v_part[i].p_tag == V_BACKUP ||
269 		    old_vtoc->v_part[i].p_tag == V_BOOT) {
270 		    old_vtoc->v_part[i].p_tag = V_UNASSIGNED;
271 		    old_vtoc->v_part[i].p_start =
272 			old_vtoc->v_part[i].p_size = 0;
273 		    last_par = i;
274 		}
275 		if ((i == WD_NODE) && (old_vtoc->v_part[i].p_tag !=
276 		    V_UNASSIGNED)) {
277 			old_vtoc->v_part[i].p_tag = V_UNASSIGNED;
278 			old_vtoc->v_part[i].p_start = 0;
279 			old_vtoc->v_part[i].p_size = 0;
280 		}
281 
282 		if (old_vtoc->v_part[i].p_tag != V_UNASSIGNED) {
283 			/* Update count of valid VTOC partitions */
284 			vtoc_part_count++;
285 
286 			/* Note the highest valid VTOC slice */
287 			highest_assigned_part = i;
288 		}
289 	}
290 	if (vtoc_part_count > vtoc->efi_nparts - 1) {
291 		/* Too many partitions to convert the VTOC label */
292 		err_print("There are %d defined VTOC ", vtoc_part_count);
293 		err_print("partitions and an EFI label\n");
294 		err_print("can only accept %d.\n", vtoc->efi_nparts - 1);
295 		if (check("Continue anyway") != 0) {
296 			/* If no, restore VTOC and return an error */
297 			*old_vtoc = old_vtoc_copy;
298 			efi_free(vtoc);
299 			return (-1);
300 		}
301 	}
302 
303 	if (highest_assigned_part > vtoc->efi_nparts - 2) {
304 		/*
305 		 * Partition indexes cannot be transferred directly since
306 		 * the highest valid VTOC index is higher than the highest
307 		 * available EFI partition.  Ask the user if it is OK to
308 		 * move the partitions to available slots
309 		 */
310 		err_print("VTOC partition %d is defined ",
311 		    highest_assigned_part);
312 		err_print("and the highest available EFI\n");
313 		err_print("partition is %d.  The partitions\n",
314 		    vtoc->efi_nparts - 2);
315 		err_print("will fit if they are re-numbered\n");
316 		if (check("OK to renumber") != 0) {
317 			/* If no, restore VTOC and return an error */
318 			*old_vtoc = old_vtoc_copy;
319 			efi_free(vtoc);
320 			return (-1);
321 		} else {
322 			compact = 1;
323 		}
324 	}
325 
326 	/*
327 	 * Now copy the VTOC partitions, remapping the indices if
328 	 * necessary.
329 	 */
330 	j = 0;
331 	for (i = 0; i < V_NUMPAR; i++) {
332 		if (old_vtoc->v_part[i].p_tag != V_UNASSIGNED) {
333 			/* Copy partition info */
334 			vtoc->efi_parts[j].p_tag = old_vtoc->v_part[i].p_tag;
335 			vtoc->efi_parts[j].p_flag = old_vtoc->v_part[i].p_flag;
336 			vtoc->efi_parts[j].p_start =
337 			    old_vtoc->v_part[i].p_start;
338 			vtoc->efi_parts[j].p_size =
339 			    old_vtoc->v_part[i].p_size;
340 			if (vtoc->efi_parts[j].p_size != 0)
341 				last_par = j;
342 			j++; /* Increment EFI index */
343 		} else {
344 			if (!compact) {
345 				j++; /* Increment EFI index */
346 			}
347 		}
348 	}
349 
350 	start = vtoc->efi_parts[last_par].p_start;
351 	size = vtoc->efi_parts[last_par].p_size;
352 	if ((start + size) > (vtoc->efi_last_u_lba - EFI_MIN_RESV_SIZE)) {
353 		size = (start + size) - (vtoc->efi_last_u_lba -
354 			    EFI_MIN_RESV_SIZE);
355 		vtoc->efi_parts[last_par].p_size -= size;
356 	}
357 	vtoc->efi_parts[vtoc->efi_nparts - 1].p_tag = V_RESERVED;
358 	vtoc->efi_parts[vtoc->efi_nparts - 1].p_start =
359 	    vtoc->efi_last_u_lba - EFI_MIN_RESV_SIZE;
360 	vtoc->efi_parts[vtoc->efi_nparts - 1].p_size = EFI_MIN_RESV_SIZE;
361 
362 	return (0);
363 }
364 
365 
366 /*
367  * This routine constructs and writes a label on the disk.  It writes both
368  * the primary and backup labels.  It assumes that there is a current
369  * partition map already defined.  It also notifies the SunOS kernel of
370  * the label and partition information it has written on the disk.
371  */
372 int
373 write_label()
374 {
375 	int	error = 0, head, sec;
376 	struct dk_label label;
377 	struct dk_label new_label;
378 	struct vtoc	vtoc;
379 	struct dk_geom	geom;
380 	struct dk_gpt	*vtoc64;
381 	int		nbackups;
382 
383 #if defined(_SUNOS_VTOC_8)
384 	int i;
385 #endif		/* defined(_SUNOS_VTOC_8) */
386 
387 	/*
388 	 * If EFI label, then write it out to disk
389 	 */
390 	if (cur_label == L_TYPE_EFI) {
391 	    enter_critical();
392 	    vtoc64 = cur_parts->etoc;
393 	    err_check(vtoc64);
394 	    if (efi_write(cur_file, vtoc64) != 0) {
395 		err_print("Warning: error writing EFI.\n");
396 		error = -1;
397 	    }
398 
399 	    cur_disk->disk_flags |= DSK_LABEL;
400 	    exit_critical();
401 	    return (error);
402 	}
403 
404 	/*
405 	 * Fill in a label structure with the geometry information.
406 	 */
407 	(void) memset((char *)&label, 0, sizeof (struct dk_label));
408 	(void) memset((char *)&new_label, 0, sizeof (struct dk_label));
409 	label.dkl_pcyl = pcyl;
410 	label.dkl_ncyl = ncyl;
411 	label.dkl_acyl = acyl;
412 
413 #if defined(_SUNOS_VTOC_16)
414 	label.dkl_bcyl = bcyl;
415 #endif			/* defined(_SUNOC_VTOC_16) */
416 
417 	label.dkl_nhead = nhead;
418 	label.dkl_nsect = nsect;
419 	label.dkl_apc = apc;
420 	label.dkl_intrlv = 1;
421 	label.dkl_rpm = cur_dtype->dtype_rpm;
422 
423 #if defined(_SUNOS_VTOC_8)
424 	/*
425 	 * Also fill in the current partition information.
426 	 */
427 	for (i = 0; i < NDKMAP; i++) {
428 		label.dkl_map[i] = cur_parts->pinfo_map[i];
429 	}
430 #endif			/* defined(_SUNOS_VTOC_8) */
431 
432 	label.dkl_magic = DKL_MAGIC;
433 
434 	/*
435 	 * Fill in the vtoc information
436 	 */
437 	label.dkl_vtoc = cur_parts->vtoc;
438 
439 	/*
440 	 * Use the current label
441 	 */
442 	bcopy(cur_disk->v_volume, label.dkl_vtoc.v_volume, LEN_DKL_VVOL);
443 
444 	/*
445 	 * Put asciilabel in; on x86 it's in the vtoc, not the label.
446 	 */
447 	(void) snprintf(label.dkl_asciilabel, sizeof (label.dkl_asciilabel),
448 	    "%s cyl %d alt %d hd %d sec %d",
449 	    cur_dtype->dtype_asciilabel, ncyl, acyl, nhead, nsect);
450 
451 #if defined(_SUNOS_VTOC_16)
452 	/*
453 	 * Also add in v_sectorsz, as the driver will.  Everyone
454 	 * else is assuming DEV_BSIZE, so we do the same.
455 	 */
456 	label.dkl_vtoc.v_sectorsz = DEV_BSIZE;
457 #endif			/* defined(_SUNOS_VTOC_16) */
458 
459 	/*
460 	 * Generate the correct checksum.
461 	 */
462 	(void) checksum(&label, CK_MAKESUM);
463 	/*
464 	 * Convert the label into a vtoc
465 	 */
466 	if (label_to_vtoc(&vtoc, &label) == -1) {
467 		return (-1);
468 	}
469 	/*
470 	 * Fill in the geometry info.  This is critical that
471 	 * we do this before writing the vtoc.
472 	 */
473 	bzero((caddr_t)&geom, sizeof (struct dk_geom));
474 	geom.dkg_ncyl = ncyl;
475 	geom.dkg_acyl = acyl;
476 
477 #if defined(_SUNOS_VTOC_16)
478 	geom.dkg_bcyl = bcyl;
479 #endif			/* defined(_SUNOS_VTOC_16) */
480 
481 	geom.dkg_nhead = nhead;
482 	geom.dkg_nsect = nsect;
483 	geom.dkg_intrlv = 1;
484 	geom.dkg_apc = apc;
485 	geom.dkg_rpm = cur_dtype->dtype_rpm;
486 	geom.dkg_pcyl = pcyl;
487 
488 	/*
489 	 * Make a quick check to see that the geometry is being
490 	 * written now is not way off from the actual capacity
491 	 * of the disk. This is only an appoximate check and
492 	 * is only for SCSI disks.
493 	 */
494 	if (SCSI && do_geometry_sanity_check() != 0) {
495 		return (-1);
496 	}
497 
498 	/*
499 	 * Lock out interrupts so we do things in sync.
500 	 */
501 	enter_critical();
502 	/*
503 	 * Do the ioctl to tell the kernel the geometry.
504 	 */
505 	if (ioctl(cur_file, DKIOCSGEOM, &geom) == -1) {
506 		err_print("Warning: error setting drive geometry.\n");
507 		error = -1;
508 	}
509 	/*
510 	 * Write the vtoc.  At the time of this writing, our
511 	 * drivers convert the vtoc back to a label, and
512 	 * then write both the primary and backup labels.
513 	 * This is not a requirement, however, as we
514 	 * always use an ioctl to read the vtoc from the
515 	 * driver, so it can do as it likes.
516 	 */
517 	if (write_vtoc(cur_file, &vtoc) != 0) {
518 		err_print("Warning: error writing VTOC.\n");
519 		error = -1;
520 	}
521 
522 	/*
523 	 * Calculate where the backup labels went.  They are always on
524 	 * the last alternate cylinder, but some older drives put them
525 	 * on head 2 instead of the last head.  They are always on the
526 	 * first 5 odd sectors of the appropriate track.
527 	 */
528 	if (cur_ctype->ctype_flags & CF_BLABEL)
529 		head  = 2;
530 	else
531 		head = nhead - 1;
532 	/*
533 	 * Read and verify the backup labels.
534 	 */
535 	nbackups = 0;
536 	for (sec = 1; ((sec < BAD_LISTCNT * 2 + 1) && (sec < nsect));
537 	    sec += 2) {
538 		if ((*cur_ops->op_rdwr)(DIR_READ, cur_file, (diskaddr_t)
539 			((chs2bn(ncyl + acyl - 1, head, sec)) + solaris_offset),
540 			1, (caddr_t)&new_label, F_NORMAL, NULL)) {
541 			err_print("Warning: error reading backup label.\n");
542 			error = -1;
543 		} else {
544 			if (bcmp((char *)&label, (char *)&new_label,
545 				sizeof (struct dk_label)) == 0) {
546 					nbackups++;
547 			}
548 		}
549 	}
550 	if (nbackups != BAD_LISTCNT) {
551 		err_print("Warning: %s\n", nbackups == 0 ?
552 			"no backup labels" :
553 			"some backup labels incorrect");
554 	}
555 	/*
556 	 * Mark the current disk as labelled and notify the kernel of what
557 	 * has happened.
558 	 */
559 	cur_disk->disk_flags |= DSK_LABEL;
560 
561 	exit_critical();
562 	return (error);
563 }
564 
565 
566 /*
567  * Read the label from the disk.
568  * Do this via the read_vtoc() library routine, then convert it to a label.
569  * We also need a DKIOCGGEOM ioctl to get the disk's geometry.
570  */
571 int
572 read_label(int fd, struct dk_label *label)
573 {
574 	struct vtoc	vtoc;
575 	struct dk_geom	geom;
576 
577 	if (read_vtoc(fd, &vtoc) < 0 || ioctl(fd, DKIOCGGEOM, &geom) == -1) {
578 		return (-1);
579 	}
580 	return (vtoc_to_label(label, &vtoc, &geom));
581 }
582 
583 int
584 get_disk_info_from_devid(int fd, struct efi_info *label)
585 {
586 	ddi_devid_t	devid;
587 	char		*s;
588 	int		n;
589 	char		*vid, *pid;
590 	int		nvid, npid;
591 	struct dk_minfo	minf;
592 	struct dk_cinfo	dkinfo;
593 
594 
595 	if (devid_get(fd, &devid)) {
596 		if (option_msg && diag_msg)
597 			err_print("devid_get failed\n");
598 		return (-1);
599 	}
600 
601 	n = devid_sizeof(devid);
602 	s = (char *)devid;
603 
604 	if (ioctl(fd, DKIOCINFO, &dkinfo) == -1) {
605 		if (option_msg && diag_msg)
606 			err_print("DKIOCINFO failed\n");
607 		return (-1);
608 	}
609 
610 	if (dkinfo.dki_ctype != DKC_DIRECT)
611 		return (-1);
612 
613 	vid = s+12;
614 	if (!(pid = strchr(vid, '=')))
615 		return (-1);
616 	nvid = pid - vid;
617 	pid += 1;
618 	npid = n - nvid - 13;
619 
620 	if (nvid > 9)
621 		nvid = 9;
622 	if (npid > 17) {
623 		pid = pid + npid - 17;
624 		npid = 17;
625 	}
626 
627 	if (ioctl(fd, DKIOCGMEDIAINFO, &minf) == -1) {
628 		devid_free(devid);
629 		return (-1);
630 	}
631 
632 	(void) strlcpy(label->vendor, vid, nvid);
633 	(void) strlcpy(label->product, pid, npid);
634 	(void) strlcpy(label->revision, "0001", 5);
635 	label->capacity = minf.dki_capacity * minf.dki_lbsize / 512;
636 
637 	devid_free(devid);
638 	return (0);
639 }
640 
641 /*
642  * Issue uscsi_inquiry and read_capacity commands to
643  * retrieve the disk's Vendor, Product, Revision and
644  * Capacity information.
645  */
646 int
647 get_disk_info(int fd, struct efi_info *label)
648 {
649 	struct scsi_inquiry	inquiry;
650 	struct scsi_capacity_16	capacity;
651 
652 	if (!get_disk_info_from_devid(fd, label))
653 		return (0);
654 
655 	if (uscsi_inquiry(fd, (char *)&inquiry, sizeof (inquiry))) {
656 		err_print("Inquiry failed on %d\n", fd);
657 		return (-1);
658 	}
659 	if (uscsi_read_capacity(fd, &capacity)) {
660 		err_print("Read Capacity failed for %d\n", fd);
661 		return (-1);
662 	}
663 
664 	(void) strlcpy(label->vendor, inquiry.inq_vid, 9);
665 	(void) strlcpy(label->product, inquiry.inq_pid, 17);
666 	(void) strlcpy(label->revision, inquiry.inq_revision, 5);
667 	label->capacity = capacity.sc_capacity;
668 
669 	/* Since we are counting from zero, add 1 to capacity */
670 	label->capacity++;
671 	return (0);
672 }
673 
674 int
675 read_efi_label(int fd, struct efi_info *label)
676 {
677 	struct dk_gpt	*vtoc64;
678 
679 	/* This could fail if there is no label already */
680 	if (efi_alloc_and_read(fd, &vtoc64) < 0) {
681 		return (-1);
682 	}
683 	if (vtoc64_to_label(label, vtoc64) != 0) {
684 		err_print("vtoc64_to_label failed\n");
685 		return (-1);
686 	}
687 	efi_free(vtoc64);
688 	if (get_disk_info(fd, label) != 0) {
689 		return (-1);
690 	}
691 	return (0);
692 }
693 
694 
695 /*
696  * We've read a 64-bit label which has no geometry information.  Use
697  * some heuristics to fake up a geometry that would match the disk in
698  * order to make the rest of format(1M) happy.
699  */
700 static int
701 vtoc64_to_label(struct efi_info *label, struct dk_gpt *vtoc)
702 {
703 	int		i, nparts = 0;
704 	struct dk_gpt	*lmap;
705 
706 	(void) memset((char *)label, 0, sizeof (struct efi_info));
707 
708 	/* XXX do a sanity check here for nparts */
709 	nparts = vtoc->efi_nparts;
710 	lmap = (struct dk_gpt *) calloc(1, (sizeof (struct dk_part) *
711 		    nparts) + sizeof (struct dk_gpt));
712 	if (lmap == NULL) {
713 		err_print("vtoc64_to_label: unable to allocate lmap\n");
714 		fullabort();
715 	}
716 	label->e_parts = lmap;
717 
718 	/*
719 	 * Copy necessary portions
720 	 * XXX Maybe we can use memcpy() ??
721 	 */
722 	lmap->efi_version = vtoc->efi_version;
723 	lmap->efi_nparts = vtoc->efi_nparts;
724 	lmap->efi_part_size = vtoc->efi_part_size;
725 	lmap->efi_lbasize = vtoc->efi_lbasize;
726 	lmap->efi_last_lba = vtoc->efi_last_lba;
727 	lmap->efi_first_u_lba = vtoc->efi_first_u_lba;
728 	lmap->efi_last_u_lba = vtoc->efi_last_u_lba;
729 	lmap->efi_flags = vtoc->efi_flags;
730 	(void) memcpy((uchar_t *)&lmap->efi_disk_uguid,
731 		(uchar_t *)&vtoc->efi_disk_uguid, sizeof (struct uuid));
732 
733 	for (i = 0; i < nparts; i++) {
734 		lmap->efi_parts[i].p_tag = vtoc->efi_parts[i].p_tag;
735 		lmap->efi_parts[i].p_flag = vtoc->efi_parts[i].p_flag;
736 		lmap->efi_parts[i].p_start = vtoc->efi_parts[i].p_start;
737 		lmap->efi_parts[i].p_size = vtoc->efi_parts[i].p_size;
738 		(void) memcpy((uchar_t *)&lmap->efi_parts[i].p_uguid,
739 		    (uchar_t *)&vtoc->efi_parts[i].p_uguid,
740 		    sizeof (struct uuid));
741 		if (vtoc->efi_parts[i].p_tag == V_RESERVED) {
742 			bcopy(vtoc->efi_parts[i].p_name,
743 			    lmap->efi_parts[i].p_name, LEN_DKL_VVOL);
744 		}
745 	}
746 	return (0);
747 }
748 
749 /*
750  * Convert vtoc/geom to label.
751  */
752 static int
753 vtoc_to_label(struct dk_label *label, struct vtoc *vtoc, struct dk_geom *geom)
754 {
755 #if defined(_SUNOS_VTOC_8)
756 	struct dk_map32		*lmap;
757 #elif defined(_SUNOS_VTOC_16)
758 	struct dkl_partition	*lmap;
759 #else
760 #error No VTOC format defined.
761 #endif			/* defined(_SUNOS_VTOC_8) */
762 
763 	struct partition	*vpart;
764 	long			nblks;
765 	int			i;
766 
767 	(void) memset((char *)label, 0, sizeof (struct dk_label));
768 
769 	/*
770 	 * Sanity-check the vtoc
771 	 */
772 	if (vtoc->v_sanity != VTOC_SANE || vtoc->v_sectorsz != DEV_BSIZE ||
773 			vtoc->v_nparts != V_NUMPAR) {
774 		return (-1);
775 	}
776 
777 	/*
778 	 * Sanity check of geometry
779 	 */
780 	if (geom->dkg_ncyl == 0 || geom->dkg_nhead == 0 ||
781 			geom->dkg_nsect == 0) {
782 		return (-1);
783 	}
784 
785 	label->dkl_magic = DKL_MAGIC;
786 
787 	/*
788 	 * Copy necessary portions of the geometry information
789 	 */
790 	label->dkl_rpm = geom->dkg_rpm;
791 	label->dkl_pcyl = geom->dkg_pcyl;
792 	label->dkl_apc = geom->dkg_apc;
793 	label->dkl_intrlv = geom->dkg_intrlv;
794 	label->dkl_ncyl = geom->dkg_ncyl;
795 	label->dkl_acyl = geom->dkg_acyl;
796 
797 #if defined(_SUNOS_VTOC_16)
798 	label->dkl_bcyl = geom->dkg_bcyl;
799 #endif			/* defined(_SUNOS_VTOC_16) */
800 
801 	label->dkl_nhead = geom->dkg_nhead;
802 	label->dkl_nsect = geom->dkg_nsect;
803 
804 #if defined(_SUNOS_VTOC_8)
805 	label->dkl_obs1 = geom->dkg_obs1;
806 	label->dkl_obs2 = geom->dkg_obs2;
807 	label->dkl_obs3 = geom->dkg_obs3;
808 #endif			/* defined(_SUNOS_VTOC_8) */
809 
810 	label->dkl_write_reinstruct = geom->dkg_write_reinstruct;
811 	label->dkl_read_reinstruct = geom->dkg_read_reinstruct;
812 
813 	/*
814 	 * Copy vtoc structure fields into the disk label dk_vtoc
815 	 */
816 	label->dkl_vtoc.v_sanity = vtoc->v_sanity;
817 	label->dkl_vtoc.v_nparts = vtoc->v_nparts;
818 	label->dkl_vtoc.v_version = vtoc->v_version;
819 
820 	(void) memcpy(label->dkl_vtoc.v_volume, vtoc->v_volume,
821 		LEN_DKL_VVOL);
822 	for (i = 0; i < V_NUMPAR; i++) {
823 		label->dkl_vtoc.v_part[i].p_tag = vtoc->v_part[i].p_tag;
824 		label->dkl_vtoc.v_part[i].p_flag = vtoc->v_part[i].p_flag;
825 	}
826 	(void) memcpy((char *)label->dkl_vtoc.v_bootinfo,
827 		(char *)vtoc->v_bootinfo, sizeof (vtoc->v_bootinfo));
828 	(void) memcpy((char *)label->dkl_vtoc.v_reserved,
829 		(char *)vtoc->v_reserved, sizeof (vtoc->v_reserved));
830 	(void) memcpy((char *)label->dkl_vtoc.v_timestamp,
831 		(char *)vtoc->timestamp, sizeof (vtoc->timestamp));
832 
833 	(void) memcpy(label->dkl_asciilabel, vtoc->v_asciilabel,
834 		LEN_DKL_ASCII);
835 
836 	/*
837 	 * Note the conversion from starting sector number
838 	 * to starting cylinder number.
839 	 * Return error if division results in a remainder.
840 	 */
841 #if defined(_SUNOS_VTOC_8)
842 	lmap = label->dkl_map;
843 
844 #elif defined(_SUNOS_VTOC_16)
845 	lmap = label->dkl_vtoc.v_part;
846 #else
847 #error No VTOC format defined.
848 #endif			/* defined(_SUNOS_VTOC_8) */
849 
850 	vpart = vtoc->v_part;
851 
852 	nblks = (int)label->dkl_nsect * (int)label->dkl_nhead;
853 
854 	for (i = 0; i < NDKMAP; i++, lmap++, vpart++) {
855 		if ((vpart->p_start % nblks) != 0 ||
856 				(vpart->p_size % nblks) != 0) {
857 			return (-1);
858 		}
859 #if defined(_SUNOS_VTOC_8)
860 		lmap->dkl_cylno = vpart->p_start / nblks;
861 		lmap->dkl_nblk = vpart->p_size;
862 
863 #elif defined(_SUNOS_VTOC_16)
864 		lmap->p_start = vpart->p_start;
865 		lmap->p_size = vpart->p_size;
866 #else
867 #error No VTOC format defined.
868 #endif			/* defined(_SUNOS_VTOC_8) */
869 	}
870 
871 	/*
872 	 * Finally, make a checksum
873 	 */
874 	(void) checksum(label, CK_MAKESUM);
875 
876 	return (0);
877 }
878 
879 
880 
881 /*
882  * Extract a vtoc structure out of a valid label
883  */
884 int
885 label_to_vtoc(struct vtoc *vtoc, struct dk_label *label)
886 {
887 #if defined(_SUNOS_VTOC_8)
888 	struct dk_map2		*lpart;
889 	struct dk_map32		*lmap;
890 	long			nblks;
891 
892 #elif defined(_SUNOS_VTOC_16)
893 	struct dkl_partition	*lpart;
894 #else
895 #error No VTOC format defined.
896 #endif				/* defined(_SUNOS_VTOC_8) */
897 
898 	struct partition	*vpart;
899 	int			i;
900 
901 	(void) memset((char *)vtoc, 0, sizeof (struct vtoc));
902 
903 	switch (label->dkl_vtoc.v_version) {
904 	case 0:
905 		/*
906 		 * No valid vtoc information in the label.
907 		 * Construct default p_flags and p_tags.
908 		 */
909 		vpart = vtoc->v_part;
910 		for (i = 0; i < V_NUMPAR; i++, vpart++) {
911 			vpart->p_tag = default_vtoc_map[i].p_tag;
912 			vpart->p_flag = default_vtoc_map[i].p_flag;
913 		}
914 		break;
915 
916 	case V_VERSION:
917 		vpart = vtoc->v_part;
918 		lpart = label->dkl_vtoc.v_part;
919 		for (i = 0; i < V_NUMPAR; i++, vpart++, lpart++) {
920 			vpart->p_tag = lpart->p_tag;
921 			vpart->p_flag = lpart->p_flag;
922 
923 #if defined(_SUNOS_VTOC_16)
924 			vpart->p_start = lpart->p_start;
925 			vpart->p_size = lpart->p_size;
926 #endif	/* defined(_SUNOS_VTOC_16) */
927 		}
928 		(void) memcpy(vtoc->v_volume, label->dkl_vtoc.v_volume,
929 			LEN_DKL_VVOL);
930 		(void) memcpy((char *)vtoc->v_bootinfo,
931 			(char *)label->dkl_vtoc.v_bootinfo,
932 				sizeof (vtoc->v_bootinfo));
933 		(void) memcpy((char *)vtoc->v_reserved,
934 			(char *)label->dkl_vtoc.v_reserved,
935 				sizeof (vtoc->v_reserved));
936 		(void) memcpy((char *)vtoc->timestamp,
937 			(char *)label->dkl_vtoc.v_timestamp,
938 				sizeof (vtoc->timestamp));
939 		break;
940 
941 	default:
942 		return (-1);
943 	}
944 
945 	/*
946 	 * XXX - this looks wrong to me....
947 	 * why are these values hardwired, rather than returned from
948 	 * the real disk label?
949 	 */
950 	vtoc->v_sanity = VTOC_SANE;
951 	vtoc->v_version = V_VERSION;
952 	vtoc->v_sectorsz = DEV_BSIZE;
953 	vtoc->v_nparts = V_NUMPAR;
954 
955 	(void) memcpy(vtoc->v_asciilabel, label->dkl_asciilabel,
956 		LEN_DKL_ASCII);
957 
958 #if defined(_SUNOS_VTOC_8)
959 	/*
960 	 * Convert partitioning information.
961 	 * Note the conversion from starting cylinder number
962 	 * to starting sector number.
963 	 */
964 	lmap = label->dkl_map;
965 	vpart = vtoc->v_part;
966 	nblks = label->dkl_nsect * label->dkl_nhead;
967 	for (i = 0; i < V_NUMPAR; i++, vpart++, lmap++) {
968 		vpart->p_start = lmap->dkl_cylno * nblks;
969 		vpart->p_size = lmap->dkl_nblk;
970 	}
971 #endif			/* defined(_SUNOS_VTOC_8) */
972 
973 	return (0);
974 }
975 
976 /*
977  * Input: File descriptor
978  * Output: 1 if disk is >1TB OR has an EFI label, 0 otherwise.
979  */
980 
981 int
982 is_efi_type(int fd)
983 {
984 	struct vtoc vtoc;
985 
986 	if (ioctl(fd, DKIOCGVTOC, &vtoc) == -1) {
987 		if (errno == ENOTSUP) {
988 			return (1);
989 		}
990 	}
991 	return (0);
992 }
993 
994 /* make sure the user specified something reasonable */
995 void
996 err_check(struct dk_gpt *vtoc)
997 {
998 	int			resv_part = -1;
999 	int			i, j;
1000 	diskaddr_t		istart, jstart, isize, jsize, endsect;
1001 	int			overlap = 0;
1002 
1003 	/*
1004 	 * make sure no partitions overlap
1005 	 */
1006 	for (i = 0; i < vtoc->efi_nparts; i++) {
1007 		/* It can't be unassigned and have an actual size */
1008 		if ((vtoc->efi_parts[i].p_tag == V_UNASSIGNED) &&
1009 		    (vtoc->efi_parts[i].p_size != 0)) {
1010 			(void) fprintf(stderr,
1011 "partition %d is \"unassigned\" but has a size of %llu\n", i,
1012 			vtoc->efi_parts[i].p_size);
1013 		}
1014 		if (vtoc->efi_parts[i].p_tag == V_UNASSIGNED) {
1015 			continue;
1016 		}
1017 		if (vtoc->efi_parts[i].p_tag == V_RESERVED) {
1018 			if (resv_part != -1) {
1019 			    (void) fprintf(stderr,
1020 "found duplicate reserved partition at %d\n",
1021 				i);
1022 			}
1023 			resv_part = i;
1024 			if (vtoc->efi_parts[i].p_size != EFI_MIN_RESV_SIZE)
1025 				(void) fprintf(stderr,
1026 "Warning: reserved partition size must be %d sectors\n",
1027 				EFI_MIN_RESV_SIZE);
1028 		}
1029 		if ((vtoc->efi_parts[i].p_start < vtoc->efi_first_u_lba) ||
1030 		    (vtoc->efi_parts[i].p_start > vtoc->efi_last_u_lba)) {
1031 			(void) fprintf(stderr,
1032 			    "Partition %d starts at %llu\n",
1033 			    i,
1034 			    vtoc->efi_parts[i].p_start);
1035 			(void) fprintf(stderr,
1036 			    "It must be between %llu and %llu.\n",
1037 			    vtoc->efi_first_u_lba,
1038 			    vtoc->efi_last_u_lba);
1039 		}
1040 		if ((vtoc->efi_parts[i].p_start +
1041 		    vtoc->efi_parts[i].p_size <
1042 		    vtoc->efi_first_u_lba) ||
1043 		    (vtoc->efi_parts[i].p_start +
1044 		    vtoc->efi_parts[i].p_size >
1045 		    vtoc->efi_last_u_lba + 1)) {
1046 			(void) fprintf(stderr,
1047 			    "Partition %d ends at %llu\n",
1048 			    i,
1049 			    vtoc->efi_parts[i].p_start +
1050 			    vtoc->efi_parts[i].p_size);
1051 			(void) fprintf(stderr,
1052 			    "It must be between %llu and %llu.\n",
1053 			    vtoc->efi_first_u_lba,
1054 			    vtoc->efi_last_u_lba);
1055 		}
1056 
1057 		for (j = 0; j < vtoc->efi_nparts; j++) {
1058 			isize = vtoc->efi_parts[i].p_size;
1059 			jsize = vtoc->efi_parts[j].p_size;
1060 			istart = vtoc->efi_parts[i].p_start;
1061 			jstart = vtoc->efi_parts[j].p_start;
1062 			if ((i != j) && (isize != 0) && (jsize != 0)) {
1063 				endsect = jstart + jsize -1;
1064 				if ((jstart <= istart) &&
1065 				    (istart <= endsect)) {
1066 					if (!overlap) {
1067 					(void) fprintf(stderr,
1068 "label error: EFI Labels do not support overlapping partitions\n");
1069 					}
1070 					(void) fprintf(stderr,
1071 "Partition %d overlaps partition %d.\n", i, j);
1072 					overlap = 1;
1073 				}
1074 			}
1075 		}
1076 	}
1077 	/* make sure there is a reserved partition */
1078 	if (resv_part == -1) {
1079 		(void) fprintf(stderr,
1080 			"no reserved partition found\n");
1081 	}
1082 }
1083 
1084 #ifdef	FOR_DEBUGGING_ONLY
1085 int
1086 dump_label(label)
1087 	struct dk_label	*label;
1088 {
1089 	int		i;
1090 
1091 	fmt_print("%s\n", label->dkl_asciilabel);
1092 
1093 	fmt_print("version:  %d\n", label->dkl_vtoc.v_version);
1094 	fmt_print("volume:   ");
1095 	for (i = 0; i < LEN_DKL_VVOL; i++) {
1096 		if (label->dkl_vtoc.v_volume[i] == 0)
1097 			break;
1098 		fmt_print("%c", label->dkl_vtoc.v_volume[i]);
1099 	}
1100 	fmt_print("\n");
1101 	fmt_print("v_nparts: %d\n", label->dkl_vtoc.v_nparts);
1102 	fmt_print("v_sanity: %lx\n", label->dkl_vtoc.v_sanity);
1103 
1104 #if defined(_SUNOS_VTOC_8)
1105 	fmt_print("rpm:      %d\n", label->dkl_rpm);
1106 	fmt_print("pcyl:     %d\n", label->dkl_pcyl);
1107 	fmt_print("apc:      %d\n", label->dkl_apc);
1108 	fmt_print("obs1:     %d\n", label->dkl_obs1);
1109 	fmt_print("obs2:     %d\n", label->dkl_obs2);
1110 	fmt_print("intrlv:   %d\n", label->dkl_intrlv);
1111 	fmt_print("ncyl:     %d\n", label->dkl_ncyl);
1112 	fmt_print("acyl:     %d\n", label->dkl_acyl);
1113 	fmt_print("nhead:    %d\n", label->dkl_nhead);
1114 	fmt_print("nsect:    %d\n", label->dkl_nsect);
1115 	fmt_print("obs3:     %d\n", label->dkl_obs3);
1116 	fmt_print("obs4:     %d\n", label->dkl_obs4);
1117 
1118 #elif defined(_SUNOS_VTOC_16)
1119 	fmt_print("rpm:      %d\n", label->dkl_rpm);
1120 	fmt_print("pcyl:     %d\n", label->dkl_pcyl);
1121 	fmt_print("apc:      %d\n", label->dkl_apc);
1122 	fmt_print("intrlv:   %d\n", label->dkl_intrlv);
1123 	fmt_print("ncyl:     %d\n", label->dkl_ncyl);
1124 	fmt_print("acyl:     %d\n", label->dkl_acyl);
1125 	fmt_print("nhead:    %d\n", label->dkl_nhead);
1126 	fmt_print("nsect:    %d\n", label->dkl_nsect);
1127 	fmt_print("bcyl:     %d\n", label->dkl_bcyl);
1128 	fmt_print("skew:     %d\n", label->dkl_skew);
1129 #else
1130 #error No VTOC format defined.
1131 #endif				/* defined(_SUNOS_VTOC_8) */
1132 	fmt_print("magic:    %0x\n", label->dkl_magic);
1133 	fmt_print("cksum:    %0x\n", label->dkl_cksum);
1134 
1135 	for (i = 0; i < NDKMAP; i++) {
1136 
1137 #if defined(_SUNOS_VTOC_8)
1138 		fmt_print("%c:        cyl=%d, blocks=%d", i+'a',
1139 			label->dkl_map[i].dkl_cylno,
1140 			label->dkl_map[i].dkl_nblk);
1141 
1142 #elif defined(_SUNOS_VTOC_16)
1143 		fmt_print("%c:        start=%d, blocks=%d", i+'a',
1144 		    label->dkl_vtoc.v_part[i].p_start,
1145 		    label->dkl_vtoc.v_part[i].p_size);
1146 #else
1147 #error No VTOC format defined.
1148 #endif				/* defined(_SUNOS_VTOC_8) */
1149 
1150 		fmt_print(",  tag=%d,  flag=%d",
1151 			label->dkl_vtoc.v_part[i].p_tag,
1152 			label->dkl_vtoc.v_part[i].p_flag);
1153 		fmt_print("\n");
1154 	}
1155 
1156 	fmt_print("read_reinstruct:  %d\n", label->dkl_read_reinstruct);
1157 	fmt_print("write_reinstruct: %d\n", label->dkl_write_reinstruct);
1158 
1159 	fmt_print("bootinfo: ");
1160 	for (i = 0; i < 3; i++) {
1161 		fmt_print("0x%x ", label->dkl_vtoc.v_bootinfo[i]);
1162 	}
1163 	fmt_print("\n");
1164 
1165 	fmt_print("reserved: ");
1166 	for (i = 0; i < 10; i++) {
1167 		if ((i % 4) == 3)
1168 			fmt_print("\n");
1169 		fmt_print("0x%x ", label->dkl_vtoc.v_reserved[i]);
1170 	}
1171 	fmt_print("\n");
1172 
1173 	fmt_print("timestamp:\n");
1174 	for (i = 0; i < NDKMAP; i++) {
1175 		if ((i % 4) == 3)
1176 			fmt_print("\n");
1177 		fmt_print("0x%x ", label->dkl_vtoc.v_timestamp[i]);
1178 	}
1179 	fmt_print("\n");
1180 
1181 	fmt_print("pad:\n");
1182 	dump("", label->dkl_pad, LEN_DKL_PAD, HEX_ONLY);
1183 
1184 	fmt_print("\n\n");
1185 }
1186 #endif	/* FOR_DEBUGGING_ONLY */
1187