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