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
58static int	do_geometry_sanity_check(void);
59static int	vtoc_to_label(struct dk_label *, struct extvtoc *,
60		struct dk_geom *, struct dk_cinfo *);
61extern int	read_extvtoc(int, struct extvtoc *);
62extern int	write_extvtoc(int, struct extvtoc *);
63static int	vtoc64_to_label(struct efi_info *, struct dk_gpt *);
64
65#ifdef	DEBUG
66static void dump_label(struct dk_label *);
67#endif
68
69/*
70 * This routine checks the given label to see if it is valid.
71 */
72int
73checklabel(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 */
93int
94checksum(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 */
134int
135trim_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 */
175static int
176do_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 */
201int
202SMI_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 */
252int
253write_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 */
466int
467read_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
482int
483get_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
519out:
520	di_fini(node);
521	return (ret);
522}
523
524int
525get_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
546int
547get_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
570int
571get_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 */
620int
621get_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
649int
650read_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 */
675static int
676vtoc64_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 */
728static int
729vtoc_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 */
874int
875label_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
970int
971is_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
983static void
984dump_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