raid_ioctl.c revision f9722deaa8da9978617bd4b5c9130f219e127193
/*
* 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 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* NAME: raid_ioctl.c
*
* DESCRIPTION: RAID driver source file containing IOCTL operations.
*
* ROUTINES PROVIDED FOR EXTERNAL USE:
* raid_commit() - commits MD database updates for a RAID metadevice
* md_raid_ioctl() - RAID metadevice IOCTL operations entry point.
*
* ROUTINES PROVIDED FOR INTERNAL USE:
* raid_getun() - Performs unit checking on a RAID metadevice
* init_col_nextio() - normal backend when zeroing column of RAID metadevice.
* init_col_int() - I/O interrupt while zeroing column of RAID metadevice.
* raid_init_columns() - Zero one or more columns of a RAID metadevice.
* raid_set() - used to create a RAID metadevice
* raid_get() - used to get the unit structure of a RAID metadevice
* raid_replace() - used to replace a component of a RAID metadevice
* raid_grow() - Concatenate to a RAID metadevice
* raid_change() - change dynamic values of a RAID metadevice
* raid_reset() - used to reset (clear / remove) a RAID metadevice
* raid_get_geom() - used to get the geometry of a RAID metadevice
* raid_get_vtoc() - used to get the VTOC on a RAID metadevice
* raid_set_vtoc() - used to set the VTOC on a RAID metadevice
* raid_get_extvtoc() - used to get the extended VTOC on a RAID metadevice
* raid_set_extvtoc() - used to set the extended VTOC on a RAID metadevice
* raid_getdevs() - return all devices within a RAID metadevice
* raid_admin_ioctl() - IOCTL operations unique to metadevices and RAID
*/
#include <sys/sysmacros.h>
extern int md_status;
extern md_ops_t raid_md_ops;
extern md_krwlock_t md_unit_array_rw;
extern mdq_anchor_t md_done_daemon;
extern mdq_anchor_t md_ff_daemonq;
extern int mdopen();
extern int mdclose();
extern void md_probe_one();
extern int md_init_probereq(md_probedev_impl_t *,
daemon_queue_t **);
extern md_resync_t md_cpr_resync;
extern void dump_mr_unit(mr_unit_t *);
typedef struct raid_ci {
int ci_col;
int ci_err;
int ci_flag;
} raid_ci_t;
/* values for the ci_flag */
#define COL_INITING (0x0001)
#define COL_INIT_DONE (0x0002)
#define COL_READY (0x0004)
/*
* NAME: raid_getun
* DESCRIPTION: performs a lot of unit checking on a RAID metadevice
* PARAMETERS: minor_t mnum - minor device number for RAID unit
* md_error_t *mde - pointer to error reporting structure
* int flags - pointer to error reporting structure
* STALE_OK - allow stale MD memory
* NO_OLD - unit must not exist
* NO_LOCK - no IOCTL lock needed
* WR_LOCK - write IOCTL lock needed
* RD_LOCK - read IOCTL lock needed
* IOLOCK *lock - pointer to IOCTL lock
*
* LOCKS: obtains unit reader or writer lock via IOLOCK
*
*/
static mr_unit_t *
{
mdi_unit_t *ui;
return (NULL);
}
return (NULL);
}
}
return (NULL);
}
return ((mr_unit_t *)1);
}
return (NULL);
}
if (flags & ARRAY_WRITER)
else if (flags & ARRAY_READER)
} else /* RD_LOCK */
}
return (NULL);
}
return (un);
}
/*
* NAME: raid_commit
* DESCRIPTION: commits MD database updates for a RAID metadevice
* PARAMETERS: mr_unit_t *un - RAID unit to update in the MD database
* mddb_recid_t *extras - array of other record IDs to update
*
* LOCKS: assumes caller holds unit writer lock
*
*/
void
{
int ri = 0;
int nrecids = 0;
return;
/* Count the extra recids */
nrecids++;
}
}
/*
* Allocate space for two recids in addition to the extras:
* one for the unit structure, one for the null terminator.
*/
nrecids += 2;
recids = (mddb_recid_t *)
}
while (*extras != 0) {
extras++;
}
}
if (ri > 0) {
}
}
static int
{
char *buf;
int i;
int err = 0;
for (i = 0; i < un->un_totalcolumncnt; i++) {
/*
* Open by device id
* If this device is hotspared
* use the hotspare key
*/
return (1);
}
SEMA_DEFAULT, NULL);
SEMA_DEFAULT, NULL);
err = 1;
if (i == 0) {
} else {
}
}
/*
* depending upon being an 64bit or 32 bit raid, the
* pre write headers have different layout
*/
err = 1;
} else {
err = 1;
}
if (err)
break;
}
return (err);
}
/*
* NAME: init_col_nextio
* DESCRIPTION: normal backend process when zeroing column of a RAID metadevice.
* PARAMETERS: raid_ci_t *cur - struct for column being zeroed
*
* LOCKS: assumes caller holds unit reader lock,
* preiodically releases and reacquires unit reader lock,
* broadcasts on unit conditional variable (un_cv)
*
*/
#define INIT_RLS_CNT 10
static void
{
/* ===> update un_percent_done */
/*
* When gorwing a device, normal I/O is still going on.
* The init thread still holds the unit reader lock which
* prevents I/O from doing state changes.
* unit reader lock.
*
* CAVEAT:
* We know we are in the middle of a grow operation and the
* unit cannot be grown or removed (through reset or halt)
* so the mr_unit_t structure will not move or disappear.
* can be in col_init_nextio at a time because they are
* placed on the md_done_daemon queue and md only processes
* one element of this queue at a time. In addition, any
* code that needs to acquire the unit writer lock to change
* state is supposed to be on the md_mstr_daemon queue so
* it can be processing while we sit here waiting to get the
* unit reader lock back.
*/
/* truncate last chunk to end_addr if needed */
}
/* set address and length for I/O bufs */
return;
}
/* finished initializing this column */
}
/*
* NAME: init_col_int
* DESCRIPTION: I/O interrupt while zeroing column of a RAID metadevice.
* PARAMETERS: buf_t *cb - I/O buffer for which interrupt occurred
*
* LOCKS: assumes caller holds unit reader or writer lock
*
*/
static int
{
return (1);
}
return (1);
}
/*
* NAME: raid_init_columns
* DESCRIPTION: Zero one or more columns of a RAID metadevice.
* PARAMETERS: minor_t mnum - RAID unit minor identifier
*
* LOCKS: obtains and releases unit reader lock,
* obtains and releases unit writer lock,
* obtains and releases md_unit_array_rw write lock,
* obtains and releases unit mutex (un_mx) lock,
* waits on unit conditional variable (un_cv)
*
*/
static void
{
mdi_unit_t *ui;
int err = 0;
int ix;
int colcnt = 0;
int col;
/*
* Increment the raid resync count for cpr
*/
/*
* initialization is a multiple step process. The first step
* is to go through the unit structure and start each device
* in the init state writing zeros over the component.
* Next initialize the prewrite areas, so the device can be
* used if a metainit -k is done. Now close the componenets.
*
* Once this complete set the state of each component being
* zeroed and set the correct state for the unit.
*
* last commit the records.
*/
/* check for active init on this column */
/* exiting is cpr safe */
/*
* Decrement the raid resync count for cpr
*/
thread_exit();
}
un->un_init_colcnt = 0;
un->un_init_iocnt = 0;
/* allocate zero-filled buffer */
continue;
/* allocate new column init structure */
un->un_init_colcnt++;
/* initialize static buf fields */
/* set address and length for I/O bufs */
/*
* Open by device id
* If this column is hotspared then
* use the hotspare key
*/
MD_OFLG_NULL)) == 0)
}
}
while (colcnt) {
colcnt = 0;
(void) init_pw_area(un,
col);
}
} else {
colcnt++;
}
}
}
/* This prevents new opens */
(void) md_io_writerlock(ui);
while (ci_chain) {
/* take this element out of the chain */
/* free this element */
RCS_INIT_ERRED, 0);
else
RCS_OKAY, 0);
}
/* free the zeroed buffer */
/* determine new unit state */
if (err == 0) {
else {
un->un_grow_tb = 0;
}
} else { /* error orcurred */
}
un->un_init_colcnt = 0;
un->un_init_iocnt = 0;
(void) md_io_writerexit(ui);
if (err) {
} else {
}
} else {
}
/*
* Decrement the raid resync count for cpr
*/
thread_exit();
/*NOTREACHED*/
}
static int
{
mdi_unit_t *ui;
int rval, i;
/* Don't start an init if the device is not available */
}
OTYP_LYR, MD_OFLG_ISINIT)) {
goto out;
}
un->un_percent_done = 0;
/* start resync_unit thread */
return (0);
out:
/* recover state */
for (i = 0; i < un->un_totalcolumncnt; i++)
} else {
}
return (rval);
}
/*
* NAME: raid_regen
*
* DESCRIPTION: regenerate all the parity on the raid device. This
* routine starts a thread that will regenerate the
* parity on a raid device. If an I/O error occurs during
* this process the entire device is placed in error.
*
* PARAMETERS: md_set_params_t *msp - ioctl packet
*/
static void
{
int err = 0;
/*
* Increment raid resync count for cpr
*/
un->un_percent_done = 0;
/*
* The following assignment is only correct because
* md_raid_strategy is fine when it's only a minor number
* and not a real dev_t. Yuck.
*/
err = 1;
break;
}
/* just to avoid rounding errors */
}
(void) md_io_writerlock(ui);
(void) md_io_writerexit(ui);
if (!err &&
if (err ||
} else {
}
/*
* Decrement the raid resync count for cpr
*/
thread_exit();
}
static int
{
mdi_unit_t *ui;
int i;
/* Don't start a regen if the device is not available */
}
(void) md_unit_writerlock(ui);
for (i = 0; i < un->un_totalcolumncnt; i++)
}
/* start resync_unit thread */
return (0);
}
static int
{
}
}
}
}
/* get locks and recheck to be sure something did not change */
return (0);
}
}
/*
* NAME: raid_set
* DESCRIPTION: used to create a RAID metadevice
* PARAMETERS: md_set_params_t *d - pointer to set data structure
* int mode - must be FWRITE
*
* LOCKS: none
*
*/
static int
{
int err;
int num_recs;
int rid;
int col;
md_set_params_t *msp = d;
return (0);
/* create the db record for this mdstruct */
#if defined(_ILP32)
#else
#endif
} else {
}
if (mr_recid < 0)
/* get the address of the mdstruct */
/*
* It is okay that we muck with the mdstruct here,
* since no one else will know about the mdstruct
* until we commit it. If we crash, the record will
* be automatically purged, since we haven't
* committed it yet.
*/
/* copy in the user's mdstruct */
return (EFAULT);
}
/* All 64 bit metadevices only support EFI labels. */
}
/*
* allocate the real recids array. since we may have to commit
* underlying metadevice records, we need an array of size:
* total number of components in raid + 3 (1 for the raid itself,
* one for the hotspare, one for the end marker).
*/
rid = 0;
un->un_resync_copysize = 0;
goto out;
}
}
goto out;
}
/*
* Update unit availability
*/
/* increment the reference count of the hot spare pool */
if (err) {
goto out;
}
rid++;
}
/*
* set the parent on any metadevice components.
* NOTE: currently soft partitions are the only metadevices
* which can appear within a RAID metadevice.
*/
}
}
/* set the end marker */
out:
if (err)
return (err);
/* only attempt to init a device that is in the init state */
return (0);
}
/*
* NAME: raid_get
* DESCRIPTION: used to get the unit structure of a RAID metadevice
* PARAMETERS: md_i_get_t *migp - pointer to get data structure
* int mode - must be FREAD
* IOLOCK *lock - pointer to IOCTL lock
*
* LOCKS: obtains unit reader lock via IOLOCK
*
*/
static int
void *migp,
int mode,
)
{
return (0);
return (0);
}
return (EFAULT);
}
return (EFAULT);
return (0);
}
/*
* NAME: raid_replace
* DESCRIPTION: used to replace a component of a RAID metadevice
* PARAMETERS: replace_params_t *mrp - pointer to replace data structure
* IOLOCK *lock - pointer to IOCTL lock
*
* LOCKS: obtains unit writer lock via IOLOCK (through raid_getun),
* obtains and releases md_unit_array_rw write lock
*
*/
static int
)
{
int force = 0;
int err = 0;
int nkeys;
int extra_rids = 0;
mdclrerror(ep);
}
}
}
/* get locks and recheck to be sure something did not change */
return (0);
}
/*
* Try to resolve devt again if NODEV64
*/
}
break;
} else {
/*
* Now we use the keys to match.
* If no key found, continue.
*/
if (nkeys == 0) {
continue;
}
if (nkeys > 1)
return (mddeverror(ep,
MDE_MULTNM, odev));
break;
}
}
}
}
if (col == -1)
force = 1;
cmd = ENABLE_COMP;
cmd = REPLACE_COMP;
/* Must use -f force flag for unit in LAST_ERRED state */
if (!force)
/* Must use -f force flag on ERRED column first */
return (mdcomperror(ep,
}
}
/* must use -f force flag on LAST_ERRED columns next */
}
(RCS_ERRED | RCS_INIT_ERRED)))
}
if (state & RCS_INIT_ERRED) {
un->un_percent_done = 0;
if (cmd == REPLACE_COMP) {
/*
* open the device by device id
*/
tmpdev));
}
/*
* If it's a metadevice, make sure it gets reparented
*/
}
/*
* If the old device was a metadevice, make sure to
* reset its parent.
*/
extra_recids[extra_rids++] =
}
} else {
/*
* not hot spared. Close the old device and
* move the new device in.
*/
}
}
/*
* If the old device is not a metadevice then
* save off the set number and key so that it
* can be removed from the namespace later.
*/
}
}
if (cmd == ENABLE_COMP) {
/*
* We trust the dev_t because we cannot determine the
* dev_t from the device id since a new disk is in the
* same location. Since this is a call from metareplace -e dx
* AND it is SCSI a new dev_t is not generated. So the
* dev_t from the mddb is used. Before enabling the device
* we check to make sure that multiple entries for the same
* device does not exist in the namespace. If they do we
* fail the ioctl.
* One of the many ways multiple entries in the name space
* can occur is if one removed the failed component in a
* RAID metadevice and put another disk that was part of
* another metadevice. After reboot metadevadm would correctly
* update the device name for the metadevice whose component
* has moved. However now in the metadb there are two entries
* for the same name (ctds) that belong to different
* metadevices. One is valid, the other is a ghost or "last
* know as" ctds.
*/
/*
* check for multiple entries in namespace for the
* same dev
*/
&nkeys) != 0)
/*
* If number of keys are greater that
* 1, then we have an invalid
* namespace. STOP and return.
*/
if (nkeys > 1)
} else {
MD_OFLG_NULL)) {
return (mdcomperror(ep,
}
tmpdev != 0);
== 1)) {
"md: could not"
" update namespace\n");
}
}
}
}
}
} else {
}
/* If the component has been replaced - clean up the name space */
}
} else {
}
mdclrerror(ep);
if (!err)
return (0);
/* be sure state */
/* is already set by this time */
/* fix state and commit record */
if (state & RCS_INIT_ERRED)
else
mdclrerror(ep);
return (0);
}
/*
* NAME: raid_set_sync
* DESCRIPTION: used to sync a component of a RAID metadevice
* PARAMETERS: md_resync_ioctl_t *mrp - pointer to resync data structure
* int mode - must be FWRITE
* IOLOCK *lock - pointer to IOCTL lock
*
* LOCKS: obtains unit writer lock via IOLOCK (through raid_getun),
* obtains and releases md_unit_array_rw write lock
*
*/
static int
)
{
int init = 0;
int resync = 0;
int regen = 0;
int ix;
int err;
return (0);
/* This prevents new opens */
regen++;
resync++;
init++;
rip->ri_percent_done = 0;
if (init) {
}
/*
* If resync is needed, it will call raid_internal_open forcing
* replay before the open completes.
* Otherwise, call raid_internal_open directly to force
* replay to complete during boot (metasync -r).
* NOTE: the unit writer lock must remain held while setting
* MD_UN_RESYNC_ACTIVE but must be released before
* calling raid_resync_unit or raid_internal_open.
*/
if (resync) {
/* Must release unit writer lock for resync */
/*
* correctly setup the devices before trying to start the
* resync operation.
*/
}
break;
}
}
rip->ri_percent_done = 0;
return (err);
}
if (regen) {
return (err);
}
/* The unit requires not work so just force replay of the device */
return (0);
}
/*
* NAME: raid_get_resync
* DESCRIPTION: used to check resync status on a component of a RAID metadevice
* PARAMETERS: md_resync_ioctl_t *mrp - pointer to resync data structure
* int mode - must be FWRITE
* IOLOCK *lock - pointer to IOCTL lock
*
* LOCKS: none
*
*/
static int
)
{
int cnt;
int ix;
uint64_t d;
return (0);
d = un->un_segsincolumn;
if (percent > 1000)
}
percent =
if (percent > 1000)
percent =
if (percent > 1000)
percent = 1000;
}
cnt = 0;
case RCS_INIT:
case RCS_ERRED:
case RCS_LAST_ERRED:
cnt++;
break;
default:
break;
}
}
d = un->un_totalcolumncnt;
return (0);
}
/*
* NAME: raid_grow
* DESCRIPTION: Concatenate to a RAID metadevice
* PARAMETERS: md_grow_params_t *mgp
* - pointer to IOCGROW data structure
* int mode - must be FWRITE
*
* LOCKS: obtains unit writer lock via IOLOCK (through raid_getun),
* obtains and releases md_unit_array_rw write lock
*
*/
static int
{
mdi_unit_t *ui;
mddb_recid_t old_vtoc = 0;
int err;
int col, i;
int tc;
int rval = 0;
}
}
}
}
}
NULL)
return (0);
return (EINVAL);
/*
* Preserve the friendly name nature of the device that is
* growing.
*/
#if defined(_ILP32)
#else
#endif
} else {
}
if (mr_recid < 0) {
return (rval);
}
/* get the address of the new unit */
/*
* It is okay that we muck with the new unit here,
* since no one else will know about the unit struct
* until we commit it. If we crash, the record will
* be automatically purged, since we haven't
* committed it yet and the old unit struct will be found.
*/
/* copy in the user's unit struct */
if (err) {
return (EFAULT);
}
/* make sure columns are being added */
return (EINVAL);
}
/*
* Save a few of the new unit structs fields.
* Before they get clobbered.
*/
/*
* Copy the old unit struct (static stuff)
* into new unit struct
*/
/*
* Restore a few of the new unit struct values.
*/
/*
* Save old column slots
*/
/*
* Allocate new column slot
*/
KM_SLEEP);
/*
* Restore old column slots
* Free the old column slots
*/
/* All 64 bit metadevices only support EFI labels. */
/*
* If the device was previously smaller than a terabyte,
* and had a vtoc record attached to it, we remove the
* vtoc record, because the layout has changed completely.
*/
(un->c.un_vtoc_id != 0)) {
new_un->c.un_vtoc_id =
}
}
/*
* allocate the real recids array. since we may have to commit
* underlying metadevice records, we need an array of size:
* total number of new components being attach + 2 (one for the
* raid itself, one for the end marker).
*/
rid = 0;
/* release pwslots already allocated by grow */
}
sizeof (mr_column_ic_t) *
return (EINVAL);
}
/*
* set parent on metadevices being added.
* NOTE: currently soft partitions are the only metadevices
* which can appear within a RAID metadevice.
*/
}
}
/* set end marker */
/* commit new unit struct */
/* delete old unit struct */
/* place new unit in in-core array */
/*
* If old_vtoc has a non zero value, we know:
* - This unit crossed the border from smaller to larger one TB
* - There was a vtoc record for the unit,
* - This vtoc record is no longer needed, because
* a new efi record has been created for this un.
*/
if (old_vtoc != 0) {
}
/* free recids */
/*
* Since the md_ioctl_writelock aquires the unit write lock
* to drop the unit write lock and then reaquire it as needed
* later.
*/
return (rval);
}
(void) md_unit_writerlock(ui);
for (i = 0; i < new_un->un_totalcolumncnt; i++) {
}
(void) md_unit_writerlock(ui);
/* create a background thread to initialize the columns */
}
/*
* NAME: raid_reset
* DESCRIPTION: used to reset (clear / remove) a RAID metadevice
* PARAMETERS: md_i_reset_t *mirp - pointer to reset data structure
*
* LOCKS: obtains and releases md_unit_array_rw write lock
*
*/
static int
{
mdi_unit_t *ui;
/*
* NOTE: need to get md_unit_writerlock to avoid conflict
* with raid_init thread.
*/
NULL) {
return (0);
}
}
}
}
/*
* Update unit availability
*/
/*
* If MN set, reset s_un_next so all nodes can have
* the same view of the next available slot when
* nodes are -w and -j
*/
if (MD_MNSET_SETNO(setno)) {
}
return (0);
}
/*
* NAME: raid_get_geom
* DESCRIPTION: used to get the geometry of a RAID metadevice
* PARAMETERS: mr_unit_t *un - RAID unit to get the geometry for
* struct dk_geom *gp - pointer to geometry data structure
*
* LOCKS: none
*
*/
static int
)
{
return (0);
}
/*
* NAME: raid_get_vtoc
* DESCRIPTION: used to get the VTOC on a RAID metadevice
* PARAMETERS: mr_unit_t *un - RAID unit to get the VTOC from
* struct vtoc *vtocp - pointer to VTOC data structure
*
* LOCKS: none
*
*/
static int
)
{
return (0);
}
/*
* NAME: raid_set_vtoc
* DESCRIPTION: used to set the VTOC on a RAID metadevice
* PARAMETERS: mr_unit_t *un - RAID unit to set the VTOC on
* struct vtoc *vtocp - pointer to VTOC data structure
*
* LOCKS: none
*
*/
static int
)
{
}
/*
* NAME: raid_get_extvtoc
* DESCRIPTION: used to get the extended VTOC on a RAID metadevice
* PARAMETERS: mr_unit_t *un - RAID unit to get the VTOC from
* struct extvtoc *vtocp - pointer to extended VTOC data structure
*
* LOCKS: none
*
*/
static int
)
{
return (0);
}
/*
* NAME: raid_set_extvtoc
* DESCRIPTION: used to set the extended VTOC on a RAID metadevice
* PARAMETERS: mr_unit_t *un - RAID unit to set the VTOC on
* struct extvtoc *vtocp - pointer to extended VTOC data structure
*
* LOCKS: none
*
*/
static int
)
{
}
/*
* NAME: raid_get_cgapart
* DESCRIPTION: used to get the dk_map on a RAID metadevice
* PARAMETERS: mr_unit_t *un - RAID unit to set the VTOC on
* struct vtoc *dkmapp - pointer to dk_map data structure
*
* LOCKS: none
*
*/
static int
)
{
return (0);
}
/*
* NAME: raid_getdevs
* DESCRIPTION: return all devices within a RAID metadevice
* PARAMETERS: md_getdevs_params_t *mgdp
* - pointer to getdevs IOCTL data structure
* int mode - should be FREAD
*
* LOCKS: obtains unit reader lock via IOLOCK
*
*/
static int
void *mgdp,
int mode,
)
{
int i, cnt;
/* check out unit */
return (0);
if ((unit_dev = md_xlate_mini_2_targ
return (ENODEV);
}
return (EFAULT);
}
cnt++;
continue;
if ((unit_dev = md_xlate_mini_2_targ
return (ENODEV);
}
return (EFAULT);
}
}
return (0);
}
/*
* NAME: raid_change
* DESCRIPTION: used to change the following dynamic values:
* the hot spare pool
* in the unit structure of a RAID metadevice
* PARAMETERS: md_change_params_t *mcp - pointer to change data structure
* IOLOCK *lock - pointer to IOCTL lock
*
* LOCKS: obtains unit writer lock via IOLOCK (through raid_getun)
*
*/
static int
)
{
int ix;
int err;
int irecid;
int inc_new_hsp = 0;
return (0);
return (0);
/* verify that no hotspare is in use */
}
}
/* replace the hot spare pool */
irecid = 0;
/* increment the reference count of the new hsp */
if (err) {
}
inc_new_hsp = 1;
irecid++;
}
/* decrement the reference count of the old hsp */
if (err) {
if (inc_new_hsp) {
(void) md_hot_spare_ifc(HSP_DECREF,
/*
* Don't need to commit the record,
* because it wasn't committed before
*/
}
return (err);
}
}
/* Now trigger hot spare processing in case one is needed. */
(void) raid_hotspares();
return (0);
}
/*
* NAME: raid_admin_ioctl
* DESCRIPTION: IOCTL operations unique to metadevices and RAID
* PARAMETERS: int cmd - IOCTL command to be executed
* void *data - pointer to IOCTL data structure
* int mode - either FREAD or FWRITE
*
* LOCKS: none
*
*/
static int
int cmd,
void *data,
int mode,
)
{
void *d = NULL;
int err = 0;
/* We can only handle 32-bit clients for internal commands */
return (EINVAL);
}
/* dispatch ioctl */
switch (cmd) {
case MD_IOCSET:
{
return (EACCES);
sz = sizeof (md_set_params_t);
break;
}
break;
}
case MD_IOCGET:
{
return (EACCES);
sz = sizeof (md_i_get_t);
break;
}
break;
}
case MD_IOCREPLACE:
{
return (EACCES);
sz = sizeof (replace_params_t);
break;
}
break;
}
case MD_IOCSETSYNC:
{
return (EACCES);
sz = sizeof (md_resync_ioctl_t);
break;
}
break;
}
case MD_IOCGETSYNC:
{
return (EACCES);
sz = sizeof (md_resync_ioctl_t);
break;
}
break;
}
case MD_IOCGROW:
{
return (EACCES);
sz = sizeof (md_grow_params_t);
break;
}
break;
}
case MD_IOCCHANGE:
{
return (EACCES);
sz = sizeof (md_raid_params_t);
break;
}
break;
}
case MD_IOCRESET:
{
return (EACCES);
sz = sizeof (md_i_reset_t);
break;
}
break;
}
case MD_IOCGET_DEVS:
{
return (EACCES);
sz = sizeof (md_getdevs_params_t);
break;
}
break;
}
case MD_IOCSETREGEN:
{
return (EACCES);
sz = sizeof (md_regen_param_t);
break;
}
break;
}
case MD_IOCPROBE_DEV:
{
md_probedev_impl_t *p = NULL;
int i;
return (EACCES);
sz = sizeof (md_probedev_t);
/* now copy in the data */
goto free_mem;
}
/*
* Sanity test the args. Test name should have the keyword
* probe.
*/
p->probe_sema = NULL;
ph = (md_probedev_t *)d;
sizeof (md_driver_t));
goto free_mem;
}
KM_SLEEP);
goto free_mem;
}
goto free_mem;
/*
* put the request on the queue and wait.
*/
(void) IOLOCK_RETURN(0, lockp);
/* wait for the events to occur */
sema_p(PROBE_SEMA(p));
}
while (md_ioctl_lock_enter() == EINTR)
;
/*
* clean up. The hdr list is freed in the probe routines
* since the list is NULL by the time we get here.
*/
if (p) {
if (p->probe_sema != NULL) {
sema_destroy(PROBE_SEMA(p));
}
mutex_destroy(PROBE_MX(p));
}
kmem_free(p, sizeof (md_probedev_impl_t));
}
break;
}
default:
return (ENOTTY);
}
/*
* copyout and free any args
*/
if (sz != 0) {
if (err == 0) {
}
}
}
return (err);
}
/*
* NAME: md_raid_ioctl
* DESCRIPTION: RAID metadevice IOCTL operations entry point.
* PARAMETERS: md_dev64_t dev - RAID device identifier
* int cmd - IOCTL command to be executed
* void *data - pointer to IOCTL data structure
* int mode - either FREAD or FWRITE
*
* LOCKS: none
*
*/
int
int cmd,
void *data,
int mode,
)
{
int err = 0;
/* handle admin ioctls */
if (mnum == MD_ADM_MINOR)
/* check unit */
return (ENXIO);
/* is this a supported ioctl? */
if (err != 0) {
return (err);
}
/* dispatch ioctl */
switch (cmd) {
case DKIOCINFO:
{
struct dk_cinfo *p;
return (EACCES);
p = kmem_alloc(sizeof (*p), KM_SLEEP);
kmem_free(p, sizeof (*p));
return (err);
}
case DKIOCGMEDIAINFO:
{
struct dk_minfo p;
return (EACCES);
return (err);
}
case DKIOCGGEOM:
{
struct dk_geom *p;
return (EACCES);
p = kmem_alloc(sizeof (*p), KM_SLEEP);
mode) != 0)
}
kmem_free(p, sizeof (*p));
return (err);
}
case DKIOCGVTOC:
{
return (EACCES);
return (err);
}
}
#ifdef _SYSCALL32
else {
}
#endif /* _SYSCALL32 */
return (err);
}
case DKIOCSVTOC:
{
return (EACCES);
}
}
#ifdef _SYSCALL32
else {
} else {
}
}
#endif /* _SYSCALL32 */
if (err == 0)
return (err);
}
case DKIOCGEXTVTOC:
{
return (EACCES);
return (err);
}
return (err);
}
case DKIOCSEXTVTOC:
{
return (EACCES);
}
if (err == 0)
return (err);
}
case DKIOCGAPART:
{
return (err);
}
mode) != 0)
}
#ifdef _SYSCALL32
else {
mode) != 0)
}
#endif /* _SYSCALL32 */
return (err);
}
case DKIOCGETEFI:
{
/*
* This one can be done centralized,
* no need to put in the same code for all types of metadevices
*/
}
case DKIOCSETEFI:
{
/*
* This one can be done centralized,
* no need to put in the same code for all types of metadevices
*/
}
case DKIOCPARTITION:
{
}
default:
return (ENOTTY);
}
}
/*
* Most functions are handled generically, except for raid-specific locking
* and checking
*/
/*
* NAME: raid_may_renexch_self
* DESCRIPTION: support routine for rename check ("MDRNM_CHECK") named service
* PARAMETERS: mr_unit_t *un - unit struct of raid unit to be renamed
* mdi_unit_t *ui - in-core unit struct of same raid unit
* md_rentxn_t *rtxnp - rename transaction state
*
* LOCKS: none
*
*/
static int
mdi_unit_t *ui,
{
from_min);
return (EINVAL);
}
return (EINVAL);
}
return (EINVAL);
}
/* we're related if trying to swap with our parent */
case MDRNOP_EXCHANGE:
if (!related) {
return (EINVAL);
}
break;
case MDRNOP_RENAME:
/*
* if from is top-level and is open, then the kernel is using
* the md_dev64_t.
*/
from_min);
return (EBUSY);
}
break;
default:
from_min);
return (EINVAL);
}
return (0); /* ok */
}
/*
* NAME: raid_rename_check
* PARAMETERS: md_rendelta_t *delta - describes changes to be made to this
* raid device for rename transaction
* md_rentxn_t *rtxnp - rename transaction state
*
* LOCKS: none
*
*/
{
int err = 0;
int column;
return (EINVAL);
}
if (colstate & RCS_LAST_ERRED) {
return (EINVAL);
}
if (colstate & RCS_INIT_ERRED) {
return (EINVAL);
}
/* How did we get this far before detecting this? */
if (colstate & RCS_RESYNC) {
return (EBUSY);
}
return (EINVAL);
}
return (EINVAL);
}
return (EINVAL);
}
}
/* self does additional checks */
}
return (err);
}
/*
* NAME: raid_rename_lock
* PARAMETERS: md_rendelta_t *delta - describes changes to be made to this
* raid device for rename transaction
* md_rentxn_t *rtxnp - rename transaction state
*
* LOCKS: io and unit locks (taken explicitly *not* via ioctl wrappers)
*
*/
{
return (0);
}
return (ENODEV);
}
return (ENODEV);
}
return (0);
}
/*
* NAME: raid_rename_unlock
* PARAMETERS: md_rendelta_t *delta - describes changes to be made to this
* raid device for rename transaction
* md_rentxn_t *rtxnp - rename transaction state
*
* LOCKS: drops io and unit locks
*
*/
/* ARGSUSED */
void
{
int col;
goto out;
}
OTYP_LYR, MD_OFLG_ISINIT) == 0) {
(void) init_pw_area(un,
}
}
out:
}