/*
* 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.
*/
#include <sys/nsc_thread.h>
#include "sd_bcache.h"
#include "sd_ft.h"
#include "sd_misc.h"
#include "sd_pcu.h"
#include "sd_io.h"
#include "sd_bio.h"
#include "sd_trace.h"
#include "sd_tdaemon.h"
extern int sdbc_use_dmchain;
int _sd_cblock_shift = 0;
int _SD_NUM_REM;
int _sd_nodes_configured;
int _SD_NETS = 0;
/*
* Normally we unregister memory at deconfig time. By setting this non-zero
* it will be delayed until unload time.
*/
int _sdbc_memtype_deconfigure_delayed = 0;
volatile int _sd_cache_dem_cnt;
volatile int _sd_cache_initialized;
#endif
static
0, 0, 0
};
/*
* Forward declare all statics that are used before defined to enforce
* parameter checking
* Some (if not all) of these could be removed if the code were reordered
*/
static void _sdbc_nodeid_deconfigure(void);
static void _sdbc_nodeid_configure(void);
static void _sdbc_thread_deconfigure(void);
static int _sdbc_thread_configure(void);
void sst_deinit();
/*
* _sdbc_memtype_configure - register with the sd layer the types of memory
* we want to use. If any of the critical memory types can't be registered
* we return non-zero otherwise 0.
*/
static int
_sdbc_memtype_configure(void)
{
return (EINVAL);
}
return (0);
}
/*
* _sdbc_memtype_deconfigure - undo the effects of _sdbc_memtype_configure.
*/
void
{
if (sdbc_hash_mem)
if (sdbc_iobuf_mem)
if (sdbc_cache_mem)
if (sdbc_stats_mem)
if (sdbc_local_mem)
if (sdbc_info_mem)
}
/*
* figure out what kind of safe storage we need
*/
{
}
static void
{
else
SS_GENPATTERN : 0;
}
/*
* _sdbc_configure - process the ioctl that describes the configuration
* for the cache. This is the main driver routine for cache configuration
* Return 0 on success, otherwise nonzero.
*
*/
int
{
int cache_bytes;
int i;
int rc;
_sd_ioset = 0;
if (_sd_cache_initialized) {
goto out;
}
if (uptr) {
sizeof (_sd_cache_param_t))) {
goto out;
}
} else {
/* copy in mgmt config info */
for (i = 0; i < CACHE_MEM_PAD; i++) {
}
/* fake the rest as a single node config */
}
/*
* Check that the requested cache size doesn't break the code.
* This test can be refined once the cache size is stored in variables
* larger than an int.
*/
for (i = 0; i < MAX_CACHE_NET; i++) {
if (_sd_cache_config.cache_mem[i] < 0) {
"negative cache size (%d) for net %d",
_sd_cache_config.cache_mem[i], i);
rc = SDBC_ENONETMEM;
goto out;
}
"cache size limited to %d megabytes for net %d",
MAX_CACHE_SIZE, i);
}
}
if (_sd_cache_config.blk_size == 0)
if (_sd_cache_config.procs == 0)
#if !defined(_SD_8K_BLKSIZE)
#else
#endif
sizeof (itmp), 0);
goto out;
}
if (((_sd_cblock_shift =
sizeof (itmp), 0);
goto out;
}
rc = SDBC_EMAGIC;
goto out;
}
if (_SD_SELF_HOST > nsc_max_nodeid ||
(void) spcs_s_inttostring(
goto out;
}
if (_SD_SELF_HOST == _SD_MIRROR_HOST) {
(void) spcs_s_inttostring(
(void) spcs_s_inttostring(
goto out;
}
/* initialize the safestore modules */
sst_init();
/* figure out which kind of safestore we need to use */
/* open and configure the safestore module */
ss_type);
goto out;
} else {
spcs_kstatus)) {
"!cannot configure safestore module for type %x",
ss_type);
(void) sst_close(sdbc_safestore);
/* try ram if possible, otherwise return */
goto out;
}
goto tryss;
}
}
if (_sdbc_memtype_configure()) {
goto out;
}
if (rc == -1) {
rc = SDBC_ENOIOBMEM;
goto out;
}
if (rc == -2) {
rc = SDBC_ENOIOBCB;
goto out;
}
}
if (_sdbc_handles_configure()) {
goto out;
}
_sd_cache_dem_cnt = 0;
/*
* nvmem support:
* if the cache did not shutdown properly we mark it as dirty.
* this must be done before _sdbc_cache_configure() so it can
* refresh sd_info_mem and sd_file_mem from nvmem if necsssary,
* and before _sdbc_ft_configure() so the ft thread will do a recovery.
*
*/
if (SAFESTORE_RECOVERY(sdbc_safestore)) {
_sdbc_ft_hold_io = 1;
"!sdbc(_sdbc_configure) cache marked dirty after"
" incomplete shutdown");
}
spcs_kstatus))) {
goto out;
}
/* ST_ALERT trace buffer */
goto out;
}
if (_sdbc_thread_configure()) {
goto out;
}
if (_sdbc_flush_configure()) {
goto out;
}
if (rc = _sdbc_dealloc_configure_dm()) {
goto out;
}
goto out;
}
if (_sdbc_ft_configure() != 0) {
goto out;
}
/*
* try to control the race between the ft thread
* and threads that will open the devices that the ft thread
* may be recovering. this synchronizing with the ft thread
* prevents sd_cadmin from returning until ft has opened
* the recovery devices, so if other apps wait for sd_cadmin
* to complete the race is prevented.
*/
while (_sdbc_ft_hold_io) {
}
#ifdef DEBUG
#endif
rc = 0;
out:
return (rc);
}
/*
* _sdbc_deconfigure - Put the cache back to the unconfigured state. Release
* any memory we allocated as part of the configuration process (but not the
*
* we can use them to produce an orderly deconfiguration.
*
* NOTE: this routine and its callee should always be capable of reversing
* the effects of _sdbc_configure no matter what partially configured
* state might be present.
*
*/
int
{
int i;
int rc;
int pinneddata = 0;
#ifdef DEBUG
#endif
/* check if there is pinned data and our mirror is down */
if (_sd_cache_files && _sd_is_mirror_down()) {
for (i = 0; i < sdbc_max_devs; i++) {
cdi = &(_sd_cache_files[i]);
continue;
/*
* if (!(cdi->cd_info->sh_failed))
* continue;
*/
if (!(_SD_CD_ALL_WRITES(i)))
continue;
goto out;
}
}
/* remember hint setting for restoration in case shutdown fails */
(void) _sd_get_node_hint(&saved_hint);
(void) _sd_set_node_hint(NSC_FORCED_WRTHRU);
/* TODO - there is a possible race between deconfig and power hits... */
if (sdbc_power)
(void) nsc_unregister_power(sdbc_power);
if (sdbc_io) {
if (rc == 0)
else {
/* Re-register-power if it was register before. */
if (sdbc_power) {
}
/* Remove NSC_FORCED_WRTHRU if we set it */
(void) _sd_clear_node_hint(
(~saved_hint) & _SD_HINT_MASK);
goto out;
}
}
sdbc_power = NULL;
#if defined(_SD_FAULT_RES)
_sd_remote_disable(0); /* notify mirror to forced_wrthru */
#endif
/*
* close devices, deconfigure processes, wait for exits
*/
if (_sd_cache_files) {
for (i = 0; i < sdbc_max_devs; i++) {
" %d not closed (%d)\n", i, rc);
}
}
}
/*
* look for pinned data
* TODO sort this out for multinode systems.
* cannot shutdown with pinned data on multinode.
* the state of pinned data should be determined in
* the close operation.
*/
if (_sd_cache_files) {
for (i = 0; i < sdbc_max_devs; i++) {
cdi = &(_sd_cache_files[i]);
continue;
/*
* if (!(cdi->cd_info->sh_failed))
* continue;
*/
if (!(_SD_CD_ALL_WRITES(i)))
continue;
"!sdbc(_sd_deconfigure) Pinned Data on cd %d(%s)",
pinneddata++;
}
}
while (_sd_cache_dem_cnt > 0) {
}
/*
* remove all dynamically allocated cache data memory
* there should be no i/o at this point
*/
/*
* At this point no thread of control should be active in the cache
* but us (unless they are blocked on the config lock).
*/
#if defined(_SD_FAULT_RES)
#endif
#if !KEEP_TRACES
/*
* This needs to happen before we unregister the memory.
*/
#endif
#if !KEEP_TRACES
#else
#endif
/*
* Call ss deconfig(),
* check for valid pointer in case _sdbc_configure()
* failed before safestrore system was initialized.
*/
if (sdbc_safestore)
/* tear down safestore system */
sst_deinit();
_SD_NETS = 0;
_sd_cblock_shift = 0;
_sd_node_hint = 0;
#ifdef DEBUG
#endif
rc = 0;
out:
return (rc);
}
static int
{
break;
return (start);
}
int
{
int lowbit;
int next_high = 0;
}
if (highbit <= 0) {
"!sdbc(get_high_bit) invalid block size %x\n", size);
return (-1);
}
return (highbit);
}
int
{
int i, page_size;
return (-1);
}
for (i = 0; i < page_size; i += 4)
}
return (0);
}
/*
* _sdbc_nodeid_deconfigure - merely a place holder until
* such time as there is something to be undone w.r.t.
* _sdbc_nodeid_configure.
*
*/
static void
_sdbc_nodeid_deconfigure(void)
{
/* My but we're quick */
}
/*
* _sdbc_nodeid_configure - configure the nodeid's we need to connect
* to any other nodes in the network.
*
*/
void
_sdbc_nodeid_configure(void)
{
if (_sd_cache_config.num_nodes == 0) {
_sd_nodes_configured = 1;
} else {
}
_SD_SELF_HOST = nsc_node_id();
}
#define num_spin 0
/*
* _sdbc_thread_deconfigure - cache is being deconfigure, stop any
* thread activity.
*
*/
static void
_sdbc_thread_deconfigure(void)
{
}
/*
* _sdbc_thread_configure - cache is being configured, initialize the
* threads we need for flushing dirty cds.
*
*/
static int
_sdbc_thread_configure(void)
{
if (!_sd_ioset)
if (!_sd_ioset)
return (EINVAL);
return (0);
}
int
{
int i;
for (i = 0; i < CACHE_MEM_PAD; i++) {
}
return (0);
}