xref: /onnv-gate/usr/src/uts/common/avs/ns/sdbc/sd_ft.c (revision 9093:cd587b0bd19c)
17836SJohn.Forte@Sun.COM /*
27836SJohn.Forte@Sun.COM  * CDDL HEADER START
37836SJohn.Forte@Sun.COM  *
47836SJohn.Forte@Sun.COM  * The contents of this file are subject to the terms of the
57836SJohn.Forte@Sun.COM  * Common Development and Distribution License (the "License").
67836SJohn.Forte@Sun.COM  * You may not use this file except in compliance with the License.
77836SJohn.Forte@Sun.COM  *
87836SJohn.Forte@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97836SJohn.Forte@Sun.COM  * or http://www.opensolaris.org/os/licensing.
107836SJohn.Forte@Sun.COM  * See the License for the specific language governing permissions
117836SJohn.Forte@Sun.COM  * and limitations under the License.
127836SJohn.Forte@Sun.COM  *
137836SJohn.Forte@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
147836SJohn.Forte@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157836SJohn.Forte@Sun.COM  * If applicable, add the following below this CDDL HEADER, with the
167836SJohn.Forte@Sun.COM  * fields enclosed by brackets "[]" replaced with your own identifying
177836SJohn.Forte@Sun.COM  * information: Portions Copyright [yyyy] [name of copyright owner]
187836SJohn.Forte@Sun.COM  *
197836SJohn.Forte@Sun.COM  * CDDL HEADER END
207836SJohn.Forte@Sun.COM  */
217836SJohn.Forte@Sun.COM /*
22*9093SRamana.Srikanth@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
237836SJohn.Forte@Sun.COM  * Use is subject to license terms.
247836SJohn.Forte@Sun.COM  */
257836SJohn.Forte@Sun.COM 
267836SJohn.Forte@Sun.COM #include <sys/types.h>
277836SJohn.Forte@Sun.COM #include <sys/ksynch.h>
287836SJohn.Forte@Sun.COM #include <sys/cmn_err.h>
297836SJohn.Forte@Sun.COM #include <sys/errno.h>
307836SJohn.Forte@Sun.COM #include <sys/kmem.h>
317836SJohn.Forte@Sun.COM #include <sys/cred.h>
327836SJohn.Forte@Sun.COM #include <sys/ddi.h>
337836SJohn.Forte@Sun.COM 
347836SJohn.Forte@Sun.COM #include <sys/nsc_thread.h>
357836SJohn.Forte@Sun.COM #include <sys/nsctl/nsctl.h>
367836SJohn.Forte@Sun.COM 
377836SJohn.Forte@Sun.COM #include <sys/sdt.h>		/* dtrace is S10 or later */
387836SJohn.Forte@Sun.COM 
397836SJohn.Forte@Sun.COM #include "sd_bcache.h"
407836SJohn.Forte@Sun.COM #include "sd_ft.h"
417836SJohn.Forte@Sun.COM #include "sd_trace.h"
427836SJohn.Forte@Sun.COM #include "sd_io.h"
437836SJohn.Forte@Sun.COM #include "sd_misc.h"
447836SJohn.Forte@Sun.COM #include <sys/ncall/ncall.h>
457836SJohn.Forte@Sun.COM 
467836SJohn.Forte@Sun.COM _sd_ft_info_t  _sd_ft_data;
477836SJohn.Forte@Sun.COM 
487836SJohn.Forte@Sun.COM static volatile int _sd_ft_exit = 0;
497836SJohn.Forte@Sun.COM static kcondvar_t _sd_ft_cv;
507836SJohn.Forte@Sun.COM int _sd_node_recovery;		/* node recovery in progress */
517836SJohn.Forte@Sun.COM /*
527836SJohn.Forte@Sun.COM  *  _sd_async_recovery:
537836SJohn.Forte@Sun.COM  *	0 = flush and wait
547836SJohn.Forte@Sun.COM  *	1 = clone and async-write
557836SJohn.Forte@Sun.COM  *	2 = quicksort, clone, and async-write
567836SJohn.Forte@Sun.COM  * quicksort allows contiguous blocks to be joined,
577836SJohn.Forte@Sun.COM  * which may greatly improve recovery time for raid devices.
587836SJohn.Forte@Sun.COM  * if kmem_alloc fails, acts as _sd_async_recovery == 1
597836SJohn.Forte@Sun.COM  */
607836SJohn.Forte@Sun.COM static int _sd_async_recovery = 2;
617836SJohn.Forte@Sun.COM static int xmem_inval_hit, xmem_inval_miss, xmem_inval_inuse;
627836SJohn.Forte@Sun.COM 
637836SJohn.Forte@Sun.COM 
647836SJohn.Forte@Sun.COM /*
657836SJohn.Forte@Sun.COM  * flag to inhibit reset of remote SCSI buses and sending of
667836SJohn.Forte@Sun.COM  * nodedown callback if mirror was deconfigured properly.
677836SJohn.Forte@Sun.COM  * - prevents trashing any I/O that may be happening on the mirror
687836SJohn.Forte@Sun.COM  *   node during a normal shutdown and prevents undesired simckd failover.
697836SJohn.Forte@Sun.COM  */
707836SJohn.Forte@Sun.COM static int mirror_clean_shutdown = 0;
717836SJohn.Forte@Sun.COM 
727836SJohn.Forte@Sun.COM /*
737836SJohn.Forte@Sun.COM  * Forward declare all statics that are used before defined to enforce
747836SJohn.Forte@Sun.COM  * parameter checking
757836SJohn.Forte@Sun.COM  * Some (if not all) of these could be removed if the code were reordered
767836SJohn.Forte@Sun.COM  */
777836SJohn.Forte@Sun.COM 
787836SJohn.Forte@Sun.COM static void _sd_health_thread(void);
797836SJohn.Forte@Sun.COM static void _sd_cache_recover(void);
807836SJohn.Forte@Sun.COM static int _sd_ft_clone(ss_centry_info_t *, int);
817836SJohn.Forte@Sun.COM static void _sd_remote_enable(void);
827836SJohn.Forte@Sun.COM static void sdbc_setmodeandftdata();
837836SJohn.Forte@Sun.COM static void _sd_cd_discard_mirror(int cd);
847836SJohn.Forte@Sun.COM static int _sd_failover_file_open(void);
857836SJohn.Forte@Sun.COM static void _sd_failover_done(void);
867836SJohn.Forte@Sun.COM static void _sd_wait_for_dirty(void);
877836SJohn.Forte@Sun.COM static void _sdbc_clear_warm_start(void);
887836SJohn.Forte@Sun.COM static int sdbc_recover_vol(ss_vol_t *, int);
897836SJohn.Forte@Sun.COM void _ncall_poke(int);
907836SJohn.Forte@Sun.COM 
917836SJohn.Forte@Sun.COM int _sdbc_ft_hold_io;
927836SJohn.Forte@Sun.COM kcondvar_t _sdbc_ft_hold_io_cv;
937836SJohn.Forte@Sun.COM kmutex_t _sdbc_ft_hold_io_lk;
947836SJohn.Forte@Sun.COM extern int sdbc_use_dmchain;
957836SJohn.Forte@Sun.COM extern void sdbc_requeue_head_dm_try(_sd_cctl_t *cc_ent);
967836SJohn.Forte@Sun.COM 
977836SJohn.Forte@Sun.COM /*
987836SJohn.Forte@Sun.COM  * _sdbc_ft_unload - cache is being unloaded (or failed to load).
997836SJohn.Forte@Sun.COM  * Deallocate any global lock/sv that we created.
1007836SJohn.Forte@Sun.COM  */
1017836SJohn.Forte@Sun.COM void
_sdbc_ft_unload(void)1027836SJohn.Forte@Sun.COM _sdbc_ft_unload(void)
1037836SJohn.Forte@Sun.COM {
1047836SJohn.Forte@Sun.COM 	cv_destroy(&_sd_ft_cv);
1057836SJohn.Forte@Sun.COM 	mutex_destroy(&_sd_ft_data.fi_lock);
1067836SJohn.Forte@Sun.COM 	cv_destroy(&_sd_ft_data.fi_rem_sv);
1077836SJohn.Forte@Sun.COM 	mutex_destroy(&_sd_ft_data.fi_sleep);
1087836SJohn.Forte@Sun.COM 	bzero(&_sd_ft_data, sizeof (_sd_ft_info_t));
1097836SJohn.Forte@Sun.COM }
1107836SJohn.Forte@Sun.COM 
1117836SJohn.Forte@Sun.COM /*
1127836SJohn.Forte@Sun.COM  * _sdbc_ft_load - cache is being loaded. Allocate all global lock/sv
1137836SJohn.Forte@Sun.COM  * that we need. Return 0 if we succeed. If we fail return -1 (don't
1147836SJohn.Forte@Sun.COM  * need to do the unload step as we expect our caller to do that).
1157836SJohn.Forte@Sun.COM  */
1167836SJohn.Forte@Sun.COM int
_sdbc_ft_load(void)1177836SJohn.Forte@Sun.COM _sdbc_ft_load(void)
1187836SJohn.Forte@Sun.COM {
1197836SJohn.Forte@Sun.COM 	/* _sd_ft_data is sure to be zeroes, don't need to bzero it */
1207836SJohn.Forte@Sun.COM 
1217836SJohn.Forte@Sun.COM 	mutex_init(&_sd_ft_data.fi_lock, NULL, MUTEX_DRIVER, NULL);
1227836SJohn.Forte@Sun.COM 	cv_init(&_sd_ft_data.fi_rem_sv, NULL, CV_DRIVER, NULL);
1237836SJohn.Forte@Sun.COM 	cv_init(&_sd_ft_cv, NULL, CV_DRIVER, NULL);
1247836SJohn.Forte@Sun.COM 	mutex_init(&_sd_ft_data.fi_sleep, NULL, MUTEX_DRIVER, NULL);
1257836SJohn.Forte@Sun.COM 	return (0);
1267836SJohn.Forte@Sun.COM }
127*9093SRamana.Srikanth@Sun.COM 
128*9093SRamana.Srikanth@Sun.COM 
1297836SJohn.Forte@Sun.COM int
_sdbc_ft_configure(void)1307836SJohn.Forte@Sun.COM _sdbc_ft_configure(void)
1317836SJohn.Forte@Sun.COM {
1327836SJohn.Forte@Sun.COM 	_sd_ft_exit = 1;
1337836SJohn.Forte@Sun.COM 	return (nsc_create_process(
134*9093SRamana.Srikanth@Sun.COM 	    (void (*)(void *))_sd_health_thread, 0, TRUE));
1357836SJohn.Forte@Sun.COM }
1367836SJohn.Forte@Sun.COM 
1377836SJohn.Forte@Sun.COM 
1387836SJohn.Forte@Sun.COM void
_sdbc_ft_deconfigure(void)1397836SJohn.Forte@Sun.COM _sdbc_ft_deconfigure(void)
1407836SJohn.Forte@Sun.COM {
1417836SJohn.Forte@Sun.COM 	_sd_ft_exit = 0;
1427836SJohn.Forte@Sun.COM 	_sd_unblock(&_sd_ft_cv);
1437836SJohn.Forte@Sun.COM 	mutex_enter(&_sd_ft_data.fi_lock);
1447836SJohn.Forte@Sun.COM 	_sd_node_recovery = 0;
1457836SJohn.Forte@Sun.COM 	cv_broadcast(&_sd_ft_data.fi_rem_sv);
1467836SJohn.Forte@Sun.COM 	mutex_exit(&_sd_ft_data.fi_lock);
1477836SJohn.Forte@Sun.COM }
1487836SJohn.Forte@Sun.COM 
1497836SJohn.Forte@Sun.COM 
1507836SJohn.Forte@Sun.COM /*
1517836SJohn.Forte@Sun.COM  * _sd_health_thread -- daemon thread on each node watches if mirror
1527836SJohn.Forte@Sun.COM  * node to has crashed, and it needs to flush the mirrors cache entries.
1537836SJohn.Forte@Sun.COM  * Note we do *not* detect that the node has come up again, but wait
1547836SJohn.Forte@Sun.COM  * for the node to inform us that it is up via _sd_cache_reenable().
1557836SJohn.Forte@Sun.COM  */
1567836SJohn.Forte@Sun.COM static void
_sd_health_thread(void)1577836SJohn.Forte@Sun.COM _sd_health_thread(void)
1587836SJohn.Forte@Sun.COM {
1597836SJohn.Forte@Sun.COM 	int warm_started = 0;
1607836SJohn.Forte@Sun.COM 
1617836SJohn.Forte@Sun.COM 	mutex_enter(&_sd_cache_lock);
1627836SJohn.Forte@Sun.COM 	_sd_cache_dem_cnt++;
1637836SJohn.Forte@Sun.COM 	mutex_exit(&_sd_cache_lock);
1647836SJohn.Forte@Sun.COM 
1657836SJohn.Forte@Sun.COM 	/* clear _sd_ft_data in case this is a cache re-enable w/o unload */
1667836SJohn.Forte@Sun.COM 
1677836SJohn.Forte@Sun.COM 	bzero(&_sd_ft_data, sizeof (_sd_ft_info_t));
1687836SJohn.Forte@Sun.COM 
1697836SJohn.Forte@Sun.COM 	sdbc_setmodeandftdata();
1707836SJohn.Forte@Sun.COM 
1717836SJohn.Forte@Sun.COM #ifdef DEBUG
172*9093SRamana.Srikanth@Sun.COM 	cmn_err(CE_NOTE, "!sdbc(_sd_health_thread) safestore "
1737836SJohn.Forte@Sun.COM 	    "is %s. Fast writes %s",
1747836SJohn.Forte@Sun.COM 	    (_SD_MIRROR_CONFIGD) ? "up" : "down",
1757836SJohn.Forte@Sun.COM 	    (_SD_NODE_HINTS & _SD_WRTHRU_MASK) ?
1767836SJohn.Forte@Sun.COM 	    "disabled" : "enabled");
1777836SJohn.Forte@Sun.COM #endif
1787836SJohn.Forte@Sun.COM 
1797836SJohn.Forte@Sun.COM 	/* CONSTCOND */
1807836SJohn.Forte@Sun.COM 	while (1) {
1817836SJohn.Forte@Sun.COM 		_sd_timed_block(HZ/8, &_sd_ft_cv);
1827836SJohn.Forte@Sun.COM 		if (_sd_ft_exit == 0) {
1837836SJohn.Forte@Sun.COM 			mutex_enter(&_sd_cache_lock);
1847836SJohn.Forte@Sun.COM 			_sd_cache_dem_cnt--;
1857836SJohn.Forte@Sun.COM 			mutex_exit(&_sd_cache_lock);
1867836SJohn.Forte@Sun.COM 			return;
1877836SJohn.Forte@Sun.COM 		}
1887836SJohn.Forte@Sun.COM 
1897836SJohn.Forte@Sun.COM 		/* NB evaluation order is important here for nvmem systems */
1907836SJohn.Forte@Sun.COM 		if (_sd_is_mirror_crashed() ||
1917836SJohn.Forte@Sun.COM 		    (warm_started = _sdbc_warm_start())) {
1927836SJohn.Forte@Sun.COM 
1937836SJohn.Forte@Sun.COM 			/*
1947836SJohn.Forte@Sun.COM 			 * Hash invalidate here. We do not want data from
1957836SJohn.Forte@Sun.COM 			 * previous failover incarnation to be cache hits, if
1967836SJohn.Forte@Sun.COM 			 * the 2 failover happens within a short time
1977836SJohn.Forte@Sun.COM 			 */
1987836SJohn.Forte@Sun.COM 			_sd_hash_invalidate_cd(-1);
1997836SJohn.Forte@Sun.COM 
2007836SJohn.Forte@Sun.COM 			/*
2017836SJohn.Forte@Sun.COM 			 * don't change mirror state when warm starting
2027836SJohn.Forte@Sun.COM 			 * nvmem systems.  _sd_mirror_down() is called in
2037836SJohn.Forte@Sun.COM 			 * in _sd_remote_enable() on nvmem systems if the
2047836SJohn.Forte@Sun.COM 			 * media is down.
2057836SJohn.Forte@Sun.COM 			 */
2067836SJohn.Forte@Sun.COM 			if (!warm_started)
2077836SJohn.Forte@Sun.COM 				if (!mirror_clean_shutdown)
2087836SJohn.Forte@Sun.COM 					_sd_mirror_down();
2097836SJohn.Forte@Sun.COM 				else
2107836SJohn.Forte@Sun.COM 					_sd_mirror_cache_down();
2117836SJohn.Forte@Sun.COM 
2127836SJohn.Forte@Sun.COM 			(void) _sd_set_node_hint(NSC_FORCED_WRTHRU);
2137836SJohn.Forte@Sun.COM 			if (!warm_started) {
2147836SJohn.Forte@Sun.COM 				/* was FAST */
2157836SJohn.Forte@Sun.COM 				mutex_enter(&_sd_ft_data.fi_lock);
2167836SJohn.Forte@Sun.COM 				_sd_node_recovery = 0;
2177836SJohn.Forte@Sun.COM 				/* was FAST */
2187836SJohn.Forte@Sun.COM 				mutex_exit(&_sd_ft_data.fi_lock);
2197836SJohn.Forte@Sun.COM 				/* Assume other side is still up */
2207836SJohn.Forte@Sun.COM 				cmn_err(CE_WARN,
221*9093SRamana.Srikanth@Sun.COM 				    "!sdbc(_sd_health_thread)"
2227836SJohn.Forte@Sun.COM 				    "Safestore is down. Fast writes %s",
2237836SJohn.Forte@Sun.COM 				    (_SD_NODE_HINTS & _SD_WRTHRU_MASK) ?
2247836SJohn.Forte@Sun.COM 				    "disabled" : "enabled");
2257836SJohn.Forte@Sun.COM 				_sd_unblock(&_sd_flush_cv);
2267836SJohn.Forte@Sun.COM 
2277836SJohn.Forte@Sun.COM 				if (SAFESTORE_LOCAL(sdbc_safestore))
2287836SJohn.Forte@Sun.COM 					continue;
2297836SJohn.Forte@Sun.COM 
2307836SJohn.Forte@Sun.COM 				/* Wait for cache to drain and panic */
2317836SJohn.Forte@Sun.COM 				_sd_wait_for_dirty();
2327836SJohn.Forte@Sun.COM 				cmn_err(CE_WARN,
233*9093SRamana.Srikanth@Sun.COM 				    "!sdbc(_sd_health_thread)"
2347836SJohn.Forte@Sun.COM 				    " dirty blocks flushed");
2357836SJohn.Forte@Sun.COM 				continue;
2367836SJohn.Forte@Sun.COM 			}
2377836SJohn.Forte@Sun.COM 			/* was FAST */
2387836SJohn.Forte@Sun.COM 			mutex_enter(&_sd_ft_data.fi_lock);
2397836SJohn.Forte@Sun.COM 			_sd_node_recovery = 1;
2407836SJohn.Forte@Sun.COM 			/* was FAST */
2417836SJohn.Forte@Sun.COM 			mutex_exit(&_sd_ft_data.fi_lock);
2427836SJohn.Forte@Sun.COM 			if (!SAFESTORE_LOCAL(sdbc_safestore))
2437836SJohn.Forte@Sun.COM 				cmn_err(CE_WARN,
244*9093SRamana.Srikanth@Sun.COM 				    "!sdbc(_sd_health_thread)"
2457836SJohn.Forte@Sun.COM 				    " Cache on node %d is down. "
2467836SJohn.Forte@Sun.COM 				    "Fast writes %s",
2477836SJohn.Forte@Sun.COM 				    _SD_MIRROR_HOST,
2487836SJohn.Forte@Sun.COM 				    (_SD_NODE_HINTS & _SD_WRTHRU_MASK) ?
2497836SJohn.Forte@Sun.COM 				    "disabled" : "enabled");
2507836SJohn.Forte@Sun.COM 			cmn_err(CE_NOTE,
251*9093SRamana.Srikanth@Sun.COM 			    "!sdbc(_sd_health_thread)"
2527836SJohn.Forte@Sun.COM 			    " Cache recovery in progress");
2537836SJohn.Forte@Sun.COM 			_sd_cache_recover();
2547836SJohn.Forte@Sun.COM 
2557836SJohn.Forte@Sun.COM 			mutex_enter(&_sd_ft_data.fi_lock);
2567836SJohn.Forte@Sun.COM 			_sd_node_recovery = 0;
2577836SJohn.Forte@Sun.COM 			_sdbc_clear_warm_start(); /* nvmem systems */
2587836SJohn.Forte@Sun.COM 			cv_broadcast(&_sd_ft_data.fi_rem_sv);
2597836SJohn.Forte@Sun.COM 			mutex_exit(&_sd_ft_data.fi_lock);
2607836SJohn.Forte@Sun.COM 			cmn_err(CE_NOTE,
261*9093SRamana.Srikanth@Sun.COM 			    "!sdbc(_sd_health_thread) %s Cache recovery done",
2627836SJohn.Forte@Sun.COM 			    _sd_async_recovery ?
2637836SJohn.Forte@Sun.COM 			    "asynchronous" : "synchronous");
2647836SJohn.Forte@Sun.COM 			/* restore previous state */
2657836SJohn.Forte@Sun.COM 			if (warm_started && !_sd_is_mirror_down()) {
2667836SJohn.Forte@Sun.COM 				(void) _sd_clear_node_hint(NSC_FORCED_WRTHRU);
2677836SJohn.Forte@Sun.COM 				cmn_err(CE_NOTE,
268*9093SRamana.Srikanth@Sun.COM 				    "!sdbc(_sd_health_thread) Fast writes %s",
2697836SJohn.Forte@Sun.COM 				    (_SD_NODE_HINTS & _SD_WRTHRU_MASK) ?
2707836SJohn.Forte@Sun.COM 				    "disabled" : "enabled");
2717836SJohn.Forte@Sun.COM 			}
2727836SJohn.Forte@Sun.COM 			warm_started = 0;
2737836SJohn.Forte@Sun.COM 
2747836SJohn.Forte@Sun.COM 		} else if (_sd_is_mirror_node_down()) {
2757836SJohn.Forte@Sun.COM 			_sd_mirror_down();
2767836SJohn.Forte@Sun.COM 		}
2777836SJohn.Forte@Sun.COM 	}
2787836SJohn.Forte@Sun.COM }
2797836SJohn.Forte@Sun.COM 
2807836SJohn.Forte@Sun.COM /*
2817836SJohn.Forte@Sun.COM  * _sdbc_recovery_io_wait - wait for i/o being done directly
2827836SJohn.Forte@Sun.COM  * out of safe storage to complete. If the i/o does not make any
2837836SJohn.Forte@Sun.COM  * progress within about 25 seconds we return EIO otherwise return 0.
2847836SJohn.Forte@Sun.COM  *
2857836SJohn.Forte@Sun.COM  */
2867836SJohn.Forte@Sun.COM static
2877836SJohn.Forte@Sun.COM int
_sdbc_recovery_io_wait(void)2887836SJohn.Forte@Sun.COM _sdbc_recovery_io_wait(void)
2897836SJohn.Forte@Sun.COM {
2907836SJohn.Forte@Sun.COM 	int tries = 0;
2917836SJohn.Forte@Sun.COM 	int last_numio = 0;
2927836SJohn.Forte@Sun.COM 
2937836SJohn.Forte@Sun.COM 	/*
2947836SJohn.Forte@Sun.COM 	 * Wait for numio to reach 0.
2957836SJohn.Forte@Sun.COM 	 * If numio has not changed for 85+ seconds,
2967836SJohn.Forte@Sun.COM 	 * break & pin blocks
2977836SJohn.Forte@Sun.COM 	 */
2987836SJohn.Forte@Sun.COM 	while (_sd_ft_data.fi_numio > 0) {
2997836SJohn.Forte@Sun.COM 		if (last_numio == _sd_ft_data.fi_numio) {
3007836SJohn.Forte@Sun.COM 			if (++tries > 512) break;
3017836SJohn.Forte@Sun.COM 		} else {
3027836SJohn.Forte@Sun.COM 			last_numio = _sd_ft_data.fi_numio;
3037836SJohn.Forte@Sun.COM 			tries = 0;
3047836SJohn.Forte@Sun.COM 		}
3057836SJohn.Forte@Sun.COM 		delay(HZ/8);
3067836SJohn.Forte@Sun.COM 	}
3077836SJohn.Forte@Sun.COM 	if (_sd_ft_data.fi_numio != 0) {
308*9093SRamana.Srikanth@Sun.COM 		cmn_err(CE_WARN, "!sdbc(_sdbc_recovery_io_wait) %d "
3097836SJohn.Forte@Sun.COM 		    "recovery i/o's not done", _sd_ft_data.fi_numio);
3107836SJohn.Forte@Sun.COM 		return (EIO);
3117836SJohn.Forte@Sun.COM 	}
3127836SJohn.Forte@Sun.COM 	return (0);
3137836SJohn.Forte@Sun.COM }
3147836SJohn.Forte@Sun.COM 
3157836SJohn.Forte@Sun.COM 
3167836SJohn.Forte@Sun.COM #if defined(_SD_FAULT_RES)
3177836SJohn.Forte@Sun.COM /*
3187836SJohn.Forte@Sun.COM  * _sd_recovery_wait()
3197836SJohn.Forte@Sun.COM  *   while _sd_node_recovery is set, accesses to mirrored devices will block
3207836SJohn.Forte@Sun.COM  *   (_sd_node_recovery-1) is count of blocked threads.
3217836SJohn.Forte@Sun.COM  */
3227836SJohn.Forte@Sun.COM int
_sd_recovery_wait(void)3237836SJohn.Forte@Sun.COM _sd_recovery_wait(void)
3247836SJohn.Forte@Sun.COM {
3257836SJohn.Forte@Sun.COM 	int blk;
3267836SJohn.Forte@Sun.COM 
3277836SJohn.Forte@Sun.COM 	mutex_enter(&_sd_ft_data.fi_lock);
3287836SJohn.Forte@Sun.COM 	blk = _sd_node_recovery ? _sd_node_recovery++ : 0;
3297836SJohn.Forte@Sun.COM 
3307836SJohn.Forte@Sun.COM 	if (blk)
3317836SJohn.Forte@Sun.COM 		cv_wait(&_sd_ft_data.fi_rem_sv, &_sd_ft_data.fi_lock);
3327836SJohn.Forte@Sun.COM 	mutex_exit(&_sd_ft_data.fi_lock);
3337836SJohn.Forte@Sun.COM 
3347836SJohn.Forte@Sun.COM 	if (!_sd_cache_initialized)
3357836SJohn.Forte@Sun.COM 		return (EINVAL);
3367836SJohn.Forte@Sun.COM 	return (0);
3377836SJohn.Forte@Sun.COM }
3387836SJohn.Forte@Sun.COM 
3397836SJohn.Forte@Sun.COM /*
3407836SJohn.Forte@Sun.COM  * _sd_recovery_wblk_wait - wait for recovery i/o to a device
3417836SJohn.Forte@Sun.COM  * to cease. If the file is closed or the cache is disabled
3427836SJohn.Forte@Sun.COM  * first return an error otherwise return 0.
3437836SJohn.Forte@Sun.COM  *
3447836SJohn.Forte@Sun.COM  * A device is being recovered from our point of view either
3457836SJohn.Forte@Sun.COM  * during failover or by putting a disk back online after
3467836SJohn.Forte@Sun.COM  * a disk failure.
3477836SJohn.Forte@Sun.COM  *
3487836SJohn.Forte@Sun.COM  * This code is used to delay access to a device while recovery
3497836SJohn.Forte@Sun.COM  * writes are in progress from either a failover or while flushing
3507836SJohn.Forte@Sun.COM  * i/o after a failed disk has been repaired.
3517836SJohn.Forte@Sun.COM  */
3527836SJohn.Forte@Sun.COM int
_sd_recovery_wblk_wait(int cd)3537836SJohn.Forte@Sun.COM _sd_recovery_wblk_wait(int cd)
3547836SJohn.Forte@Sun.COM {
3557836SJohn.Forte@Sun.COM 	_sd_cd_info_t *cdi = &_sd_cache_files[cd];
3567836SJohn.Forte@Sun.COM 
3577836SJohn.Forte@Sun.COM 	while (_sd_cache_initialized &&
358*9093SRamana.Srikanth@Sun.COM 	    FILE_OPENED(cd) && cdi->cd_recovering) {
3597836SJohn.Forte@Sun.COM 		/* spawn writer if none */
3607836SJohn.Forte@Sun.COM 		if (!cdi->cd_writer) (void) cd_writer(cd);
3617836SJohn.Forte@Sun.COM 		delay(HZ/8);
3627836SJohn.Forte@Sun.COM 	}
3637836SJohn.Forte@Sun.COM 	if (!_sd_cache_initialized || !FILE_OPENED(cd))
3647836SJohn.Forte@Sun.COM 		return (EINVAL);
3657836SJohn.Forte@Sun.COM 	return (0);
3667836SJohn.Forte@Sun.COM }
3677836SJohn.Forte@Sun.COM 
3687836SJohn.Forte@Sun.COM /*
3697836SJohn.Forte@Sun.COM  * Recover from a crash of another node:
3707836SJohn.Forte@Sun.COM  *
3717836SJohn.Forte@Sun.COM  * 1) Open all remote files
3727836SJohn.Forte@Sun.COM  * 2) Allocate other node's buffers and new buffer headers
3737836SJohn.Forte@Sun.COM  * 3) Flush all dirty buffers to disk
3747836SJohn.Forte@Sun.COM  * 4) Deallocate resources
3757836SJohn.Forte@Sun.COM  */
3767836SJohn.Forte@Sun.COM static void
_sd_cache_recover(void)3777836SJohn.Forte@Sun.COM _sd_cache_recover(void)
3787836SJohn.Forte@Sun.COM {
3797836SJohn.Forte@Sun.COM 	int cblocks_processed;
3807836SJohn.Forte@Sun.COM 
3817836SJohn.Forte@Sun.COM 	SDTRACE(ST_ENTER|SDF_RECOVER, SDT_INV_CD, 0, SDT_INV_BL, 0, 0);
3827836SJohn.Forte@Sun.COM 
3837836SJohn.Forte@Sun.COM 	/* was FAST */
3847836SJohn.Forte@Sun.COM 	mutex_enter(&_sd_ft_data.fi_lock);
3857836SJohn.Forte@Sun.COM 	_sd_ft_data.fi_numio = 0;
3867836SJohn.Forte@Sun.COM 	/* was FAST */
3877836SJohn.Forte@Sun.COM 	mutex_exit(&_sd_ft_data.fi_lock);
3887836SJohn.Forte@Sun.COM 
3897836SJohn.Forte@Sun.COM #ifdef _SD_DRIVE_RESP
3907836SJohn.Forte@Sun.COM 	if (!mirror_clean_shutdown)
3917836SJohn.Forte@Sun.COM 		_raw_reset_other();
3927836SJohn.Forte@Sun.COM #endif
3937836SJohn.Forte@Sun.COM 	mirror_clean_shutdown = 0;
3947836SJohn.Forte@Sun.COM 
3957836SJohn.Forte@Sun.COM 	cblocks_processed = _sd_failover_file_open();
3967836SJohn.Forte@Sun.COM 
3977836SJohn.Forte@Sun.COM 	/* allow cache config to proceed */
3987836SJohn.Forte@Sun.COM 	mutex_enter(&_sdbc_ft_hold_io_lk);
3997836SJohn.Forte@Sun.COM 	_sdbc_ft_hold_io = 0;
4007836SJohn.Forte@Sun.COM 	cv_signal(&_sdbc_ft_hold_io_cv);
4017836SJohn.Forte@Sun.COM 	mutex_exit(&_sdbc_ft_hold_io_lk);
4027836SJohn.Forte@Sun.COM 
4037836SJohn.Forte@Sun.COM 	/* wait for sequential recovery to complete */
4047836SJohn.Forte@Sun.COM 	if (!_sd_async_recovery && cblocks_processed)
4057836SJohn.Forte@Sun.COM 		(void) _sdbc_recovery_io_wait();
4067836SJohn.Forte@Sun.COM 
4077836SJohn.Forte@Sun.COM 	_sd_failover_done();
4087836SJohn.Forte@Sun.COM 
4097836SJohn.Forte@Sun.COM 	if (cblocks_processed)
4107836SJohn.Forte@Sun.COM 		cmn_err(CE_NOTE,
411*9093SRamana.Srikanth@Sun.COM 		    "!sdbc %ssynchronous recovery complete "
4127836SJohn.Forte@Sun.COM 		    "%d cache blocks processed",
4137836SJohn.Forte@Sun.COM 		    _sd_async_recovery ? "a" : "",
4147836SJohn.Forte@Sun.COM 		    cblocks_processed);
4157836SJohn.Forte@Sun.COM 
4167836SJohn.Forte@Sun.COM 	SDTRACE(ST_EXIT|SDF_RECOVER, SDT_INV_CD, 0, SDT_INV_BL, 0, 0);
4177836SJohn.Forte@Sun.COM }
4187836SJohn.Forte@Sun.COM 
4197836SJohn.Forte@Sun.COM void
_sd_mirror_iodone(void)4207836SJohn.Forte@Sun.COM _sd_mirror_iodone(void)
4217836SJohn.Forte@Sun.COM {
4227836SJohn.Forte@Sun.COM 	/* was FAST */
4237836SJohn.Forte@Sun.COM 	mutex_enter(&_sd_ft_data.fi_lock);
4247836SJohn.Forte@Sun.COM 	_sd_ft_data.fi_numio--;
4257836SJohn.Forte@Sun.COM 	/* was FAST */
4267836SJohn.Forte@Sun.COM 	mutex_exit(&_sd_ft_data.fi_lock);
4277836SJohn.Forte@Sun.COM }
4287836SJohn.Forte@Sun.COM 
4297836SJohn.Forte@Sun.COM 
4307836SJohn.Forte@Sun.COM 
4317836SJohn.Forte@Sun.COM /*
4327836SJohn.Forte@Sun.COM  * _sd_ft_clone -- clone cache block from ft area, retry write or pin.
4337836SJohn.Forte@Sun.COM  */
4347836SJohn.Forte@Sun.COM static int
_sd_ft_clone(ss_centry_info_t * ft_cent,int async)4357836SJohn.Forte@Sun.COM _sd_ft_clone(ss_centry_info_t *ft_cent, int async)
4367836SJohn.Forte@Sun.COM {
4377836SJohn.Forte@Sun.COM 	_sd_cctl_t *ent;
4387836SJohn.Forte@Sun.COM 	int cd = ft_cent->sc_cd;
4397836SJohn.Forte@Sun.COM 	nsc_off_t cblk = ft_cent->sc_fpos;
4407836SJohn.Forte@Sun.COM 	int dirty = ft_cent->sc_dirty;
4417836SJohn.Forte@Sun.COM 	ss_resource_t *res = ft_cent->sc_res;
4427836SJohn.Forte@Sun.COM 	_sd_cd_info_t *cdi;
4437836SJohn.Forte@Sun.COM 
4447836SJohn.Forte@Sun.COM 	SDTRACE(ST_ENTER|SDF_FT_CLONE, cd, BLK_FBAS, cblk, dirty, _SD_NO_NET);
4457836SJohn.Forte@Sun.COM 	cdi = &(_sd_cache_files[cd]);
4467836SJohn.Forte@Sun.COM 	if ((cdi->cd_info->sh_failed != 2) && !FILE_OPENED(cd)) {
447*9093SRamana.Srikanth@Sun.COM 		cmn_err(CE_WARN, "!sdbc(_sd_ft_clone) recovery "
4487836SJohn.Forte@Sun.COM 		    "write failed: cd %x; cblk %" NSC_SZFMT "; dirty %x",
4497836SJohn.Forte@Sun.COM 		    cd, cblk, dirty);
4507836SJohn.Forte@Sun.COM 		SDTRACE(ST_EXIT|SDF_FT_CLONE,
4517836SJohn.Forte@Sun.COM 		    cd, BLK_FBAS, cblk, dirty, EINTR);
4527836SJohn.Forte@Sun.COM 		return (-1);
4537836SJohn.Forte@Sun.COM 	}
4547836SJohn.Forte@Sun.COM 
4557836SJohn.Forte@Sun.COM 	/*
4567836SJohn.Forte@Sun.COM 	 * allocate new cache entry and read data
4577836SJohn.Forte@Sun.COM 	 */
4587836SJohn.Forte@Sun.COM 	ent = sdbc_centry_alloc_blks(cd, cblk, 1, 0);
4597836SJohn.Forte@Sun.COM 
4607836SJohn.Forte@Sun.COM 	if (SSOP_READ_CBLOCK(sdbc_safestore, res, (void *)ent->cc_data,
4617836SJohn.Forte@Sun.COM 	    CACHE_BLOCK_SIZE, 0) == SS_ERR) {
462*9093SRamana.Srikanth@Sun.COM 		cmn_err(CE_WARN, "!sdbc(_sd_ft_clone) read of "
4637836SJohn.Forte@Sun.COM 		    "pinned data block failed. cannot recover "
4647836SJohn.Forte@Sun.COM 		    "0x%p size 0x%x", (void *)res, CACHE_BLOCK_SIZE);
4657836SJohn.Forte@Sun.COM 
4667836SJohn.Forte@Sun.COM 		/* _sd_process_failure ?? */
4677836SJohn.Forte@Sun.COM 		_sd_centry_release(ent);
4687836SJohn.Forte@Sun.COM 		return (-1);
4697836SJohn.Forte@Sun.COM 	}
4707836SJohn.Forte@Sun.COM 
4717836SJohn.Forte@Sun.COM 	ent->cc_write = ft_cent;
4727836SJohn.Forte@Sun.COM 	ent->cc_dirty = ent->cc_valid = (ushort_t)dirty;
4737836SJohn.Forte@Sun.COM 	ent->cc_flag |= (ft_cent->sc_flag & CC_PINNABLE);
4747836SJohn.Forte@Sun.COM 
4757836SJohn.Forte@Sun.COM 	ent->cc_chain = NULL;
4767836SJohn.Forte@Sun.COM 
4777836SJohn.Forte@Sun.COM 	/*
4787836SJohn.Forte@Sun.COM 	 * _sd_process_failure() adds to failed list & does pinned callback
4797836SJohn.Forte@Sun.COM 	 * otherwise async flush
4807836SJohn.Forte@Sun.COM 	 */
4817836SJohn.Forte@Sun.COM 	if (cdi->cd_info->sh_failed) { /* raw device open/reserve failed */
4827836SJohn.Forte@Sun.COM 		mutex_enter(&cdi->cd_lock);
4837836SJohn.Forte@Sun.COM 		(cdi->cd_info->sh_numio)++;
4847836SJohn.Forte@Sun.COM 		mutex_exit(&cdi->cd_lock);
4857836SJohn.Forte@Sun.COM 		(void) _sd_process_failure(ent);
4867836SJohn.Forte@Sun.COM 	} else {
4877836SJohn.Forte@Sun.COM 
4887836SJohn.Forte@Sun.COM 		if (cdi->cd_global->sv_pinned != _SD_NO_HOST) {
4897836SJohn.Forte@Sun.COM 			cdi->cd_global->sv_pinned = _SD_NO_HOST;
4907836SJohn.Forte@Sun.COM 			SSOP_SETVOL(sdbc_safestore, cdi->cd_global);
4917836SJohn.Forte@Sun.COM 		}
4927836SJohn.Forte@Sun.COM 
4937836SJohn.Forte@Sun.COM 		if (async) {
4947836SJohn.Forte@Sun.COM 			_sd_enqueue_dirty(cd, ent, ent, 1);
4957836SJohn.Forte@Sun.COM 		} else {
4967836SJohn.Forte@Sun.COM 			/*
4977836SJohn.Forte@Sun.COM 			 * this is sync write with asynchronous callback
4987836SJohn.Forte@Sun.COM 			 * (queue to disk and return).
4997836SJohn.Forte@Sun.COM 			 */
5007836SJohn.Forte@Sun.COM 
5017836SJohn.Forte@Sun.COM 			mutex_enter(&(cdi->cd_lock));
5027836SJohn.Forte@Sun.COM 			(cdi->cd_info->sh_numio)++;
5037836SJohn.Forte@Sun.COM 			mutex_exit(&cdi->cd_lock);
5047836SJohn.Forte@Sun.COM 			_sd_async_flcent(ent, cdi->cd_crdev);
5057836SJohn.Forte@Sun.COM 		}
5067836SJohn.Forte@Sun.COM 	}
5077836SJohn.Forte@Sun.COM 	_sd_centry_release(ent);
5087836SJohn.Forte@Sun.COM 	SDTRACE(ST_EXIT|SDF_FT_CLONE, cd, BLK_FBAS, cblk, dirty, _SD_NO_NET);
5097836SJohn.Forte@Sun.COM 	return (0);
5107836SJohn.Forte@Sun.COM }
5117836SJohn.Forte@Sun.COM 
5127836SJohn.Forte@Sun.COM 
5137836SJohn.Forte@Sun.COM /*
5147836SJohn.Forte@Sun.COM  * _sd_repin_cd - scan for dirty blocks held by mirror node.
5157836SJohn.Forte@Sun.COM  *
5167836SJohn.Forte@Sun.COM  * sdbc on this node is being attached to cd. If sdbc on other
5177836SJohn.Forte@Sun.COM  * node had failed writes (pinnable or not) we need to take
5187836SJohn.Forte@Sun.COM  * responsbility for them now here.
5197836SJohn.Forte@Sun.COM  */
5207836SJohn.Forte@Sun.COM int
_sd_repin_cd(int cd)5217836SJohn.Forte@Sun.COM _sd_repin_cd(int cd)
5227836SJohn.Forte@Sun.COM {
5237836SJohn.Forte@Sun.COM 	ss_voldata_t *cd_gl;
5247836SJohn.Forte@Sun.COM 	_sd_cd_info_t *cdi;
5257836SJohn.Forte@Sun.COM 
5267836SJohn.Forte@Sun.COM 	if (!FILE_OPENED(cd))
5277836SJohn.Forte@Sun.COM 		return (EINVAL);
5287836SJohn.Forte@Sun.COM 
5297836SJohn.Forte@Sun.COM 	cdi = &_sd_cache_files[cd];
5307836SJohn.Forte@Sun.COM 	if (cdi->cd_global->sv_pinned == _SD_NO_HOST)
5317836SJohn.Forte@Sun.COM 		return (0);
5327836SJohn.Forte@Sun.COM 
5337836SJohn.Forte@Sun.COM 	cd_gl = _sdbc_gl_file_info + cd;
5347836SJohn.Forte@Sun.COM 
5357836SJohn.Forte@Sun.COM 	if (sdbc_recover_vol(cd_gl->sv_vol, cd))
5367836SJohn.Forte@Sun.COM 		_sd_cd_discard_mirror(cd);
5377836SJohn.Forte@Sun.COM 
5387836SJohn.Forte@Sun.COM 	return (0);
5397836SJohn.Forte@Sun.COM }
5407836SJohn.Forte@Sun.COM 
5417836SJohn.Forte@Sun.COM 
5427836SJohn.Forte@Sun.COM static int
_sd_cache_mirror_enable(int host)5437836SJohn.Forte@Sun.COM _sd_cache_mirror_enable(int host)
5447836SJohn.Forte@Sun.COM {
5457836SJohn.Forte@Sun.COM 	if (_sd_cache_initialized) {
5467836SJohn.Forte@Sun.COM 		if (host != _SD_MIRROR_HOST) {
547*9093SRamana.Srikanth@Sun.COM 			cmn_err(CE_WARN, "!sdbc(_sd_cache_mirror_enable) "
5487836SJohn.Forte@Sun.COM 			    "Configured mirror %x. Got message from %x",
5497836SJohn.Forte@Sun.COM 			    _SD_MIRROR_HOST, host);
5507836SJohn.Forte@Sun.COM 			return (-EINVAL);
5517836SJohn.Forte@Sun.COM 		}
5527836SJohn.Forte@Sun.COM 		if (_sd_node_recovery) (void) _sd_recovery_wait();
5537836SJohn.Forte@Sun.COM 		if (_sd_cache_initialized && _sd_is_mirror_down()) {
5547836SJohn.Forte@Sun.COM 			int i;
5557836SJohn.Forte@Sun.COM 
5567836SJohn.Forte@Sun.COM 			/* make sure any pinned data we have is now refreshed */
5577836SJohn.Forte@Sun.COM 			for (i = 0; i < sdbc_max_devs; i++)
5587836SJohn.Forte@Sun.COM 				if (FILE_OPENED(i))
5597836SJohn.Forte@Sun.COM 					(void) _sdbc_remote_store_pinned(i);
5607836SJohn.Forte@Sun.COM 
5617836SJohn.Forte@Sun.COM 			cmn_err(CE_NOTE,
562*9093SRamana.Srikanth@Sun.COM 			    "!sdbc(_sd_cache_mirror_enable) Cache on "
5637836SJohn.Forte@Sun.COM 			    "mirror node %d is up. Fast writes enabled",
5647836SJohn.Forte@Sun.COM 			    host);
5657836SJohn.Forte@Sun.COM 			_sd_mirror_up();
5667836SJohn.Forte@Sun.COM 			(void) _sd_clear_node_hint(NSC_FORCED_WRTHRU);
5677836SJohn.Forte@Sun.COM 		}
5687836SJohn.Forte@Sun.COM 	}
5697836SJohn.Forte@Sun.COM 	_sd_ft_data.fi_host_state = _SD_HOST_CONFIGURED;
5707836SJohn.Forte@Sun.COM 	return (_sd_cache_initialized);
5717836SJohn.Forte@Sun.COM }
5727836SJohn.Forte@Sun.COM 
5737836SJohn.Forte@Sun.COM 
5747836SJohn.Forte@Sun.COM /*
5757836SJohn.Forte@Sun.COM  * two stage mirror disable:
5767836SJohn.Forte@Sun.COM  *	stage 0: set FORCED_WRTHRU hint (cache shutdown started)
5777836SJohn.Forte@Sun.COM  *	stage 1: mirror shutdown completed
5787836SJohn.Forte@Sun.COM  */
5797836SJohn.Forte@Sun.COM static int
_sd_cache_mirror_disable(int host,int stage)5807836SJohn.Forte@Sun.COM _sd_cache_mirror_disable(int host, int stage)
5817836SJohn.Forte@Sun.COM {
5827836SJohn.Forte@Sun.COM 	if (_sd_cache_initialized) {
5837836SJohn.Forte@Sun.COM 
5847836SJohn.Forte@Sun.COM 		if (host != _SD_MIRROR_HOST)
5857836SJohn.Forte@Sun.COM 			return (0);
5867836SJohn.Forte@Sun.COM 		if (stage == 0) {
5877836SJohn.Forte@Sun.COM 			(void) _sd_set_node_hint(NSC_FORCED_WRTHRU);
5887836SJohn.Forte@Sun.COM 			return (0);
5897836SJohn.Forte@Sun.COM 		}
5907836SJohn.Forte@Sun.COM 		_sd_ft_data.fi_host_state = _SD_HOST_DECONFIGURED;
5917836SJohn.Forte@Sun.COM 		mirror_clean_shutdown = 1;
5927836SJohn.Forte@Sun.COM 		_sd_unblock(&_sd_ft_cv);
5937836SJohn.Forte@Sun.COM 	} else {
5947836SJohn.Forte@Sun.COM 		_sd_ft_data.fi_host_state = _SD_HOST_NONE;
5957836SJohn.Forte@Sun.COM 	}
5967836SJohn.Forte@Sun.COM 	return (0);
5977836SJohn.Forte@Sun.COM }
5987836SJohn.Forte@Sun.COM 
5997836SJohn.Forte@Sun.COM /*
6007836SJohn.Forte@Sun.COM  * set the fault tolerant data to indicate the state
6017836SJohn.Forte@Sun.COM  * of the safestore host.  set mode to writethru if appropriate
6027836SJohn.Forte@Sun.COM  */
6037836SJohn.Forte@Sun.COM static void
sdbc_setmodeandftdata()6047836SJohn.Forte@Sun.COM sdbc_setmodeandftdata()
6057836SJohn.Forte@Sun.COM {
6067836SJohn.Forte@Sun.COM 	/*
6077836SJohn.Forte@Sun.COM 	 * if single node local safestore or ram safestore
6087836SJohn.Forte@Sun.COM 	 * then mark host state as carashed/_SD_HOST_NONE and set writethru
6097836SJohn.Forte@Sun.COM 	 */
6107836SJohn.Forte@Sun.COM 	if (SAFESTORE_LOCAL(sdbc_safestore)) {
6117836SJohn.Forte@Sun.COM 		if (!SAFESTORE_SAFE(sdbc_safestore)) {
6127836SJohn.Forte@Sun.COM 			_sd_mirror_down();	/* mirror node down */
6137836SJohn.Forte@Sun.COM 			(void) _sd_set_node_hint(NSC_FORCED_WRTHRU);
6147836SJohn.Forte@Sun.COM 		} else {
6157836SJohn.Forte@Sun.COM 			_sd_ft_data.fi_host_state = _SD_HOST_CONFIGURED;
6167836SJohn.Forte@Sun.COM 			if (_sdbc_warm_start())
6177836SJohn.Forte@Sun.COM 				(void) _sd_set_node_hint(NSC_FORCED_WRTHRU);
6187836SJohn.Forte@Sun.COM 		}
6197836SJohn.Forte@Sun.COM 	} else
6207836SJohn.Forte@Sun.COM 		_sd_remote_enable();
6217836SJohn.Forte@Sun.COM }
6227836SJohn.Forte@Sun.COM 
6237836SJohn.Forte@Sun.COM static void
_sd_remote_enable(void)6247836SJohn.Forte@Sun.COM _sd_remote_enable(void)
6257836SJohn.Forte@Sun.COM {
6267836SJohn.Forte@Sun.COM 	ncall_t *ncall;
6277836SJohn.Forte@Sun.COM 	long r;
6287836SJohn.Forte@Sun.COM 
6297836SJohn.Forte@Sun.COM 	if (ncall_alloc(_SD_MIRROR_HOST, 0, _SD_NO_NET, &ncall)) {
6307836SJohn.Forte@Sun.COM 		_sd_mirror_down();	/* mirror node down */
6317836SJohn.Forte@Sun.COM 		(void) _sd_set_node_hint(NSC_FORCED_WRTHRU);
6327836SJohn.Forte@Sun.COM 		return;
6337836SJohn.Forte@Sun.COM 	}
6347836SJohn.Forte@Sun.COM 
6357836SJohn.Forte@Sun.COM 	r = ncall_send(ncall, 0, SD_ENABLE, _SD_SELF_HOST);
6367836SJohn.Forte@Sun.COM 	if (!r) (void) ncall_read_reply(ncall, 1, &r);
6377836SJohn.Forte@Sun.COM 	ncall_free(ncall);
6387836SJohn.Forte@Sun.COM 
6397836SJohn.Forte@Sun.COM 	if (r == 1) {		/* _sd_cache_initialized */
6407836SJohn.Forte@Sun.COM 		if (!_sd_is_mirror_crashed() &&
6417836SJohn.Forte@Sun.COM 		    _sd_ft_data.fi_host_state == _SD_HOST_NONE)
6427836SJohn.Forte@Sun.COM 			_sd_ft_data.fi_host_state = _SD_HOST_CONFIGURED;
6437836SJohn.Forte@Sun.COM 		return;
6447836SJohn.Forte@Sun.COM 	}
6457836SJohn.Forte@Sun.COM 	if (r == ENOLINK)
6467836SJohn.Forte@Sun.COM 		_sd_mirror_down();		/* mirror node down */
6477836SJohn.Forte@Sun.COM 	else
6487836SJohn.Forte@Sun.COM 		_sd_mirror_cache_down();	/* mirror up, but no cache */
6497836SJohn.Forte@Sun.COM 	(void) _sd_set_node_hint(NSC_FORCED_WRTHRU);
6507836SJohn.Forte@Sun.COM }
6517836SJohn.Forte@Sun.COM 
6527836SJohn.Forte@Sun.COM 
6537836SJohn.Forte@Sun.COM void
_sd_remote_disable(int stage)6547836SJohn.Forte@Sun.COM _sd_remote_disable(int stage)
6557836SJohn.Forte@Sun.COM {
6567836SJohn.Forte@Sun.COM 	ncall_t *ncall;
6577836SJohn.Forte@Sun.COM 
6587836SJohn.Forte@Sun.COM 	if (ncall_alloc(_SD_MIRROR_HOST, 0, 0, &ncall) == 0)
6597836SJohn.Forte@Sun.COM 		(void) ncall_send(ncall, NCALL_ASYNC, SD_DISABLE,
6607836SJohn.Forte@Sun.COM 		    _SD_SELF_HOST, stage);
6617836SJohn.Forte@Sun.COM }
6627836SJohn.Forte@Sun.COM 
6637836SJohn.Forte@Sun.COM void
r_sd_ifs_cache_enable(ncall_t * ncall,int * ap)6647836SJohn.Forte@Sun.COM r_sd_ifs_cache_enable(ncall_t *ncall, int *ap)
6657836SJohn.Forte@Sun.COM {
6667836SJohn.Forte@Sun.COM 	ncall_reply(ncall, _sd_cache_mirror_enable(*ap));
6677836SJohn.Forte@Sun.COM }
6687836SJohn.Forte@Sun.COM 
6697836SJohn.Forte@Sun.COM 
6707836SJohn.Forte@Sun.COM 
6717836SJohn.Forte@Sun.COM void
r_sd_ifs_cache_disable(ncall_t * ncall,int * ap)6727836SJohn.Forte@Sun.COM r_sd_ifs_cache_disable(ncall_t *ncall, int *ap)
6737836SJohn.Forte@Sun.COM {
6747836SJohn.Forte@Sun.COM 	(void) _sd_cache_mirror_disable(ap[0], ap[1]);
6757836SJohn.Forte@Sun.COM 	ncall_done(ncall);
6767836SJohn.Forte@Sun.COM }
6777836SJohn.Forte@Sun.COM 
6787836SJohn.Forte@Sun.COM #else /* (_SD_FAULT_RES) */
6797836SJohn.Forte@Sun.COM 
r_sd_ifs_cache_enable()6807836SJohn.Forte@Sun.COM void r_sd_ifs_cache_enable()  {; }
r_sd_ifs_cache_disable()6817836SJohn.Forte@Sun.COM void r_sd_ifs_cache_disable() {; }
6827836SJohn.Forte@Sun.COM 
6837836SJohn.Forte@Sun.COM #endif /* (_SD_FAULT_RES) */
6847836SJohn.Forte@Sun.COM 
6857836SJohn.Forte@Sun.COM /*
6867836SJohn.Forte@Sun.COM  * invalidate cache hash table entries for given device
6877836SJohn.Forte@Sun.COM  * or (-1) all devices belonging to mirrored node
6887836SJohn.Forte@Sun.COM  */
6897836SJohn.Forte@Sun.COM void
_sd_hash_invalidate_cd(int CD)6907836SJohn.Forte@Sun.COM _sd_hash_invalidate_cd(int CD)
6917836SJohn.Forte@Sun.COM {
6927836SJohn.Forte@Sun.COM 	int i;
6937836SJohn.Forte@Sun.COM 	_sd_cd_info_t *cdi;
6947836SJohn.Forte@Sun.COM 	_sd_hash_hd_t *hptr;
6957836SJohn.Forte@Sun.COM 	_sd_cctl_t *cc_ent, *ent;
6967836SJohn.Forte@Sun.COM 	_sd_hash_bucket_t *bucket;
6977836SJohn.Forte@Sun.COM 	int cd;
6987836SJohn.Forte@Sun.COM 	nsc_off_t blk;
6997836SJohn.Forte@Sun.COM 
7007836SJohn.Forte@Sun.COM 	for (i = 0; i < (_sd_htable->ht_size); i++) {
7017836SJohn.Forte@Sun.COM 		bucket = (_sd_htable->ht_buckets + i);
7027836SJohn.Forte@Sun.COM 		mutex_enter(bucket->hb_lock);
7037836SJohn.Forte@Sun.COM 		hptr = bucket->hb_head;
7047836SJohn.Forte@Sun.COM 		while (hptr) {
7057836SJohn.Forte@Sun.COM 			cc_ent = (_sd_cctl_t *)hptr;
7067836SJohn.Forte@Sun.COM 			cd = CENTRY_CD(cc_ent);
7077836SJohn.Forte@Sun.COM 			blk = CENTRY_BLK(cc_ent);
7087836SJohn.Forte@Sun.COM 			cdi = &_sd_cache_files[cd];
7097836SJohn.Forte@Sun.COM 
7107836SJohn.Forte@Sun.COM 			/*
7117836SJohn.Forte@Sun.COM 			 * Skip if device doesn't match or pinned.
7127836SJohn.Forte@Sun.COM 			 * (-1) skip attached cd's
7137836SJohn.Forte@Sun.COM 			 */
714*9093SRamana.Srikanth@Sun.COM 			if ((CD != -1 && (cd != CD || CENTRY_PINNED(cc_ent))) ||
715*9093SRamana.Srikanth@Sun.COM 			    (CD == -1 && nsc_held(cdi->cd_rawfd))) {
716*9093SRamana.Srikanth@Sun.COM 				hptr = hptr->hh_next;
717*9093SRamana.Srikanth@Sun.COM 				continue;
7187836SJohn.Forte@Sun.COM 			}
7197836SJohn.Forte@Sun.COM 			mutex_exit(bucket->hb_lock);
7207836SJohn.Forte@Sun.COM 
7217836SJohn.Forte@Sun.COM 			ent = cc_ent;
7227836SJohn.Forte@Sun.COM 		fl1:
7237836SJohn.Forte@Sun.COM 			if (CC_CD_BLK_MATCH(cd, blk, ent) ||
7247836SJohn.Forte@Sun.COM 			    (ent = (_sd_cctl_t *)_sd_hash_search(cd, blk,
7257836SJohn.Forte@Sun.COM 			    _sd_htable))) {
7267836SJohn.Forte@Sun.COM 				if (SET_CENTRY_INUSE(ent)) {
7277836SJohn.Forte@Sun.COM 					xmem_inval_inuse++;
7287836SJohn.Forte@Sun.COM 					_sd_cc_wait(cd, blk, ent, CC_INUSE);
7297836SJohn.Forte@Sun.COM 					goto fl1; /* try again */
7307836SJohn.Forte@Sun.COM 				}
7317836SJohn.Forte@Sun.COM 
7327836SJohn.Forte@Sun.COM 				/* cc_inuse is set, delete on block match */
7337836SJohn.Forte@Sun.COM 				if (CC_CD_BLK_MATCH(cd, blk, ent)) {
7347836SJohn.Forte@Sun.COM 					xmem_inval_hit++;
735*9093SRamana.Srikanth@Sun.COM 					(void) _sd_hash_delete(
736*9093SRamana.Srikanth@Sun.COM 					    (struct _sd_hash_hd *)ent,
737*9093SRamana.Srikanth@Sun.COM 					    _sd_htable);
7387836SJohn.Forte@Sun.COM 
7397836SJohn.Forte@Sun.COM 					if (sdbc_use_dmchain) {
7407836SJohn.Forte@Sun.COM 
7417836SJohn.Forte@Sun.COM 						/* attempt to que head */
7427836SJohn.Forte@Sun.COM 						if (ent->cc_alloc_size_dm) {
7437836SJohn.Forte@Sun.COM 							sdbc_requeue_head_dm_try
744*9093SRamana.Srikanth@Sun.COM 							    (ent);
7457836SJohn.Forte@Sun.COM 						}
7467836SJohn.Forte@Sun.COM 					} else
7477836SJohn.Forte@Sun.COM 						_sd_requeue_head(ent);
7487836SJohn.Forte@Sun.COM 
7497836SJohn.Forte@Sun.COM 				} else
7507836SJohn.Forte@Sun.COM 					xmem_inval_miss++;
7517836SJohn.Forte@Sun.COM 
7527836SJohn.Forte@Sun.COM 				CLEAR_CENTRY_INUSE(ent);
7537836SJohn.Forte@Sun.COM 			}
7547836SJohn.Forte@Sun.COM 			mutex_enter(bucket->hb_lock);
7557836SJohn.Forte@Sun.COM 			hptr = bucket->hb_head;
7567836SJohn.Forte@Sun.COM 		}
7577836SJohn.Forte@Sun.COM 		mutex_exit(bucket->hb_lock);
7587836SJohn.Forte@Sun.COM 	}
7597836SJohn.Forte@Sun.COM }
7607836SJohn.Forte@Sun.COM 
7617836SJohn.Forte@Sun.COM 
7627836SJohn.Forte@Sun.COM /*
7637836SJohn.Forte@Sun.COM  * _sd_cd_online(cd,discard)
7647836SJohn.Forte@Sun.COM  *	clear local error state.
7657836SJohn.Forte@Sun.COM  *	if (discard && _attached != _SD_SELF_HOST) then release buffers.
7667836SJohn.Forte@Sun.COM  *	if (!discard && _attached != _SD_MIRROR_HOST) then re-issue I/Os
7677836SJohn.Forte@Sun.COM  *		(add to dirty pending queue).
7687836SJohn.Forte@Sun.COM  * returns:
7697836SJohn.Forte@Sun.COM  *	0	success
7707836SJohn.Forte@Sun.COM  *	EINVAL	invalid device or not failed
7717836SJohn.Forte@Sun.COM  *	EBUSY	attached by this node, or by active mirror
7727836SJohn.Forte@Sun.COM  */
7737836SJohn.Forte@Sun.COM static int
_sd_cd_online(int cd,int discard)7747836SJohn.Forte@Sun.COM _sd_cd_online(int cd, int discard)
7757836SJohn.Forte@Sun.COM {
7767836SJohn.Forte@Sun.COM 	_sd_cd_info_t *cdi = &_sd_cache_files[cd];
7777836SJohn.Forte@Sun.COM 	int failed, num;
7787836SJohn.Forte@Sun.COM 	_sd_cctl_t *cc_ent, *cc_next, *cc_last, *cc_first, *cc_next_chain;
7797836SJohn.Forte@Sun.COM 
7807836SJohn.Forte@Sun.COM 	/*
7817836SJohn.Forte@Sun.COM 	 * in the case where a failed device has been closed and
7827836SJohn.Forte@Sun.COM 	 * then re-opened, sh_failed will be zero because it is
7837836SJohn.Forte@Sun.COM 	 * cleared in _sd_open_cd().  hence the test for
7847836SJohn.Forte@Sun.COM 	 * _pinned != _SD_SELF_HOST which allows the restore to
7857836SJohn.Forte@Sun.COM 	 * proceed in this scenario.
7867836SJohn.Forte@Sun.COM 	 */
7877836SJohn.Forte@Sun.COM 	if (cd < 0 || cd >= sdbc_max_devs)
7887836SJohn.Forte@Sun.COM 		return (EINVAL);
7897836SJohn.Forte@Sun.COM 
7907836SJohn.Forte@Sun.COM 	if (!cdi->cd_info || !cdi->cd_global)
7917836SJohn.Forte@Sun.COM 		return (EINVAL);
7927836SJohn.Forte@Sun.COM 
7937836SJohn.Forte@Sun.COM 	if ((cdi->cd_info->sh_failed == 0) &&
7947836SJohn.Forte@Sun.COM 	    (cdi->cd_global->sv_pinned != _SD_SELF_HOST))
7957836SJohn.Forte@Sun.COM 		return (0);
7967836SJohn.Forte@Sun.COM 
7977836SJohn.Forte@Sun.COM 	if (_sd_nodes_configured > 1) {
7987836SJohn.Forte@Sun.COM 
7997836SJohn.Forte@Sun.COM 		/* can't discard while attached on multinode systems */
8007836SJohn.Forte@Sun.COM 		if (discard && (cdi->cd_global->sv_attached == _SD_SELF_HOST))
8017836SJohn.Forte@Sun.COM 			return (EBUSY);
8027836SJohn.Forte@Sun.COM 
8037836SJohn.Forte@Sun.COM 		if (!discard &&		/* attached by active mirror! */
8047836SJohn.Forte@Sun.COM 		    (cdi->cd_global->sv_attached == _SD_MIRROR_HOST) &&
8057836SJohn.Forte@Sun.COM 		    !_sd_is_mirror_down())
8067836SJohn.Forte@Sun.COM 			return (EBUSY);
8077836SJohn.Forte@Sun.COM 	}
8087836SJohn.Forte@Sun.COM 
8097836SJohn.Forte@Sun.COM 	mutex_enter(&cdi->cd_lock);
8107836SJohn.Forte@Sun.COM 
8117836SJohn.Forte@Sun.COM 	cc_ent = cdi->cd_fail_head;
8127836SJohn.Forte@Sun.COM 	failed = cdi->cd_info->sh_numfail;
8137836SJohn.Forte@Sun.COM 	cdi->cd_fail_head = NULL;
8147836SJohn.Forte@Sun.COM 	cdi->cd_info->sh_numfail = 0;
8157836SJohn.Forte@Sun.COM 	cdi->cd_info->sh_failed = 0;
8167836SJohn.Forte@Sun.COM 	cdi->cd_global->sv_pinned = _SD_NO_HOST;
8177836SJohn.Forte@Sun.COM 	SSOP_SETVOL(sdbc_safestore, cdi->cd_global);
8187836SJohn.Forte@Sun.COM 
8197836SJohn.Forte@Sun.COM 	if (cc_ent == NULL) {
8207836SJohn.Forte@Sun.COM 		mutex_exit(&cdi->cd_lock);
8217836SJohn.Forte@Sun.COM 		return (0);
8227836SJohn.Forte@Sun.COM 	}
8237836SJohn.Forte@Sun.COM 	/* prevent any new i/o from arriving for this cd */
8247836SJohn.Forte@Sun.COM 	if (!discard)
8257836SJohn.Forte@Sun.COM 		cdi->cd_recovering = 1;
8267836SJohn.Forte@Sun.COM 
8277836SJohn.Forte@Sun.COM 	mutex_exit(&cdi->cd_lock);
8287836SJohn.Forte@Sun.COM 
8297836SJohn.Forte@Sun.COM 	num = 0;
8307836SJohn.Forte@Sun.COM 	cc_first = cc_ent;
8317836SJohn.Forte@Sun.COM 	for (; cc_ent; cc_ent = cc_next_chain) {
8327836SJohn.Forte@Sun.COM 		cc_next_chain = cc_ent->cc_dirty_link;
8337836SJohn.Forte@Sun.COM 
8347836SJohn.Forte@Sun.COM 		for (; cc_ent; cc_ent = cc_next) {
8357836SJohn.Forte@Sun.COM 			cc_next = cc_ent->cc_dirty_next;
8367836SJohn.Forte@Sun.COM 			cc_last = cc_ent;
8377836SJohn.Forte@Sun.COM 			num++;
8387836SJohn.Forte@Sun.COM 
8397836SJohn.Forte@Sun.COM 			if (discard) {
8407836SJohn.Forte@Sun.COM 				ss_centry_info_t *wctl;
8417836SJohn.Forte@Sun.COM 				/* was FAST */
8427836SJohn.Forte@Sun.COM 				mutex_enter(&cc_ent->cc_lock);
8437836SJohn.Forte@Sun.COM 				cc_ent->cc_valid = cc_ent->cc_dirty = 0;
8447836SJohn.Forte@Sun.COM 				cc_ent->cc_flag &= ~(CC_PEND_DIRTY|CC_PINNED);
8457836SJohn.Forte@Sun.COM 				cc_ent->cc_dirty_next = NULL;
8467836SJohn.Forte@Sun.COM 				cc_ent->cc_dirty_link = NULL;
8477836SJohn.Forte@Sun.COM 				wctl = cc_ent->cc_write;
8487836SJohn.Forte@Sun.COM 				cc_ent->cc_write = NULL;
8497836SJohn.Forte@Sun.COM 				/* was FAST */
8507836SJohn.Forte@Sun.COM 				mutex_exit(&cc_ent->cc_lock);
8517836SJohn.Forte@Sun.COM 				if (wctl) {
8527836SJohn.Forte@Sun.COM 					wctl->sc_flag = 0;
8537836SJohn.Forte@Sun.COM 					wctl->sc_dirty = 0;
8547836SJohn.Forte@Sun.COM 
8557836SJohn.Forte@Sun.COM 					SSOP_SETCENTRY(sdbc_safestore, wctl);
8567836SJohn.Forte@Sun.COM 					SSOP_DEALLOCRESOURCE(sdbc_safestore,
8577836SJohn.Forte@Sun.COM 					    wctl->sc_res);
8587836SJohn.Forte@Sun.COM 				}
8597836SJohn.Forte@Sun.COM 
8607836SJohn.Forte@Sun.COM 				continue;
8617836SJohn.Forte@Sun.COM 			}
8627836SJohn.Forte@Sun.COM 
8637836SJohn.Forte@Sun.COM 			/* Clear PEND_DIRTY, iocount & iostatus */
8647836SJohn.Forte@Sun.COM 			if (SET_CENTRY_INUSE(cc_ent) == 0) {
8657836SJohn.Forte@Sun.COM 				cc_ent->cc_flag &= ~CC_PEND_DIRTY;
8667836SJohn.Forte@Sun.COM 				cc_ent->cc_iocount = 0;
8677836SJohn.Forte@Sun.COM 				cc_ent->cc_iostatus = 0; /* _SD_IO_NONE */
8687836SJohn.Forte@Sun.COM 				CLEAR_CENTRY_INUSE(cc_ent);
8697836SJohn.Forte@Sun.COM 			} else {
8707836SJohn.Forte@Sun.COM 				/* was FAST */
8717836SJohn.Forte@Sun.COM 				mutex_enter(&cc_ent->cc_lock);
8727836SJohn.Forte@Sun.COM 				cc_ent->cc_flag &= ~CC_PEND_DIRTY;
8737836SJohn.Forte@Sun.COM 				cc_ent->cc_iocount = 0;
8747836SJohn.Forte@Sun.COM 				cc_ent->cc_iostatus = 0; /* _SD_IO_NONE */
8757836SJohn.Forte@Sun.COM 				/* was FAST */
8767836SJohn.Forte@Sun.COM 				mutex_exit(&cc_ent->cc_lock);
8777836SJohn.Forte@Sun.COM 			}
8787836SJohn.Forte@Sun.COM 		}
8797836SJohn.Forte@Sun.COM 	}
8807836SJohn.Forte@Sun.COM 	if (num != failed)
881*9093SRamana.Srikanth@Sun.COM 		cmn_err(CE_WARN, "!sdbc(_sd_cd_online) count %d vs numfail %d",
8827836SJohn.Forte@Sun.COM 		    num, failed);
8837836SJohn.Forte@Sun.COM 	if (discard) {
8847836SJohn.Forte@Sun.COM 		_sd_hash_invalidate_cd(cd);
8857836SJohn.Forte@Sun.COM 		return (0);
8867836SJohn.Forte@Sun.COM 	}
8877836SJohn.Forte@Sun.COM 
8887836SJohn.Forte@Sun.COM 	_sd_enqueue_dirty_chain(cd, cc_first, cc_last, num);
8897836SJohn.Forte@Sun.COM 	/* make sure data gets flushed in case there is no new I/O */
8907836SJohn.Forte@Sun.COM 	(void) nsc_reserve(cdi->cd_rawfd, NSC_MULTI);
8917836SJohn.Forte@Sun.COM 	(void) _sd_wait_for_flush(cd);
8927836SJohn.Forte@Sun.COM 	cdi->cd_recovering = 0;
8937836SJohn.Forte@Sun.COM 	nsc_release(cdi->cd_rawfd);
8947836SJohn.Forte@Sun.COM 
8957836SJohn.Forte@Sun.COM 	return (0);
8967836SJohn.Forte@Sun.COM }
8977836SJohn.Forte@Sun.COM 
8987836SJohn.Forte@Sun.COM #if defined(_SD_FAULT_RES)
8997836SJohn.Forte@Sun.COM 
9007836SJohn.Forte@Sun.COM /*
9017836SJohn.Forte@Sun.COM  * This node has disk attached, discard pins held by mirror
9027836SJohn.Forte@Sun.COM  */
9037836SJohn.Forte@Sun.COM static void
_sd_cd_discard_mirror(int cd)9047836SJohn.Forte@Sun.COM _sd_cd_discard_mirror(int cd)
9057836SJohn.Forte@Sun.COM {
9067836SJohn.Forte@Sun.COM 	ncall_t *ncall;
9077836SJohn.Forte@Sun.COM 	if (ncall_alloc(_SD_MIRROR_HOST, 0, 0, &ncall))
9087836SJohn.Forte@Sun.COM 		return;
9097836SJohn.Forte@Sun.COM 	(void) ncall_send(ncall, NCALL_ASYNC, SD_CD_DISCARD, cd);
9107836SJohn.Forte@Sun.COM }
9117836SJohn.Forte@Sun.COM 
9127836SJohn.Forte@Sun.COM void
r_cd_discard(ncall_t * ncall,int * ap)9137836SJohn.Forte@Sun.COM r_cd_discard(ncall_t *ncall, int *ap)
9147836SJohn.Forte@Sun.COM {
9157836SJohn.Forte@Sun.COM 	int r, cd = *ap;
9167836SJohn.Forte@Sun.COM 	if (_sd_cache_initialized) {
9177836SJohn.Forte@Sun.COM 		SDTRACE(ST_ENTER|SDF_ONLINE, cd, 1, SDT_INV_BL, 1, 0);
9187836SJohn.Forte@Sun.COM 		r = _sd_cd_online(cd, 1);
9197836SJohn.Forte@Sun.COM 		SDTRACE(ST_EXIT|SDF_ONLINE, cd, 1, SDT_INV_BL, 1, r);
9207836SJohn.Forte@Sun.COM 	}
9217836SJohn.Forte@Sun.COM 	ncall_done(ncall);
9227836SJohn.Forte@Sun.COM }
9237836SJohn.Forte@Sun.COM 
9247836SJohn.Forte@Sun.COM /*
9257836SJohn.Forte@Sun.COM  * _sd_failover_file_open -
9267836SJohn.Forte@Sun.COM  *	on failover, open devices which are not attached by this node.
9277836SJohn.Forte@Sun.COM  */
9287836SJohn.Forte@Sun.COM static int
_sd_failover_file_open(void)9297836SJohn.Forte@Sun.COM _sd_failover_file_open(void)
9307836SJohn.Forte@Sun.COM {
9317836SJohn.Forte@Sun.COM 	int rc, cd, flag = 0;
9327836SJohn.Forte@Sun.COM 	ss_voldata_t *cd_gl;
9337836SJohn.Forte@Sun.COM 	_sd_cd_info_t *cdi;
9347836SJohn.Forte@Sun.COM 	int cblocks_processed = 0;
9357836SJohn.Forte@Sun.COM 	extern ss_voldata_t *_sdbc_gl_file_info;
9367836SJohn.Forte@Sun.COM 
9377836SJohn.Forte@Sun.COM 	for (cd = 0; cd < sdbc_max_devs; cd++) {
9387836SJohn.Forte@Sun.COM 		cd_gl = _sdbc_gl_file_info + cd;
9397836SJohn.Forte@Sun.COM 		cdi = &(_sd_cache_files[cd]);
9407836SJohn.Forte@Sun.COM 
9417836SJohn.Forte@Sun.COM 		/*
9427836SJohn.Forte@Sun.COM 		 * If the cd is open and reserved we certainly don't
9437836SJohn.Forte@Sun.COM 		 * need to do it again. However the recovery code
9447836SJohn.Forte@Sun.COM 		 * must be racing some other cache usage which could
9457836SJohn.Forte@Sun.COM 		 * be bad.  We really need to be able to lock out
9467836SJohn.Forte@Sun.COM 		 * all cache activity for this cd that is not tied
9477836SJohn.Forte@Sun.COM 		 * to the recovery process. This doesn't seem to be
9487836SJohn.Forte@Sun.COM 		 * feasible in sdbc since a competing thread could
9497836SJohn.Forte@Sun.COM 		 * already be finished doing an alloc_buf. If this
9507836SJohn.Forte@Sun.COM 		 * hole is to be closed sd-ctl must be more in
9517836SJohn.Forte@Sun.COM 		 * control of the failover process.
9527836SJohn.Forte@Sun.COM 		 */
9537836SJohn.Forte@Sun.COM 		if (FILE_OPENED(cd) && nsc_held(cdi->cd_rawfd))
9547836SJohn.Forte@Sun.COM 			continue;
9557836SJohn.Forte@Sun.COM 
9567836SJohn.Forte@Sun.COM 		/*
9577836SJohn.Forte@Sun.COM 		 * this constuct says that, on non-nvmem systems,
9587836SJohn.Forte@Sun.COM 		 * if we are attempting to open a "local" device and
9597836SJohn.Forte@Sun.COM 		 * nothing is pinned, then continue.  i.e. open only
9607836SJohn.Forte@Sun.COM 		 * remote devices or devices that have pinned data.
9617836SJohn.Forte@Sun.COM 		 * for recovery on nvmem systems we open all devices.
9627836SJohn.Forte@Sun.COM 		 */
9637836SJohn.Forte@Sun.COM 		if ((!_sdbc_warm_start()) &&
964*9093SRamana.Srikanth@Sun.COM 		    ((cd_gl->sv_attached != _SD_MIRROR_HOST) &&
965*9093SRamana.Srikanth@Sun.COM 		    (cd_gl->sv_pinned != _SD_MIRROR_HOST) &&
966*9093SRamana.Srikanth@Sun.COM 		    (cd_gl->sv_pinned != _SD_SELF_HOST)))
9677836SJohn.Forte@Sun.COM 			continue;
968*9093SRamana.Srikanth@Sun.COM 		if (!cd_gl->sv_volname || !cd_gl->sv_volname[0])
9697836SJohn.Forte@Sun.COM 			continue;
9707836SJohn.Forte@Sun.COM 
9717836SJohn.Forte@Sun.COM 		if (_sd_open_cd(cd_gl->sv_volname, cd, flag) < 0) {
972*9093SRamana.Srikanth@Sun.COM 			cmn_err(CE_WARN, "!sdbc(_sd_failover_file_open) "
9737836SJohn.Forte@Sun.COM 			    "Unable to open disk partition %s",
9747836SJohn.Forte@Sun.COM 			    cd_gl->sv_volname);
9757836SJohn.Forte@Sun.COM 			continue;
9767836SJohn.Forte@Sun.COM 		}
9777836SJohn.Forte@Sun.COM 
9787836SJohn.Forte@Sun.COM 		SDTRACE(ST_INFO|SDF_RECOVER, cd, 0, 0, 0, 0);
9797836SJohn.Forte@Sun.COM 		rc = nsc_reserve(cdi->cd_rawfd, NSC_MULTI);
9807836SJohn.Forte@Sun.COM 		if (rc == 0) {
9817836SJohn.Forte@Sun.COM 			cdi->cd_failover = 1;
9827836SJohn.Forte@Sun.COM 		}
9837836SJohn.Forte@Sun.COM 
9847836SJohn.Forte@Sun.COM 		if (rc != 0) cdi->cd_info->sh_failed = 1;
9857836SJohn.Forte@Sun.COM 
9867836SJohn.Forte@Sun.COM 		cblocks_processed += sdbc_recover_vol(cd_gl->sv_vol, cd);
9877836SJohn.Forte@Sun.COM 	}
9887836SJohn.Forte@Sun.COM 
9897836SJohn.Forte@Sun.COM 	return (cblocks_processed);
9907836SJohn.Forte@Sun.COM }
9917836SJohn.Forte@Sun.COM 
9927836SJohn.Forte@Sun.COM 
9937836SJohn.Forte@Sun.COM static int
sdbc_recover_vol(ss_vol_t * vol,int cd)9947836SJohn.Forte@Sun.COM sdbc_recover_vol(ss_vol_t *vol, int cd)
9957836SJohn.Forte@Sun.COM {
9967836SJohn.Forte@Sun.COM 	ss_cdirkey_t key;
9977836SJohn.Forte@Sun.COM 	ss_cdir_t cdir;
9987836SJohn.Forte@Sun.COM 	ss_voldata_t *cd_gl = _sdbc_gl_file_info + cd;
9997836SJohn.Forte@Sun.COM 	ss_centry_info_t *cinfo;
10007836SJohn.Forte@Sun.COM 	ss_centry_info_t centry;
10017836SJohn.Forte@Sun.COM 	int cblocks_processed = 0;
10027836SJohn.Forte@Sun.COM 	int err;
10037836SJohn.Forte@Sun.COM 	ss_centry_info_t *sdbc_get_cinfo_byres(ss_resource_t *);
10047836SJohn.Forte@Sun.COM 
10057836SJohn.Forte@Sun.COM 	/* setup the key to get a volume directory stream of centrys */
10067836SJohn.Forte@Sun.COM 	key.ck_type  = CDIR_VOL;
10077836SJohn.Forte@Sun.COM 	key.cdk_u.ck_vol = vol;
10087836SJohn.Forte@Sun.COM 
10097836SJohn.Forte@Sun.COM 	if (SSOP_GETCDIR(sdbc_safestore, &key, &cdir)) {
1010*9093SRamana.Srikanth@Sun.COM 		cmn_err(CE_WARN, "!sdbc(sdbc_recover_vol): "
10117836SJohn.Forte@Sun.COM 		    "cannot recover volume %s",
10127836SJohn.Forte@Sun.COM 		    cd_gl->sv_volname);
10137836SJohn.Forte@Sun.COM 		return (0);
10147836SJohn.Forte@Sun.COM 	}
10157836SJohn.Forte@Sun.COM 
10167836SJohn.Forte@Sun.COM 	/* cycle through the cdir getting resource tokens and reading centrys */
10177836SJohn.Forte@Sun.COM 	/*CONSTANTCONDITION*/
10187836SJohn.Forte@Sun.COM 	while (1) {
10197836SJohn.Forte@Sun.COM 
10207836SJohn.Forte@Sun.COM 		if ((err = SSOP_GETCDIRENT(sdbc_safestore, &cdir, &centry))
1021*9093SRamana.Srikanth@Sun.COM 		    == SS_ERR) {
1022*9093SRamana.Srikanth@Sun.COM 			cmn_err(CE_WARN, "!sdbc(sdbc_recover_vol): "
1023*9093SRamana.Srikanth@Sun.COM 			    "cache entry read failure %s %p",
1024*9093SRamana.Srikanth@Sun.COM 			    cd_gl->sv_volname, (void *)centry.sc_res);
10257836SJohn.Forte@Sun.COM 
10267836SJohn.Forte@Sun.COM 			continue;
10277836SJohn.Forte@Sun.COM 		}
10287836SJohn.Forte@Sun.COM 
10297836SJohn.Forte@Sun.COM 
10307836SJohn.Forte@Sun.COM 		if (err == SS_EOF)
10317836SJohn.Forte@Sun.COM 			break; /* done */
10327836SJohn.Forte@Sun.COM 
10337836SJohn.Forte@Sun.COM 
10347836SJohn.Forte@Sun.COM 		/*
10357836SJohn.Forte@Sun.COM 		 * this get into double caching consistency
10367836SJohn.Forte@Sun.COM 		 * need to resolve this jgk
10377836SJohn.Forte@Sun.COM 		 */
10387836SJohn.Forte@Sun.COM 		if ((cinfo = sdbc_get_cinfo_byres(centry.sc_res)) == NULL) {
10397836SJohn.Forte@Sun.COM 			/* should not happen */
1040*9093SRamana.Srikanth@Sun.COM 			cmn_err(CE_WARN, "!sdbc(sdbc_recover_vol): "
10417836SJohn.Forte@Sun.COM 			    "invalid ss resource %p", (void *)centry.sc_res);
10427836SJohn.Forte@Sun.COM 			continue;
10437836SJohn.Forte@Sun.COM 		}
10447836SJohn.Forte@Sun.COM 		bcopy(&centry, cinfo, sizeof (ss_centry_info_t));
10457836SJohn.Forte@Sun.COM 
10467836SJohn.Forte@Sun.COM 		/*
10477836SJohn.Forte@Sun.COM 		 * note
10487836SJohn.Forte@Sun.COM 		 * ss should return a stream of dirty blocks ordered
10497836SJohn.Forte@Sun.COM 		 * by block number.  if it turns out that ss will not support
10507836SJohn.Forte@Sun.COM 		 * this then sorting for async recovery will have to be
10517836SJohn.Forte@Sun.COM 		 * done here  jgk
10527836SJohn.Forte@Sun.COM 		 */
10537836SJohn.Forte@Sun.COM 		ASSERT(cinfo->sc_dirty);
10547836SJohn.Forte@Sun.COM 
10557836SJohn.Forte@Sun.COM 		if (!cinfo->sc_dirty) /* should not happen */
10567836SJohn.Forte@Sun.COM 			continue;
10577836SJohn.Forte@Sun.COM 
10587836SJohn.Forte@Sun.COM 		/*
10597836SJohn.Forte@Sun.COM 		 * clone mirror cache entry and do
10607836SJohn.Forte@Sun.COM 		 * 	async I/O or sync I/O or pin if sh_failed
10617836SJohn.Forte@Sun.COM 		 */
10627836SJohn.Forte@Sun.COM 		(void) _sd_ft_clone(cinfo, _sd_async_recovery);
10637836SJohn.Forte@Sun.COM 		++cblocks_processed;
10647836SJohn.Forte@Sun.COM 	}
10657836SJohn.Forte@Sun.COM 
10667836SJohn.Forte@Sun.COM 
10677836SJohn.Forte@Sun.COM 	if (cblocks_processed)
10687836SJohn.Forte@Sun.COM 		cmn_err(CE_NOTE,
1069*9093SRamana.Srikanth@Sun.COM 		    "!sdbc(sdbc_recover_vol) %d cache blocks processed for "
1070*9093SRamana.Srikanth@Sun.COM 		    "volume %s", cblocks_processed, cd_gl->sv_volname);
10717836SJohn.Forte@Sun.COM 
10727836SJohn.Forte@Sun.COM 	return (cblocks_processed);
10737836SJohn.Forte@Sun.COM }
10747836SJohn.Forte@Sun.COM 
10757836SJohn.Forte@Sun.COM /*
10767836SJohn.Forte@Sun.COM  * _sd_failover_done -
10777836SJohn.Forte@Sun.COM  *	mark failover open'd devices as requiring nsc_release()
10787836SJohn.Forte@Sun.COM  *	when all queued I/O's have drained.
10797836SJohn.Forte@Sun.COM  */
10807836SJohn.Forte@Sun.COM static void
_sd_failover_done(void)10817836SJohn.Forte@Sun.COM _sd_failover_done(void)
10827836SJohn.Forte@Sun.COM {
10837836SJohn.Forte@Sun.COM 	_sd_cd_info_t *cdi;
10847836SJohn.Forte@Sun.COM 	int cd;
10857836SJohn.Forte@Sun.COM 
10867836SJohn.Forte@Sun.COM 	for (cd = 0; cd < sdbc_max_devs; cd++) {
10877836SJohn.Forte@Sun.COM 		cdi = &(_sd_cache_files[cd]);
10887836SJohn.Forte@Sun.COM 
10897836SJohn.Forte@Sun.COM 		if (FILE_OPENED(cd) && cdi->cd_failover)
10907836SJohn.Forte@Sun.COM 			cdi->cd_failover = 2;
10917836SJohn.Forte@Sun.COM 	}
10927836SJohn.Forte@Sun.COM }
10937836SJohn.Forte@Sun.COM 
10947836SJohn.Forte@Sun.COM #endif /* (_SD_FAULT_RES) */
10957836SJohn.Forte@Sun.COM 
10967836SJohn.Forte@Sun.COM /*
10977836SJohn.Forte@Sun.COM  * _sd_uncommit - discard local buffer modifications
10987836SJohn.Forte@Sun.COM  *	clear the valid bits.
10997836SJohn.Forte@Sun.COM  */
11007836SJohn.Forte@Sun.COM int
_sd_uncommit(_sd_buf_handle_t * handle,nsc_off_t fba_pos,nsc_size_t fba_len,int flag)11017836SJohn.Forte@Sun.COM _sd_uncommit(_sd_buf_handle_t *handle, nsc_off_t fba_pos, nsc_size_t fba_len,
11027836SJohn.Forte@Sun.COM     int flag)
11037836SJohn.Forte@Sun.COM {
11047836SJohn.Forte@Sun.COM 	int cd;
11057836SJohn.Forte@Sun.COM 	sdbc_cblk_fba_t st_cblk_len;	/* FBA len of starting cache block */
11067836SJohn.Forte@Sun.COM 	sdbc_cblk_fba_t end_cblk_len;	/* FBA len of ending cache block */
11077836SJohn.Forte@Sun.COM 	sdbc_cblk_fba_t st_cblk_off;	/* FBA offset into starting cblock */
11087836SJohn.Forte@Sun.COM 	nsc_size_t cc_len;
11097836SJohn.Forte@Sun.COM 	int bits;
11107836SJohn.Forte@Sun.COM 	_sd_cctl_t *cc_ent;
11117836SJohn.Forte@Sun.COM 
11127836SJohn.Forte@Sun.COM 	cd = HANDLE_CD(handle);
11137836SJohn.Forte@Sun.COM 
11147836SJohn.Forte@Sun.COM 	ASSERT_HANDLE_LIMITS(handle, fba_pos, fba_len);
11157836SJohn.Forte@Sun.COM 
11167836SJohn.Forte@Sun.COM 	if ((handle->bh_flag & NSC_WRBUF) == 0) {
11177836SJohn.Forte@Sun.COM 		DTRACE_PROBE(_sd_uncommit_end_handle_write);
11187836SJohn.Forte@Sun.COM 
11197836SJohn.Forte@Sun.COM 		return (EINVAL);
11207836SJohn.Forte@Sun.COM 	}
11217836SJohn.Forte@Sun.COM 
11227836SJohn.Forte@Sun.COM 	if (fba_len == 0) {
11237836SJohn.Forte@Sun.COM 		DTRACE_PROBE(_sd_uncommit_end_zero_len);
11247836SJohn.Forte@Sun.COM 		return (NSC_DONE);
11257836SJohn.Forte@Sun.COM 	}
11267836SJohn.Forte@Sun.COM 
11277836SJohn.Forte@Sun.COM 	SDTRACE(ST_ENTER|SDF_UNCOMMIT, cd, fba_len, fba_pos, flag, 0);
11287836SJohn.Forte@Sun.COM 
11297836SJohn.Forte@Sun.COM 	cc_ent = handle->bh_centry;
11307836SJohn.Forte@Sun.COM 	while (CENTRY_BLK(cc_ent) != FBA_TO_BLK_NUM(fba_pos))
11317836SJohn.Forte@Sun.COM 		cc_ent = cc_ent->cc_chain;
11327836SJohn.Forte@Sun.COM 
11337836SJohn.Forte@Sun.COM 	cc_len = fba_len;	/* current length */
11347836SJohn.Forte@Sun.COM 	st_cblk_off = BLK_FBA_OFF(fba_pos);
11357836SJohn.Forte@Sun.COM 	st_cblk_len = (BLK_FBAS - st_cblk_off);
11367836SJohn.Forte@Sun.COM 	if ((nsc_size_t)st_cblk_len >= fba_len) {
11377836SJohn.Forte@Sun.COM 		end_cblk_len = 0;
11387836SJohn.Forte@Sun.COM 		st_cblk_len = (sdbc_cblk_fba_t)fba_len;
11397836SJohn.Forte@Sun.COM 	}
11407836SJohn.Forte@Sun.COM 	else
11417836SJohn.Forte@Sun.COM 		end_cblk_len = BLK_FBA_OFF(fba_pos + fba_len);
11427836SJohn.Forte@Sun.COM 
11437836SJohn.Forte@Sun.COM 	/*
11447836SJohn.Forte@Sun.COM 	 * Check if remote write-cache spool is dirty,
11457836SJohn.Forte@Sun.COM 	 * if not, we can just discard local valid bits.
11467836SJohn.Forte@Sun.COM 	 */
11477836SJohn.Forte@Sun.COM 	bits = SDBC_GET_BITS(st_cblk_off, st_cblk_len);
11487836SJohn.Forte@Sun.COM 	cc_ent->cc_valid &= ~bits;
11497836SJohn.Forte@Sun.COM 
11507836SJohn.Forte@Sun.COM 	cc_len -= st_cblk_len;
11517836SJohn.Forte@Sun.COM 	cc_ent = cc_ent->cc_chain;
11527836SJohn.Forte@Sun.COM 	bits = SDBC_GET_BITS(0, BLK_FBAS);
11537836SJohn.Forte@Sun.COM 
11547836SJohn.Forte@Sun.COM 	while (cc_len > (nsc_size_t)end_cblk_len) {
11557836SJohn.Forte@Sun.COM 		cc_ent->cc_valid = 0;
11567836SJohn.Forte@Sun.COM 		cc_ent = cc_ent->cc_chain;
11577836SJohn.Forte@Sun.COM 		cc_len -= BLK_FBAS;
11587836SJohn.Forte@Sun.COM 	}
11597836SJohn.Forte@Sun.COM 
11607836SJohn.Forte@Sun.COM #if defined(_SD_DEBUG)
11617836SJohn.Forte@Sun.COM 	if (cc_len != end_cblk_len)
1162*9093SRamana.Srikanth@Sun.COM 		cmn_err(CE_WARN, "!fba_len %" NSC_SZFMT " end_cblk_len %d in "
11637836SJohn.Forte@Sun.COM 		    "_sd_write", fba_len, end_cblk_len);
11647836SJohn.Forte@Sun.COM #endif
11657836SJohn.Forte@Sun.COM 
11667836SJohn.Forte@Sun.COM 	if (cc_len) {
11677836SJohn.Forte@Sun.COM 		bits = SDBC_GET_BITS(0, end_cblk_len);
11687836SJohn.Forte@Sun.COM 		cc_ent->cc_valid &= ~bits;
11697836SJohn.Forte@Sun.COM 	}
11707836SJohn.Forte@Sun.COM 	SDTRACE(ST_EXIT|SDF_UNCOMMIT, cd, fba_len, fba_pos, flag, 0);
11717836SJohn.Forte@Sun.COM 
11727836SJohn.Forte@Sun.COM 	return (NSC_DONE);
11737836SJohn.Forte@Sun.COM }
11747836SJohn.Forte@Sun.COM 
11757836SJohn.Forte@Sun.COM static void
_sd_wait_for_dirty(void)11767836SJohn.Forte@Sun.COM _sd_wait_for_dirty(void)
11777836SJohn.Forte@Sun.COM {
11787836SJohn.Forte@Sun.COM 	int cd;
11797836SJohn.Forte@Sun.COM 
11807836SJohn.Forte@Sun.COM 	for (cd = 0; cd < sdbc_max_devs; cd++) {
11817836SJohn.Forte@Sun.COM 		while (_SD_CD_WBLK_USED(cd))
11827836SJohn.Forte@Sun.COM 			delay(HZ);
11837836SJohn.Forte@Sun.COM 	}
11847836SJohn.Forte@Sun.COM }
11857836SJohn.Forte@Sun.COM 
11867836SJohn.Forte@Sun.COM /*
11877836SJohn.Forte@Sun.COM  * _sd_wait_for_flush - wait for all i/o for this cd to cease.
11887836SJohn.Forte@Sun.COM  * This function assumes that no further i/o are being issued
11897836SJohn.Forte@Sun.COM  * against this device. This assumption is enforced by sd-ctl
11907836SJohn.Forte@Sun.COM  * when called from _sd_flush_cd. Recovery also uses this
11917836SJohn.Forte@Sun.COM  * wait and it enforces this assumption (somewhat imperfectly)
11927836SJohn.Forte@Sun.COM  * by using cd_recovering.
11937836SJohn.Forte@Sun.COM  * We must see progress in getting i/o complete within 25 seconds
11947836SJohn.Forte@Sun.COM  * or we will return an error. If we complete normally (all i/o done)
11957836SJohn.Forte@Sun.COM  * we return 0.
11967836SJohn.Forte@Sun.COM  */
11977836SJohn.Forte@Sun.COM int
_sd_wait_for_flush(int cd)11987836SJohn.Forte@Sun.COM _sd_wait_for_flush(int cd)
11997836SJohn.Forte@Sun.COM {
12007836SJohn.Forte@Sun.COM 	_sd_cd_info_t *cdi = &(_sd_cache_files[cd]);
12017836SJohn.Forte@Sun.COM 	int tries = 0, used, last_used = 0, inprogress = 0;
12027836SJohn.Forte@Sun.COM 
12037836SJohn.Forte@Sun.COM 	if (!(_SD_CD_WBLK_USED(cd)))
12047836SJohn.Forte@Sun.COM 		return (0);
12057836SJohn.Forte@Sun.COM 	/*
12067836SJohn.Forte@Sun.COM 	 * Wait for WBLK_USED to reach 0.
12077836SJohn.Forte@Sun.COM 	 * If unchanged for 32+ seconds returns EAGAIN
12087836SJohn.Forte@Sun.COM 	 */
12097836SJohn.Forte@Sun.COM 	if (!cdi->cd_writer)
12107836SJohn.Forte@Sun.COM 		(void) cd_writer(cd); /* spawn writer if not already running */
12117836SJohn.Forte@Sun.COM 
12127836SJohn.Forte@Sun.COM 	while (((used = _SD_CD_WBLK_USED(cd)) != 0) || cdi->cd_writer) {
12137836SJohn.Forte@Sun.COM 		if (last_used == used &&
12147836SJohn.Forte@Sun.COM 		    inprogress == cdi->cd_write_inprogress) {
12157836SJohn.Forte@Sun.COM 			if (cdi->cd_info->sh_failed)
12167836SJohn.Forte@Sun.COM 				break;
12177836SJohn.Forte@Sun.COM 			if (++tries > 128) {
1218*9093SRamana.Srikanth@Sun.COM 				cmn_err(CE_WARN, "!sdbc(_sd_wait_for_flush) "
12197836SJohn.Forte@Sun.COM 				    "%s still has %d blocks pending %d"
12207836SJohn.Forte@Sun.COM 				    " in progress (@ %lx)",
12217836SJohn.Forte@Sun.COM 				    cdi->cd_info->sh_filename, last_used,
12227836SJohn.Forte@Sun.COM 				    inprogress, nsc_lbolt());
12237836SJohn.Forte@Sun.COM 				return (EAGAIN);
12247836SJohn.Forte@Sun.COM 			}
12257836SJohn.Forte@Sun.COM 		} else {
12267836SJohn.Forte@Sun.COM 			last_used = used;
12277836SJohn.Forte@Sun.COM 			inprogress = cdi->cd_write_inprogress;
12287836SJohn.Forte@Sun.COM 			tries = 0;
12297836SJohn.Forte@Sun.COM 		}
12307836SJohn.Forte@Sun.COM 		_sd_unblock(&_sd_flush_cv);
12317836SJohn.Forte@Sun.COM 		delay(HZ/4);
12327836SJohn.Forte@Sun.COM 	}
12337836SJohn.Forte@Sun.COM 	if (cdi->cd_info->sh_failed)
12347836SJohn.Forte@Sun.COM 		return (EIO);
12357836SJohn.Forte@Sun.COM 	else
12367836SJohn.Forte@Sun.COM 		return (0);
12377836SJohn.Forte@Sun.COM }
12387836SJohn.Forte@Sun.COM 
12397836SJohn.Forte@Sun.COM 
12407836SJohn.Forte@Sun.COM static
12417836SJohn.Forte@Sun.COM int _sd_ft_warm_start;
12427836SJohn.Forte@Sun.COM 
12437836SJohn.Forte@Sun.COM int
_sdbc_warm_start(void)12447836SJohn.Forte@Sun.COM _sdbc_warm_start(void)
12457836SJohn.Forte@Sun.COM {
12467836SJohn.Forte@Sun.COM 	return (_sd_ft_warm_start);
12477836SJohn.Forte@Sun.COM }
12487836SJohn.Forte@Sun.COM 
12497836SJohn.Forte@Sun.COM void
_sdbc_clear_warm_start(void)12507836SJohn.Forte@Sun.COM _sdbc_clear_warm_start(void)
12517836SJohn.Forte@Sun.COM {
12527836SJohn.Forte@Sun.COM 	_sd_ft_warm_start = 0;
12537836SJohn.Forte@Sun.COM }
12547836SJohn.Forte@Sun.COM 
12557836SJohn.Forte@Sun.COM void
_sdbc_set_warm_start(void)12567836SJohn.Forte@Sun.COM _sdbc_set_warm_start(void)
12577836SJohn.Forte@Sun.COM {
12587836SJohn.Forte@Sun.COM 	_sd_ft_warm_start = 1;
12597836SJohn.Forte@Sun.COM }
12607836SJohn.Forte@Sun.COM 
12617836SJohn.Forte@Sun.COM /*ARGSUSED*/
12627836SJohn.Forte@Sun.COM void
_ncall_poke(int host)12637836SJohn.Forte@Sun.COM _ncall_poke(int host)
12647836SJohn.Forte@Sun.COM {
12657836SJohn.Forte@Sun.COM 	cmn_err(CE_PANIC, " NYI - _ncall_poke");
12667836SJohn.Forte@Sun.COM }
1267