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 */
25
26 /*
27 * This file contains the code relating to label manipulation.
28 */
29
30 #include <string.h>
31 #include <stdlib.h>
32 #include <memory.h>
33 #include <sys/isa_defs.h>
34 #include <sys/efi_partition.h>
35 #include <sys/vtoc.h>
36 #include <sys/uuid.h>
37 #include <errno.h>
38 #include <devid.h>
39 #include "global.h"
40 #include "label.h"
41 #include "misc.h"
42 #include "main.h"
43 #include "partition.h"
44 #include "ctlr_scsi.h"
45 #include "checkdev.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
checklabel(label)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
checksum(label,mode)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
trim_id(id)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
do_geometry_sanity_check()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
SMI_vtoc_to_EFI(int fd,struct dk_gpt ** new_vtoc)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
write_label()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
read_label(int fd,struct dk_label * label)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
get_disk_info_from_devid(int fd,struct efi_info * label)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
get_disk_info(int fd,struct efi_info * label)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
read_efi_label(int fd,struct efi_info * label)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
vtoc64_to_label(struct efi_info * label,struct dk_gpt * vtoc)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
vtoc_to_label(struct dk_label * label,struct extvtoc * vtoc,struct dk_geom * geom,struct dk_cinfo * cinfo)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
label_to_vtoc(struct extvtoc * vtoc,struct dk_label * label)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
is_efi_type(int fd)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
err_check(struct dk_gpt * vtoc)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
dump_label(label)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