label.c revision 3ccda6479cf240cd732ac4b7a8a82fcc1716496d
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* This file contains the code relating to label manipulation.
*/
#include "global.h"
#include "label.h"
#include "misc.h"
#include "main.h"
#include "partition.h"
#include "ctlr_scsi.h"
#include <string.h>
#include <stdlib.h>
#include <memory.h>
#include <sys/isa_defs.h>
#include <sys/efi_partition.h>
#include <errno.h>
#include <devid.h>
#if defined(_FIRMWARE_NEEDS_FDISK)
#include "menu_fdisk.h"
#endif /* defined(_FIRMWARE_NEEDS_FDISK) */
#ifndef WD_NODE
#define WD_NODE 7
#endif
#ifdef __STDC__
/*
* Prototypes for ANSI C compilers
*/
static int do_geometry_sanity_check(void);
extern int write_vtoc(int, struct vtoc *);
#else /* __STDC__ */
/*
* Prototypes for non-ANSI C compilers
*/
static int do_geometry_sanity_check();
static int vtoc_to_label();
extern int read_vtoc();
extern int write_vtoc();
static int vtoc64_to_label();
#endif /* __STDC__ */
/*
* This routine checks the given label to see if it is valid.
*/
int
{
/*
* Check the magic number.
*/
return (0);
/*
* Check the checksum.
*/
return (0);
return (1);
}
/*
* This routine checks or calculates the label checksum, depending on
* the mode it is called in.
*/
int
int mode;
{
/*
* If we are generating a checksum, don't include the checksum
* in the rolling xor.
*/
if (mode == CK_MAKESUM)
count -= 1;
/*
* Take the xor of all the half-words in the label.
*/
while (count--) {
}
/*
* If we are checking the checksum, the total will be zero for
* a correct checksum, so we can just return the sum.
*/
if (mode == CK_CHECKSUM)
return (sum);
/*
* If we are generating the checksum, fill it in.
*/
else {
return (0);
}
}
/*
* This routine is used to extract the id string from the string stored
* in a disk label. The problem is that the string in the label has
* the physical characteristics of the drive appended to it. The approach
* is to find the beginning of the physical attributes portion of the string
* and truncate it there.
*/
int
char *id;
{
register char *c;
/*
* Start at the end of the string. When we match the word ' cyl',
* we are at the beginning of the attributes.
*/
/*
* Remove any white space.
*/
for (; (((*(c - 1) == ' ') || (*(c - 1) == '\t')) &&
(c >= id)); c--);
break;
}
}
/*
* If we ran off the beginning of the string, something is wrong.
*/
if (c < id)
return (-1);
/*
* Truncate the string.
*/
*c = '\0';
return (0);
}
/*
* This routine is used by write_label() to do a quick sanity check on the
* supplied geometry. This is not a thorough check.
*
* The SCSI READ_CAPACITY command is used here to get the capacity of the
* disk. But, the available area to store data on a disk is usually less
* than this. So, if the specified geometry evaluates to a value which falls
* in this margin, then such illegal geometries can slip through the cracks.
*/
static int
{
struct scsi_capacity_16 capacity;
err_print("Warning: Unable to get capacity."
" Cannot check geometry\n");
return (0); /* Just ignore this problem */
}
err_print("\nWarning: Current geometry overshoots "
"actual geometry of disk\n\n");
if (check("Continue labelling disk") != 0)
return (-1);
return (0); /* Just ignore this problem */
}
return (0);
}
/*
* expand the internal 32-bit SMI VTOC into the 64-bit EFI version
* for writing it out to the disk
*/
int
{
int i, j;
int vtoc_part_count = 0;
int highest_assigned_part = 0;
int last_par = 0;
int compact = 0;
struct vtoc old_vtoc_copy;
err_print("SMI vtoc to EFI failed\n");
return (-1);
}
/*
* Prepare old VTOC table for transfer by ensuring the
* tags are set correctly. Also collect information
* about the old VTOC table including the number of
* valid VTOC partitions and the highest VTOC partition
* in use. An EFI label provides fewer partitions, so
* it is possible that the VTOC partitions cannot all be
* transferred.
*/
for (i = 0; i < V_NUMPAR; i++) {
/*
* we may be carrying around old tags from the
* default partition table. If the partition
* is really unassigned, set the tag correctly
*/
/*
* Likewise, if the partition is not empty, don't
* write it out as "unassigned."
*/
}
last_par = i;
}
V_UNASSIGNED)) {
}
/* Update count of valid VTOC partitions */
/* Note the highest valid VTOC slice */
}
}
/* Too many partitions to convert the VTOC label */
err_print("partitions and an EFI label\n");
if (check("Continue anyway") != 0) {
/* If no, restore VTOC and return an error */
return (-1);
}
}
/*
* Partition indexes cannot be transferred directly since
* the highest valid VTOC index is higher than the highest
* available EFI partition. Ask the user if it is OK to
* move the partitions to available slots
*/
err_print("VTOC partition %d is defined ",
err_print("and the highest available EFI\n");
err_print("partition is %d. The partitions\n",
err_print("will fit if they are re-numbered\n");
if (check("OK to renumber") != 0) {
/* If no, restore VTOC and return an error */
return (-1);
} else {
compact = 1;
}
}
/*
* Now copy the VTOC partitions, remapping the indices if
* necessary.
*/
j = 0;
for (i = 0; i < V_NUMPAR; i++) {
/* Copy partition info */
last_par = j;
j++; /* Increment EFI index */
} else {
if (!compact) {
j++; /* Increment EFI index */
}
}
}
}
return (0);
}
/*
* This routine constructs and writes a label on the disk. It writes both
* the primary and backup labels. It assumes that there is a current
* partition map already defined. It also notifies the SunOS kernel of
* the label and partition information it has written on the disk.
*/
int
{
int nbackups;
#if defined(_SUNOS_VTOC_8)
int i;
#endif /* defined(_SUNOS_VTOC_8) */
/*
* If EFI label, then write it out to disk
*/
if (cur_label == L_TYPE_EFI) {
err_print("Warning: error writing EFI.\n");
error = -1;
}
return (error);
}
/*
* Fill in a label structure with the geometry information.
*/
#if defined(_SUNOS_VTOC_16)
#endif /* defined(_SUNOC_VTOC_16) */
#if defined(_SUNOS_VTOC_8)
/*
* Also fill in the current partition information.
*/
for (i = 0; i < NDKMAP; i++) {
}
#endif /* defined(_SUNOS_VTOC_8) */
/*
* Fill in the vtoc information
*/
/*
* Use the current label
*/
/*
* Put asciilabel in; on x86 it's in the vtoc, not the label.
*/
"%s cyl %d alt %d hd %d sec %d",
#if defined(_SUNOS_VTOC_16)
/*
* Also add in v_sectorsz, as the driver will. Everyone
* else is assuming DEV_BSIZE, so we do the same.
*/
#endif /* defined(_SUNOS_VTOC_16) */
/*
* Generate the correct checksum.
*/
/*
* Convert the label into a vtoc
*/
return (-1);
}
/*
* Fill in the geometry info. This is critical that
* we do this before writing the vtoc.
*/
#if defined(_SUNOS_VTOC_16)
#endif /* defined(_SUNOS_VTOC_16) */
/*
* Make a quick check to see that the geometry is being
* written now is not way off from the actual capacity
* of the disk. This is only an appoximate check and
* is only for SCSI disks.
*/
if (SCSI && do_geometry_sanity_check() != 0) {
return (-1);
}
/*
* Lock out interrupts so we do things in sync.
*/
/*
* Do the ioctl to tell the kernel the geometry.
*/
err_print("Warning: error setting drive geometry.\n");
error = -1;
}
/*
* Write the vtoc. At the time of this writing, our
* drivers convert the vtoc back to a label, and
* then write both the primary and backup labels.
* This is not a requirement, however, as we
* always use an ioctl to read the vtoc from the
* driver, so it can do as it likes.
*/
err_print("Warning: error writing VTOC.\n");
error = -1;
}
/*
* Calculate where the backup labels went. They are always on
* the last alternate cylinder, but some older drives put them
* on head 2 instead of the last head. They are always on the
* first 5 odd sectors of the appropriate track.
*/
head = 2;
else
/*
* Read and verify the backup labels.
*/
nbackups = 0;
sec += 2) {
err_print("Warning: error reading backup label.\n");
error = -1;
} else {
sizeof (struct dk_label)) == 0) {
nbackups++;
}
}
}
if (nbackups != BAD_LISTCNT) {
"no backup labels" :
"some backup labels incorrect");
}
/*
* Mark the current disk as labelled and notify the kernel of what
* has happened.
*/
return (error);
}
/*
* Read the label from the disk.
* Do this via the read_vtoc() library routine, then convert it to a label.
* We also need a DKIOCGGEOM ioctl to get the disk's geometry.
*/
int
{
return (-1);
}
}
int
{
char *s;
int n;
if (option_msg && diag_msg)
err_print("devid_get failed\n");
return (-1);
}
n = devid_sizeof(devid);
s = (char *)devid;
if (option_msg && diag_msg)
err_print("DKIOCINFO failed\n");
return (-1);
}
return (-1);
vid = s+12;
return (-1);
pid += 1;
if (nvid > 9)
nvid = 9;
if (npid > 17) {
npid = 17;
}
return (-1);
}
return (0);
}
/*
* Issue uscsi_inquiry and read_capacity commands to
* retrieve the disk's Vendor, Product, Revision and
* Capacity information.
*/
int
{
struct scsi_inquiry inquiry;
struct scsi_capacity_16 capacity;
return (0);
return (-1);
}
return (-1);
}
/* Since we are counting from zero, add 1 to capacity */
return (0);
}
int
{
/* This could fail if there is no label already */
return (-1);
}
err_print("vtoc64_to_label failed\n");
return (-1);
}
return (-1);
}
return (0);
}
/*
* We've read a 64-bit label which has no geometry information. Use
* some heuristics to fake up a geometry that would match the disk in
* order to make the rest of format(1M) happy.
*/
static int
{
int i, nparts = 0;
/* XXX do a sanity check here for nparts */
err_print("vtoc64_to_label: unable to allocate lmap\n");
fullabort();
}
/*
* Copy necessary portions
* XXX Maybe we can use memcpy() ??
*/
for (i = 0; i < nparts; i++) {
sizeof (struct uuid));
}
}
return (0);
}
/*
*/
static int
{
#if defined(_SUNOS_VTOC_8)
#elif defined(_SUNOS_VTOC_16)
struct dkl_partition *lmap;
#else
#endif /* defined(_SUNOS_VTOC_8) */
long nblks;
int i;
/*
* Sanity-check the vtoc
*/
return (-1);
}
/*
* Sanity check of geometry
*/
return (-1);
}
/*
* Copy necessary portions of the geometry information
*/
#if defined(_SUNOS_VTOC_16)
#endif /* defined(_SUNOS_VTOC_16) */
#if defined(_SUNOS_VTOC_8)
#endif /* defined(_SUNOS_VTOC_8) */
/*
* Copy vtoc structure fields into the disk label dk_vtoc
*/
for (i = 0; i < V_NUMPAR; i++) {
}
/*
* Note the conversion from starting sector number
* to starting cylinder number.
* Return error if division results in a remainder.
*/
#if defined(_SUNOS_VTOC_8)
#elif defined(_SUNOS_VTOC_16)
#else
#endif /* defined(_SUNOS_VTOC_8) */
return (-1);
}
#if defined(_SUNOS_VTOC_8)
#elif defined(_SUNOS_VTOC_16)
#else
#endif /* defined(_SUNOS_VTOC_8) */
}
/*
* Finally, make a checksum
*/
return (0);
}
/*
* Extract a vtoc structure out of a valid label
*/
int
{
#if defined(_SUNOS_VTOC_8)
long nblks;
#elif defined(_SUNOS_VTOC_16)
struct dkl_partition *lpart;
#else
#endif /* defined(_SUNOS_VTOC_8) */
int i;
case 0:
/*
* No valid vtoc information in the label.
* Construct default p_flags and p_tags.
*/
}
break;
case V_VERSION:
#if defined(_SUNOS_VTOC_16)
#endif /* defined(_SUNOS_VTOC_16) */
}
sizeof (vtoc->v_bootinfo));
sizeof (vtoc->v_reserved));
break;
default:
return (-1);
}
/*
* XXX - this looks wrong to me....
* why are these values hardwired, rather than returned from
* the real disk label?
*/
#if defined(_SUNOS_VTOC_8)
/*
* Convert partitioning information.
* Note the conversion from starting cylinder number
* to starting sector number.
*/
}
#endif /* defined(_SUNOS_VTOC_8) */
return (0);
}
/*
* Input: File descriptor
* Output: 1 if disk is >1TB OR has an EFI label, 0 otherwise.
*/
int
is_efi_type(int fd)
{
return (1);
}
}
return (0);
}
/* make sure the user specified something reasonable */
void
{
int resv_part = -1;
int i, j;
int overlap = 0;
/*
* make sure no partitions overlap
*/
for (i = 0; i < vtoc->efi_nparts; i++) {
/* It can't be unassigned and have an actual size */
"partition %d is \"unassigned\" but has a size of %llu\n", i,
}
continue;
}
if (resv_part != -1) {
"found duplicate reserved partition at %d\n",
i);
}
resv_part = i;
"Warning: reserved partition size must be %d sectors\n",
}
"Partition %d starts at %llu\n",
i,
"It must be between %llu and %llu.\n",
}
vtoc->efi_first_u_lba) ||
"Partition %d ends at %llu\n",
i,
"It must be between %llu and %llu.\n",
}
for (j = 0; j < vtoc->efi_nparts; j++) {
if (!overlap) {
"label error: EFI Labels do not support overlapping partitions\n");
}
"Partition %d overlaps partition %d.\n", i, j);
overlap = 1;
}
}
}
}
/* make sure there is a reserved partition */
if (resv_part == -1) {
"no reserved partition found\n");
}
}
#ifdef FOR_DEBUGGING_ONLY
int
{
int i;
fmt_print("volume: ");
for (i = 0; i < LEN_DKL_VVOL; i++) {
break;
}
fmt_print("\n");
#if defined(_SUNOS_VTOC_8)
#elif defined(_SUNOS_VTOC_16)
#else
#endif /* defined(_SUNOS_VTOC_8) */
for (i = 0; i < NDKMAP; i++) {
#if defined(_SUNOS_VTOC_8)
#elif defined(_SUNOS_VTOC_16)
#else
#endif /* defined(_SUNOS_VTOC_8) */
fmt_print(", tag=%d, flag=%d",
fmt_print("\n");
}
fmt_print("bootinfo: ");
for (i = 0; i < 3; i++) {
}
fmt_print("\n");
fmt_print("reserved: ");
for (i = 0; i < 10; i++) {
if ((i % 4) == 3)
fmt_print("\n");
}
fmt_print("\n");
fmt_print("timestamp:\n");
for (i = 0; i < NDKMAP; i++) {
if ((i % 4) == 3)
fmt_print("\n");
}
fmt_print("\n");
fmt_print("pad:\n");
fmt_print("\n\n");
}
#endif /* FOR_DEBUGGING_ONLY */