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