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