/*
* 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 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#define _SCM_
#include <sys/nsc_thread.h>
#include "sd_bcache.h"
#include "sd_misc.h"
#include "sd_trace.h"
#include "sd_ft.h"
#include "sd_io.h"
#include "sd_bio.h"
#include "sd_pcu.h"
#include "sd_tdaemon.h"
#include "sdbc_ioctl.h"
/*
* A global variable to set the threshold for large writes to
* be in write through mode when NVRAM is present. This should
* solve the NVRAM bandwidth problem.
*/
int sdbc_wrthru_len;
int sdbc_max_devs = 0;
static int _sd_debug_level = 0;
static int _sdbc_attached = 0;
static int sdbcunload(void);
static int sdbcload(void);
int *rvp);
#ifdef sun
/*
* Solaris specific driver module interface code.
*/
#ifdef USES_SOFT_STATE
struct sdbc_state {
};
#endif /* USES_SOFT_STATE */
sdbcopen, /* open */
sdbcclose, /* close */
nodev, /* not a block driver, strategy not an entry point */
_sdbc_print, /* no print routine */
nodev, /* no dump routine */
nodev, /* read */
nodev, /* write */
(int (*) ()) sdbcioctl, /* ioctl */
nodev, /* no devmap routine */
nodev, /* no mmap routine */
nodev, /* no segmap routine */
nochpoll, /* no chpoll routine */
0, /* not a STREAMS driver, no cb_str routine */
};
DEVO_REV, /* Driver build version */
0, /* device reference count */
};
"nws:Storage Cache:" ISS_VERSION_STR,
};
};
/*
* dynmem interface
*/
static int mutex_and_condvar_flag;
/*
* Solaris module load time code
*/
int
_init(void)
{
int err;
#ifdef USES_SOFT_STATE
#endif /* USES_SOFT_STATE */
/*
* It is "load" time, call the unixware equivalent.
*/
if (!err)
if (err) {
(void) sdbcunload();
#ifdef USES_SOFT_STATE
#endif /* USES_SOFT_STATE */
}
if (!err) {
MUTEX_DRIVER, NULL);
}
return (err);
}
/*
* Solaris module unload time code
*/
int
_fini(void)
{
int err;
if (_sd_cache_initialized) {
return (EBUSY);
} else if (_sd_ioset &&
return (EBUSY);
}
int, err,
struct modlinkage *, &sdbc_modlinkage);
err = sdbcunload();
#ifdef USES_SOFT_STATE
#endif /* USES_SOFT_STATE */
if (mutex_and_condvar_flag) {
}
}
return (err);
}
/*
* Solaris module info code
*/
int
{
}
/*ARGSUSED*/
static int
{
return (DDI_PROBE_SUCCESS);
}
/*
* Attach an instance of the device. This happens before an open
* can succeed.
*/
static int
{
if (cmd != DDI_ATTACH)
return (DDI_FAILURE);
/*
* Get the threshold value for setting large writes in
* write through mode(when NVRAM is present)
*/
/* Get sdbc_max_fbas from sdbc.conf */
if (sdbc_max_fbas > _SD_MAX_FBAS) {
"!_sdbc_attach: sdbc_max_fbas set to %d", _SD_MAX_FBAS);
}
/*
* -get the maximum list length for multipage dynmem
* -time between aging
* -number of agings before dealloc
* -what to report D0=shutdown, D1=thread variables
*/
#define MINOR_NUMBER 0
#ifdef MINOR_NAME
/* free anything we allocated here */
return (DDI_FAILURE);
}
#endif /* MINOR_NAME */
/* Announce presence of the device */
/* mark the device as attached, opens may proceed */
_sdbc_attached = 1;
return (DDI_SUCCESS);
}
/*ARGSUSED*/
static int
{
if (cmd == DDI_DETACH) {
/*
* Check first if the cache is still in use
* and if it is, prevent the detach.
*/
return (EBUSY);
_sdbc_attached = 0;
return (DDI_SUCCESS);
} else
return (DDI_FAILURE);
}
/*ARGSUSED*/
static int
{
return (DDI_SUCCESS);
}
/*ARGSUSED*/
static int
{
#ifdef USES_SOFT_STATE
int instance;
#endif /* USES_SOFT_STATE */
int rc;
switch (cmd) {
case DDI_INFO_DEVT2INSTANCE:
/* The "instance" number is the minor number */
rc = DDI_SUCCESS;
break;
case DDI_INFO_DEVT2DEVINFO:
#ifdef USES_SOFT_STATE
/* the instance number is the minor number */
return (DDI_FAILURE);
#else
#endif /* USES_SOFT_STATE */
rc = DDI_SUCCESS;
break;
default:
rc = DDI_FAILURE;
break;
}
return (rc);
}
/*ARGSUSED*/
int
{
return (0);
}
#else
#endif /* sun */
static int sdbc_inited;
static int
sdbcinit(void)
{
int rc;
sdbc_inited = 0;
#ifdef m88k
return (rc);
#endif
/*
* Initialize the bitmap array that would be useful in determining
* if the mask is not fragmented, instead of determinig this
* at run time. Also initialize a lookup array for each mask, with
* the starting position, the length, and the mask subset
*/
if ((rc = _sdbc_iobuf_load()) != 0)
return (rc);
if ((rc = _sdbc_handles_load()) != 0)
return (rc);
if ((rc = _sdbc_tr_load()) != 0)
return (rc);
if ((rc = _sdbc_ft_load()) != 0)
return (rc);
if ((rc = _sdbc_tdaemon_load()) != 0)
return (rc);
if ((rc = _sdbc_hash_load()) != 0)
return (rc);
#ifdef DEBUG
#endif
sdbc_inited = 1;
return (0);
}
static int
sdbcunload(void)
{
if (_sd_cache_initialized) {
"!sdbc(sdbcunload) cannot unload module - cache in use!");
return (EEXIST);
}
#ifdef m88k
(void) hpf_unregister_module("SDBC");
#endif
#ifdef DEBUG
#endif
/*
* Normally we would unregister memory at deconfig time.
* However when chasing things like memory leaks it is
* useful to defer until unload time.
*/
return (0);
}
static int
sdbcload(void)
{
int err;
(void) sdbcunload();
return (err);
}
return (0);
}
/* ARGSUSED */
static int
{
/*
* If we were statically linked in then returning an error out
* of sdbcinit won't prevent someone from coming thru here.
* We must prevent them from getting any further.
*/
if (!sdbc_inited)
return (EINVAL);
if (nd < nsc_min_nodeid) {
"!sdbc(sdbcopen) open failed, systemid (%d) must be >= %d",
nd, nsc_min_nodeid);
return (EINVAL);
}
if (!_sdbc_attached)
return (ENXIO);
return (0);
}
/* ARGSUSED */
static int
{
return (0);
}
#ifdef _MULTI_DATAMODEL
static int
/*
* convert_ioctl-args - Do a case by case conversion of a ILP32 ioctl
* structure to an LP64 structure.
* The main concern here is whether to sign-extend or not. The rule
* is that pointers are not sign extended, the rest are obvious.
* Since most everything is sign-extended the definition of
* _sdbc_ioctl32_t uses signed fields.
*
*/
{
return (EFAULT);
switch (cmd) {
case SDBC_UNUSED_1:
case SDBC_UNUSED_2:
case SDBC_UNUSED_3:
"!sdbc(convert_ioctl_args) obsolete sdbc ioctl used");
return (EINVAL);
case SDBC_ADUMP:
break;
case SDBC_TEST_INIT:
break;
case SDBC_TEST_START:
break;
case SDBC_TEST_END:
break;
case SDBC_ENABLE:
case SDBC_VERSION:
break;
case SDBC_DISABLE:
break;
case SDBC_GET_CLUSTER_SIZE:
break;
/* get the gl_file data */
case SDBC_GET_CLUSTER_DATA:
/* pointer to array[2*cluster_size] */
break;
/* get the size of the global info pages for each board */
case SDBC_GET_GLMUL_SIZES:
break;
/* get the global info about write blocks */
case SDBC_GET_GLMUL_INFO:
/* pointer to array[2*(sum of GLMUL_SIZES)] */
break;
case SDBC_SET_CD_HINT:
break;
case SDBC_GET_CD_HINT:
break;
case SDBC_SET_NODE_HINT:
break;
case SDBC_GET_NODE_HINT:
break;
case SDBC_STATS:
break;
case SDBC_ZAP_STATS:
break;
case SDBC_GET_CD_BLK:
break;
case SDBC_GET_CONFIG:
break;
case SDBC_SET_CONFIG:
break;
case SDBC_MAXFILES:
break;
#ifdef DEBUG
/* toggle flusher flag for testing */
case SDBC_TOGGLE_FLUSH:
break;
case SDBC_INJ_IOERR: /* cd, errnum */
break;
/* clear injected i/o errors */
case SDBC_CLR_IOERR: /* cd */
break;
#endif /* DEBUG */
default:
return (EINVAL);
}
return (0);
}
#endif /* _MULTI_DATAMODEL */
static int
{
char *taddr;
#ifdef _MULTI_DATAMODEL
#endif /* _MULTI_DATAMODEL */
int rc;
if (_sd_cache_initialized == 0) {
return (EINVAL);
}
/* copyin the block number */
mode)) {
return (EFAULT);
}
#ifdef _MULTI_DATAMODEL
mode)) {
return (EFAULT);
}
} else {
return (EFAULT);
}
}
#else /* _MULTI_DATAMODEL */
return (EFAULT);
}
#endif /* _MULTI_DATAMODEL */
if (lookup_file != NULL)
return (ENOENT);
}
rc = 0;
/* get the write data if any */
if (sdbc_safestore) {
"!sdbc(sdbc_get_cd_blk) cc_write 0x%p sc-res 0x%p",
KM_NOSLEEP)) == NULL) {
"!sdbc(sdbc_get_cd_blk) kmem_alloc failed."
" cannot get write data");
} else if (SSOP_READ_CBLOCK(sdbc_safestore,
CACHE_BLOCK_SIZE, 0) == SS_ERR) {
"!safestore read failed");
CACHE_BLOCK_SIZE)) {
"!sdbc(sdbc_get_cd_blk) copyout failed."
" cannot get write data");
}
}
}
if (taddr)
return (rc);
}
/* ARGSUSED */
static int
{
int rc = 0;
int convert_32 = 0;
*rvp = 0;
#ifdef _MULTI_DATAMODEL
int rc;
convert_32 = 1;
return (rc);
} else {
return (EFAULT);
}
}
#else /* _MULTI_DATAMODEL */
return (EFAULT);
}
#endif /* _MULTI_DATAMODEL */
kstatus = spcs_s_kcreate();
if (!kstatus)
return (ENOMEM);
switch (cmd) {
case SDBC_UNUSED_1:
case SDBC_UNUSED_2:
case SDBC_UNUSED_3:
case SDBC_ADUMP:
break;
case SDBC_TEST_INIT:
break;
case SDBC_TEST_START:
break;
case SDBC_TEST_END:
rc = _sd_test_end();
break;
case SDBC_ENABLE:
(void) _sdbc_deconfigure(kstatus);
return (spcs_s_ocopyoutf
}
case SDBC_DISABLE:
if (_sd_cache_initialized == 0) {
}
case SDBC_GET_CLUSTER_SIZE:
if (_sd_cache_initialized == 0) {
}
break;
/* get the gl_file data */
case SDBC_GET_CLUSTER_DATA:
if (_sd_cache_initialized == 0) {
}
break;
/* get the size of the global info pages for each board */
case SDBC_GET_GLMUL_SIZES:
if (_sd_cache_initialized == 0) {
}
break;
/* get the global info about write blocks */
case SDBC_GET_GLMUL_INFO:
if (_sd_cache_initialized == 0) {
}
break;
case SDBC_SET_CD_HINT:
if (_sd_cache_initialized == 0)
return (spcs_s_ocopyoutf(&kstatus,
case SDBC_GET_CD_HINT:
{
if (_sd_cache_initialized == 0)
return (spcs_s_ocopyoutf(&kstatus,
rc));
}
case SDBC_SET_NODE_HINT:
if (rc)
rc));
/* FALLTHRU */
case SDBC_GET_NODE_HINT:
{
rc));
}
case SDBC_STATS:
case SDBC_ZAP_STATS:
case SDBC_GET_CD_BLK:
if (_sd_cache_initialized == 0)
return (spcs_s_ocopyoutf(&kstatus,
break;
case SDBC_GET_CONFIG:
{
sizeof (_sdbc_config_t),
mode)) {
return (EFAULT);
}
(void) ddi_copyout(&sdbc_config_info,
sizeof (_sdbc_config_t),
mode);
}
case SDBC_SET_CONFIG:
{
sizeof (_sdbc_config_t),
mode)) {
return (EFAULT);
}
(void) _sdbc_deconfigure(kstatus);
return (spcs_s_ocopyoutf
}
}
case SDBC_MAXFILES:
sizeof (sdbc_max_devs)))
else
rc = 0;
break;
case SDBC_VERSION:
{
sizeof (cache_version_t), mode)) {
break;
}
break;
}
#ifdef DEBUG
/* toggle flusher flag for testing */
case SDBC_TOGGLE_FLUSH:
_sdbc_flush_flag ^= 1;
*rvp = _sdbc_flush_flag;
rc = 0;
/* inject i/o errors */
case SDBC_INJ_IOERR: /* cd, errnum */
if (_sd_cache_initialized == 0)
return (spcs_s_ocopyoutf(&kstatus,
break;
/* clear injected i/o errors */
case SDBC_CLR_IOERR: /* cd */
if (_sd_cache_initialized == 0)
return (spcs_s_ocopyoutf(&kstatus,
break;
#endif /* DEBUG */
default:
break;
}
return (rc);
}
/*
* _sd_timed_block - sleep waiting for ticks time delay.
* ticks - # of ticks to sleep
* cvp - pointer to the cv we wait on while we delay.
*
* NO spin locks can be held at entry!
*
*/
void
{
}
/*
* _sd_unblock - awake a sleeper waiting on cv pointed to by cvp.
*
* NO spin locks can be held at entry as we may sleep.
*
*/
void
{
}
/* ARGSUSED */
void
{
#if defined(_SD_FBA_DATA_LOG)
nsc_size_t i;
#endif /* _SD_FBA_DATA_LOG */
}
/* ARGSUSED */
void
{
#if defined(_SD_FBA_DATA_LOG)
if (st_cblk_len >= fba_len) {
end_cblk_len = 0;
} else {
}
fba_len -= st_cblk_len;
while (fba_len > end_cblk_len) {
}
#endif /* _SD_FBA_DATA_LOG */
}
void
_sd_zap_stats(void)
{
int i;
if (_sd_cache_stats == NULL)
return;
_sd_cache_stats->st_rdhits = 0;
_sd_cache_stats->st_rdmiss = 0;
_sd_cache_stats->st_wrhits = 0;
_sd_cache_stats->st_wrmiss = 0;
_sd_lru_q.sq_noreq_stat = 0;
_sd_lru_q.sq_req_stat = 0;
for (i = 0; i < sdbc_max_devs; i++) {
}
}
/*
* Return the cache sizes used by the Sense Subsystem Status CCW
*/
int
{
int psize;
*asize = 0;
*wsize = 0;
/*
* add in the total cache size and the
* non-volatile (battery-backed) cache size.
*/
if (_sd_net_config.sn_configured) {
}
return (0);
}
/*PRINTFLIKE2*/
void
{
if (level <= _sd_debug_level) {
}
}
int
char **filename)
{
if (FILE_OPENED(cd) != 0) {
if (cc_ent = (_sd_cctl_t *)
return (0);
}
}
return (-1);
}
/*
* central dyn mem processing vars edit rtn.
* input a local copy and xfer to global
*
* sec0,sec1,sec2
* range check 1 to 255 (arbitrary but in any case must be <= 2000 due to
* 32bit signed int limits in later calc)
* aging_ct
* range check 1 to 255 (only 8 bits reserved for aging ctr)
*
*/
int
{
if (process_vars->max_dyn_list > 0)
/* no edit on monitor_dynmem_process */
/* no edit on process_directive */
if (process_vars->cache_aging_ct1 > 0 &&
if (process_vars->cache_aging_ct2 > 0 &&
if (process_vars->cache_aging_ct3 > 0 &&
if (process_vars->cache_aging_sec1 > 0 &&
if (process_vars->cache_aging_sec2 > 0 &&
if (process_vars->cache_aging_sec3 > 0 &&
if (process_vars->cache_aging_pcnt1 >= 0 &&
if (process_vars->cache_aging_pcnt2 >= 0 &&
if (process_vars->max_holds_pcnt >= 0 &&
return (0);
}
{
return (dev_dip);
}