cmlb.c revision e8fb11a1575b42dcd5c49341c588d9f6cd636135
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (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 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* This module provides support for labeling operations for target
* drivers.
*/
#include <sys/efi_partition.h>
#include <sys/cmlb_impl.h>
/*
* Driver minor node structure and data table
*/
struct driver_minor_data {
char *name;
int type;
};
static struct driver_minor_data dk_minor_data[] = {
{"a", 0, S_IFBLK},
#if defined(_SUNOS_VTOC_16)
#endif /* defined(_SUNOS_VTOC_16) */
#if defined(_FIRMWARE_NEEDS_FDISK)
#endif /* defined(_FIRMWARE_NEEDS_FDISK) */
{"a,raw", 0, S_IFCHR},
#if defined(_SUNOS_VTOC_16)
#endif /* defined(_SUNOS_VTOC_16) */
#if defined(_FIRMWARE_NEEDS_FDISK)
#endif /* defined(_FIRMWARE_NEEDS_FDISK) */
{0}
};
static struct driver_minor_data dk_minor_data_efi[] = {
{"a", 0, S_IFBLK},
#if defined(_FIRMWARE_NEEDS_FDISK)
#endif /* defined(_FIRMWARE_NEEDS_FDISK) */
{"a,raw", 0, S_IFCHR},
#if defined(_FIRMWARE_NEEDS_FDISK)
#endif /* defined(_FIRMWARE_NEEDS_FDISK) */
{0}
};
extern struct mod_ops mod_miscops;
/*
* Global buffer and mutex for debug logging
*/
static char cmlb_log_buffer[1024];
static kmutex_t cmlb_log_mutex;
&mod_miscops, /* Type of module */
"Common Labeling module %I%"
};
static struct modlinkage modlinkage = {
};
/* Local function prototypes */
void *tg_cookie);
void *tg_cookie);
static void cmlb_swap_efi_gpt(efi_gpt_t *e);
void *tg_cookie);
#if defined(_SUNOS_VTOC_8)
#endif
void *tg_cookie);
#endif
#if defined(_FIRMWARE_NEEDS_FDISK)
#endif
#if defined(_SUNOS_VTOC_16)
#endif
void *tg_cookie);
void *tg_cookie);
void *tg_cookie);
void *tg_cookie);
void *tg_cookie);
void *tg_cookie);
void *tg_cookie);
int flag);
#endif
const char *fmt, ...);
int
_init(void)
{
return (mod_install(&modlinkage));
}
int
{
}
int
_fini(void)
{
int err;
return (err);
}
return (err);
}
/*
* cmlb_dbg is used for debugging to log additional info
* Level of output is controlled via cmlb_level_mask setting.
*/
static void
{
uint_t level_mask = 0;
/*
* Filter messages based on the global component and level masks,
* also print if cl matches the value of cmlb_debug_cl, or if
* cmlb_debug_cl is set to NULL.
*/
if (comp & CMLB_TRACE)
if (comp & CMLB_ERROR)
if ((cmlb_level_mask & level_mask) &&
}
}
/*
* cmlb_log is basically a duplicate of scsi_log. It is redefined here
* so that this module does not depend on scsi module.
*/
static void
{
}
static void
{
static char name[256];
int log_only = 0;
int boot_only = 0;
int console_only = 0;
if (dev) {
} else {
name[0] = '\0';
}
} else {
}
switch (cmlb_log_buffer[0]) {
case '!':
log_only = 1;
break;
case '?':
boot_only = 1;
break;
case '^':
console_only = 1;
break;
}
switch (level) {
case CE_NOTE:
/* FALLTHROUGH */
case CE_CONT:
case CE_WARN:
case CE_PANIC:
if (boot_only) {
} else if (console_only) {
} else if (log_only) {
} else {
}
break;
case CE_IGNORE:
break;
default:
break;
}
}
/*
* cmlb_alloc_handle:
*
* Allocates a handle.
*
* Arguments:
* cmlbhandlep pointer to handle
*
* Notes:
* Allocates a handle and stores the allocated handle in the area
* pointed to by cmlbhandlep
*
* Context:
* Kernel thread only (can sleep).
*/
void
{
}
/*
* cmlb_free_handle
*
* Frees handle.
*
* Arguments:
* cmlbhandlep pointer to handle
*/
void
{
}
}
/*
* cmlb_attach:
*
* Attach handle to device, create minor nodes for device.
*
* Arguments:
* devi pointer to device's dev_info structure.
* tgopsp pointer to array of functions cmlb can use to callback
* to target driver.
*
* device_type Peripheral device type as defined in
*
* is_removable whether or not device is removable.
* 0 non-removable, 1 removable.
*
* is_hotpluggable whether or not device is hotpluggable.
* 0 non-hotpluggable, 1 hotpluggable.
*
* node_type minor node type (as used by ddi_create_minor_node)
*
* alter_behavior
* bit flags:
*
* CMLB_CREATE_ALTSLICE_VTOC_16_DTYPE_DIRECT: create
* an alternate slice for the default label, if
* device type is DTYPE_DIRECT an architectures default
* label type is VTOC16.
* Otherwise alternate slice will no be created.
*
*
* CMLB_FAKE_GEOM_LABEL_IOCTLS_VTOC8: report a default
* geometry and label for DKIOCGGEOM and DKIOCGVTOC
* on architecture with VTOC8 label types.
*
* CMLB_OFF_BY_ONE: do the workaround for legacy off-by-
* one bug in obtaining capacity (in sd):
* SCSI READ_CAPACITY command returns the LBA number of the
* last logical block, but sd once treated this number as
* disks' capacity on x86 platform. And LBAs are addressed
* based 0. So the last block was lost on x86 platform.
*
* Now, we remove this workaround. In order for present sd
* driver to work with disks which are labeled/partitioned
* via previous sd, we add workaround as follows:
*
* 1) Locate backup EFI label: cmlb searches the next to
* last
* block for backup EFI label. If fails, it will
* turn to the last block for backup EFI label;
*
* 2) Clear backup EFI label: cmlb first search the last
* block for backup EFI label, and will search the
* next to last block only if failed for the last
* block.
*
* 3) Calculate geometry:refer to cmlb_convert_geometry()
* If capacity increasing by 1 causes disks' capacity
* to cross over the limits in table CHS_values,
* geometry info will change. This will raise an issue:
* In case that primary VTOC label is destroyed, format
* commandline can restore it via backup VTOC labels.
* And format locates backup VTOC labels by use of
* geometry. So changing geometry will
* prevent format from finding backup VTOC labels. To
* eliminate this side effect for compatibility,
* sd uses (capacity -1) to calculate geometry;
*
* 4) 1TB disks: some important data structures use
* so that sd doesn't support a disk with capacity
* larger than 1TB on 32-bit platform. However,
* for exactly 1TB disk, it was treated as (1T - 512)B
* in the past, and could have valid Solaris
* partitions. To workaround this, if an exactly 1TB
* disk has Solaris fdisk partition, it will be allowed
* to work with sd.
*
*
*
* cmlbhandle cmlb handle associated with device
*
* tg_cookie cookie from target driver to be passed back to target
* driver when we call back to it through tg_ops.
*
* Notes:
* Assumes a default label based on capacity for non-removable devices.
* If capacity > 1TB, EFI is assumed otherwise VTOC (default VTOC
* for the architecture).
*
* For removable devices, default label type is assumed to be VTOC
* type. Create minor nodes based on a default label type.
* Label on the media is not validated.
* minor number consists of:
* if _SUNOS_VTOC_8 is defined
* lowest 3 bits is taken as partition number
* the rest is instance number
* if _SUNOS_VTOC_16 is defined
* lowest 6 bits is taken as partition number
* the rest is instance number
*
*
* Return values:
* 0 Success
* ENXIO creating minor nodes failed.
* EINVAL invalid arg, unsupported tg_ops version
*/
int
{
int status;
return (EINVAL);
if (is_removable != 0) {
/* set default EFI if > 1TB */
}
}
/* create minor nodes based on default label type */
if (cmlb_create_minor_nodes(cl) != 0) {
return (ENXIO);
}
return (0);
}
/*
* cmlb_detach:
*
* Invalidate in-core labeling data and remove all minor nodes for
* the device associate with handle.
*
* Arguments:
* cmlbhandle cmlb handle associated with device.
*
* tg_cookie cookie from target driver to be passed back to target
* driver when we call back to it through tg_ops.
*
*/
/*ARGSUSED1*/
void
{
}
/*
* cmlb_validate:
*
* Validates label.
*
* Arguments
* cmlbhandle cmlb handle associated with device.
*
* flags operation flags. used for verbosity control
*
* tg_cookie cookie from target driver to be passed back to target
* driver when we call back to it through tg_ops.
*
*
* Notes:
* If new label type is different from the current, adjust minor nodes
* accordingly.
*
* Return values:
* 0 success
* Note: having fdisk but no solaris partition is assumed
* success.
*
* ENOMEM memory allocation failed
* EIO i/o errors during read or get capacity
* EACCESS reservation conflicts
* EINVAL label was corrupt, or no default label was assumed
* ENXIO invalid handle
*/
int
{
int rval;
int ret = 0;
/*
* Temp work-around checking cl for NULL since there is a bug
* in sd_detach calling this routine from taskq_dispatch
* inited function.
*/
return (ENXIO);
return (ENXIO);
}
ret = 0;
} else {
}
} else {
if (ret == 0)
}
if (ret == 0)
(void) cmlb_create_minor_nodes(cl);
return (ret);
}
/*
* cmlb_invalidate:
* Invalidate in core label data
*
* Arguments:
* cmlbhandle cmlb handle associated with device.
* tg_cookie cookie from target driver to be passed back to target
* driver when we call back to it through tg_ops.
*/
/*ARGSUSED1*/
void
{
return;
}
/*
* cmlb_is_valid
*
* Arguments:
* cmlbhandle cmlb handle associated with device.
*
* Return values:
* FALSE otherwise.
*
*/
int
{
if (cmlbhandle == NULL)
return (FALSE);
return (cl->cl_f_geometry_is_valid);
}
/*
* cmlb_close:
*
* Close the device, revert to a default label minor node for the device,
* if it is removable.
*
* Arguments:
* cmlbhandle cmlb handle associated with device.
*
* tg_cookie cookie from target driver to be passed back to target
* driver when we call back to it through tg_ops.
* Return values:
* 0 Success
* ENXIO Re-creating minor node failed.
*/
/*ARGSUSED1*/
int
{
/* revert to default minor node for this device */
if (ISREMOVABLE(cl)) {
(void) cmlb_create_minor_nodes(cl);
}
return (0);
}
/*
* cmlb_get_devid_block:
* get the block number where device id is stored.
*
* Arguments:
* cmlbhandle cmlb handle associated with device.
* devidblockp pointer to block number.
* tg_cookie cookie from target driver to be passed back to target
* driver when we call back to it through tg_ops.
*
* Notes:
* It stores the block number of device id in the area pointed to
* by devidblockp.
* with the block number of device id.
*
* Return values:
* 0 success
* EINVAL device id does not apply to current label type.
*/
/*ARGSUSED2*/
int
void *tg_cookie)
{
return (EINVAL);
}
return (EINVAL);
}
} else {
return (EINVAL);
}
} else {
/* this geometry doesn't allow us to write a devid */
return (EINVAL);
}
/*
* Subtract 2 guarantees that the next to last cylinder
* is used
*/
}
*devidblockp = blk;
return (0);
}
/*
* cmlb_partinfo:
* Get partition info for specified partition number.
*
* Arguments:
* cmlbhandle cmlb handle associated with device.
* part partition number
* nblocksp pointer to number of blocks
* startblockp pointer to starting block
* partnamep pointer to name of partition
* tagp pointer to tag info
* tg_cookie cookie from target driver to be passed back to target
* driver when we call back to it through tg_ops.
*
*
* Notes:
* If in-core label is not valid, this functions tries to revalidate
* the label. If label is valid, it stores the total number of blocks
* in this partition in the area pointed to by nblocksp, starting
* block number in area pointed to by startblockp, pointer to partition
* name in area pointed to by partnamep, and tag value in area
* pointed by tagp.
* For EFI labels, tag value will be set to 0.
*
* For all nblocksp, startblockp and partnamep, tagp, a value of NULL
* indicates the corresponding info is not requested.
*
*
* Return values:
* 0 success
* EINVAL no valid label or requested partition number is invalid.
*
*/
int
{
int rval;
return (EINVAL);
}
} else {
0, tg_cookie);
} else {
if (startblockp != NULL)
*nblocksp = (diskaddr_t)
*tagp = V_UNASSIGNED;
else
rval = 0;
}
/* consistent with behavior of sd for getting minor name */
}
return (rval);
}
/* Caller should make sure Test Unit Ready succeeds before calling this. */
/*ARGSUSED*/
int
{
int err;
int status;
return (EIO);
}
switch (cmd) {
case DKIOCSVTOC:
case DKIOCSGEOM:
case DKIOCSETEFI:
case DKIOCSMBOOT:
break;
default:
/*
* fail if > 1TB disk and there is not already a VTOC
* on the disk.i.e either EFI or blank
*
* PHYGEOM AND VIRTGEOM succeeds when disk is
* EFI labeled but <1TB
*/
switch (cmd) {
case DKIOCGAPART:
case DKIOCGGEOM:
case DKIOCGVTOC:
case DKIOCSAPART:
case DKIOCG_PHYGEOM:
case DKIOCG_VIRTGEOM:
return (ENOTSUP);
}
} else {
(cl->cl_solaris_size > 0)) {
/*
* it is EFI, so return ENOTSUP for
* these
*/
switch (cmd) {
case DKIOCGAPART:
case DKIOCGGEOM:
case DKIOCGVTOC:
case DKIOCSVTOC:
case DKIOCSAPART:
return (ENOTSUP);
}
}
}
}
}
switch (cmd) {
case DKIOCGGEOM:
break;
case DKIOCSGEOM:
break;
case DKIOCGAPART:
break;
case DKIOCSAPART:
break;
case DKIOCGVTOC:
break;
case DKIOCGETEFI:
break;
case DKIOCPARTITION:
break;
case DKIOCSVTOC:
break;
case DKIOCSETEFI:
break;
case DKIOCGMBOOT:
break;
case DKIOCSMBOOT:
break;
case DKIOCG_PHYGEOM:
#else
#endif
break;
case DKIOCG_VIRTGEOM:
#else
#endif
break;
case DKIOCPARTINFO:
#else
#endif
break;
default:
}
return (err);
}
{
}
/*
* Function: cmlb_check_update_blockcount
*
* Description: If current capacity value is invalid, obtains the
* current capacity from target driver.
*
* Return Code: 0 success
* EIO failure
*/
static int
{
int status;
if (status != 0) {
return (EIO);
}
if (status != 0)
return (EIO);
return (0);
} else
return (EIO);
} else
return (0);
}
/*
* Function: cmlb_create_minor_nodes
*
* Description: Create or adjust the minor device nodes for the instance.
* Minor nodes are created based on default label type,
* current label type and last label type we created
* minor nodes based on.
*
*
* Arguments: cl - driver soft state (unit) structure
*
* Return Code: 0 success
* ENXIO failure.
*
* Context: Kernel thread context
*/
static int
{
struct driver_minor_data *dmdp;
int instance;
char name[48];
/* check the most common case */
/* do nothing */
return (0);
}
/* we should never get here */
return (ENXIO);
}
/* first time during attach */
/* Create all the minor nodes for this target. */
/*
* Clean up any nodes that may have been
* created, in case this fails in the middle
* of the loop.
*/
return (ENXIO);
}
dmdp++;
}
return (0);
}
/* Not first time */
/* close time, revert to default. */
} else {
/*
* do nothing since the type for which we last created
* nodes matches the default
*/
return (0);
}
} else {
/* We are not closing, use current label type */
} else {
/*
* do nothing since the type for which we last created
* nodes matches the current label type
*/
return (0);
}
}
/*
* Currently we only fix up the s7 node when we are switching
* label types from or to EFI. This is consistent with
* current behavior of sd.
*/
if (newlabeltype == CMLB_LABEL_EFI &&
/* from vtoc to EFI */
} else {
/* from efi to vtoc */
}
return (0);
}
/*
* Function: cmlb_validate_geometry
*
* Description: Read the label from the disk (if present). Update the unit's
* geometry and vtoc information from the data in the label.
* Verify that the label is valid.
*
* Arguments:
* cl driver soft state (unit) structure
*
* forcerevalid force revalidation even if we are already valid.
* flags operation flags from target driver. Used for verbosity
* control at this time.
* tg_cookie cookie from target driver to be passed back to target
* driver when we call back to it through tg_ops.
*
* Return Code: 0 - Successful completion
* EINVAL - Invalid value in cl->cl_tgt_blocksize or
* cl->cl_blockcount; or label on disk is corrupted
* or unreadable.
* EACCES - Reservation conflict at the device.
* ENOMEM - Resource allocation error
* ENOTSUP - geometry not applicable
*
* Context: Kernel thread only (can sleep).
*/
static int
void *tg_cookie)
{
int label_error = 0;
int count;
int forced_under_1t = 0;
#endif
return (ENOTSUP);
return (0);
}
return (EIO);
#if defined(_SUNOS_VTOC_16)
/*
* Set up the "whole disk" fdisk partition; this should always
* exist, regardless of whether the disk contains an fdisk table
* or vtoc.
*/
/*
* note if capacity > uint32_max we should be using efi,
* and not use p0, so the truncation does not matter.
*/
#endif
/*
* Refresh the logical and physical geometry caches.
* and scsi_ifgetcap("geometry").
*/
if (label_error == 0) {
/* found a valid EFI label */
"cmlb_validate_geometry: found EFI label\n");
/*
* solaris_size and geometry_is_valid are set in
* cmlb_use_efi
*/
return (ENOTSUP);
}
/* NO EFI label found */
if (capacity > DK_MAX_BLOCKS) {
if (label_error == ESRCH) {
/*
* they've configured a LUN over 1TB, but used
* format.dat to restrict format's view of the
* capacity to be under 1TB
*/
/* i.e > 1Tb with a VTOC < 1TB */
if (!(flags & CMLB_SILENT)) {
CE_WARN, "is >1TB and has a VTOC label: "
"use format(1M) to either decrease the");
CE_NOTE, "size to be < 1TB or relabel the "
"disk with an EFI label");
forced_under_1t = 1;
#endif
}
} else {
/* unlabeled disk over 1TB */
/*
* Refer to comments on off-by-1 at the head of the file
* A 1TB disk was treated as (1T - 512)B in the past,
* thus, it might have valid solaris partition. We
* will return ENOTSUP later only if this disk has no
* valid solaris partition.
*/
#endif
return (ENOTSUP);
}
}
label_error = 0;
/*
* at this point it is either labeled with a VTOC or it is
* under 1TB (<= 1TB actually for off-by-1)
*/
/*
* Only DIRECT ACCESS devices will have Scl labels.
* CD's supposedly have a Scl label, too
*/
int rval;
/*
* Note: This will set up cl->cl_solaris_size and
* cl->cl_solaris_offset.
*/
return (rval);
}
/*
* Refer to comments on off-by-1 at the head of the file
* This is for 1TB disk only. Since that there is no
* solaris partitions, return ENOTSUP as we do for
* >1TB disk.
*/
return (ENOTSUP);
#endif
/*
* Found fdisk table but no Solaris partition entry,
* so don't call cmlb_uselabel() and don't create
* a default label.
*/
label_error = 0;
goto no_solaris_partition;
}
/*
* Refer to comments on off-by-1 at the head of the file
* Now, this 1TB disk has valid solaris partition. It
* must be created by previous sd driver, we have to
* treat it as (1T-512)B.
*/
(forced_under_1t != 1)) {
/*
* Refer to cmlb_read_fdisk, when there is no
* fdisk partition table, cl_solaris_size is
* set to disk's capacity. In this case, we
* need to adjust it
*/
}
#endif
buffer_size = sizeof (struct dk_label);
"label_addr: 0x%x allocation size: 0x%x\n",
return (ENOMEM);
switch (rval) {
case 0:
/*
* cmlb_uselabel will establish that the geometry
* is valid.
*/
if (cmlb_uselabel(cl,
} else
break;
case EACCES:
break;
default:
break;
}
}
/*
* If a valid label was not found, AND if no reservation conflict
* was detected, then go ahead and create a default label (4069506).
*
* Note: currently, for VTOC_8 devices, the default label is created
* for removables and hotpluggables only. For VTOC_16 devices, the
* default label will be created for all devices.
* (see cmlb_build_default_label)
*/
#if defined(_SUNOS_VTOC_8)
(label_error != EACCES)) {
#elif defined(_SUNOS_VTOC_16)
if (label_error != EACCES) {
#endif
}
label_error = 0;
}
#if defined(_SUNOS_VTOC_16)
/*
* If we have valid geometry, set up the remaining fdisk partitions.
* Note that dkl_cylno is not used for the fdisk map entries, so
* we set it to an entirely bogus value.
*/
}
#endif
#if defined(_SUNOS_VTOC_8)
#elif defined(_SUNOS_VTOC_16)
#else
#error "No VTOC format defined."
#endif
}
return (label_error);
}
#if defined(_SUNOS_VTOC_16)
/*
* Macro: MAX_BLKS
*
* This macro is used for table entries where we need to have the largest
* possible sector value for that head & SPT (sectors per track)
* combination. Other entries for some smaller disk sizes are set by
* convention to match those used by X86 BIOS usage.
*/
/*
* Function: cmlb_convert_geometry
*
* Description: Convert physical geometry into a dk_geom structure. In
* other words, make sure we don't wrap 16-bit values.
* e.g. converting from geom_cache to dk_geom
*
* Context: Kernel thread only
*/
static void
{
int i;
static const struct chs_values {
} CHS_values[] = {
{0x00200000, 64, 32}, /* 1GB or smaller disk. */
{0x01000000, 128, 32}, /* 8GB or smaller disk. */
};
/* Unlabeled SCSI floppy device */
if (capacity <= 0x1000) {
return;
}
/*
* For all devices we calculate cylinders using the
* heads and sectors we assign based on capacity of the
* device. The table is designed to be compatible with the
* way other operating systems lay out fdisk tables for X86
* and to insure that the cylinders never exceed 65535 to
* prevent problems with X86 ioctls that report geometry.
* We use SPT that are multiples of 63, since other OSes that
* are not limited to 16-bits for cylinders stop at 63 SPT
* we make do by using multiples of 63 SPT.
*
* Note than capacities greater than or equal to 1TB will simply
* get the largest geometry from the table. This should be okay
* since disks this large shouldn't be using CHS values anyway.
*/
;
}
#endif
/*
* Function: cmlb_resync_geom_caches
*
* Description: (Re)initialize both geometry caches: the virtual geometry
* information is extracted from the HBA (the "geometry"
* capability), and the physical geometry cache data is
* generated by issuing MODE SENSE commands.
*
* Arguments:
* cl driver soft state (unit) structure
* capacity disk capacity in #blocks
* tg_cookie cookie from target driver to be passed back to target
* driver when we call back to it through tg_ops.
*
* Context: Kernel thread only (can sleep).
*/
static void
void *tg_cookie)
{
unsigned short nhead;
unsigned short nsect;
int spc;
int ret;
/*
* Ask the controller for its logical geometry.
* Note: if the HBA does not support scsi_ifgetcap("geometry"),
* then the lgeom cache will be invalid.
*/
/*
* Initialize the pgeom cache from lgeom, so that if MODE SENSE
* doesn't work, DKIOCG_PHYSGEOM can return reasonable values.
*/
/*
* Note: Perhaps this needs to be more adaptive? The rationale
* is that, if there's no HBA geometry from the HBA driver, any
* guess is good, since this is the physical geometry. If MODE
* SENSE fails this gives a max cylinder size for non-LBA access
*/
nhead = 255;
nsect = 63;
} else {
}
} else {
}
/*
* Retrieve fresh geometry data from the hardware, stash it
* here temporarily before we rebuild the incore label.
*
* We want to use the MODE SENSE commands to derive the
* physical geometry of the device, but if either command
* fails, the logical geometry is used as the fallback for
* disk label geometry.
*/
/*
* Now update the real copy while holding the mutex. This
* way the global copy is never in an inconsistent state.
*/
"(cached from lgeom)\n");
" ncyl: %ld; acyl: %d; nhead: %d; nsect: %d\n",
}
/*
* Function: cmlb_read_fdisk
*
* Description: utility routine to read the fdisk table.
*
* Arguments:
* cl driver soft state (unit) structure
* capacity disk capacity in #blocks
* tg_cookie cookie from target driver to be passed back to target
* driver when we call back to it through tg_ops.
*
* Return Code: 0 for success (includes not reading for no_fdisk_present case
* errnos from tg_rw if failed to read the first block.
*
* Context: Kernel thread only (can sleep).
*/
/*ARGSUSED*/
static int
{
#if defined(_NO_FDISK_PRESENT)
cl->cl_solaris_offset = 0;
return (0);
#elif defined(_FIRMWARE_NEEDS_FDISK)
int i;
char sigbuf[2];
int uidx;
int rval;
int lba = 0;
/*
* Start off assuming no fdisk table
*/
solaris_offset = 0;
if (rval != 0) {
"cmlb_read_fdisk: fdisk read err\n");
goto done;
}
/*
* The fdisk table does not begin on a 4-byte boundary within the
* master boot record, so we copy it to an aligned structure to avoid
* alignment exceptions on some processors.
*/
/*
* Check for lba support before verifying sig; sig might not be
* there, say on a blank disk, but the max_chs mark may still
* be present.
*
* Note: LBA support and BEFs are an x86-only concept but this
* code should work OK on SPARC as well.
*/
/*
* First, check for lba-access-ok on root node (or prom root node)
* if present there, don't need to search fdisk table.
*/
"lba-access-ok", 0) != 0) {
/* All drives do LBA; don't search fdisk table */
lba = 1;
} else {
/* Okay, look for mark in fdisk table */
/* accumulate "lba" value from all partitions */
}
}
if (lba != 0) {
"lba-access-ok", 0) == 0) {
/* not found; create it */
"cmlb_read_fdisk: Can't create lba "
"property for instance %d\n",
}
}
}
/*
* Endian-independent signature check
*/
"cmlb_read_fdisk: no fdisk\n");
goto done;
}
#ifdef CMLBDEBUG
if (cmlb_level_mask & CMLB_LOGMASK_INFO) {
"numsect sysid bootid\n");
for (i = 0; i < FD_NUMPART; i++, fdp++) {
" %d: %8d %8d 0x%08x 0x%08x\n",
}
}
#endif
/*
* Try to find the unix partition
*/
uidx = -1;
solaris_offset = 0;
solaris_size = 0;
int relsect;
int numsect;
continue;
}
/*
* Data in the fdisk table is little-endian.
*/
continue;
}
/*
* use the last active solaris partition id found
* (there should only be 1 active partition id)
*
* if there are no active solaris partition id
* then use the first inactive solaris partition id
*/
uidx = i;
}
}
done:
/*
* Clear the VTOC info, only if the Solaris partition entry
* has moved, changed size, been deleted, or if the size of
* the partition is too small to even fit the label sector.
*/
solaris_size <= DK_LABEL_LOC) {
}
return (rval);
#else /* #elif defined(_FIRMWARE_NEEDS_FDISK) */
#error "fdisk table presence undetermined for this platform."
#endif /* #if defined(_NO_FDISK_PRESENT) */
}
static void
{
_NOTE(ASSUMING_PROTECTED(*e))
}
static void
{
int i;
_NOTE(ASSUMING_PROTECTED(*p))
for (i = 0; i < nparts; i++) {
p[i].efi_gpe_PartitionTypeGUID);
/* PartitionAttrs */
}
}
static int
{
return (EINVAL);
/* at least 96 bytes in this version of the spec. */
return (EINVAL);
/* this should be 128 bytes */
return (EINVAL);
return (0);
}
static int
void *tg_cookie)
{
int i;
int rval = 0;
diskaddr_t cap = 0;
int iofailed = 0;
goto done_err1;
}
if (rval) {
iofailed = 1;
goto done_err;
}
/* not ours */
goto done_err;
}
if (rval) {
iofailed = 1;
goto done_err;
}
/*
* Couldn't read the primary, try the backup. Our
* capacity at this point could be based on CHS, so
* check what the device reports.
*/
if (rval) {
iofailed = 1;
goto done_err;
}
/*
* CMLB_OFF_BY_ONE case, we check the next to last block first
* for backup GPT header, otherwise check the last block.
*/
!= 0) {
iofailed = 1;
goto done_err;
}
goto done_err;
tg_cookie)) != 0)
goto done_err;
goto done_err;
}
if (!(flags & CMLB_SILENT))
"primary label corrupt; using backup\n");
}
if (rval) {
iofailed = 1;
goto done_err;
}
}
/* Fill in partition table. */
for (i = 0; i < nparts; i++) {
if (partitions->efi_gpe_StartingLBA != 0 ||
partitions->efi_gpe_EndingLBA != 0) {
}
&uuid_type_reserved, sizeof (struct uuid)) == 0) {
cl->cl_reserved = i;
}
}
if (i == WD_NODE) {
/*
* minor number 7 corresponds to the whole disk
*/
}
partitions++;
}
cl->cl_solaris_offset = 0;
/* clear the vtoc label */
return (0);
/*
* if we didn't find something that could look like a VTOC
* and the disk is over 1TB, we know there isn't a valid label.
* Otherwise let cmlb_uselabel decide what to do. We only
* want to invalidate this if we're certain the label isn't
* valid because cmlb_prop_op will now fail, which in turn
* causes things like opens and stats on the partition to fail.
*/
}
return (rval);
}
/*
* Function: cmlb_uselabel
*
* Description: Validate the disk label and update the relevant data (geometry,
* partition, vtoc, and capacity data) in the cmlb_lun struct.
* Marks the geometry of the unit as being valid.
*
* Arguments: cl: unit struct.
* dk_label: disk label
*
* Return Code: CMLB_LABEL_IS_VALID: Label read from disk is OK; geometry,
* partition, vtoc, and capacity data are good.
*
* CMLB_LABEL_IS_INVALID: Magic number or checksum error in the
* label; or computed capacity does not jibe with capacity
* reported from the READ CAPACITY command.
*
* Context: Kernel thread only (can sleep).
*/
static int
{
short *sp;
short sum;
short count;
int label_error = CMLB_LABEL_IS_VALID;
int i;
int part_end;
#if defined(_SUNOS_VTOC_16)
struct dkl_partition *vpartp;
#endif
/* Validate the magic number of the label. */
#if defined(__sparc)
if (!(flags & CMLB_SILENT))
"Corrupt label; wrong magic number\n");
}
#endif
return (CMLB_LABEL_IS_INVALID);
}
/* Validate the checksum of the label. */
sum = 0;
while (count--) {
}
if (sum != 0) {
#if defined(_SUNOS_VTOC_16)
#elif defined(_SUNOS_VTOC_8)
#endif
if (!(flags & CMLB_SILENT))
"Corrupt label - label checksum failed\n");
}
return (CMLB_LABEL_IS_INVALID);
}
/*
* Fill in geometry structure with data from label.
*/
#if defined(_SUNOS_VTOC_8)
#endif
#if defined(_SUNOS_VTOC_16)
#endif
#endif
/*
* Currently we rely on the values in the label being accurate. If
* dkl_rpm or dkl_pcly are zero in the label, use a default value.
*
* Note: In the future a MODE SENSE may be used to retrieve this data,
* although this command is optional in SCSI-2.
*/
/*
* The Read and Write reinstruct values may not be valid
* for older disks.
*/
/* Fill in partition table. */
#if defined(_SUNOS_VTOC_8)
for (i = 0; i < NDKMAP; i++) {
}
#endif
#if defined(_SUNOS_VTOC_16)
/* Prevent divide by zero */
if (track_capacity == 0) {
if (!(flags & CMLB_SILENT))
"Corrupt label - zero nhead or nsect value\n");
return (CMLB_LABEL_IS_INVALID);
}
}
#endif
/* Fill in VTOC Structure. */
#if defined(_SUNOS_VTOC_8)
/*
* The 8-slice vtoc does not include the ascii label; save it into
* the device's soft state structure here.
*/
#endif
/* Now look for a valid capacity. */
/* we may have > 1 alts cylinder */
#else
#endif
}
/*
* Force check here to ensure the computed capacity is valid.
* If capacity is zero, it indicates an invalid label and
* we should abort updating the relevant data then.
*/
if (label_capacity == 0) {
if (!(flags & CMLB_SILENT))
"Corrupt label - no valid capacity could be "
"retrieved\n");
return (CMLB_LABEL_IS_INVALID);
}
/* Mark the geometry as valid. */
/*
* if we got invalidated when mutex exit and entered again,
* if blockcount different than when we came in, need to
* retry from beginning of cmlb_validate_geometry.
* revisit this on next phase of utilizing this for
* sd.
*/
#if defined(_SUNOS_VTOC_8)
/*
* We can't let this happen on drives that are subdivided
* into logical disks (i.e., that have an fdisk table).
* The cl_blockcount field should always hold the full media
* size in sectors, period. This code would overwrite
* cl_blockcount with the size of the Solaris fdisk partition.
*/
"cmlb_uselabel: Label %d blocks; Drive %d blocks\n",
#endif /* defined(_SUNOS_VTOC_8) */
goto done;
}
/* For CDROMs, we trust that the data in the label is OK. */
#if defined(_SUNOS_VTOC_8)
for (i = 0; i < NDKMAP; i++) {
break;
}
}
#endif
#if defined(_SUNOS_VTOC_16)
break;
}
}
#endif
} else {
/* label_capacity > cl->cl_blockcount */
if (!(flags & CMLB_SILENT)) {
"Corrupt label - bad geometry\n");
"Label says %llu blocks; Drive says %llu blocks\n",
}
}
done:
" ncyl: %d; acyl: %d; nhead: %d; nsect: %d\n",
" label_capacity: %d; intrlv: %d; rpm: %d\n",
return (label_error);
}
/*
* Function: cmlb_build_default_label
*
* Description: Generate a default label for those devices that do not have
* one, e.g., new media, removable cartridges, etc..
*
* Context: Kernel thread only
*/
/*ARGSUSED*/
static void
{
#if defined(_SUNOS_VTOC_16)
#endif
#if defined(_SUNOS_VTOC_8)
/*
* Note: This is a legacy check for non-removable devices on VTOC_8
* only. This may be a valid check for VTOC_16 as well.
* Once we understand why there is this difference between SPARC and
* x86 platform, we could remove this legacy check.
*/
return;
}
#endif
#if defined(_SUNOS_VTOC_8)
/*
* It's a REMOVABLE media, therefore no label (on sparc, anyway).
* But it is still necessary to set up various geometry information,
* and we are doing this here.
*/
/*
* For the rpm, we use the minimum for the disk. For the head, cyl,
* and number of sector per track, if the capacity <= 1GB, head = 64,
* sect = 32. else head = 255, sect 63 Note: the capacity should be
* equal to C*H*S values. This will cause some truncation of size due
* to round off errors. For CD-ROMs, this truncation can have adverse
* side effects, so returning ncyl and nhead as 1. The nsect will
* overflow for most of CD-ROMs as nsect is of type ushort. (4190569)
*/
int is_writable;
/*
* Preserve the old behavior for non-writable
* medias. Since dkg_nsect is a ushort, it
* will lose bits as cdroms have more than
* 65536 sectors. So if we recalculate
* capacity, it will become much shorter.
* But the dkg_* information is not
* used for CDROMs so it is OK. But for
* Writable CDs we need this information
* to be valid (for newfs say). So we
* make nsect and nhead > 1 that way
* nsect can still stay within ushort limit
* without losing any bits.
*/
if (is_writable) {
} else {
}
} else {
/* unlabeled SCSI floppy device */
} else {
}
}
#elif defined(_SUNOS_VTOC_16)
if (cl->cl_solaris_size == 0) {
/*
* Got fdisk table but no solaris entry therefore
* don't create a default label
*/
return;
}
/*
* For CDs we continue to use the physical geometry to calculate
* number of cylinders. All other devices must convert the
* physical geometry (cmlb_geom) to values that will fit
* in a dk_geom structure.
*/
} else {
/* Convert physical geometry to disk geometry */
/*
* Refer to comments related to off-by-1 at the
* header of this file.
* Before caculating geometry, capacity should be
* decreased by 1.
*/
else
}
/*
* CD's don't use the "heads * sectors * cyls"-type of
* geometry, but instead use the entire capacity of the media.
*/
} else {
/*
* Hard disks and removable media cartridges
*/
/* Add boot slice */
if ((cl->cl_alter_behavior &
}
}
/* Add backup slice */
#else
#error "No VTOC format defined."
#endif
"cmlb_build_default_label: Default label created: "
"cyl: %d\tacyl: %d\tnhead: %d\tnsect: %d\tcap: %d\n",
}
#if defined(_FIRMWARE_NEEDS_FDISK)
/*
* Max CHS values, as they are encoded into bytes, for 1022/254/63
*/
#define LBA_MAX_HEAD (254)
/*
* Function: cmlb_has_max_chs_vals
*
* Description: Return TRUE if Cylinder-Head-Sector values are all at maximum.
*
* Arguments: fdp - ptr to CHS info
*
* Return Code: True or false
*
* Context: Any.
*/
static int
{
}
#endif
/*
* Function: cmlb_dkio_get_geometry
*
* Description: This routine is the driver entry point for handling user
* requests to get the device geometry (DKIOCGGEOM).
*
* Arguments:
* arg pointer to user provided dk_geom structure specifying
* the controller's notion of the current geometry.
*
* flag this argument is a pass through to ddi_copyxxx()
* directly from the mode argument of ioctl().
*
* tg_cookie cookie from target driver to be passed back to target
* driver when we call back to it through tg_ops.
*
* Return Code: 0
* EFAULT
* ENXIO
* EIO
*/
static int
void *tg_cookie)
{
int rval = 0;
/*
* cmlb_validate_geometry does not spin a disk up
* if it was spcl down. We need to make sure it
* is ready.
*/
#if defined(_SUNOS_VTOC_8)
/*
* This is to return a default label geometry even when we
* do not really assume a default label for the device.
* dad driver utilizes this.
*/
rval = 0;
}
}
#endif
if (rval) {
return (rval);
}
if (cl->cl_solaris_size == 0) {
return (EIO);
}
#endif
/*
* Make a local copy of the soft state geometry to avoid some potential
* race conditions associated with holding the mutex and updating the
* write_reinstruct value
*/
if (tmp_geom->dkg_write_reinstruct == 0) {
cmlb_rot_delay) / (int)60000);
}
flag);
if (rval != 0) {
}
return (rval);
}
/*
* Function: cmlb_dkio_set_geometry
*
* Description: This routine is the driver entry point for handling user
* requests to set the device geometry (DKIOCSGEOM). The actual
* device geometry is not updated, just the driver "notion" of it.
*
* Arguments:
* arg pointer to user provided dk_geom structure used to set
* the controller's notion of the current geometry.
*
* flag this argument is a pass through to ddi_copyxxx()
* directly from the mode argument of ioctl().
*
* tg_cookie cookie from target driver to be passed back to target
* driver when we call back to it through tg_ops.
*
* Return Code: 0
* EFAULT
* ENXIO
* EIO
*/
static int
{
int rval = 0;
int i;
if (cl->cl_solaris_size == 0) {
return (EIO);
}
#endif
/*
* We need to copy the user specified geometry into local
* storage and then update the softstate. We don't want to hold
* the mutex and copyin directly from the user to the soft state
*/
if (rval != 0) {
return (EFAULT);
}
for (i = 0; i < NDKMAP; i++) {
#endif
}
return (rval);
}
/*
* Function: cmlb_dkio_get_partition
*
* Description: This routine is the driver entry point for handling user
* requests to get the partition table (DKIOCGAPART).
*
* Arguments:
* arg pointer to user provided dk_allmap structure specifying
* the controller's notion of the current partition table.
*
* flag this argument is a pass through to ddi_copyxxx()
* directly from the mode argument of ioctl().
*
* tg_cookie cookie from target driver to be passed back to target
* driver when we call back to it through tg_ops.
*
* Return Code: 0
* EFAULT
* ENXIO
* EIO
*/
static int
void *tg_cookie)
{
int rval = 0;
int size;
/*
* Make sure the geometry is valid before getting the partition
* information.
*/
return (rval);
}
if (cl->cl_solaris_size == 0) {
return (EIO);
}
#endif
#ifdef _MULTI_DATAMODEL
case DDI_MODEL_ILP32: {
int i;
for (i = 0; i < NDKMAP; i++) {
}
if (rval != 0) {
}
break;
}
case DDI_MODEL_NONE:
if (rval != 0) {
}
break;
}
#else /* ! _MULTI_DATAMODEL */
if (rval != 0) {
}
#endif /* _MULTI_DATAMODEL */
return (rval);
}
/*
* Function: cmlb_dkio_set_partition
*
* Description: This routine is the driver entry point for handling user
* requests to set the partition table (DKIOCSAPART). The actual
* device partition is not updated.
*
* Arguments:
* arg - pointer to user provided dk_allmap structure used to set
* the controller's notion of the partition table.
* flag - this argument is a pass through to ddi_copyxxx()
* directly from the mode argument of ioctl().
*
* Return Code: 0
* EINVAL
* EFAULT
* ENXIO
* EIO
*/
static int
{
int rval = 0;
int size;
int i;
#if defined(_SUNOS_VTOC_16)
struct dkl_partition *vp;
#endif
/*
* Set the map for all logical partitions. We lock
* the priority just to make sure an interrupt doesn't
* come in while the map is half updated.
*/
return (ENOTSUP);
}
if (cl->cl_solaris_size == 0) {
return (EIO);
}
#ifdef _MULTI_DATAMODEL
case DDI_MODEL_ILP32: {
if (rval != 0) {
return (EFAULT);
}
for (i = 0; i < NDKMAP; i++) {
}
break;
}
case DDI_MODEL_NONE:
if (rval != 0) {
return (EFAULT);
}
break;
}
#else /* ! _MULTI_DATAMODEL */
if (rval != 0) {
return (EFAULT);
}
#endif /* _MULTI_DATAMODEL */
/* Note: The size used in this bcopy is set based upon the data model */
#if defined(_SUNOS_VTOC_16)
#endif /* defined(_SUNOS_VTOC_16) */
for (i = 0; i < NDKMAP; i++) {
#if defined(_SUNOS_VTOC_16)
vp++;
#endif /* defined(_SUNOS_VTOC_16) */
#endif
}
return (rval);
}
/*
* Function: cmlb_dkio_get_vtoc
*
* Description: This routine is the driver entry point for handling user
* requests to get the current volume table of contents
* (DKIOCGVTOC).
*
* Arguments:
* arg pointer to user provided vtoc structure specifying
* the current vtoc.
*
* flag this argument is a pass through to ddi_copyxxx()
* directly from the mode argument of ioctl().
*
* tg_cookie cookie from target driver to be passed back to target
* driver when we call back to it through tg_ops.
*
* Return Code: 0
* EFAULT
* ENXIO
* EIO
*/
static int
{
#if defined(_SUNOS_VTOC_8)
#endif /* defined(_SUNOS_VTOC_8) */
int rval = 0;
#if defined(_SUNOS_VTOC_8)
/*
* This is to return a default label even when we do not
* really assume a default label for the device.
* dad driver utilizes this.
*/
rval = 0;
}
}
#endif
if (rval) {
return (rval);
}
#if defined(_SUNOS_VTOC_8)
#ifdef _MULTI_DATAMODEL
case DDI_MODEL_ILP32: {
struct vtoc32 user_vtoc32;
return (EFAULT);
}
break;
}
case DDI_MODEL_NONE:
return (EFAULT);
}
break;
}
#else /* ! _MULTI_DATAMODEL */
return (EFAULT);
}
#endif /* _MULTI_DATAMODEL */
#elif defined(_SUNOS_VTOC_16)
#ifdef _MULTI_DATAMODEL
/*
* The cl_vtoc structure is a "struct dk_vtoc" which is always
* 32-bit to maintain compatibility with existing on-disk
* structures. Thus, we need to convert the structure when copying
* it out to a datamodel-dependent "struct vtoc" in a 64-bit
* program. If the target is a 32-bit program, then no conversion
* is necessary.
*/
/* LINTED: logical expression always true: op "||" */
case DDI_MODEL_ILP32:
return (EFAULT);
}
break;
case DDI_MODEL_NONE: {
return (EFAULT);
}
break;
}
}
#else /* ! _MULTI_DATAMODEL */
flag)) {
return (EFAULT);
}
#endif /* _MULTI_DATAMODEL */
#else
#error "No VTOC format defined."
#endif
return (rval);
}
static int
{
int rval = 0;
void *buffer;
return (EFAULT);
(cl->cl_tgt_blocksize == 0)) {
return (EINVAL);
}
return (rval);
}
#if defined(_SUNOS_VTOC_8)
/*
* Function: cmlb_build_user_vtoc
*
* Description: This routine populates a pass by reference variable with the
* current volume table of contents.
*
* Arguments: cl - driver soft state (unit) structure
* user_vtoc - pointer to vtoc structure to be populated
*/
static void
{
int nblks;
int i;
/*
* Return vtoc structure fields in the provided VTOC area, addressed
* by *vtoc.
*/
for (i = 0; i < 10; i++)
/*
* Convert partitioning information.
*
* Note the conversion from starting cylinder number
* to starting sector number.
*/
for (i = 0; i < V_NUMPAR; i++) {
lmap++;
lpart++;
vpart++;
/* (4364927) */
}
}
#endif
static int
void *tg_cookie)
{
struct partition64 p64;
int rval = 0;
sizeof (struct partition64), flag)) {
return (EFAULT);
}
if (rval != 0)
goto done_error;
goto done_error;
/* couldn't find it */
goto done_error;
}
/*
* if we're dealing with a partition that's out of the normal
* 16K block, adjust accordingly
*/
if (rval) {
goto done_error;
}
sizeof (struct uuid));
return (rval);
}
/*
* Function: cmlb_dkio_set_vtoc
*
* Description: This routine is the driver entry point for handling user
* requests to set the current volume table of contents
* (DKIOCSVTOC).
*
* Arguments:
* dev the device number
* arg pointer to user provided vtoc structure used to set the
* current vtoc.
*
* flag this argument is a pass through to ddi_copyxxx()
* directly from the mode argument of ioctl().
*
* tg_cookie cookie from target driver to be passed back to target
* driver when we call back to it through tg_ops.
*
* Return Code: 0
* EFAULT
* ENXIO
* EINVAL
* ENOTSUP
*/
static int
void *tg_cookie)
{
int rval = 0;
#ifdef _MULTI_DATAMODEL
case DDI_MODEL_ILP32: {
struct vtoc32 user_vtoc32;
return (EFAULT);
}
break;
}
case DDI_MODEL_NONE:
return (EFAULT);
}
break;
}
#else /* ! _MULTI_DATAMODEL */
return (EFAULT);
}
#endif /* _MULTI_DATAMODEL */
return (ENOTSUP);
}
return (EINVAL);
}
#endif
return (EINVAL);
}
"cmlb_dkio_set_vtoc: "
"Failed validate geometry\n");
}
}
}
return (rval);
}
/*
* Function: cmlb_build_label_vtoc
*
* Description: This routine updates the driver soft state current volume table
* of contents based on a user specified vtoc.
*
* Arguments: cl - driver soft state (unit) structure
* user_vtoc - pointer to vtoc structure specifying vtoc to be used
* to update the driver soft state.
*
* Return Code: 0
* EINVAL
*/
static int
{
int nblks;
#if defined(_SUNOS_VTOC_8)
int ncyl;
#endif /* defined(_SUNOS_VTOC_8) */
int i;
/* Sanity-check the vtoc */
"cmlb_build_label_vtoc: vtoc not valid\n");
return (EINVAL);
}
if (nblks == 0) {
"cmlb_build_label_vtoc: geom nblks is 0\n");
return (EINVAL);
}
#if defined(_SUNOS_VTOC_8)
for (i = 0; i < V_NUMPAR; i++) {
"cmlb_build_label_vtoc: p_start not multiply of"
"nblks part %d p_start %d nblks %d\n", i,
return (EINVAL);
}
ncyl++;
}
"cmlb_build_label_vtoc: ncyl %d > dkg_ncyl %d"
"p_size %ld p_start %ld nblks %d part number %d"
"tag %d\n",
return (EINVAL);
}
vpart++;
}
#endif /* defined(_SUNOS_VTOC_8) */
/* Put appropriate vtoc structure fields into the disk label */
#if defined(_SUNOS_VTOC_16)
/*
* The vtoc is always a 32bit data structure to maintain the
* on-disk format. Convert "in place" instead of doing bcopy.
*/
/*
* in the 16-slice vtoc, starting sectors are expressed in
* numbers *relative* to the start of the Solaris fdisk partition.
*/
}
#elif defined(_SUNOS_VTOC_8)
for (i = 0; i < 10; i++)
/*
* Note the conversion from starting sector number
* to starting cylinder number.
* Return error if division results in a remainder.
*/
lmap++;
lpart++;
vpart++;
/* (4387723) */
#ifdef _LP64
} else {
}
#else
#endif
}
#else
#error "No VTOC format defined."
#endif
return (0);
}
/*
* Function: cmlb_clear_efi
*
* Description: This routine clears all EFI labels.
*
* Arguments:
* cl driver soft state (unit) structure
*
* tg_cookie cookie from target driver to be passed back to target
* driver when we call back to it through tg_ops.
* Return Code: void
*/
static void
{
int rval;
goto done;
}
if (rval == 0) {
/* clear primary */
"cmlb_clear_efi: clear primary label failed\n");
}
}
/* the backup */
if (rval) {
goto done;
}
!= 0) {
goto done;
}
if (rval == 0) {
/* clear backup */
tg_cookie))) {
"cmlb_clear_efi: clear backup label failed\n");
}
} else {
/*
* Refer to comments related to off-by-1 at the
* header of this file
*/
EFI_LABEL_SIZE, tg_cookie)) != 0) {
goto done;
}
if (rval == 0) {
/* clear legacy backup EFI label */
"cmlb_clear_efi clear legacy backup@%lu\n",
cap - 2);
EFI_LABEL_SIZE, tg_cookie))) {
"cmlb_clear_efi: clear legacy backup label "
"failed\n");
}
}
}
done:
}
/*
* Function: cmlb_set_vtoc
*
* Description: This routine writes data to the appropriate positions
*
* Arguments:
* cl driver soft state (unit) structure
*
* dkl the data to be written
*
* tg_cookie cookie from target driver to be passed back to target
* driver when we call back to it through tg_ops.
*
* Return: void
*/
static int
{
int sec;
int blk;
int head;
int cyl;
int rval;
#else
/* Write the primary label at block 0 of the solaris partition. */
label_addr = 0;
#endif
if (rval != 0) {
return (rval);
}
/*
* Calculate where the backup labels go. 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.
*
* We have no choice at this point, but to believe that the
* disk label is valid. Use the geometry of the disk
* as described in the label.
*/
/*
* Write and verify the backup labels. Make sure we don't try to
* write past the last cylinder.
*/
#endif
"cmlb_set_vtoc: wrote backup label %d\n", blk);
if (rval != 0) {
goto exit;
}
}
exit:
return (rval);
}
/*
* Function: cmlb_clear_vtoc
*
* Description: This routine clears out the VTOC labels.
*
* Arguments:
* cl driver soft state (unit) structure
*
* tg_cookie cookie from target driver to be passed back to target
* driver when we call back to it through tg_ops.
*
* Return: void
*/
static void
{
/*
* cmlb_set_vtoc uses these fields in order to figure out
* where to overwrite the backup labels
*/
}
/*
* Function: cmlb_write_label
*
* Description: This routine will validate and write the driver soft state vtoc
* contents to the device.
*
* Arguments:
* cl cmlb handle
*
* tg_cookie cookie from target driver to be passed back to target
* driver when we call back to it through tg_ops.
*
*
* Return Code: the code returned by cmlb_send_scsi_cmd()
* 0
* EINVAL
* ENXIO
* ENOMEM
*/
static int
{
short sum;
short *sp;
int i;
int rval;
#if defined(_SUNOS_VTOC_8)
for (i = 0; i < NDKMAP; i++) {
}
#elif defined(_SUNOS_VTOC_16)
#else
#error "No VTOC format defined."
#endif
/* Construct checksum for the new disk label */
sum = 0;
i = sizeof (struct dk_label) / sizeof (short);
while (i--) {
}
exit:
return (rval);
}
static int
void *tg_cookie)
{
int rval = 0;
void *buffer;
return (EFAULT);
} else {
/*
* let's clear the vtoc labels and clear the softstate
* vtoc.
*/
"cmlb_dkio_set_efi: CLEAR VTOC\n");
} else
(cl->cl_tgt_blocksize == 0)) {
return (EINVAL);
}
if (rval == 0) {
}
}
return (rval);
}
/*
* Function: cmlb_dkio_get_mboot
*
* Description: This routine is the driver entry point for handling user
* requests to get the current device mboot (DKIOCGMBOOT)
*
* Arguments:
* arg pointer to user provided mboot structure specifying
* the current mboot.
*
* flag this argument is a pass through to ddi_copyxxx()
* directly from the mode argument of ioctl().
*
* tg_cookie cookie from target driver to be passed back to target
* driver when we call back to it through tg_ops.
*
* Return Code: 0
* EINVAL
* EFAULT
* ENXIO
*/
static int
{
int rval;
#if defined(_SUNOS_VTOC_8)
#elif defined(_SUNOS_VTOC_16)
#endif
return (EINVAL);
}
/*
* Read the mboot block, located at absolute block 0 on the target.
*/
buffer_size = sizeof (struct mboot);
"cmlb_dkio_get_mboot: allocation size: 0x%x\n", buffer_size);
}
}
return (rval);
}
/*
* Function: cmlb_dkio_set_mboot
*
* Description: This routine is the driver entry point for handling user
* requests to validate and set the device master boot
* (DKIOCSMBOOT).
*
* Arguments:
* arg pointer to user provided mboot structure used to set the
* master boot.
*
* flag this argument is a pass through to ddi_copyxxx()
* directly from the mode argument of ioctl().
*
* tg_cookie cookie from target driver to be passed back to target
* driver when we call back to it through tg_ops.
*
* Return Code: 0
* EINVAL
* EFAULT
* ENXIO
*/
static int
{
int rval;
#if defined(_SUNOS_VTOC_8)
return (EINVAL);
}
#endif
return (EINVAL);
}
return (EFAULT);
}
/* Is this really a master boot record? */
return (EINVAL);
}
if (rval == 0) {
/*
* mboot has been written successfully.
* update the fdisk and vtoc tables in memory
*/
return (rval);
}
}
#ifdef __lock_lint
#endif
#else
if (rval == 0) {
/*
* mboot has been written successfully.
* set up the default geometry and VTOC
*/
}
#endif
return (rval);
}
/*
* Function: cmlb_setup_default_geometry
*
* Description: This local utility routine sets the default geometry as part of
* setting the device mboot.
*
* Arguments:
* cl driver soft state (unit) structure
*
* tg_cookie cookie from target driver to be passed back to target
* driver when we call back to it through tg_ops.
*
*
* Note: This may be redundant with cmlb_build_default_label.
*/
static void
{
int ret;
int geom_base_cap = 1;
/* zero out the soft state geometry and partition table. */
/*
* For the rpm, we use the minimum for the disk.
* For the head, cyl and number of sector per track,
* if the capacity <= 1GB, head = 64, sect = 32.
* else head = 255, sect 63
* Note: the capacity should be equal to C*H*S values.
* This will cause some truncation of size due to
* round off errors. For CD-ROMs, this truncation can
* have adverse side effects, so returning ncyl and
* nhead as 1. The nsect will overflow for most of
* CD-ROMs as nsect is of type ushort.
*/
/*
* newfs currently can not handle 255 ntracks for SPARC
* so get the geometry from target driver instead of coming up
* with one based on capacity.
*/
if (ret == 0) {
geom_base_cap = 0;
} else {
"cmlb_setup_default_geometry: "
"tg_getphygeom failed %d\n", ret);
/* do default setting, geometry based on capacity */
}
}
if (geom_base_cap) {
/* Needed for unlabeled SCSI floppies. */
} else {
}
} else {
}
}
/*
* Function: cmlb_update_fdisk_and_vtoc
*
* Description: This local utility routine updates the device fdisk and vtoc
* as part of setting the device mboot.
*
* Arguments:
* cl driver soft state (unit) structure
*
* tg_cookie cookie from target driver to be passed back to target
* driver when we call back to it through tg_ops.
*
*
* Return Code: 0 for success or errno-type return code.
*
* Note:x86: This looks like a duplicate of cmlb_validate_geometry(), but
* these did exist separately in x86 sd.c.
*/
static int
{
int count;
int label_rc = 0;
int fdisk_rval;
return (EINVAL);
#if defined(_SUNOS_VTOC_16)
/*
* Set up the "whole disk" fdisk partition; this should always
* exist, regardless of whether the disk contains an fdisk table
* or vtoc.
*/
#endif /* defined(_SUNOS_VTOC_16) */
/*
* copy the lbasize and capacity so that if they're
* reset while we're not holding the CMLB_MUTEX(cl), we will
* continue to use valid values after the CMLB_MUTEX(cl) is
* reacquired.
*/
/*
* refresh the logical and physical geometry caches.
* and scsi_ifgetcap("geometry").
*/
/*
* Only DIRECT ACCESS devices will have Scl labels.
* CD's supposedly have a Scl label, too
*/
if (fdisk_rval != 0) {
return (fdisk_rval);
}
/*
* Found fdisk table but no Solaris partition entry,
* so don't call cmlb_uselabel() and don't create
* a default label.
*/
label_rc = 0;
goto no_solaris_partition;
}
} else if (capacity < 0) {
return (EINVAL);
}
/*
* For Removable media We reach here if we have found a
* SOLARIS PARTITION.
* If cl_f_geometry_is_valid is FALSE it indicates that the SOLARIS
* PARTITION has changed from the previous one, hence we will setup a
* default VTOC in this case.
*/
/* if we get here it is writable */
/* we are called from SMBOOT, and after a write of fdisk */
label_rc = 0;
}
#if defined(_SUNOS_VTOC_16)
/*
* If we have valid geometry, set up the remaining fdisk partitions.
* Note that dkl_cylno is not used for the fdisk map entries, so
* we set it to an entirely bogus value.
*/
}
#endif
#if defined(_SUNOS_VTOC_8)
#elif defined(_SUNOS_VTOC_16)
#else
#error "No VTOC format defined."
#endif
}
return (label_rc);
}
#endif
static int
{
int err = 0;
/* Return the driver's notion of the media's logical geometry */
/*
* If there is no HBA geometry available, or
* if the HBA returned us something that doesn't
* really fit into an Int 13/function 8 geometry
* result, just fail the ioctl. See PSARC 1998/313.
*/
} else {
} else {
err = 0;
}
}
return (err);
}
#endif
static int
{
int err = 0;
/* Return the driver's notion of the media physical geometry */
/*
* We succeeded in getting a geometry, but
* right now it is being reported as just the
* Solaris fdisk partition, just like for
* DKIOCGGEOM. We need to change that to be
* correct for the entire disk now.
*/
} else {
/*
* This disk does not have a Solaris VTOC
* so we must present a physical geometry
* that will remain consistent regardless
* of how the disk is used. This will ensure
* that the geometry does not change regardless
* of the fdisk partition type (ie. EFI, FAT32,
* Solaris, etc).
*/
} else {
/*
* Invalid cl_blockcount can generate invalid
* dk_geom and may result in division by zero
* system failure. Should make sure blockcount
* is valid before using it here.
*/
if (cl->cl_blockcount == 0) {
return (err);
}
/*
* Refer to comments related to off-by-1 at the
* header of this file
*/
else
}
}
} else {
err = 0;
}
return (err);
}
#endif
static int
{
int err = 0;
/*
* Return parameters describing the selected disk slice.
* Note: this ioctl is for the intel platform only
*/
int part;
/* don't check cl_solaris_size for pN */
} else {
struct part_info p;
#ifdef _MULTI_DATAMODEL
case DDI_MODEL_ILP32:
{
struct part_info32 p32;
break;
}
case DDI_MODEL_NONE:
{
if (ddi_copyout(&p, (void *)arg, sizeof (p),
flag))
break;
}
}
#else /* ! _MULTI_DATAMODEL */
#endif /* _MULTI_DATAMODEL */
}
return (err);
}
#endif