/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
* Copyright (c) 2011 Bayard G. Bell. All rights reserved.
*/
#include <sys/sysmacros.h>
#ifndef lint
#endif
extern md_ops_t *md_opslist;
extern int md_status;
extern void md_clear_hot_spare_interface();
static void
{
}
static hot_spare_t *
{
return (hs);
}
if (must_exist)
ASSERT(0);
return ((hot_spare_t *)NULL);
}
static int
{
/* Scan the hot spare pool list */
if (hsp != (hot_spare_pool_t *)0)
return (0);
/* create a hot spare pool record */
#if defined(_ILP32)
#else
setno);
#endif
} else {
setno);
}
if (recid < 0) {
}
/* get the record addr */
hsp->hsp_refcount = 0;
hsp->hsp_nhotspares = 0;
return (0);
}
static int
{
int i;
int delete_hsp = 0;
int irecid;
int hsp_created = 0;
int num_keys_old = 0;
/* Not much to do here in case of a dryrun */
return (0);
}
/* create an empty hot spare pool */
return (seths_create_hsp(shs));
}
/* Scan the hot spare list */
while (hs) {
break;
}
}
/*
* Did not find match for device using devnum so use
* key associated with shs_component_old just
* in case there is a match but the match's dev is NODEV.
* If unable to find a unique key for shs_component_old
* then fail since namespace has multiple entries
* for this old component and we shouldn't allow
* an addition of a hotspare in this case.
*/
shs->shs_component_old));
}
/*
* If more than one key matches given old_dev - fail command
* since shouldn't add new hotspare if namespace has
* multiple entries.
*/
if (num_keys_old > 1) {
shs->shs_component_old));
}
/*
* If there is no key for this entry then fail since
* a key for this entry should exist.
*/
if (num_keys_old == 0) {
shs->shs_component_old));
}
/* Scan the hot spare list again */
while (hs) {
/*
* Only need to compare keys when hs_devnum is NODEV.
*/
break;
}
}
}
/* create a hot spare record */
#if defined(_ILP32)
#else
#endif
} else {
}
if (recid < 0) {
shs->shs_component_old));
}
/* get the addr */
0);
hs->hs_refcount = 0;
}
/* Scan the hot spare pool list */
prev_hsp = (hot_spare_pool_t *)0;
while (hsp) {
break;
}
}
/* create a hot spare pool record */
if (recid < 0) {
}
/* get the record addr */
sizeof (*hsp), HSP_ONDSK_STR_OFF);
hsp->hsp_refcount = 0;
hsp->hsp_nhotspares = 0;
/* force prev_hsp to NULL, this will cause hsp to be linked */
prev_hsp = (hot_spare_pool_t *)0;
hsp_created = 1;
} else {
/*
* Make sure the hot spare is not already in the pool.
*/
for (i = 0; i < hsp->hsp_nhotspares; i++)
}
/*
* Create a new hot spare pool record
* This gives us the one extra hs slot,
* because there is one slot in the
* hot_spare_pool struct
*/
new_size = sizeof (hot_spare_pool_ond_t) +
/*
* The Friendly Name status of the new HSP should duplicate
* the status of the existing one.
*/
options =
} else {
}
if (recid < 0) {
hsp->hsp_self_id));
}
new_size = sizeof (hot_spare_pool_t) +
/* get the record addr */
/* copy the old record into the new one */
(size_t)((sizeof (hot_spare_pool_t) +
- sizeof (mddb_recid_t))));
/* mark the old hsp to be deleted */
delete_hsp = 1;
}
} else {
}
/* lock the db records */
irecid = 2;
if (delete_hsp)
/* increment the reference count */
hs->hs_refcount++;
/* add the hs at the end of the hot spare pool */
hsp->hsp_nhotspares++;
/*
* NOTE: We do not commit the previous hot spare pool record.
* There is no need, the link gets rebuilt at boot time.
*/
if (prev_hsp)
else
if (delete_hsp)
/* commit the db records */
if (delete_hsp) {
/* delete the old hot spare pool record */
}
if (hsp_created) {
}
return (0);
}
static int
{
/* Scan the hot spare pool list */
prev_hsp = (hot_spare_pool_t *)0;
while (hsp) {
break;
}
}
}
if (hsp->hsp_nhotspares != 0) {
}
if (hsp->hsp_refcount != 0) {
}
/* In case of a dryrun, we're done here */
return (0);
}
/*
* NOTE: We do not commit the previous hot spare pool record.
* There is no need, the link gets rebuilt at boot time.
*/
if (prev_hsp)
else
md_expldev(hspid));
return (0);
}
static int
{
int i;
int delete_hs = 0;
int num_keys_old = 0;
/* delete the hot spare pool */
return (seths_delete_hsp(shs));
}
/* Scan the hot spare list */
prev_hs = (hot_spare_t *)0;
while (hs) {
break;
}
}
/*
* Unable to find device using devnum so use
* key associated with shs_component_old instead.
* If unable to find a unique key for shs_component_old
* then fail since namespace has multiple entries
* for this old component and we're unable to determine
* which key is the valid match for shs_component_old.
*
* Only need to compare keys when hs_devnum is NODEV.
*/
shs->shs_component_old));
}
/*
* If more than one key matches given old_dev - fail command
* since shouldn't add new hotspare if namespace has
* multiple entries.
*/
if (num_keys_old > 1) {
shs->shs_component_old));
}
/*
* If there is no key for this entry then fail since
* a key for this entry should exist.
*/
if (num_keys_old == 0) {
shs->shs_component_old));
}
/* Scan the hot spare list again */
prev_hs = (hot_spare_t *)0;
while (hs) {
/*
* Only need to compare keys when hs_devnum is NODEV.
*/
break;
}
}
}
shs->shs_component_old));
}
/* Scan the hot spare pool list */
if (hsp == (hot_spare_pool_t *)0) {
}
/* check for force flag and state of hot spare */
}
}
/*
* Make sure the device is in the pool.
*/
for (i = 0; i < hsp->hsp_nhotspares; i++) {
break;
}
}
if (i >= hsp->hsp_nhotspares) {
}
/* In case of a dryrun, we're done here */
return (0);
}
/* lock the db records */
recids[2] = 0;
hs->hs_refcount--;
if (hs->hs_refcount == 0) {
/*
* NOTE: We do not commit the previous hot spare record.
* There is no need, the link we get rebuilt at boot time.
*/
if (prev_hs) {
} else
/* mark the hot spare to be deleted */
delete_hs = 1;
recids[1] = 0;
}
/* find the location of the hs in the hsp */
for (i = 0; i < hsp->hsp_nhotspares; i++) {
break;
}
/* remove the hs from the hsp */
for (i++; i < hsp->hsp_nhotspares; i++)
hsp->hsp_nhotspares--;
/* commit the db records */
if (delete_hs)
return (0);
}
static int
{
int new_found = 0;
int i;
int delete_hs = 0;
int num_keys_old = 0;
/* Scan the hot spare list */
prev_hs = (hot_spare_t *)0;
while (hs) {
break;
}
}
/*
* Unable to find device using devnum so use
* key associated with shs_component_old instead.
* If unable to find a unique key for shs_component_old
* then fail since namespace has multiple entries
* for this old component and we're unable to determine
* which key is the valid match for shs_component_old.
*
* Only need to compare keys when hs_devnum is NODEV.
*/
shs->shs_component_old));
}
/*
* If more than one key matches given old_dev - fail command
* since unable to determine which key is correct.
*/
if (num_keys_old > 1) {
shs->shs_component_old));
}
/*
* If there is no key for this entry then fail since
* a key for this entry should exist.
*/
if (num_keys_old == 0) {
shs->shs_component_old));
}
/* Scan the hot spare list again */
prev_hs = (hot_spare_t *)0;
while (hs) {
/*
* Only need to compare keys when hs_devnum is NODEV.
*/
break;
}
}
}
shs->shs_component_old));
}
/* check the force flag and the state of the hot spare */
}
/* Scan the hot spare pool list */
if (hsp == (hot_spare_pool_t *)0) {
}
/*
* Make sure the old device is in the pool.
*/
for (i = 0; i < hsp->hsp_nhotspares; i++) {
break;
}
}
if (i >= hsp->hsp_nhotspares) {
}
/* Scan the hot spare list for the new hs */
new_found = 0;
while (new_hs) {
new_found = 1;
break;
}
}
/*
* Make sure the new device is not already in the pool.
* We don't have to search the hs in this hsp, if the
* new hs was just created. Only if the hot spare was found.
*/
if (new_found) {
for (i = 0; i < hsp->hsp_nhotspares; i++)
}
}
/* In case of a dryrun, we're done here */
return (0);
}
/*
* Create the new hotspare
*/
if (!new_found) {
/* create a hot spare record */
#if defined(_ILP32)
#else
#endif
} else {
}
if (recid < 0) {
shs->shs_component_new));
}
/* get the addr */
sizeof (*new_hs), 0);
new_hs->hs_refcount = 0;
}
/* lock the db records */
recids[3] = 0;
hs->hs_refcount--;
if (hs->hs_refcount == 0) {
/*
* NOTE: We do not commit the previous hot spare record.
* There is no need, the link we get rebuilt at boot time.
*/
if (prev_hs) {
} else
/* mark hs to be deleted in the correct order */
delete_hs = 1;
recids[2] = 0;
}
/* link into the hs list */
new_hs->hs_refcount++;
if (!new_found) {
/* do this AFTER the old dev is possibly removed */
}
/* find the location of the old hs in the hsp */
for (i = 0; i < hsp->hsp_nhotspares; i++) {
break;
}
}
} else {
}
/* commit the db records */
if (delete_hs)
return (0);
}
static int
{
int num_keys_old = 0;
/*
* Find device by using key associated with shs_component_old.
* If unable to find a unique key for shs_component_old
* then fail since namespace has multiple entries
* for this old component and we're unable to determine
* which key is the valid match for shs_component_old.
* This failure keeps a hotspare from being enabled on a slice
* that may already be in use by another metadevice.
*/
shs->shs_component_old));
}
/*
* If more than one key matches given old_dev - fail command
* since unable to determine which key is correct.
*/
if (num_keys_old > 1) {
shs->shs_component_old));
}
/*
* If there is no key for this entry then fail since
* a key for this entry should exist.
*/
if (num_keys_old == 0) {
shs->shs_component_old));
}
/* Scan the hot spare list for the hs */
while (hs) {
/*
* Since component may or may not be currently in the system,
* use the keys to find a match (not the devt).
*/
break;
}
}
shs->shs_component_old));
}
/* make sure it's broken */
}
/* In case of a dryrun, we're done here */
return (0);
}
/* fix it */
/* commit the db records */
recids[1] = 0;
return (0);
}
static int
)
{
/* Scan the hot spare list for the hs */
while (hs) {
break;
}
}
ghs->ghs_devnum));
}
return (0);
}
static void
{
int i;
for (i = 0; i < hsp->hsp_nhotspares; i++) {
}
}
static int
void *d,
int mode
)
{
int err = 0;
/* Scan the hot spare pool list */
}
sizeof (get_hsp_t);
return (0);
}
return (EFAULT);
return (err);
}
static int
)
{
case ADD_HOT_SPARE:
case DELETE_HOT_SPARE:
return (seths_delete(shs));
case REPLACE_HOT_SPARE:
return (seths_replace(shs));
case FIX_HOT_SPARE:
return (seths_enable(shs));
default:
}
}
static void
hotspares_poke_hotspares(void)
{
int i;
for (i = 0; i < MD_NOPS; i++) {
/* handle change */
if (poke_hs)
(void) (*poke_hs)();
}
}
/*ARGSUSED4*/
static int
int cmd,
void *data,
int mode,
)
{
void *d = NULL;
int err = 0;
/* single thread */
return (ENOTTY);
/* We can only handle 32-bit clients for internal commands */
return (EINVAL);
}
mutex_enter(&md_mx);
while (md_status & MD_GBL_HS_LOCK)
mutex_exit(&md_mx);
/* dispatch ioctl */
switch (cmd) {
case MD_IOCSET_HS: /* setup hot spares and pools */
{
break;
}
sz = sizeof (set_hs_params_t);
break;
}
break;
}
case MD_IOCGET_HS: /* get hot spare info */
{
break;
}
sz = sizeof (get_hs_params_t);
break;
}
break;
}
case MD_IOCGET: /* get hot spare pool info */
{
break;
}
sz = sizeof (md_i_get_t);
break;
}
break;
}
default:
}
/*
* copyout and free any args
*/
if (sz != 0) {
if (err == 0) {
}
}
}
/* un single thread */
mutex_enter(&md_mx);
md_status &= ~MD_GBL_HS_LOCK;
mutex_exit(&md_mx);
/* handle change */
/* return success */
return (err);
}
static void
{
switch (rbp->rb_revision) {
case MDDB_REV_RB:
case MDDB_REV_RBFN:
/*
* Needs to convert to internal 64 bit
*/
newreqsize = sizeof (hot_spare_t);
break;
case MDDB_REV_RB64:
case MDDB_REV_RB64FN:
break;
}
#if defined(_ILP32)
sizeof (devname));
"are not accessible on a 32 bit kernel\n", devname);
}
#endif
if (hs->hs_refcount == 0) {
return;
}
}
static void
{
return;
}
}
static int
{
int gotsomething;
if (cmd == MD_SNARF_CLEANUP)
return (0);
gotsomething = 0;
continue;
switch (mddb_getrectype2(recid)) {
case HSP_REC:
gotsomething = 1;
break;
case HS_REC:
gotsomething = 1;
break;
default:
ASSERT(0);
}
}
if (gotsomething)
return (gotsomething);
return (0);
}
static int
{
if (cmd == MD_HALT_CLOSE)
return (0);
if (cmd == MD_HALT_OPEN)
return (0);
if (cmd == MD_HALT_CHECK)
return (0);
if (cmd == MD_HALT_UNLOAD)
return (0);
if (cmd != MD_HALT_DOIT)
return (1);
/*
* Find all the hotspares for set "setno"
* and remove them from the hot_spare_list.
*/
/*
* Find all the hotspare pools for set "setno"
* and remove them from the hot_spare_pools list.
* Also remove from the get_next list.
*/
}
return (0);
}
static hot_spare_t *
int labeled,
{
return ((hot_spare_t *)0);
*start = 0;
return (hs);
return (hs);
}
return ((hot_spare_t *)0);
}
static int
int labeled,
{
int i;
*hs_id = 0;
return (-1);
for (i = 0; i < hsp->hsp_nhotspares; i++) {
continue;
/* NOTE: Mirror code commits the hs record */
return (0);
}
return (-1);
}
/* ARGSUSED3 */
static int
{
int i;
/*
* That is because we always allocate the whole hs.
* Later if we choose to allocate only what is needed
* which part is being unreseved.
*/
*hs_id = 0;
return (-1);
for (i = 0; i < hsp->hsp_nhotspares; i++) {
continue;
if (new_state == HSS_BROKEN) {
}
if (new_state == HSS_AVAILABLE) {
}
return (0);
}
return (-1);
}
static int
{
*hsp_id = 0;
if (id < 0)
return (0);
return (-1);
if (incref)
hsp->hsp_refcount++;
else
hsp->hsp_refcount--;
/* NOTE: Stripe code commits the hsp record */
return (0);
}
static int
{
return (0);
return (0);
}
static intptr_t
int bool,
{
mutex_enter(&md_mx);
while (md_status & MD_GBL_HS_LOCK)
/* If md_halt has been run do not continue */
mutex_exit(&md_mx);
return (ENXIO);
}
mutex_exit(&md_mx);
switch (cmd) {
case HS_GET:
break;
case HS_FREE:
break;
case HS_BAD:
break;
case HSP_INCREF:
break;
case HSP_DECREF:
break;
case HS_MKDEV:
break;
}
mutex_enter(&md_mx);
md_status &= ~MD_GBL_HS_LOCK;
mutex_exit(&md_mx);
return (err);
}
static void
)
{
int i;
/*
* Fixup the pool and hotspares
*/
for (i = 0; i < hsp_ond->hsp_nhotspares; i++) {
}
}
static void
)
{
switch (rbp->rb_revision) {
case MDDB_REV_RB:
case MDDB_REV_RBFN:
/*
* 32 bit hotspare
*/
break;
case MDDB_REV_RB64:
case MDDB_REV_RB64FN:
break;
}
/*
* Fixup the setno
*/
}
static int
)
{
int gotsomething;
gotsomething = 0;
continue;
switch (mddb_getrectype2(recid)) {
case HSP_REC:
gotsomething = 1;
break;
case HS_REC:
gotsomething = 1;
break;
default:
ASSERT(0);
}
}
return (gotsomething);
}
{hotspares_interface, "hot spare interface"},
{NULL, 0}
};
NULL, /* open */
NULL, /* close */
NULL, /* strategy */
NULL, /* print */
NULL, /* dump */
NULL, /* read */
NULL, /* write */
hotspares_ioctl, /* hotspares_ioctl, */
hotspares_snarf, /* hotspares_snarf */
hotspares_halt, /* halt */
NULL, /* aread */
NULL, /* awrite */
hotspares_imp_set, /* import set */
hotspares_named_services /* named_services */
};
static void
{
/* prevent access to services that may have been imported */
}
/* define the module linkage */