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