cmlb.c revision de6d0fcd730431ea0d586564c1551016efe19f56
/*
* 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 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* This module provides support for labeling operations for target
* drivers.
*/
#include <sys/efi_partition.h>
#include <sys/cmlb_impl.h>
#endif
#include <sys/ddi_impldefs.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}
};
#if defined(_FIRMWARE_NEEDS_FDISK)
static struct driver_minor_data dk_ext_minor_data[] = {
{0}
};
#endif /* defined(_FIRMWARE_NEEDS_FDISK) */
#endif /* if defined(__i386) || defined(__amd64) */
static struct driver_minor_data dk_minor_data_efi[] = {
{"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}
};
/*
* Declare the dynamic properties implemented in prop_op(9E) implementation
* that we want to have show up in a di_init(3DEVINFO) device tree snapshot
* of drivers that call cmlb_attach().
*/
static i_ddi_prop_dyn_t cmlb_prop_dyn[] = {
{"device-nblocks", DDI_PROP_TYPE_INT64},
{"device-blksize", DDI_PROP_TYPE_INT},
{NULL}
};
/*
* This implies an upper limit of 8192 GPT partitions
* in one transfer for GUID Partition Entry Array.
*/
/*
* External kernel interfaces
*/
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"
};
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);
void *tg_cookie);
void *tg_cookie);
void *tg_cookie);
void *tg_cookie);
int flag);
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.
*
* is_hotpluggable whether or not device is 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 geometry calculation,
* 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.
*
*
*
* CMLB_FAKE_LABEL_ONE_PARTITION: create s0 and s2 covering
* the entire disk, if there is no valid partition info.
* If there is a valid Solaris partition, s0 and s2 will
* only cover the entire Solaris partition.
*
*
* 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);
cl->cl_logical_drive_count = 0;
#endif
if (!is_removable) {
/* set default EFI if > 2TB */
}
}
/* create minor nodes based on default label type */
if (cmlb_create_minor_nodes(cl) != 0) {
return (ENXIO);
}
/* Define the dynamic properties for devinfo spapshots. */
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);
}
if (cl->cl_f_geometry_is_valid) {
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:
* B_FALSE otherwise.
*
*/
{
if (cmlbhandle == NULL)
return (B_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);
}
if ((!cl->cl_f_geometry_is_valid) ||
return (EINVAL);
}
} else {
return (EINVAL);
}
} else {
/* if the disk is unlabeled, don't write a devid to it */
return (EINVAL);
}
/* 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;
int ext_part;
#endif
return (EINVAL);
}
} else {
if (!cl->cl_f_geometry_is_valid)
#if defined(_SUNOS_VTOC_16)
if (((!cl->cl_f_geometry_is_valid) ||
(part != P0_RAW_DISK)) {
#else
if ((!cl->cl_f_geometry_is_valid) ||
#endif
} else {
if (startblockp != NULL)
*nblocksp = (diskaddr_t)
*tagp =
rval = 0;
}
/* consistent with behavior of sd for getting minor name */
#if defined(_FIRMWARE_NEEDS_FDISK)
} else
#endif
#endif
}
}
return (rval);
}
/*
* cmlb_efi_label_capacity:
* Get capacity stored in EFI disk label.
*
* Arguments:
* cmlbhandle cmlb handle associated with device.
* capacity pointer to capacity stored in EFI disk label.
* 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 and is an EFI label, it stores the capacity
* in disk label in the area pointed to by capacity.
*
*
* Return values:
* 0 success
* EINVAL no valid EFI label or capacity is NULL.
*
*/
int
void *tg_cookie)
{
int rval;
return (EINVAL);
}
if (!cl->cl_f_geometry_is_valid)
0, tg_cookie);
} else {
rval = 0;
}
return (rval);
}
/* Caller should make sure Test Unit Ready succeeds before calling this. */
/*ARGSUSED*/
int
{
int err;
return (EIO);
}
switch (cmd) {
case DKIOCSEXTVTOC:
case DKIOCSGEOM:
case DKIOCSETEFI:
case DKIOCSMBOOT:
case DKIOCSETEXTPART:
#endif
break;
case DKIOCSVTOC:
case DKIOCPARTINFO:
#endif
return (EOVERFLOW);
}
break;
default:
switch (cmd) {
case DKIOCGVTOC:
case DKIOCGAPART:
case DKIOCSAPART:
/* GPT label on disk */
return (ENOTSUP);
} else if
return (EOVERFLOW);
}
break;
case DKIOCGGEOM:
/* GPT label on disk */
return (ENOTSUP);
}
break;
default:
break;
}
}
switch (cmd) {
case DKIOCGGEOM:
break;
case DKIOCSGEOM:
break;
case DKIOCGAPART:
break;
case DKIOCSAPART:
break;
case DKIOCGVTOC:
break;
case DKIOCGEXTVTOC:
break;
case DKIOCGETEFI:
break;
case DKIOCPARTITION:
break;
case DKIOCSVTOC:
break;
case DKIOCSEXTVTOC:
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;
case DKIOCEXTPARTINFO:
#else
#endif
break;
case DKIOCSETEXTPART:
break;
#endif
default:
}
/*
* An ioctl that succeeds and changed ('set') size(9P) information
* needs to invalidate the cached devinfo snapshot to avoid having
* old information being returned in a snapshots.
*
* NB: When available, call ddi_change_minor_node() to clear
* SSIZEVALID in specfs vnodes via spec_size_invalidate().
*/
if (err == 0) {
switch (cmd) {
case DKIOCSGEOM:
case DKIOCSAPART:
case DKIOCSVTOC:
case DKIOCSEXTVTOC:
case DKIOCSETEFI:
}
}
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 (cl->cl_f_geometry_is_valid)
return (0);
if (status != 0) {
return (EIO);
}
if (status != 0)
return (EIO);
if (!cl->cl_is_removable) {
}
return (0);
} else {
return (EIO);
}
}
static int
{
if (internal)
return (ddi_create_internal_pathname(dip,
else
return (ddi_create_minor_node(dip,
}
/*
* 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;
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 > int32_max(1TB) we are in 64bit environment
* so no truncation happens
*/
#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 > CMLB_EXTVTOC_LIMIT) {
if (label_error == ESRCH) {
/*
* they've configured a LUN over 2TB, but used
* format.dat to restrict format's view of the
* capacity to be under 2TB in some earlier Solaris
* release.
*/
/* i.e > 2TB with a VTOC < 2TB */
if (!(flags & CMLB_SILENT) &&
CE_NOTE, "!Disk (%s%d) is limited to 2 TB "
"due to VTOC label. To use the full "
"capacity of the disk, use format(1M) to "
CMLB_LABEL(cl),
}
} else {
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);
}
/*
* 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;
}
"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
if (!cl->cl_f_geometry_is_valid) {
}
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)
/*
* 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
{
/* Unlabeled SCSI floppy device */
if (capacity < 160) {
/* Less than 80K */
return;
} else if (capacity <= 0x1000) {
return;
}
/*
* For all devices we calculate cylinders using the heads and sectors
* we assign based on capacity of the device. The algorithm 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.
* For some smaller disk sizes we report geometry that matches those
* used by X86 BIOS usage. For larger disks, 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.
*
* The following table (in order) illustrates some end result
* calculations:
*
* Maximum number of blocks nhead nsect
*
* 2097152 (1GB) 64 32
* 16777216 (8GB) 128 32
* 1052819775 (502.02GB) 255 63
* 2105639550 (0.98TB) 255 126
* 3158459325 (1.47TB) 255 189
* 4211279100 (1.96TB) 255 252
* 5264098875 (2.45TB) 255 315
* ...
*
* For Solid State Drive(SSD), it uses 4K page size inside and may be
* double with every new generation. If the I/O is not aligned with
* page size on SSDs, SSDs perform a lot slower.
* By default, Solaris partition starts from cylinder 1. It will be
* misaligned even with 4K if using heads(255) and SPT(63). To
* workaround the problem, if the device is SSD, we use heads(224) and
* SPT multiple of 56. Thus the default Solaris partition starts from
* a position that aligns with 128K on a 512 bytes sector size SSD.
*/
if (capacity <= 0x200000) {
} else if (capacity <= 0x01000000) {
} else {
int is_solid_state;
unsigned short nhead;
unsigned short nsect;
if (is_solid_state) {
nhead = 224;
nsect = 56;
} else {
nhead = 255;
nsect = 63;
}
/* make dkg_nsect be smallest multiple of nsect */
}
}
#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 {
}
if (spc == 0)
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_update_ext_minor_nodes
*
*
* Arguments:
* cl driver soft state (unit) structure
* num_parts Number of logical drives found on the LUN
*
* Should be called with the mutex held
*
* Return Code: 0 for success
*
* Context: User and Kernel thread
*
*/
static int
{
int i, count;
char name[48];
int instance;
char *devnm;
if (cl->cl_logical_drive_count) {
for (i = 0; i < cl->cl_logical_drive_count; i++) {
demdp++;
demdpr++;
}
/* There are existing device nodes. Remove them */
}
for (i = 0; i < num_parts; i++) {
/*
* Clean up any nodes that may have been
* created, in case this fails in the middle
* of the loop.
*/
cl->cl_logical_drive_count = 0;
return (ENXIO);
}
/*
* Clean up any nodes that may have been
* created, in case this fails in the middle
* of the loop.
*/
cl->cl_logical_drive_count = 0;
return (ENXIO);
}
demdp++;
demdpr++;
}
/* Update the cl_map array for logical drives */
}
cl->cl_logical_drive_count = i;
cl->cl_update_ext_minor_nodes = 0;
return (0);
}
/*
* Function: cmlb_validate_ext_part
*
* Description: utility routine to validate an extended partition's
* metadata as found on disk
*
* Arguments:
* cl driver soft state (unit) structure
* part partition number of the extended partition
* epart partition number of the logical drive
* start absolute sector number of the start of the logical
* drive being validated
* size size of logical drive being validated
*
* Return Code: 0 for success
*
* Context: User and Kernel thread
*
* Algorithm :
* Error cases are :
* 1. If start block is lesser than or equal to the end block
* 2. If either start block or end block is beyond the bounadry
* of the extended partition.
* 3. start or end block overlap with existing partitions.
* To check this, first make sure that the start block doesnt
* overlap with existing partitions. Then, calculate the
* possible end block for the given start block that doesnt
* overlap with existing partitions. This can be calculated by
* first setting the possible end block to the end of the
* extended partition (optimistic) and then, checking if there
* is any other partition that lies after the start of the
* partition being validated. If so, set the possible end to
* one block less than the beginning of the next nearest partition
* If the actual end block is greater than the calculated end
* block, we have an overlap.
*
*/
static int
{
int i;
return (1);
}
/*
* Check if the logical drive boundaries are within that of the
* extended partition.
*/
return (1);
}
/*
* epart will be equal to FD_NUMPART if it is the first logical drive.
* There is no need to check for overlaps with other logical drives,
* since it is the only logical drive that we have come across so far.
*/
if (epart == FD_NUMPART) {
return (0);
}
/* Check for overlaps with existing logical drives */
i = FD_NUMPART;
return (1);
}
}
i++;
}
return (1);
}
return (0);
}
/*
* Function: cmlb_is_linux_swap
*
* Description: utility routine to verify if a partition is a linux swap
* partition or not.
*
* Arguments:
* cl driver soft state (unit) structure
* part_start absolute sector number of the start of the partition
* being verified
* 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
*
* Context: User and Kernel thread
*
* Notes:
* The linux swap magic "SWAP-SPACE" or "SWAPSPACE2" is found as the
* last 10 bytes of a disk block whose size is that of the linux page
* size. This disk block is found at the beginning of the swap partition.
*/
static int
{
int i;
int rval = -1;
char *buf, *linux_swap_magic;
/* Known linux kernel page sizes */
return (ENOMEM);
}
/*
* Check if there is a sane Solaris VTOC
* If there is a valid vtoc, no need to lookup
* for the linux swap signature.
*/
if (rval != 0) {
"cmlb_is_linux_swap: disk vtoc read err\n");
goto done;
}
rval = -1;
goto done;
}
/* No valid vtoc, so check for linux swap signature */
for (i = 0; i < sizeof (linux_pg_size_arr)/sizeof (uint32_t); i++) {
if (rval != 0) {
"cmlb_is_linux_swap: disk read err\n");
break;
}
rval = -1;
/* Found a linux swap */
rval = 0;
break;
}
}
done:
return (rval);
}
#endif
/*
* 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, k;
char sigbuf[2];
int uidx;
int rval;
int lba = 0;
int ext_part_exists = 0;
int ld_count = 0;
#endif
/*
* 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;
/*
* Stores relative block offset from the beginning of the
* Extended Partition.
*/
int ext_relsect = 0;
#endif
continue;
}
/*
* Data in the fdisk table is little-endian.
*/
/* Support only one extended partition per LUN */
(ext_part_exists == 0)) {
int j;
ext_part_exists = 1;
for (j = FD_NUMPART; j < FDISK_PARTS; j++) {
if (rval != 0) {
"cmlb_read_fdisk: Extended "
"partition read err\n");
goto done;
}
/*
* The first ipart entry provides the offset
* at which the logical drive starts off from
* the beginning of the container partition
* and the size of the logical drive.
* The second ipart entry provides the offset
* of the next container partition from the
* beginning of the extended partition.
*/
sizeof (eparts));
if (logdrive_offset <= 0 || ext_numsect <= 0)
break;
/* Boundary condition and overlap checking */
ext_numsect)) {
break;
}
/*
* Indicates change from previous
* partinfo. Need to recreate
* logical device nodes.
*/
}
ld_count++;
tg_cookie) != 0)) ||
if (uidx == -1) {
uidx = 0;
}
}
break;
}
}
#endif
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
*/
tg_cookie) != 0))) {
#endif
uidx = i;
}
#endif
}
}
/*
* the fmap entries correspoding to those deleted drives.
*/
for (k = ld_count + FD_NUMPART;
}
}
if (cl->cl_update_ext_minor_nodes) {
if (rval != 0) {
goto done;
}
}
#endif
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);
}
/*
* This function returns B_FALSE if there is a valid MBR signature and no
* partition table entries of type EFI_PMBR (0xEE). Otherwise it returns B_TRUE.
*
* The EFI spec (1.10 and later) requires having a Protective MBR (PMBR) to
* recognize the disk as GPT partitioned. However, some other OS creates an MBR
* where a PMBR entry is not the only one. Also, if the first block has been
* corrupted, currently best attempt to allow data access would be to try to
* check for GPT headers. Hence in case of more than one partition entry, but
* at least one EFI_PMBR partition type or no valid magic number, the function
* returns B_TRUE to continue with looking for GPT header.
*/
static boolean_t
{
int i;
return (B_TRUE);
}
return (B_TRUE);
}
return (B_FALSE);
}
static int
void *tg_cookie)
{
int i;
int rval = 0;
diskaddr_t cap = 0;
int iofailed = 0;
#if defined(_FIRMWARE_NEEDS_FDISK)
#endif
if (rval) {
iofailed = 1;
goto done_err;
}
/* not ours */
goto done_err;
}
#if defined(_FIRMWARE_NEEDS_FDISK)
if (is_mbr)
else
goto done_err;
}
#else
goto done_err;
}
#endif
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
* if the disk capacity is expanded after disk is
* labeled, minor number 7 represents the capacity
* indicated by the disk label.
*/
if (alternate_lba == 1) {
/*
* We are using backup label. Since we can
* find a valid label at the end of disk,
* the disk capacity is not expanded.
*/
} else {
}
}
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;
#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 {
/* Less than 80K */
/* 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 calculating geometry, capacity should be
* decreased by 1.
*/
else
}
if (phys_spc == 0)
return;
/* disable devid */
} 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 */
/*
* single slice (s0) covering the entire disk
*/
}
#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 B_TRUE if Cylinder-Head-Sector values are all at maximum.
*
* Arguments: fdp - ptr to CHS info
*
* Return Code: True or false
*
* Context: Any.
*/
static boolean_t
{
}
#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;
return (EOVERFLOW);
}
#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);
}
/*
* Function: cmlb_dkio_get_extvtoc
*/
static int
void *tg_cookie)
{
#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)
/*
* Checking callers data model does not make much sense here
* since extvtoc will always be equivalent to 64bit vtoc.
* What is important is whether the kernel is in 32 or 64 bit
*/
#ifdef _LP64
return (EFAULT);
}
#else
return (EFAULT);
}
#endif
#elif defined(_SUNOS_VTOC_16)
/*
* 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 extvtoc
*/
return (EFAULT);
#else
#error "No VTOC format defined."
#endif
return (rval);
}
/*
* This routine implements the DKIOCGETEFI ioctl. This ioctl is currently
*/
static int
{
int rval = 0;
void *buffer;
return (EFAULT);
if (user_efi.dki_length == 0 ||
return (EINVAL);
(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 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;
int n_gpe_per_blk = 0;
sizeof (struct partition64), flag)) {
return (EFAULT);
}
if (rval != 0)
goto done_error;
goto done_error;
/* couldn't find it */
goto done_error;
}
/*
* Read the block that contains the requested GPE.
*/
if (rval) {
goto done_error;
}
/* Byte swap only the requested GPE */
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 (EOVERFLOW);
}
return (EINVAL);
}
#endif
return (EINVAL);
}
/*
* cmlb_dkio_set_vtoc creates duplicate minor nodes when
* relabeling an SMI disk. To avoid that we remove them
* before creating.
* It should be OK to remove a non-existed minor node.
*/
if (cmlb_validate_geometry(cl,
"cmlb_dkio_set_vtoc: "
"Failed validate geometry\n");
}
}
}
return (rval);
}
/*
* Function: cmlb_dkio_set_extvtoc
*/
static int
void *tg_cookie)
{
int rval = 0;
/*
* Checking callers data model does not make much sense here
* since extvtoc will always be equivalent to 64bit vtoc.
* What is important is whether the kernel is in 32 or 64 bit
*/
#ifdef _LP64
return (EFAULT);
}
#else
struct extvtoc user_extvtoc;
return (EFAULT);
}
#endif
return (EINVAL);
}
#endif
return (EINVAL);
}
/*
* cmlb_dkio_set_extvtoc creates duplicate minor nodes when
* relabeling an SMI disk. To avoid that we remove them
* before creating.
* It should be OK to remove a non-existed minor node.
*/
if (cmlb_validate_geometry(cl,
"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
{
#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 */
tg_cookie)) {
"cmlb_clear_efi: clear primary label failed\n");
}
}
/* the backup */
if (rval) {
goto done;
}
tg_cookie)) != 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
*/
goto done;
}
if (rval == 0) {
/* clear legacy backup EFI label */
"cmlb_clear_efi clear legacy backup@%lu\n",
cap - 2);
"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 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.
*/
blk = (diskaddr_t)(
#endif
"cmlb_set_vtoc: wrote backup label %llx\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);
}
/*
* This routine implements the DKIOCSETEFI ioctl. This ioctl is currently
* the Protective MBR.
*/
static int
void *tg_cookie)
{
int rval = 0;
void *buffer;
return (EFAULT);
if (user_efi.dki_length == 0 ||
return (EINVAL);
(cl->cl_tgt_blocksize == 0) ||
return (EINVAL);
}
} else {
/*
* let's clear the vtoc labels and clear the softstate
* vtoc.
*/
"cmlb_dkio_set_efi: CLEAR VTOC\n");
} else
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.
*/
"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);
}
/*ARGSUSED*/
static int
void *tg_cookie)
{
int fdisk_rval;
if (fdisk_rval != 0) {
return (fdisk_rval);
}
return (fdisk_rval);
}
#endif
/*
* 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) {
/* Less than 80K */
/* 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 B_FALSE it indicates that the SOLARIS
* PARTITION has changed from the previous one, hence we will setup a
* default VTOC in this case.
*/
if (!cl->cl_f_geometry_is_valid) {
/* 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
void *tg_cookie)
{
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
}
}
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);
}
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 extpart_info p;
}
return (err);
}
#endif
int
{
int callers_length;
/* Always fallback to ddi_prop_op... */
}
/* Pick up capacity and blocksize information. */
if (capacity == 0)
goto fallback;
if (lbasize == 0)
/* Check for dynamic property of whole device. */
if (dev == DDI_DEV_T_ANY) {
/* Fallback to ddi_prop_op if we don't understand. */
dp = DP_NBLOCKS;
dp = DP_BLKSIZE;
else
goto fallback;
/* get callers length, establish length of our dynamic prop */
if (dp == DP_NBLOCKS)
else if (dp == DP_BLKSIZE)
/* service request for the length of the property */
return (DDI_PROP_SUCCESS);
switch (prop_op) {
case PROP_LEN_AND_VAL_ALLOC:
(mod_flags & DDI_PROP_CANSLEEP) ?
return (DDI_PROP_NO_MEMORY);
break;
case PROP_LEN_AND_VAL_BUF:
/* the length of the prop and the request must match */
if (callers_length != *lengthp)
return (DDI_PROP_INVAL_ARG);
break;
default:
return (DDI_PROP_INVAL_ARG);
}
/* transfer the value into the buffer */
if (dp == DP_NBLOCKS)
else if (dp == DP_BLKSIZE)
return (DDI_PROP_SUCCESS);
}
/*
* Support dynamic size oriented properties of partition. Requests
* issued under conditions where size is valid are passed to
* ddi_prop_op_nblocks with the size information, otherwise the
* request is passed to ddi_prop_op. Size depends on valid geometry.
*/
if (!cmlb_is_valid(cmlbhandle))
goto fallback;
/* Get partition nblocks value. */
/*
* Assume partition information is in sys_blocksize units, compute
* divisor for size(9P) property representation.
*/
/* Now let ddi_prop_op_nblocks_blksize() handle the request. */
}