md_ioctl.c revision b6c8bd52ccb0f3491c2bd1f5867985cef630564a
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* Driver for Virtual Disk.
*/
#include <sys/sysmacros.h>
#include <sys/efi_partition.h>
extern int md_nmedh;
extern md_set_io_t md_set_io[];
extern int md_status;
extern int md_ioctl_cnt;
extern int md_in_upgrade;
/* md.c */
extern kcondvar_t md_cv;
/* md_med.c */
extern int med_addr_tab_nents;
static int md_mn_commd_present;
/* md_mddb.c */
extern void mddb_setexit(mddb_set_t *s);
/*
* md_mn_is_commd_present:
* ----------------------
* Determine if commd is running on this node.
*
* Returns:
* 1 if commd has been started
* 0 if commd has not been started or has exited
*/
int
md_mn_is_commd_present(void)
{
return (md_mn_commd_present ? 1 : 0);
}
/*
* md_mn_clear_commd_present:
* -------------------------
* Clear the commd_present flag. Called only from a CPR request to suspend /
* terminate a resync thread. We clear the md_mn_commd_present flag so that
* any RPC request that was in transit can complete with a failure and _not_
* result in an unexpected system panic.
*/
void
{
md_mn_commd_present = 0;
}
static int
)
{
int err;
mddb_set_t *s;
return (-1);
mddb_setexit(s);
return (-1);
}
mddb_setexit(s);
return (0);
}
static int
{
char *name;
int err = 0;
/*
* Don't allow addition of new names to namespace during upgrade.
*/
if (MD_UPGRADE) {
return (EAGAIN);
}
return (EACCES);
return (0);
return (ENODEV);
if (err) {
goto out;
}
else
char *drvnm;
}
goto out;
}
out:
return (err);
}
static int
int mode
)
{
char *name;
int err = 0;
return (0);
return (ENODEV);
else
char *drvnm;
if (MD_UPGRADE)
else
}
if (MD_UPGRADE)
else
}
if (err) {
if (err < 0)
goto out;
}
if (err) {
if (err < 0)
goto out;
}
if (err) {
goto out;
}
out:
return (err);
}
/*ARGSUSED*/
static int
char *dname,
char *pname,
int mode
)
{
return (0);
return (0);
return (0);
return (ENODEV);
else
}
/*ARGSUSED*/
static int
int mode
)
{
return (0);
return (0);
return (0);
return (ENODEV);
else
}
/*ARGSUSED*/
static int
char *dname,
char *pname,
int mode
)
{
return (0);
return (0);
return (0);
return (ENODEV);
else
}
/*ARGSUSED*/
static int
int mode
)
{
return (0);
return (EINVAL);
return (ENODEV);
else
return (0);
}
/*ARGSUSED*/
static int
{
return (0);
return (ENODEV);
else
}
/*ARGSUSED*/
static int
{
mdi_unit_t *ui;
return (0);
}
return (ENODEV);
}
setno);
return (0);
}
/*ARGSUSED*/
static int
{
int modindex;
int found = 0;
return (0);
else
}
if (modindex == -1) {
}
while (next) {
found = 1;
break;
}
found = 1;
/* continue looking for smallest */
}
}
if (! found)
return (0);
}
/*ARGSUSED*/
static int
getnum_ioctl(void *d, int mode)
{
int modindex;
int sz;
int err = 0;
int minor_array_length;
int count = 0;
struct md_i_getnum *gn = d;
/* number of specified devices in specified set - if 0 return count */
if (minor_array_length > md_nunits)
return (EINVAL);
return (0);
} else {
}
}
if (modindex == -1) {
}
/* if array length is not 0 then allocate the output buffers */
if (minor_array_length != 0) {
}
count = 0;
while (next) {
if ((minor_array_length > 0) &&
(count < minor_array_length)) {
m_ptr++;
}
count++;
}
}
/* now copy the array back */
if (minor_array_length > 0) {
}
return (err);
}
/*ARGSUSED*/
static int
)
{
int cnt = 0;
int err = 0;
return (0);
return (EINVAL);
}
return (ENODEV);
if (cnt == -1)
err = -1;
err = -1;
}
} else {
/* invalid mode */
}
return (err);
}
/*ARGSUSED*/
static int
int mode
)
{
int err = 0;
return (0);
return (EINVAL);
}
return (ENODEV);
/*
* Tell user that replica is not in devid mode
*/
& MDDB_DEVID_STYLE) && md_keep_repl_state) {
}
/*
* If user is prepared to receive the devid allocate a kernel buffer.
*/
if (nm->devid_size != 0) {
/* check for bogus value of devid_size */
return (EINVAL);
}
}
if (err) {
if (err < 0)
goto out;
}
/*
* If devid size was already known to user then give them the devid.
*/
out:
return (err);
}
int
{
/* Verify that setno is in valid range */
return (EINVAL);
/*
* When adding the first disk to a MN diskset, the master
* needs to be set (in order to write out the mddb)
* before the set is snarfed or even before the set
* is marked as a MNset in the md_set structure.
* So, don't check for MNset or SNARFED and don't call
* mddb_setenter. In order to discourage bad ioctl calls,
* verify that magic field in structure is set correctly.
*/
return (EINVAL);
if (info->c_current_host_master)
else
return (0);
}
/*
* Set the devid for the namespace record identified by the tuple
* [setno, sideno, key]. The key is the namespace key. The md_getdevnum()
* function is used to actually regenerate the devid.
*/
/*ARGSUSED*/
static int
int mode
)
{
/*
* If upgrading do not allow modification of the namespace.
*/
if (MD_UPGRADE)
return (EAGAIN);
return (0);
return (0);
return (EINVAL);
return (ENODEV);
return (ENODEV);
return (0);
}
/*ARGSUSED*/
static int
int mode
)
{
int err = 0;
return (0);
return (0);
return (ENODEV);
goto out;
}
if (err) {
if (err < 0)
goto out;
}
out:
return (err);
}
static int
{
void *data;
int status;
int flags;
return (EINVAL);
return (0);
return (ENODEV);
case MD_DB_GETNEXTREC:
/*
* Is ur_recid a valid one ?
*/
return (EINVAL);
}
break;
case MD_DB_COMMIT_ONE:
/*
* Is ur_recid a valid one?
*/
return (EINVAL);
return (ENXIO);
/*
* For MN sets we panic if there are too few database replicas
* and we're attempting to add entries to the log.
*/
if (status != 0) {
"md: Panic due to lack of DiskSuite state\n"
" database replicas. Fewer than 50%% of "
"the total were available,\n so panic to "
"ensure data integrity.");
}
}
break;
case MD_DB_COMMIT_MANY:
return (EINVAL);
return (EFAULT);
}
while (*recids != 0) {
/*
* Is recid a valid ?
*/
return (EINVAL);
}
return (ENXIO);
}
}
/*
* For MN sets we panic if there are too few database replicas
* and we're attempting to add entries to the log.
*/
if (status != 0) {
"md: Panic due to lack of DiskSuite state\n"
" database replicas. Fewer than 50%% of "
"the total were available,\n so panic to "
"ensure data integrity.");
}
}
break;
case MD_DB_GETDATA:
/*
* Check ur_recid
*/
return (EINVAL);
return (ENXIO);
return (EINVAL);
return (EFAULT);
}
break;
case MD_DB_SETDATA:
return (EINVAL);
return (ENXIO);
return (EINVAL);
return (EFAULT);
}
break;
case MD_DB_DELETE:
return (EINVAL);
return (ENXIO);
if (status < 0)
break;
case MD_DB_CREATE:
{
int mn_set = 0;
mn_set = 1;
return (EINVAL);
else
break;
}
case MD_DB_GETSTATUS:
return (EINVAL);
break;
case MD_DB_GETSIZE:
return (EINVAL);
break;
case MD_DB_MAKEID:
return (EINVAL);
break;
default:
return (EINVAL);
}
return (0);
}
static int
)
{
mdi_unit_t *ui;
return (ENXIO);
}
return (0);
}
/*
* mddb_didstat_from_user -- called for DIDSTAT ioctl. 2 different calling
* scenarios.
* 1) data->mode == MD_FIND_INVDID
* when user is inquiring about the existence of invalid device id's.
* Upon return to the user d->cnt may have a value in it.
* 2) data->mode == MD_GET_INVDID
* when the user wants a list of the invalid device id's.
* In this case d->ctdp is non Null and cnt has a value in it.
*
* Basically this routine along with mddb_didstat_to_user can be eliminated
* by pushing ddi_copyout down to lower level interfaces. To minimize impact
* just keep the current implementation intact.
*/
static int
void **d,
int mode,
)
{
void *d2;
*ds_ctd_addr = 0;
sz1 = sizeof (md_i_didstat_t);
return (EFAULT);
}
/*
* ds_ctd_addr has actual user ctdp
*/
if (sz2 <= 0) {
return (EINVAL);
}
return (EINVAL);
}
*d = (void *)d1;
return (0);
}
/*
* mddb_didstat_to_user -- see comment for mddb_didstat_from_user. In this
* case d->cnt could have a value in it for either usage of
* the ioctl.
*/
/*ARGSUSED*/
static int
void *d,
int mode,
)
{
void *d2;
d1 = (md_i_didstat_t *)d;
sz1 = sizeof (md_i_didstat_t);
/*
* Copy out from kernel ctdp to user ctdp area
*/
return (EFAULT);
}
}
return (EFAULT);
}
return (0);
}
static int
void **d,
int mode,
)
{
void *d2;
void *d3;
*c_devid_addr = 0;
sz1 = sizeof (mddb_config_t);
return (EFAULT);
}
return (EINVAL);
}
return (EFAULT);
}
return (EINVAL);
}
if (ddi_copyin(
return (EFAULT);
}
}
} else {
}
*d = (void *)d1;
return (0);
}
/*ARGSUSED*/
static int
void *d,
int mode,
)
{
void *d2;
void *d3;
d1 = (mddb_config_t *)d;
sz1 = sizeof (mddb_config_t);
/* Only copyout devid if valid */
return (EFAULT);
}
}
}
}
}
if (sz2)
if (sz3)
return (EFAULT);
}
if (d1)
if (sz2)
if (sz3)
return (0);
}
/*
* NAME: get_tstate
* PURPOSE: Return unit's transient error state to user.
* INPUT: device node (set + metadevice number)
* OUTPUT: gu->tstate
* RETURNS: 0 on success
* EINVAL on failure
*/
static int
{
mdi_unit_t *ui;
return (EINVAL);
}
return (EINVAL);
return (0);
}
/*
* NAME: md_clu_ioctl
* PURPOSE: depending on clu_cmd:
* - Check open state,
* - lock opens and check open state
* - unlock opens again
* INPUT: metadevice and clu_cmd
* OUTPUT: open state (for MD_MN_LCU_UNLOCK always 0)
* RETURNS: 0 on success
* EINVAL on failure
*/
int
{
mdi_unit_t *ui;
return (EINVAL);
}
}
case MD_MN_LCU_CHECK:
/* No lock here, just checking */
break;
case MD_MN_LCU_LOCK:
/* This inhibits later opens to succeed */
/* In case the md is opened, reset the lock immediately */
if (clu->clu_isopen != 0) {
}
break;
case MD_MN_LCU_UNLOCK:
break;
}
return (0);
}
/*
* NAME: mkdev_ioctl
* PURPOSE: Create device node for specified set / metadevice tuple
* INPUT: device tuple (set number + metadevice number)
* OUTPUT: None
* RETURNS: 0 on success
* EINVAL on failure
*/
static int
{
mdclrerror(&p->mde);
/* Validate arguments passed in to ioctl */
if (setno >= MD_MAXSETS) {
return (EINVAL);
}
if (p->mnum >= MD_MAXUNITS) {
return (EINVAL);
}
/* Create the device node */
return (ENODEV);
}
return (0);
}
/*
* admin device ioctls
*/
static int
{
void *d = NULL;
int err = 0;
int err_to_user = 0;
int mddb_config_case = 0;
int mddb_didstat_case = 0;
caddr_t c_devid_addr = 0;
caddr_t c_old_devid_addr = 0;
caddr_t ds_ctd_addr = 0;
/* For now we can only handle 32-bit clients for internal commands */
return (EINVAL);
}
switch (cmd) {
case DKIOCINFO:
{
return (EACCES);
break;
}
case MD_DB_USEDEV:
{
return (EACCES);
mddb_config_case = 1;
if (err)
return (err);
break;
}
case MD_DB_GETDEV:
{
return (EACCES);
mddb_config_case = 1;
if (err)
return (err);
break;
}
case MD_DB_GETDRVNM:
{
return (EACCES);
mddb_config_case = 1;
if (err)
return (err);
break;
}
case MD_DB_ENDDEV:
{
return (EACCES);
mddb_config_case = 1;
if (err)
return (err);
break;
}
case MD_DB_DELDEV:
{
return (EACCES);
mddb_config_case = 1;
if (err)
return (err);
cp = (mddb_config_t *)d;
break;
if (setno == MD_LOCAL_SET)
break;
break;
/*
* if the last db replica of a diskset is deleted
* unload everything.
*/
/* Requesting a release, clean up everything */
break;
}
case MD_DB_NEWDEV:
{
return (EACCES);
mddb_config_case = 1;
if (err)
return (err);
cp = (mddb_config_t *)d;
break;
}
case MD_DB_NEWSIDE:
{
return (EACCES);
mddb_config_case = 1;
if (err)
return (err);
break;
}
case MD_DB_DELSIDE:
{
return (EACCES);
mddb_config_case = 1;
if (err)
return (err);
break;
}
case MD_DB_SETDID:
{
return (EACCES);
}
mddb_config_case = 1;
if (err) {
return (err);
}
break;
}
case MD_GRAB_SET:
{
return (EACCES);
mddb_config_case = 1;
if (err)
return (err);
cp = (mddb_config_t *)d;
break;
setno);
break;
}
case MD_RELEASE_SET:
{
return (EACCES);
mddb_config_case = 1;
if (err)
return (err);
/* shorthand */
cp = (mddb_config_t *)d;
/* If the user requests a release, clean up everything */
if (MD_MNSET_SETNO(setno)) {
/*
* md_tas_block_setio will block the set if
* there are no outstanding I/O requests,
* otherwise it returns -1.
*/
break;
}
} else {
/*
* Should not return something other than 1
*/
break;
}
}
break;
}
case MD_DB_GETOPTLOC:
{
return (EACCES);
sz = sizeof (mddb_optloc_t);
break;
}
break;
}
case MD_HALT:
{
return (EACCES);
/* already have the ioctl lock */
return (md_halt(MD_GBL_IOCTL_LOCK));
}
case MD_IOCSET_NM:
{
return (EACCES);
sz = sizeof (mdnm_params_t);
break;
}
/* check data integrity */
break;
}
if ((((mdnm_params_t *)d)->devname_len == 0) ||
break;
}
break;
}
break;
}
case MD_IOCGET_NM:
{
return (EACCES);
sz = sizeof (mdnm_params_t);
break;
}
/* check data integrity */
break;
}
break;
}
break;
}
case MD_IOCNXTKEY_NM:
{
return (EACCES);
sz = sizeof (mdnm_params_t);
break;
}
break;
}
case MD_IOCREM_NM:
{
return (EACCES);
sz = sizeof (mdnm_params_t);
break;
}
/* check data integrity */
break;
}
break;
}
case MD_IOCGET_TSTATE:
{
return (EACCES);
sz = sizeof (md_i_get_tstate_t);
break;
}
break;
}
case MD_IOCGET_DRVNM:
{
return (EACCES);
sz = sizeof (md_i_driverinfo_t);
break;
}
/* check data integrity */
break;
}
break;
}
break;
}
case MD_IOCGET_NEXT:
{
return (EACCES);
sz = sizeof (md_i_getnext_t);
break;
}
/* check data integrity */
break;
}
break;
}
case MD_DB_USERREQ:
case MD_MN_DB_USERREQ:
{
return (EACCES);
sz = sizeof (mddb_userreq_t);
break;
}
break;
}
case MD_IOCGET_NUM:
{
return (EACCES);
sz = sizeof (md_i_getnum_t);
break;
}
break;
}
case MD_DB_OWNSET:
{
return (EACCES);
sz = sizeof (mddb_ownset_t);
break;
}
break;
}
((mddb_ownset_t *)d)->owns_set =
break;
}
case MD_IOCGETNSET:
{
return (EACCES);
break;
}
break;
}
case MD_IOCGETNUNITS:
{
return (EACCES);
break;
}
break;
}
case MD_IOCGVERSION:
{
return (EACCES);
break;
}
break;
}
case MD_IOCSET_FLAGS:
{
return (EACCES);
sz = sizeof (md_set_userflags_t);
break;
}
/* check data integrity */
break;
}
break;
}
case MD_IOCRENAME:
{
return (EACCES);
}
sz = sizeof (md_rename_t);
break;
}
break;
}
case MD_IOCISOPEN:
{
md_isopen_t *p;
mdi_unit_t *ui;
return (EACCES);
sz = sizeof (md_isopen_t);
break;
}
p = (md_isopen_t *)d;
break;
}
break;
}
break;
}
case MD_MED_GET_LST:
{
return (EACCES);
sz = sizeof (mddb_med_parm_t);
break;
}
medpp = (mddb_med_parm_t *)d;
break;
}
case MD_MED_SET_LST:
{
return (EACCES);
sz = sizeof (mddb_med_parm_t);
break;
}
medpp = (mddb_med_parm_t *)d;
break;
}
case MD_MED_UPD_MED:
{
return (EACCES);
sz = sizeof (mddb_med_upd_parm_t);
break;
}
break;
}
case MD_MED_GET_NMED:
{
return (EACCES);
sizeof (int), mode) != 0) {
break;
}
break;
}
case MD_MED_GET_TAG:
{
return (EACCES);
sz = sizeof (mddb_dtag_get_parm_t);
break;
}
break;
}
case MD_MED_USE_TAG:
{
return (EACCES);
sz = sizeof (mddb_dtag_use_parm_t);
break;
}
break;
}
case MD_MED_ACCEPT:
{
return (EACCES);
sz = sizeof (mddb_accept_parm_t);
break;
}
break;
}
case MD_MED_GET_TLEN:
{
return (EACCES);
sz = sizeof (mddb_med_t_parm_t);
break;
}
break;
}
case MD_MED_GET_T:
{
return (EACCES);
(sizeof (mddb_med_t_ent_t) * med_addr_tab_nents);
break;
}
break;
}
case MD_MED_SET_T:
{
return (EACCES);
(sizeof (mddb_med_t_ent_t) * med_addr_tab_nents);
break;
}
break;
}
case MD_GET_SETSTAT:
{
return (EACCES);
sz = sizeof (md_gs_stat_parm_t);
break;
}
gsp = (md_gs_stat_parm_t *)d;
break;
}
break;
}
case MD_SETNMDID:
{
return (EACCES);
sz = sizeof (mdnm_params_t);
break;
}
break;
}
case MD_IOCUPD_NM:
{
char *dname;
char *pname;
return (EACCES);
sz = sizeof (mdnm_params_t);
break;
}
(devnamelen == 0) || (pathnamelen == 0)) {
return (EINVAL);
}
/* alloc memory for devname */
if (ddi_copyin(
break;
}
if (ddi_copyin(
break;
}
mode);
break;
}
case MD_IOCUPD_LOCNM:
{
char *dname;
char *pname;
return (EACCES);
sz = sizeof (mdnm_params_t);
break;
}
(devnamelen == 0) || (pathnamelen == 0)) {
return (EINVAL);
}
/* alloc memory for devname */
if (ddi_copyin(
break;
}
if (ddi_copyin(
break;
}
break;
}
case MD_SET_SETSTAT:
{
#ifdef DEBUG
/* Can be used to set the s_status flags from user code */
return (EACCES);
sz = sizeof (md_gs_stat_parm_t);
break;
}
gsp = (md_gs_stat_parm_t *)d;
break;
}
#endif /* DEBUG */
break;
}
case MD_IOCGET_DID:
{
return (EACCES);
sz = sizeof (mdnm_params_t);
break;
}
break;
}
case MD_IOCSET_DID:
{
return (EACCES);
sz = sizeof (mdnm_params_t);
break;
}
break;
}
case MD_IOCGET_DIDMIN:
{
return (EACCES);
sz = sizeof (mdnm_params_t);
break;
}
break;
}
break;
}
case MD_IOCDID_STAT:
{
return (EACCES);
mddb_didstat_case = 1;
if (err) {
return (err);
}
break;
}
case MD_UPGRADE_STAT:
{
return (EACCES);
sizeof (int), mode) != 0) {
break;
}
break;
}
case MD_SETMASTER:
{
return (EACCES);
sz = sizeof (mddb_setmaster_config_t);
break;
}
break;
}
case MD_MN_SET_DOORH:
{
/* This ioctl sets the global kernel variable mdmn_door_handle */
} else {
err = 0;
}
break;
}
#ifdef DEBUG
case MD_MN_CHECK_DOOR1:
{
/* This ioctl sends a message through a previously opened door */
int ret;
int msg_test = 11111111;
int nloops = 0;
} else {
err = 0;
}
/*
* This is a way to tell ksend_message() to use different sets.
* Odd numbers go to set 1 even numbers go to set 2
*/
if (nloops & 0x1) {
setno = 1;
} else {
setno = 2;
}
while (nloops--) {
(char *)&msg_test,
sizeof (msg_test),
result);
if (ret != 0) {
}
}
break;
}
case MD_MN_CHECK_DOOR2:
{
/* This ioctl sends a message through a previously opened door */
int ret;
int msg_test = 22222222;
int nloops = 0;
} else {
err = 0;
}
/*
* This is a way to tell ksend_message() to use different sets.
* Odd numbers go to set 1 even numbers go to set 2
*/
if (nloops & 0x1) {
setno = 1;
} else {
setno = 2;
}
while (nloops--) {
(char *)&msg_test,
sizeof (msg_test),
result);
if (ret != 0) {
}
}
break;
}
#endif
case MD_MN_OPEN_TEST:
{
sz = sizeof (md_clu_open_t);
break;
}
break;
}
case MD_MN_SET_NODEID:
{
return (EACCES);
sz = sizeof (mddb_set_node_params_t);
break;
}
snp = (mddb_set_node_params_t *)d;
break;
}
if (md_mn_mynode_id == MD_MN_INVALID_NID)
#ifdef DEBUG
"node doesn't match nodeid being set 0x%x\n",
#endif /* DEBUG */
err = 0;
break;
}
case MD_IOCGUNIQMSGID:
{
return (EACCES);
uniqtime32(&tv);
/* high 32 bits are the seconds */
/* low 32 bits are the micro secs */
/*
* This is never called for submessages, so we better
* null out the submessage ID
*/
!= 0) {
break;
}
break;
}
/*
* suspend the IO's for a given set number.
*
* If setno = 0 is specified, try operation on all snarfed MN disksets.
* If there are no snarfed MN disksets, then return success.
*
* If a specific set number is given, then return EINVAL if unable
* to perform operation.
*/
case MD_MN_SUSPEND_SET:
{
int rval = 0;
int i;
return (EACCES);
return (EFAULT);
}
if (setno >= MD_MAXSETS) {
return (EINVAL);
}
mutex_enter(&md_mx);
if (setno == 0) {
/* if set number is 0, we walk all sets */
(MD_SET_SNARFED|MD_SET_MNSET)) ==
}
}
} else {
/* If unable to halt specified set, set EINVAL */
(MD_SET_SNARFED|MD_SET_MNSET)) ==
} else {
}
}
mutex_exit(&md_mx);
return (rval);
}
/*
* resume the IO's for a given set number.
*
* If setno = 0 is specified, try operation on all snarfed MN disksets.
* If there are no snarfed MN disksets, then return success.
*
* If a specific set number is given, then return EINVAL if unable
* to perform operation.
*/
case MD_MN_RESUME_SET:
{
int resumed_set = 0;
int rval = 0;
int i;
return (EACCES);
return (EFAULT);
}
if (setno >= MD_MAXSETS) {
return (EINVAL);
}
/* if 0 is specified as the set number, we walk all sets */
mutex_enter(&md_mx);
if (setno == 0) {
/* if set number is 0, we walk all sets */
(MD_SET_SNARFED|MD_SET_MNSET)) ==
resumed_set = 1;
}
}
} else {
/* If unable to resume specified set, set EINVAL */
(MD_SET_SNARFED|MD_SET_MNSET)) ==
resumed_set = 1;
} else {
}
}
/*
* In case we actually resumed at least one set,
* Inform all threads waiting for this change
*/
if (resumed_set == 1) {
}
mutex_exit(&md_mx);
return (rval);
}
case MD_MN_MDDB_PARSE:
{
return (EACCES);
sz = sizeof (mddb_parse_parm_t);
break;
}
break;
}
case MD_MN_MDDB_BLOCK:
{
return (EACCES);
sz = sizeof (mddb_block_parm_t);
break;
}
break;
}
case MD_MN_MDDB_OPTRECFIX:
{
return (EACCES);
sz = sizeof (mddb_optrec_parm_t);
break;
}
break;
}
case MD_MN_CHK_WRT_MDDB:
{
return (EACCES);
sz = sizeof (mddb_config_t);
break;
}
break;
}
case MD_MN_SET_SETFLAGS:
case MD_MN_GET_SETFLAGS:
{
return (EACCES);
sz = sizeof (mddb_setflags_config_t);
break;
}
break;
}
case MD_MN_COMMD_ERR:
{
char *msg;
sz = sizeof (md_mn_commd_err_t);
break;
}
cmp = (md_mn_commd_err_t *)d;
break;
}
break;
}
break;
}
case MD_IOCMAKE_DEV:
{
return (EACCES);
sz = sizeof (md_mkdev_params_t);
return (ENOMEM);
break;
}
break;
}
/*
* Update md_mn_commd_present global to reflect presence or absence of
* /usr/sbin/rpc.mdcommd. This allows us to determine if an RPC failure
* is expected during a mdmn_ksend_message() handshake. If the commd is
* not present then an RPC failure is acceptable. If the commd _is_
* present then an RPC failure means we have an inconsistent view across
* the cluster.
*/
case MD_MN_SET_COMMD_RUNNING:
{
return (EACCES);
err = 0;
break;
}
case MD_IOCIMP_LOAD:
{
return (EACCES);
break;
}
break;
}
case MD_DB_LBINITTIME:
{
return (EACCES);
mddb_config_case = 1;
if (err)
return (err);
break;
}
default:
return (ENOTTY); /* used by next level up */
}
/*
* copyout and free any args
*/
if (mddb_config_case) {
} else if (mddb_didstat_case) {
} else if (sz != 0) {
}
}
if (err)
return (err);
return (err_to_user);
}
int
{
int modindex;
int err;
/*
* see if we can do this without involving the subdriver
*/
return (err);
/*
* see what subdriver we need
*/
return (ENOTTY);
return (ENODEV);
return (EFAULT);
/*
* load subdriver if not already loaded
*/
return (ENOTTY);
/*
* dispatch to subdriver
*/
}
void
)
{
}
void
{
caddr_t v;
/*
* Return vtoc structure fields in the provided VTOC area, addressed
* by *vtoc.
*
*/
if (un->c.un_vtoc_id) {
/* if this seems to be a sane vtoc, just copy it ... */
} else {
/* ... else assume a vtoc32 was stored here */
}
else
return;
}
un->c.un_vtoc_id = 0;
}
else
}
int
{
int i;
caddr_t v;
/*
* Sanity-check the vtoc
*/
return (EINVAL);
/* don't allow to create a vtoc for a big metadevice */
return (ENOTSUP);
/*
* Validate the partition table
*/
if (i == 0) {
sb = 0;
else
return (EINVAL);
return (EINVAL);
continue;
}
/* all other partitions must be zero */
return (EINVAL);
return (EINVAL);
}
if (un->c.un_vtoc_id) {
/*
* If there's enough space in the record, and the
* existing record is a vtoc record (not EFI),
* we just can use the existing space.
* Otherwise, we create a new MDDB_VTOC record for
* this unit.
*/
v = mddb_getrecaddr(recid);
recids[2] = 0;
return (0);
}
un->c.un_vtoc_id = 0;
}
}
if (recid < 0) {
return (ENOSPC);
}
recids[2] = 0;
v = mddb_getrecaddr(recid);
return (0);
}
void
{
/* skip the first cyl */
}
/*
* md_get_efi
* INPUT:
* un; the md_unit
* buf; the buffer that is preallocated by the calling routine and
* capable of taking the EFI label for this unit
* OUTPUT:
* A filled buffer, containing one struct efi_gpt followed by one
* struct efi_gpe, because a md efi only has one valid partition
* We fetch that date either from the mddb (like vtoc)
* or we a fake an EFI label.
*
* NOTES:
* We do not provide for any global unique identifiers,
* We also use the field c.un_vtoc_id, as the semantic is very similar
* When we are called, it's already checked, that this unit has an EFI
* label and not a vtoc
*/
void
{
caddr_t v;
/* first comes the header */
/*
* We don't fill out any of these:
*
* efi_header->efi_gpt_HeaderCRC32;
* efi_header->efi_gpt_DiskGUID;
* efi_header->efi_gpt_PartitionEntryArrayCRC32;
* efi_header->efi_gpt_Reserved1;
* efi_header->efi_gpt_MyLBA;
* efi_header->efi_gpt_AlternateLBA;
* efi_header->efi_gpt_Reserved2[LEN_EFI_PAD];
* efi_header->efi_gpt_PartitionEntryLBA;
*/
/*
* We copy back one partition, of type reserved,
* which may contain the name of the metadevice
* (this is what was used to be v_volume for a vtoc device)
* if no name is stored in the vtoc record, we hand an empty name
* to the user
*/
efi_part->efi_gpe_StartingLBA = 0;
if (un->c.un_vtoc_id) {
return;
}
un->c.un_vtoc_id = 0;
}
/*
* We don't fill out any of these
* efi_part->efi_gpe_UniquePartitionGUID
* efi_part->efi_gpe_Attributes
*/
}
/*
* md_set_efi
* INPUT:
* un; a md_unit
* buf; a buffer that is holding an EFI label for this unit
*
* PURPOSE:
* Perform some sanity checks on the EFI label provided,
* Then store efi_gpe_PartitionName in the mddb
* and link the unit's c.un_vtoc_id field to it.
*
* RETURN:
* EINVAL if any of the sanity checks fail
* 0 on succes
*
* NOTES:
* We do not provide for any global unique identifiers,
* We also use the field c.un_vtoc_id, as the semantic is very similar
* When we are called, it's already checked, that this unit has an EFI
* label and not a vtoc
*/
int
{
caddr_t v;
struct uuid md_efi_reserved_le;
/*
* Sanity-check the EFI label
*/
return (EINVAL);
/*
* Validate the partition
*/
if (efi_part->efi_gpe_StartingLBA != 0 ||
sizeof (struct uuid))) {
return (EINVAL);
}
/*
* If no name is specified, we have nothing to do and return success.
* because efi_gpe_PartitionName is in unicode form, we have to
* check the first two bytes of efi_gpe_PartitionName.
*/
return (0);
}
if (un->c.un_vtoc_id) {
/*
* If there's enough space in the record, and the
* existing record is an EFI record (not vtoc),
* we just can use the existing space.
* Otherwise, we create a new MDDB_EFILABEL record for
* this unit.
*/
v = mddb_getrecaddr(recid);
return (0);
}
un->c.un_vtoc_id = 0;
}
}
if (recid < 0) {
return (ENOSPC);
}
recids[2] = 0;
v = mddb_getrecaddr(recid);
return (0);
}
int
{
int rval = 0;
mdi_unit_t *ui;
return (EACCES);
return (EFAULT);
/*
* If the user specified a zero length or a null pointer, we give them
* the number of bytes to alloc in user land.
*/
return (EFAULT);
return (0);
}
/* Bad size specified, better not answer to that query */
return (EINVAL);
return (ENXIO);
/*
* We don't want to allocate as much bytes as we are told,
* because we know the good size is MD_EFI_LABEL_SIZE
*/
return (rval);
}
int
{
int rval = 0;
mdi_unit_t *ui;
return (EACCES);
return (ENXIO);
return (EFAULT);
/* Sanity check of the skeleton */
return (EINVAL);
/*
* It's only a real EFI label if the location is 1
* in all other cases, we do nothing but say we did.
*/
return (0); /* success */
/* And here we copy in the real data */
} else {
}
return (rval);
}
/*
* md_dkiocpartition()
* Return the appropriate partition64 structure for a given metadevice.
*
* Actually the only real information being returned is the number of blocks
* of the specified metadevice.
* The starting block is always 0, and so is the partition number, because
* metadevices don't have slices.
*
* This function is generic for all types of metadevices.
*/
int
{
struct partition64 p64;
mdi_unit_t *ui;
int rval = 0;
return (EACCES);
return (ENXIO);
return (EFAULT);
return (ESRCH);
/* All metadevices share the same PartitionTypeGUID (see md_get_efi) */
}
return (rval);
}