xref: /onnv-gate/usr/src/uts/common/avs/ns/rdc/rdc_health.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 /*
277836SJohn.Forte@Sun.COM  * RDC interface health monitoring code.
287836SJohn.Forte@Sun.COM  */
297836SJohn.Forte@Sun.COM 
307836SJohn.Forte@Sun.COM #include <sys/types.h>
317836SJohn.Forte@Sun.COM #include <sys/ksynch.h>
327836SJohn.Forte@Sun.COM #include <sys/errno.h>
337836SJohn.Forte@Sun.COM #include <sys/debug.h>
347836SJohn.Forte@Sun.COM #include <sys/cmn_err.h>
357836SJohn.Forte@Sun.COM #include <sys/kmem.h>
367836SJohn.Forte@Sun.COM 
377836SJohn.Forte@Sun.COM #include <sys/errno.h>
387836SJohn.Forte@Sun.COM 
397836SJohn.Forte@Sun.COM #ifdef _SunOS_2_6
407836SJohn.Forte@Sun.COM /*
417836SJohn.Forte@Sun.COM  * on 2.6 both dki_lock.h and rpc/types.h define bool_t so we
427836SJohn.Forte@Sun.COM  * define enum_t here as it is all we need from rpc/types.h
437836SJohn.Forte@Sun.COM  * anyway and make it look like we included it. Yuck.
447836SJohn.Forte@Sun.COM  */
457836SJohn.Forte@Sun.COM #define	_RPC_TYPES_H
467836SJohn.Forte@Sun.COM typedef int enum_t;
477836SJohn.Forte@Sun.COM #else
487836SJohn.Forte@Sun.COM #ifndef DS_DDICT
497836SJohn.Forte@Sun.COM #include <rpc/types.h>
507836SJohn.Forte@Sun.COM #endif
517836SJohn.Forte@Sun.COM #endif /* _SunOS_2_6 */
527836SJohn.Forte@Sun.COM 
537836SJohn.Forte@Sun.COM #include <sys/ddi.h>
547836SJohn.Forte@Sun.COM #include <sys/nsc_thread.h>
557836SJohn.Forte@Sun.COM #ifdef DS_DDICT
567836SJohn.Forte@Sun.COM #include <sys/nsctl/contract.h>
577836SJohn.Forte@Sun.COM #endif
587836SJohn.Forte@Sun.COM #include <sys/nsctl/nsctl.h>
597836SJohn.Forte@Sun.COM 
607836SJohn.Forte@Sun.COM #include <sys/unistat/spcs_s.h>
617836SJohn.Forte@Sun.COM #include <sys/unistat/spcs_s_k.h>
627836SJohn.Forte@Sun.COM #include <sys/unistat/spcs_errors.h>
637836SJohn.Forte@Sun.COM 
647836SJohn.Forte@Sun.COM #include "rdc_io.h"
657836SJohn.Forte@Sun.COM #include "rdc_clnt.h"
667836SJohn.Forte@Sun.COM 
677836SJohn.Forte@Sun.COM 
687836SJohn.Forte@Sun.COM /*
697836SJohn.Forte@Sun.COM  * Forward declarations.
707836SJohn.Forte@Sun.COM  */
717836SJohn.Forte@Sun.COM 
727836SJohn.Forte@Sun.COM static void rdc_update_health(rdc_if_t *);
737836SJohn.Forte@Sun.COM 
747836SJohn.Forte@Sun.COM /*
757836SJohn.Forte@Sun.COM  * Global data.
767836SJohn.Forte@Sun.COM  */
777836SJohn.Forte@Sun.COM 
787836SJohn.Forte@Sun.COM /*
797836SJohn.Forte@Sun.COM  * These structures are added when a new host name is introduced to the
807836SJohn.Forte@Sun.COM  * kernel. They never disappear (but that won't waste much space at all).
817836SJohn.Forte@Sun.COM  */
827836SJohn.Forte@Sun.COM typedef struct rdc_link_down {
837836SJohn.Forte@Sun.COM 	char host[MAX_RDC_HOST_SIZE];	/* The host name of this link */
847836SJohn.Forte@Sun.COM 	int waiting;			/* A user is waiting to be woken up */
857836SJohn.Forte@Sun.COM 	int link_down;			/* The current state of the link */
867836SJohn.Forte@Sun.COM 	struct rdc_link_down *next;	/* Chain */
877836SJohn.Forte@Sun.COM 	kcondvar_t syncd_cv;		/* Syncd wakeup */
887836SJohn.Forte@Sun.COM 	kmutex_t syncd_mutex;		/* Lock for syncd_cv */
897836SJohn.Forte@Sun.COM } rdc_link_down_t;
907836SJohn.Forte@Sun.COM static rdc_link_down_t *rdc_link_down = NULL;
917836SJohn.Forte@Sun.COM 
927836SJohn.Forte@Sun.COM int rdc_health_thres = RDC_HEALTH_THRESHOLD;
937836SJohn.Forte@Sun.COM rdc_if_t *rdc_if_top;
947836SJohn.Forte@Sun.COM 
957836SJohn.Forte@Sun.COM 
967836SJohn.Forte@Sun.COM /*
977836SJohn.Forte@Sun.COM  * IPv6 addresses are represented as 16bit hexadecimal integers
987836SJohn.Forte@Sun.COM  * separated by colons. Contiguous runs of zeros can be abbreviated by
997836SJohn.Forte@Sun.COM  * double colons:
1007836SJohn.Forte@Sun.COM  *	FF02:0:0:0:0:1:200E:8C6C
1017836SJohn.Forte@Sun.COM  *		|
1027836SJohn.Forte@Sun.COM  *		v
1037836SJohn.Forte@Sun.COM  *	  FF02::1:200E:8C6C
1047836SJohn.Forte@Sun.COM  */
1057836SJohn.Forte@Sun.COM void
rdc_if_ipv6(const uint16_t * addr,char * buf)1067836SJohn.Forte@Sun.COM rdc_if_ipv6(const uint16_t *addr, char *buf)
1077836SJohn.Forte@Sun.COM {
1087836SJohn.Forte@Sun.COM 	const int end = 8;	/* 8 shorts, 128 bits in an IPv6 address */
1097836SJohn.Forte@Sun.COM 	int i;
1107836SJohn.Forte@Sun.COM 
1117836SJohn.Forte@Sun.COM 	for (i = 0; i < end; i++) {
1127836SJohn.Forte@Sun.COM 		if (i > 0)
1137836SJohn.Forte@Sun.COM 			(void) sprintf(buf, "%s:", buf);
1147836SJohn.Forte@Sun.COM 
1157836SJohn.Forte@Sun.COM 		if (addr[i] != 0 || i == 0 || i == (end - 1)) {
1167836SJohn.Forte@Sun.COM 			/* first, last, or non-zero value */
1177836SJohn.Forte@Sun.COM 			(void) sprintf(buf, "%s%x", buf, (int)addr[i]);
1187836SJohn.Forte@Sun.COM 		} else {
1197836SJohn.Forte@Sun.COM 			if ((i + 1) < end && addr[i + 1] != 0) {
1207836SJohn.Forte@Sun.COM 				/* single zero */
1217836SJohn.Forte@Sun.COM 				(void) sprintf(buf, "%s%x", buf, (int)addr[i]);
1227836SJohn.Forte@Sun.COM 			} else {
1237836SJohn.Forte@Sun.COM 				/* skip contiguous zeros */
1247836SJohn.Forte@Sun.COM 				while ((i + 1) < end && addr[i + 1] == 0)
1257836SJohn.Forte@Sun.COM 					i++;
1267836SJohn.Forte@Sun.COM 			}
1277836SJohn.Forte@Sun.COM 		}
1287836SJohn.Forte@Sun.COM 	}
1297836SJohn.Forte@Sun.COM }
1307836SJohn.Forte@Sun.COM 
1317836SJohn.Forte@Sun.COM static void
rdc_if_xxx(rdc_if_t * ip,char * updown)1327836SJohn.Forte@Sun.COM rdc_if_xxx(rdc_if_t *ip, char *updown)
1337836SJohn.Forte@Sun.COM {
1347836SJohn.Forte@Sun.COM 	if (strcmp("inet6", ip->srv->ri_knconf->knc_protofmly) == 0) {
1357836SJohn.Forte@Sun.COM 		uint16_t *this = (uint16_t *)ip->ifaddr.buf;
1367836SJohn.Forte@Sun.COM 		uint16_t *other = (uint16_t *)ip->r_ifaddr.buf;
1377836SJohn.Forte@Sun.COM 		char this_str[256], other_str[256];
1387836SJohn.Forte@Sun.COM 
1397836SJohn.Forte@Sun.COM 		bzero(this_str, sizeof (this_str));
1407836SJohn.Forte@Sun.COM 		bzero(other_str, sizeof (other_str));
1417836SJohn.Forte@Sun.COM 		rdc_if_ipv6(&this[4], this_str);
1427836SJohn.Forte@Sun.COM 		rdc_if_ipv6(&other[4], other_str);
1437836SJohn.Forte@Sun.COM 
144*9093SRamana.Srikanth@Sun.COM 		cmn_err(CE_NOTE, "!SNDR: Interface %s <==> %s : %s",
1457836SJohn.Forte@Sun.COM 		    this_str, other_str, updown);
1467836SJohn.Forte@Sun.COM 	} else {
1477836SJohn.Forte@Sun.COM 		uchar_t *this = (uchar_t *)ip->ifaddr.buf;
1487836SJohn.Forte@Sun.COM 		uchar_t *other = (uchar_t *)ip->r_ifaddr.buf;
1497836SJohn.Forte@Sun.COM 
1507836SJohn.Forte@Sun.COM 		cmn_err(CE_NOTE,
151*9093SRamana.Srikanth@Sun.COM 		    "!SNDR: Interface %d.%d.%d.%d <==> %d.%d.%d.%d : %s",
1527836SJohn.Forte@Sun.COM 		    (int)this[4], (int)this[5], (int)this[6], (int)this[7],
1537836SJohn.Forte@Sun.COM 		    (int)other[4], (int)other[5], (int)other[6], (int)other[7],
1547836SJohn.Forte@Sun.COM 		    updown);
1557836SJohn.Forte@Sun.COM 	}
1567836SJohn.Forte@Sun.COM }
1577836SJohn.Forte@Sun.COM 
1587836SJohn.Forte@Sun.COM 
1597836SJohn.Forte@Sun.COM static void
rdc_if_down(rdc_if_t * ip)1607836SJohn.Forte@Sun.COM rdc_if_down(rdc_if_t *ip)
1617836SJohn.Forte@Sun.COM {
1627836SJohn.Forte@Sun.COM 	rdc_if_xxx(ip, "Down");
1637836SJohn.Forte@Sun.COM }
1647836SJohn.Forte@Sun.COM 
1657836SJohn.Forte@Sun.COM 
1667836SJohn.Forte@Sun.COM static void
rdc_if_up(rdc_if_t * ip)1677836SJohn.Forte@Sun.COM rdc_if_up(rdc_if_t *ip)
1687836SJohn.Forte@Sun.COM {
1697836SJohn.Forte@Sun.COM 	rdc_if_xxx(ip, "Up");
1707836SJohn.Forte@Sun.COM }
1717836SJohn.Forte@Sun.COM 
1727836SJohn.Forte@Sun.COM 
1737836SJohn.Forte@Sun.COM /*
1747836SJohn.Forte@Sun.COM  * Health monitor for a single interface.
1757836SJohn.Forte@Sun.COM  *
1767836SJohn.Forte@Sun.COM  * The secondary sends ping RPCs to the primary.
1777836SJohn.Forte@Sun.COM  * The primary just stores the results and updates its structures.
1787836SJohn.Forte@Sun.COM  */
1797836SJohn.Forte@Sun.COM static void
rdc_health_thread(void * arg)1807836SJohn.Forte@Sun.COM rdc_health_thread(void *arg)
1817836SJohn.Forte@Sun.COM {
1827836SJohn.Forte@Sun.COM 	rdc_if_t *ip = (rdc_if_t *)arg;
1837836SJohn.Forte@Sun.COM 	struct rdc_ping ping;
1847836SJohn.Forte@Sun.COM 	struct rdc_ping6 ping6;
1857836SJohn.Forte@Sun.COM 	struct timeval t;
1867836SJohn.Forte@Sun.COM 	int down = 1;
1877836SJohn.Forte@Sun.COM 	int ret, err;
1887836SJohn.Forte@Sun.COM 	int sec = 0;
1897836SJohn.Forte@Sun.COM 	char ifaddr[RDC_MAXADDR];
1907836SJohn.Forte@Sun.COM 	char r_ifaddr[RDC_MAXADDR];
1917836SJohn.Forte@Sun.COM 	uint16_t *sp;
1927836SJohn.Forte@Sun.COM 
1937836SJohn.Forte@Sun.COM 	bcopy(ip->ifaddr.buf, ifaddr, ip->ifaddr.len);
1947836SJohn.Forte@Sun.COM 	sp = (uint16_t *)ifaddr;
1957836SJohn.Forte@Sun.COM 	*sp = htons(*sp);
1967836SJohn.Forte@Sun.COM 	bcopy(ip->r_ifaddr.buf, r_ifaddr, ip->r_ifaddr.len);
1977836SJohn.Forte@Sun.COM 	sp = (uint16_t *)r_ifaddr;
1987836SJohn.Forte@Sun.COM 	*sp = htons(*sp);
1997836SJohn.Forte@Sun.COM 
2007836SJohn.Forte@Sun.COM 	while ((ip->exiting != 1) && (net_exit != ATM_EXIT)) {
2017836SJohn.Forte@Sun.COM 		delay(HZ);
2027836SJohn.Forte@Sun.COM 
2037836SJohn.Forte@Sun.COM 		/* setup RPC timeout */
2047836SJohn.Forte@Sun.COM 
2057836SJohn.Forte@Sun.COM 		t.tv_sec = rdc_rpc_tmout;
2067836SJohn.Forte@Sun.COM 		t.tv_usec = 0;
2077836SJohn.Forte@Sun.COM 
2087836SJohn.Forte@Sun.COM 		if (ip->issecondary && !ip->no_ping) {
2097836SJohn.Forte@Sun.COM 			if (ip->rpc_version < RDC_VERSION7) {
2107836SJohn.Forte@Sun.COM 				bcopy(ip->r_ifaddr.buf, ping6.p_ifaddr,
2117836SJohn.Forte@Sun.COM 				    RDC_MAXADDR);
2127836SJohn.Forte@Sun.COM 			/* primary ifaddr */
2137836SJohn.Forte@Sun.COM 				bcopy(ip->ifaddr.buf, ping6.s_ifaddr,
2147836SJohn.Forte@Sun.COM 				    RDC_MAXADDR);
2157836SJohn.Forte@Sun.COM 			/* secondary ifaddr */
2167836SJohn.Forte@Sun.COM 				err = rdc_clnt_call_any(ip->srv, ip,
217*9093SRamana.Srikanth@Sun.COM 				    RDCPROC_PING4, xdr_rdc_ping6,
218*9093SRamana.Srikanth@Sun.COM 				    (char *)&ping6, xdr_int, (char *)&ret, &t);
2197836SJohn.Forte@Sun.COM 			} else {
2207836SJohn.Forte@Sun.COM 				ping.p_ifaddr.buf = r_ifaddr;
2217836SJohn.Forte@Sun.COM 				ping.p_ifaddr.len = ip->r_ifaddr.len;
2227836SJohn.Forte@Sun.COM 				ping.p_ifaddr.maxlen = ip->r_ifaddr.len;
2237836SJohn.Forte@Sun.COM 				ping.s_ifaddr.buf = ifaddr;
2247836SJohn.Forte@Sun.COM 				ping.s_ifaddr.len = ip->ifaddr.len;
2257836SJohn.Forte@Sun.COM 				ping.s_ifaddr.maxlen = ip->ifaddr.len;
2267836SJohn.Forte@Sun.COM 				err = rdc_clnt_call_any(ip->srv, ip,
227*9093SRamana.Srikanth@Sun.COM 				    RDCPROC_PING4, xdr_rdc_ping, (char *)&ping,
228*9093SRamana.Srikanth@Sun.COM 				    xdr_int, (char *)&ret, &t);
2297836SJohn.Forte@Sun.COM 			}
2307836SJohn.Forte@Sun.COM 
2317836SJohn.Forte@Sun.COM 
2327836SJohn.Forte@Sun.COM 			if (err || ret) {
2337836SJohn.Forte@Sun.COM 				/* RPC failed - link is down */
2347836SJohn.Forte@Sun.COM 				if (!down && !ip->isprimary) {
2357836SJohn.Forte@Sun.COM 					/*
2367836SJohn.Forte@Sun.COM 					 * don't print messages if also
2377836SJohn.Forte@Sun.COM 					 * a primary - the primary will
2387836SJohn.Forte@Sun.COM 					 * take care of it.
2397836SJohn.Forte@Sun.COM 					 */
2407836SJohn.Forte@Sun.COM 					rdc_if_down(ip);
2417836SJohn.Forte@Sun.COM 					down = 1;
2427836SJohn.Forte@Sun.COM 				}
2437836SJohn.Forte@Sun.COM 				rdc_dump_alloc_bufs(ip);
2447836SJohn.Forte@Sun.COM 				ip->no_ping = 1;
2457836SJohn.Forte@Sun.COM 
2467836SJohn.Forte@Sun.COM 				/*
2477836SJohn.Forte@Sun.COM 				 * Start back at the max possible version
2487836SJohn.Forte@Sun.COM 				 * since the remote server could come back
2497836SJohn.Forte@Sun.COM 				 * on a different protocol version.
2507836SJohn.Forte@Sun.COM 				 */
2517836SJohn.Forte@Sun.COM 				mutex_enter(&rdc_ping_lock);
2527836SJohn.Forte@Sun.COM 				ip->rpc_version = RDC_VERS_MAX;
2537836SJohn.Forte@Sun.COM 				mutex_exit(&rdc_ping_lock);
2547836SJohn.Forte@Sun.COM 			} else {
2557836SJohn.Forte@Sun.COM 				if (down && !ip->isprimary) {
2567836SJohn.Forte@Sun.COM 					/*
2577836SJohn.Forte@Sun.COM 					 * was failed, but now ok
2587836SJohn.Forte@Sun.COM 					 *
2597836SJohn.Forte@Sun.COM 					 * don't print messages if also
2607836SJohn.Forte@Sun.COM 					 * a primary - the primary will
2617836SJohn.Forte@Sun.COM 					 * take care of it.
2627836SJohn.Forte@Sun.COM 					 */
2637836SJohn.Forte@Sun.COM 					rdc_if_up(ip);
2647836SJohn.Forte@Sun.COM 					down = 0;
2657836SJohn.Forte@Sun.COM 				}
2667836SJohn.Forte@Sun.COM 			}
2677836SJohn.Forte@Sun.COM 		}
2687836SJohn.Forte@Sun.COM 		if (!ip->isprimary && down && ++sec == 5) {
2697836SJohn.Forte@Sun.COM 				sec = 0;
2707836SJohn.Forte@Sun.COM 				rdc_dump_alloc_bufs(ip);
2717836SJohn.Forte@Sun.COM 		}
2727836SJohn.Forte@Sun.COM 
2737836SJohn.Forte@Sun.COM 		if (ip->isprimary)
2747836SJohn.Forte@Sun.COM 			rdc_update_health(ip);
2757836SJohn.Forte@Sun.COM 	}
2767836SJohn.Forte@Sun.COM 
2777836SJohn.Forte@Sun.COM 	/* signal that this thread is done */
2787836SJohn.Forte@Sun.COM 	ip->exiting = 2;
2797836SJohn.Forte@Sun.COM }
2807836SJohn.Forte@Sun.COM 
2817836SJohn.Forte@Sun.COM 
2827836SJohn.Forte@Sun.COM int
rdc_isactive_if(struct netbuf * addr,struct netbuf * r_addr)2837836SJohn.Forte@Sun.COM rdc_isactive_if(struct netbuf *addr, struct netbuf *r_addr)
2847836SJohn.Forte@Sun.COM {
2857836SJohn.Forte@Sun.COM 	rdc_if_t *ip;
2867836SJohn.Forte@Sun.COM 	int rc = 0;
2877836SJohn.Forte@Sun.COM 
2887836SJohn.Forte@Sun.COM 	/* search for existing interface structure */
2897836SJohn.Forte@Sun.COM 
2907836SJohn.Forte@Sun.COM 	mutex_enter(&rdc_ping_lock);
2917836SJohn.Forte@Sun.COM 	for (ip = rdc_if_top; ip; ip = ip->next) {
2927836SJohn.Forte@Sun.COM 		if (ip->exiting != 0)
2937836SJohn.Forte@Sun.COM 			continue;
2947836SJohn.Forte@Sun.COM 		if (((bcmp(ip->ifaddr.buf, addr->buf, addr->len) == 0) &&
2957836SJohn.Forte@Sun.COM 		    (bcmp(ip->r_ifaddr.buf, r_addr->buf, r_addr->len) == 0)) ||
2967836SJohn.Forte@Sun.COM 		    ((bcmp(ip->r_ifaddr.buf, addr->buf, addr->len) == 0) &&
2977836SJohn.Forte@Sun.COM 		    (bcmp(ip->ifaddr.buf, r_addr->buf, r_addr->len) == 0))) {
2987836SJohn.Forte@Sun.COM 			/* found matching interface structure */
2997836SJohn.Forte@Sun.COM 			if (ip->isprimary && !ip->if_down) {
3007836SJohn.Forte@Sun.COM 				rc = 1;
3017836SJohn.Forte@Sun.COM 			} else if (ip->issecondary && !ip->no_ping) {
3027836SJohn.Forte@Sun.COM 				rc = 1;
3037836SJohn.Forte@Sun.COM 			}
3047836SJohn.Forte@Sun.COM 			break;
3057836SJohn.Forte@Sun.COM 		}
3067836SJohn.Forte@Sun.COM 	}
3077836SJohn.Forte@Sun.COM 	mutex_exit(&rdc_ping_lock);
3087836SJohn.Forte@Sun.COM 	return (rc);
3097836SJohn.Forte@Sun.COM }
3107836SJohn.Forte@Sun.COM 
3117836SJohn.Forte@Sun.COM /*
3127836SJohn.Forte@Sun.COM  * Set the rdc rpc version of the rdc_if_t.
3137836SJohn.Forte@Sun.COM  *
3147836SJohn.Forte@Sun.COM  * Called from incoming rpc calls which start before
3157836SJohn.Forte@Sun.COM  * the health service becomes established.
3167836SJohn.Forte@Sun.COM  */
3177836SJohn.Forte@Sun.COM void
rdc_set_if_vers(rdc_u_info_t * urdc,rpcvers_t vers)3187836SJohn.Forte@Sun.COM rdc_set_if_vers(rdc_u_info_t *urdc, rpcvers_t vers)
3197836SJohn.Forte@Sun.COM {
3207836SJohn.Forte@Sun.COM 	rdc_if_t *ip;
3217836SJohn.Forte@Sun.COM 	struct netbuf *addr, *r_addr;
3227836SJohn.Forte@Sun.COM 
3237836SJohn.Forte@Sun.COM 	if (rdc_get_vflags(urdc) & RDC_PRIMARY) {
3247836SJohn.Forte@Sun.COM 		addr = &(urdc->primary.addr);
3257836SJohn.Forte@Sun.COM 		r_addr = &(urdc->secondary.addr);
3267836SJohn.Forte@Sun.COM 	} else {
3277836SJohn.Forte@Sun.COM 		addr = &(urdc->secondary.addr);
3287836SJohn.Forte@Sun.COM 		r_addr = &(urdc->primary.addr);
3297836SJohn.Forte@Sun.COM 	}
3307836SJohn.Forte@Sun.COM 
3317836SJohn.Forte@Sun.COM 	/* search for existing interface structure */
3327836SJohn.Forte@Sun.COM 
3337836SJohn.Forte@Sun.COM 	mutex_enter(&rdc_ping_lock);
3347836SJohn.Forte@Sun.COM 	for (ip = rdc_if_top; ip; ip = ip->next) {
3357836SJohn.Forte@Sun.COM 		if (ip->exiting != 0)
3367836SJohn.Forte@Sun.COM 			continue;
3377836SJohn.Forte@Sun.COM 		if (((bcmp(ip->ifaddr.buf, addr->buf, addr->len) == 0) &&
3387836SJohn.Forte@Sun.COM 		    (bcmp(ip->r_ifaddr.buf, r_addr->buf, r_addr->len) == 0)) ||
3397836SJohn.Forte@Sun.COM 		    ((bcmp(ip->r_ifaddr.buf, addr->buf, addr->len) == 0) &&
3407836SJohn.Forte@Sun.COM 		    (bcmp(ip->ifaddr.buf, r_addr->buf, r_addr->len) == 0))) {
3417836SJohn.Forte@Sun.COM 			/* found matching interface structure */
3427836SJohn.Forte@Sun.COM 			ip->rpc_version = vers;
3437836SJohn.Forte@Sun.COM #ifdef DEBUG
344*9093SRamana.Srikanth@Sun.COM 			cmn_err(CE_NOTE, "!rdc intf %p rpc version set to %u",
345*9093SRamana.Srikanth@Sun.COM 			    (void *)ip, vers);
3467836SJohn.Forte@Sun.COM #endif
3477836SJohn.Forte@Sun.COM 			break;
3487836SJohn.Forte@Sun.COM 		}
3497836SJohn.Forte@Sun.COM 	}
3507836SJohn.Forte@Sun.COM 	mutex_exit(&rdc_ping_lock);
3517836SJohn.Forte@Sun.COM }
3527836SJohn.Forte@Sun.COM 
3537836SJohn.Forte@Sun.COM /*
3547836SJohn.Forte@Sun.COM  * Free all the rdc_link_down structures (only at module unload time)
3557836SJohn.Forte@Sun.COM  */
3567836SJohn.Forte@Sun.COM void
rdc_link_down_free()3577836SJohn.Forte@Sun.COM rdc_link_down_free()
3587836SJohn.Forte@Sun.COM {
3597836SJohn.Forte@Sun.COM 	rdc_link_down_t *p;
3607836SJohn.Forte@Sun.COM 	rdc_link_down_t *q;
3617836SJohn.Forte@Sun.COM 
3627836SJohn.Forte@Sun.COM 	if (rdc_link_down == NULL)
3637836SJohn.Forte@Sun.COM 		return;
3647836SJohn.Forte@Sun.COM 
3657836SJohn.Forte@Sun.COM 	for (p = rdc_link_down->next; p != rdc_link_down; ) {
3667836SJohn.Forte@Sun.COM 		q = p;
3677836SJohn.Forte@Sun.COM 		p = p->next;
3687836SJohn.Forte@Sun.COM 		kmem_free(q, sizeof (*q));
3697836SJohn.Forte@Sun.COM 	}
3707836SJohn.Forte@Sun.COM 	kmem_free(rdc_link_down, sizeof (*q));
3717836SJohn.Forte@Sun.COM 	rdc_link_down = NULL;
3727836SJohn.Forte@Sun.COM }
3737836SJohn.Forte@Sun.COM 
3747836SJohn.Forte@Sun.COM 
3757836SJohn.Forte@Sun.COM /*
3767836SJohn.Forte@Sun.COM  * Look up the supplied hostname in the rdc_link_down chain. Add a new
3777836SJohn.Forte@Sun.COM  * entry if it isn't found. Return a pointer to the new or found entry.
3787836SJohn.Forte@Sun.COM  */
3797836SJohn.Forte@Sun.COM static rdc_link_down_t *
rdc_lookup_host(char * host)3807836SJohn.Forte@Sun.COM rdc_lookup_host(char *host)
3817836SJohn.Forte@Sun.COM {
3827836SJohn.Forte@Sun.COM 	rdc_link_down_t *p;
3837836SJohn.Forte@Sun.COM 
3847836SJohn.Forte@Sun.COM 	mutex_enter(&rdc_ping_lock);
3857836SJohn.Forte@Sun.COM 
3867836SJohn.Forte@Sun.COM 	if (rdc_link_down == NULL) {
3877836SJohn.Forte@Sun.COM 		rdc_link_down = kmem_zalloc(sizeof (*rdc_link_down), KM_SLEEP);
3887836SJohn.Forte@Sun.COM 		rdc_link_down->next = rdc_link_down;
3897836SJohn.Forte@Sun.COM 	}
3907836SJohn.Forte@Sun.COM 
3917836SJohn.Forte@Sun.COM 	for (p = rdc_link_down->next; p != rdc_link_down; p = p->next) {
3927836SJohn.Forte@Sun.COM 		if (strcmp(host, p->host) == 0) {
3937836SJohn.Forte@Sun.COM 			/* Match */
3947836SJohn.Forte@Sun.COM 			mutex_exit(&rdc_ping_lock);
3957836SJohn.Forte@Sun.COM 			return (p);
3967836SJohn.Forte@Sun.COM 		}
3977836SJohn.Forte@Sun.COM 	}
3987836SJohn.Forte@Sun.COM 
3997836SJohn.Forte@Sun.COM 	/* No match, must create a new entry */
4007836SJohn.Forte@Sun.COM 
4017836SJohn.Forte@Sun.COM 	p = kmem_zalloc(sizeof (*p), KM_SLEEP);
4027836SJohn.Forte@Sun.COM 	p->link_down = 1;
4037836SJohn.Forte@Sun.COM 	p->next = rdc_link_down->next;
4047836SJohn.Forte@Sun.COM 	rdc_link_down->next = p;
4057836SJohn.Forte@Sun.COM 	(void) strncpy(p->host, host, MAX_RDC_HOST_SIZE);
4067836SJohn.Forte@Sun.COM 	mutex_init(&p->syncd_mutex, NULL, MUTEX_DRIVER, NULL);
4077836SJohn.Forte@Sun.COM 	cv_init(&p->syncd_cv, NULL, CV_DRIVER, NULL);
4087836SJohn.Forte@Sun.COM 
4097836SJohn.Forte@Sun.COM 	mutex_exit(&rdc_ping_lock);
4107836SJohn.Forte@Sun.COM 	return (p);
4117836SJohn.Forte@Sun.COM }
4127836SJohn.Forte@Sun.COM 
4137836SJohn.Forte@Sun.COM 
4147836SJohn.Forte@Sun.COM /*
4157836SJohn.Forte@Sun.COM  * Handle the RDC_LINK_DOWN ioctl.
4167836SJohn.Forte@Sun.COM  * The user specifies which host he is interested in.
4177836SJohn.Forte@Sun.COM  * This function is woken up when the link to that host goes down.
4187836SJohn.Forte@Sun.COM  */
4197836SJohn.Forte@Sun.COM 
4207836SJohn.Forte@Sun.COM /* ARGSUSED3 */
4217836SJohn.Forte@Sun.COM int
_rdc_link_down(void * arg,int mode,spcs_s_info_t kstatus,int * rvp)4227836SJohn.Forte@Sun.COM _rdc_link_down(void *arg, int mode, spcs_s_info_t kstatus, int *rvp)
4237836SJohn.Forte@Sun.COM {
4247836SJohn.Forte@Sun.COM 	char host[MAX_RDC_HOST_SIZE];
4257836SJohn.Forte@Sun.COM 	rdc_link_down_t *syncdp;
4267836SJohn.Forte@Sun.COM 	clock_t timeout = RDC_SYNC_EVENT_TIMEOUT * 2; /* 2 min */
4277836SJohn.Forte@Sun.COM 	int rc = 0;
4287836SJohn.Forte@Sun.COM 
4297836SJohn.Forte@Sun.COM 	if (ddi_copyin(arg, host, MAX_RDC_HOST_SIZE, mode))
4307836SJohn.Forte@Sun.COM 		return (EFAULT);
4317836SJohn.Forte@Sun.COM 
4327836SJohn.Forte@Sun.COM 
4337836SJohn.Forte@Sun.COM 	syncdp = rdc_lookup_host(host);
4347836SJohn.Forte@Sun.COM 
4357836SJohn.Forte@Sun.COM 	mutex_enter(&syncdp->syncd_mutex);
4367836SJohn.Forte@Sun.COM 	if (!syncdp->link_down) {
4377836SJohn.Forte@Sun.COM 		syncdp->waiting = 1;
4387836SJohn.Forte@Sun.COM 		if (cv_timedwait_sig(&syncdp->syncd_cv, &syncdp->syncd_mutex,
4397836SJohn.Forte@Sun.COM 		    nsc_lbolt() + timeout) == 0) {
4407836SJohn.Forte@Sun.COM 			/* Woken by a signal, not a link down event */
4417836SJohn.Forte@Sun.COM 			syncdp->waiting = 0;
4427836SJohn.Forte@Sun.COM 			rc = EAGAIN;
4437836SJohn.Forte@Sun.COM 			spcs_s_add(kstatus, rc);
4447836SJohn.Forte@Sun.COM 		}
4457836SJohn.Forte@Sun.COM 
4467836SJohn.Forte@Sun.COM 	}
4477836SJohn.Forte@Sun.COM 	mutex_exit(&syncdp->syncd_mutex);
4487836SJohn.Forte@Sun.COM 
4497836SJohn.Forte@Sun.COM 	return (rc);
4507836SJohn.Forte@Sun.COM }
4517836SJohn.Forte@Sun.COM 
4527836SJohn.Forte@Sun.COM 
4537836SJohn.Forte@Sun.COM /*
4547836SJohn.Forte@Sun.COM  * Add an RDC set to an interface
4557836SJohn.Forte@Sun.COM  *
4567836SJohn.Forte@Sun.COM  * If the interface is new, add it to the list of interfaces.
4577836SJohn.Forte@Sun.COM  */
4587836SJohn.Forte@Sun.COM rdc_if_t *
rdc_add_to_if(rdc_srv_t * svp,struct netbuf * addr,struct netbuf * r_addr,int primary)4597836SJohn.Forte@Sun.COM rdc_add_to_if(rdc_srv_t *svp, struct netbuf *addr, struct netbuf *r_addr,
4607836SJohn.Forte@Sun.COM     int primary)
4617836SJohn.Forte@Sun.COM {
4627836SJohn.Forte@Sun.COM 	rdc_if_t *new, *ip;
4637836SJohn.Forte@Sun.COM 
4647836SJohn.Forte@Sun.COM 	if ((addr->buf == NULL) || (r_addr->buf == NULL))
4657836SJohn.Forte@Sun.COM 		return (NULL);
4667836SJohn.Forte@Sun.COM 
4677836SJohn.Forte@Sun.COM 	/* setup a new interface structure */
4687836SJohn.Forte@Sun.COM 	new = (rdc_if_t *)kmem_zalloc(sizeof (*new), KM_SLEEP);
4697836SJohn.Forte@Sun.COM 	if (!new)
4707836SJohn.Forte@Sun.COM 		return (NULL);
4717836SJohn.Forte@Sun.COM 
4727836SJohn.Forte@Sun.COM 	dup_rdc_netbuf(addr, &new->ifaddr);
4737836SJohn.Forte@Sun.COM 	dup_rdc_netbuf(r_addr, &new->r_ifaddr);
4747836SJohn.Forte@Sun.COM 	new->rpc_version = RDC_VERS_MAX;
4757836SJohn.Forte@Sun.COM 	new->srv = rdc_create_svinfo(svp->ri_hostname, &svp->ri_addr,
4767836SJohn.Forte@Sun.COM 	    svp->ri_knconf);
4777836SJohn.Forte@Sun.COM 	new->old_pulse = -1;
4787836SJohn.Forte@Sun.COM 	new->new_pulse = 0;
4797836SJohn.Forte@Sun.COM 
4807836SJohn.Forte@Sun.COM 	if (!new->srv) {
4817836SJohn.Forte@Sun.COM 		free_rdc_netbuf(&new->r_ifaddr);
4827836SJohn.Forte@Sun.COM 		free_rdc_netbuf(&new->ifaddr);
4837836SJohn.Forte@Sun.COM 		kmem_free(new, sizeof (*new));
4847836SJohn.Forte@Sun.COM 		return (NULL);
4857836SJohn.Forte@Sun.COM 	}
4867836SJohn.Forte@Sun.COM 
4877836SJohn.Forte@Sun.COM 	/* search for existing interface structure */
4887836SJohn.Forte@Sun.COM 
4897836SJohn.Forte@Sun.COM 	mutex_enter(&rdc_ping_lock);
4907836SJohn.Forte@Sun.COM 
4917836SJohn.Forte@Sun.COM 	for (ip = rdc_if_top; ip; ip = ip->next) {
4927836SJohn.Forte@Sun.COM 		if ((bcmp(ip->ifaddr.buf, addr->buf, addr->len) == 0) &&
4937836SJohn.Forte@Sun.COM 		    (bcmp(ip->r_ifaddr.buf, r_addr->buf, r_addr->len) == 0) &&
4947836SJohn.Forte@Sun.COM 		    ip->exiting == 0) {
4957836SJohn.Forte@Sun.COM 			/* found matching interface structure */
4967836SJohn.Forte@Sun.COM 			break;
4977836SJohn.Forte@Sun.COM 		}
4987836SJohn.Forte@Sun.COM 	}
4997836SJohn.Forte@Sun.COM 
5007836SJohn.Forte@Sun.COM 	if (!ip) {
5017836SJohn.Forte@Sun.COM 		/* add new into the chain */
5027836SJohn.Forte@Sun.COM 
5037836SJohn.Forte@Sun.COM 		new->next = rdc_if_top;
5047836SJohn.Forte@Sun.COM 		rdc_if_top = new;
5057836SJohn.Forte@Sun.COM 		ip = new;
5067836SJohn.Forte@Sun.COM 
5077836SJohn.Forte@Sun.COM 		/* start daemon */
5087836SJohn.Forte@Sun.COM 
5097836SJohn.Forte@Sun.COM 		ip->last = nsc_time();
5107836SJohn.Forte@Sun.COM 		ip->deadness = 1;
5117836SJohn.Forte@Sun.COM 		ip->if_down = 1;
5127836SJohn.Forte@Sun.COM 
5137836SJohn.Forte@Sun.COM 		if (nsc_create_process(rdc_health_thread, ip, TRUE)) {
5147836SJohn.Forte@Sun.COM 			mutex_exit(&rdc_ping_lock);
5157836SJohn.Forte@Sun.COM 			return (NULL);
5167836SJohn.Forte@Sun.COM 		}
5177836SJohn.Forte@Sun.COM 	}
5187836SJohn.Forte@Sun.COM 
5197836SJohn.Forte@Sun.COM 	/* mark usage type */
5207836SJohn.Forte@Sun.COM 
5217836SJohn.Forte@Sun.COM 	if (primary) {
5227836SJohn.Forte@Sun.COM 		ip->isprimary = 1;
5237836SJohn.Forte@Sun.COM 	} else {
5247836SJohn.Forte@Sun.COM 		ip->issecondary = 1;
5257836SJohn.Forte@Sun.COM 		ip->no_ping = 0;
5267836SJohn.Forte@Sun.COM 	}
5277836SJohn.Forte@Sun.COM 
5287836SJohn.Forte@Sun.COM 	mutex_exit(&rdc_ping_lock);
5297836SJohn.Forte@Sun.COM 
5307836SJohn.Forte@Sun.COM 	/* throw away new if it was not used */
5317836SJohn.Forte@Sun.COM 
5327836SJohn.Forte@Sun.COM 	if (ip != new) {
5337836SJohn.Forte@Sun.COM 		free_rdc_netbuf(&new->r_ifaddr);
5347836SJohn.Forte@Sun.COM 		free_rdc_netbuf(&new->ifaddr);
5357836SJohn.Forte@Sun.COM 		rdc_destroy_svinfo(new->srv);
5367836SJohn.Forte@Sun.COM 		kmem_free(new, sizeof (*new));
5377836SJohn.Forte@Sun.COM 	}
5387836SJohn.Forte@Sun.COM 
5397836SJohn.Forte@Sun.COM 	return (ip);
5407836SJohn.Forte@Sun.COM }
5417836SJohn.Forte@Sun.COM 
5427836SJohn.Forte@Sun.COM 
5437836SJohn.Forte@Sun.COM /*
5447836SJohn.Forte@Sun.COM  * Update an interface following the removal of an RDC set.
5457836SJohn.Forte@Sun.COM  *
5467836SJohn.Forte@Sun.COM  * If there are no more RDC sets using the interface, delete it from
5477836SJohn.Forte@Sun.COM  * the list of interfaces.
5487836SJohn.Forte@Sun.COM  *
5497836SJohn.Forte@Sun.COM  * Either clear krdc->intf, or ensure !IS_CONFIGURED(krdc) before calling this.
5507836SJohn.Forte@Sun.COM  */
5517836SJohn.Forte@Sun.COM void
rdc_remove_from_if(rdc_if_t * ip)5527836SJohn.Forte@Sun.COM rdc_remove_from_if(rdc_if_t *ip)
5537836SJohn.Forte@Sun.COM {
5547836SJohn.Forte@Sun.COM 	rdc_k_info_t *krdc;
5557836SJohn.Forte@Sun.COM 	rdc_u_info_t *urdc;
5567836SJohn.Forte@Sun.COM 	rdc_if_t **ipp;
5577836SJohn.Forte@Sun.COM 	int pfound = 0;
5587836SJohn.Forte@Sun.COM 	int sfound = 0;
5597836SJohn.Forte@Sun.COM 	int delete = 1;
5607836SJohn.Forte@Sun.COM 	int index;
5617836SJohn.Forte@Sun.COM 
5627836SJohn.Forte@Sun.COM 	mutex_enter(&rdc_ping_lock);
5637836SJohn.Forte@Sun.COM 
5647836SJohn.Forte@Sun.COM 	/*
5657836SJohn.Forte@Sun.COM 	 * search for RDC sets using this interface and update
5667836SJohn.Forte@Sun.COM 	 * the isprimary and issecondary flags.
5677836SJohn.Forte@Sun.COM 	 */
5687836SJohn.Forte@Sun.COM 
5697836SJohn.Forte@Sun.COM 	for (index = 0; index < rdc_max_sets; index++) {
5707836SJohn.Forte@Sun.COM 		krdc = &rdc_k_info[index];
5717836SJohn.Forte@Sun.COM 		urdc = &rdc_u_info[index];
5727836SJohn.Forte@Sun.COM 		if (IS_CONFIGURED(krdc) && krdc->intf == ip) {
5737836SJohn.Forte@Sun.COM 			delete = 0;
5747836SJohn.Forte@Sun.COM 
5757836SJohn.Forte@Sun.COM 			if (rdc_get_vflags(urdc) & RDC_PRIMARY) {
5767836SJohn.Forte@Sun.COM 				pfound = 1;
5777836SJohn.Forte@Sun.COM 			} else {
5787836SJohn.Forte@Sun.COM 				sfound = 1;
5797836SJohn.Forte@Sun.COM 			}
5807836SJohn.Forte@Sun.COM 
5817836SJohn.Forte@Sun.COM 			if (pfound && sfound)
5827836SJohn.Forte@Sun.COM 				break;
5837836SJohn.Forte@Sun.COM 		}
5847836SJohn.Forte@Sun.COM 	}
5857836SJohn.Forte@Sun.COM 
5867836SJohn.Forte@Sun.COM 	ip->isprimary = pfound;
5877836SJohn.Forte@Sun.COM 	ip->issecondary = sfound;
5887836SJohn.Forte@Sun.COM 
5897836SJohn.Forte@Sun.COM 	if (!delete || ip->exiting > 0) {
5907836SJohn.Forte@Sun.COM 		mutex_exit(&rdc_ping_lock);
5917836SJohn.Forte@Sun.COM 		return;
5927836SJohn.Forte@Sun.COM 	}
5937836SJohn.Forte@Sun.COM 
5947836SJohn.Forte@Sun.COM 	/* mark and wait for daemon to exit */
5957836SJohn.Forte@Sun.COM 
5967836SJohn.Forte@Sun.COM 	ip->exiting = 1;
5977836SJohn.Forte@Sun.COM 
5987836SJohn.Forte@Sun.COM 	mutex_exit(&rdc_ping_lock);
5997836SJohn.Forte@Sun.COM 
6007836SJohn.Forte@Sun.COM 	while (ip->exiting == 1)
6017836SJohn.Forte@Sun.COM 		delay(drv_usectohz(10));
6027836SJohn.Forte@Sun.COM 
6037836SJohn.Forte@Sun.COM 	mutex_enter(&rdc_ping_lock);
6047836SJohn.Forte@Sun.COM 
6057836SJohn.Forte@Sun.COM 	ASSERT(ip->exiting == 2);
6067836SJohn.Forte@Sun.COM 
6077836SJohn.Forte@Sun.COM 	/* remove from chain */
6087836SJohn.Forte@Sun.COM 
6097836SJohn.Forte@Sun.COM 	for (ipp = &rdc_if_top; *ipp; ipp = &((*ipp)->next)) {
6107836SJohn.Forte@Sun.COM 		if (*ipp == ip) {
6117836SJohn.Forte@Sun.COM 			*ipp = ip->next;
6127836SJohn.Forte@Sun.COM 			break;
6137836SJohn.Forte@Sun.COM 		}
6147836SJohn.Forte@Sun.COM 	}
6157836SJohn.Forte@Sun.COM 
6167836SJohn.Forte@Sun.COM 	mutex_exit(&rdc_ping_lock);
6177836SJohn.Forte@Sun.COM 
6187836SJohn.Forte@Sun.COM 	/* free unused interface structure */
6197836SJohn.Forte@Sun.COM 
6207836SJohn.Forte@Sun.COM 	free_rdc_netbuf(&ip->r_ifaddr);
6217836SJohn.Forte@Sun.COM 	free_rdc_netbuf(&ip->ifaddr);
6227836SJohn.Forte@Sun.COM 	rdc_destroy_svinfo(ip->srv);
6237836SJohn.Forte@Sun.COM 	kmem_free(ip, sizeof (*ip));
6247836SJohn.Forte@Sun.COM }
6257836SJohn.Forte@Sun.COM 
6267836SJohn.Forte@Sun.COM 
6277836SJohn.Forte@Sun.COM /*
6287836SJohn.Forte@Sun.COM  * Check the status of the link to the secondary, and optionally update
6297836SJohn.Forte@Sun.COM  * the primary-side ping variables.
6307836SJohn.Forte@Sun.COM  *
6317836SJohn.Forte@Sun.COM  * For use on a primary only.
6327836SJohn.Forte@Sun.COM  *
6337836SJohn.Forte@Sun.COM  * Returns:
6347836SJohn.Forte@Sun.COM  *	TRUE	- interface up.
6357836SJohn.Forte@Sun.COM  *	FALSE	- interface down.
6367836SJohn.Forte@Sun.COM  */
6377836SJohn.Forte@Sun.COM int
rdc_check_secondary(rdc_if_t * ip,int update)6387836SJohn.Forte@Sun.COM rdc_check_secondary(rdc_if_t *ip, int update)
6397836SJohn.Forte@Sun.COM {
6407836SJohn.Forte@Sun.COM 	int rc = TRUE;
6417836SJohn.Forte@Sun.COM 
6427836SJohn.Forte@Sun.COM 	if (!ip || !ip->isprimary) {
6437836SJohn.Forte@Sun.COM #ifdef DEBUG
6447836SJohn.Forte@Sun.COM 		cmn_err(CE_WARN,
645*9093SRamana.Srikanth@Sun.COM 		    "!rdc_check_secondary: ip %p, isprimary %d, issecondary %d",
6467836SJohn.Forte@Sun.COM 		    (void *) ip, ip ? ip->isprimary : 0,
647*9093SRamana.Srikanth@Sun.COM 		    ip ? ip->issecondary : 0);
6487836SJohn.Forte@Sun.COM #endif
6497836SJohn.Forte@Sun.COM 		return (FALSE);
6507836SJohn.Forte@Sun.COM 	}
6517836SJohn.Forte@Sun.COM 
6527836SJohn.Forte@Sun.COM 	if (!ip->deadness) {
6537836SJohn.Forte@Sun.COM #ifdef DEBUG
654*9093SRamana.Srikanth@Sun.COM 		cmn_err(CE_WARN, "!rdc_check_secondary: ip %p, ip->deadness %d",
655*9093SRamana.Srikanth@Sun.COM 		    (void *) ip, ip->deadness);
6567836SJohn.Forte@Sun.COM #endif
6577836SJohn.Forte@Sun.COM 		return (FALSE);
6587836SJohn.Forte@Sun.COM 	}
6597836SJohn.Forte@Sun.COM 
6607836SJohn.Forte@Sun.COM 	if (!update) {
6617836SJohn.Forte@Sun.COM 		/* quick look */
6627836SJohn.Forte@Sun.COM 		return ((ip->deadness > rdc_health_thres) ? FALSE : TRUE);
6637836SJohn.Forte@Sun.COM 	}
6647836SJohn.Forte@Sun.COM 
6657836SJohn.Forte@Sun.COM 	/* update (slow) with lock */
6667836SJohn.Forte@Sun.COM 
6677836SJohn.Forte@Sun.COM 	mutex_enter(&rdc_ping_lock);
6687836SJohn.Forte@Sun.COM 
6697836SJohn.Forte@Sun.COM 	if (ip->old_pulse == ip->new_pulse) {
6707836SJohn.Forte@Sun.COM 		/*
6717836SJohn.Forte@Sun.COM 		 * ping has not been received since last update
6727836SJohn.Forte@Sun.COM 		 * or we have not yet been pinged,
6737836SJohn.Forte@Sun.COM 		 * the health thread has started only as a
6747836SJohn.Forte@Sun.COM 		 * local client so far, not so on the other side
6757836SJohn.Forte@Sun.COM 		 */
6767836SJohn.Forte@Sun.COM 
6777836SJohn.Forte@Sun.COM 		if (ip->last != nsc_time()) {
6787836SJohn.Forte@Sun.COM 			/* time has passed, so move closer to death */
6797836SJohn.Forte@Sun.COM 
6807836SJohn.Forte@Sun.COM 			ip->last = nsc_time();
6817836SJohn.Forte@Sun.COM 			ip->deadness++;
6827836SJohn.Forte@Sun.COM 
6837836SJohn.Forte@Sun.COM 			if (ip->deadness <= 0) {
6847836SJohn.Forte@Sun.COM 				/* avoid the wrap */
6857836SJohn.Forte@Sun.COM 				ip->deadness = rdc_health_thres + 1;
6867836SJohn.Forte@Sun.COM 			}
6877836SJohn.Forte@Sun.COM 		}
6887836SJohn.Forte@Sun.COM 
6897836SJohn.Forte@Sun.COM 		if (ip->deadness > rdc_health_thres) {
6907836SJohn.Forte@Sun.COM 			rc = FALSE;
6917836SJohn.Forte@Sun.COM 			/*
6927836SJohn.Forte@Sun.COM 			 * Start back at the max possible version
6937836SJohn.Forte@Sun.COM 			 * since the remote server could come back
6947836SJohn.Forte@Sun.COM 			 * on a different protocol version.
6957836SJohn.Forte@Sun.COM 			 */
6967836SJohn.Forte@Sun.COM 			ip->rpc_version = RDC_VERS_MAX;
6977836SJohn.Forte@Sun.COM 		}
6987836SJohn.Forte@Sun.COM 	} else {
6997836SJohn.Forte@Sun.COM 		ip->old_pulse = ip->new_pulse;
7007836SJohn.Forte@Sun.COM 	}
7017836SJohn.Forte@Sun.COM 
7027836SJohn.Forte@Sun.COM 	mutex_exit(&rdc_ping_lock);
7037836SJohn.Forte@Sun.COM 	return (rc);
7047836SJohn.Forte@Sun.COM }
7057836SJohn.Forte@Sun.COM 
7067836SJohn.Forte@Sun.COM 
7077836SJohn.Forte@Sun.COM /*
7087836SJohn.Forte@Sun.COM  * Update the interface structure with the latest ping info, and
7097836SJohn.Forte@Sun.COM  * perform interface up/down transitions if required.
7107836SJohn.Forte@Sun.COM  *
7117836SJohn.Forte@Sun.COM  * For use on a primary only.
7127836SJohn.Forte@Sun.COM  */
7137836SJohn.Forte@Sun.COM static void
rdc_update_health(rdc_if_t * ip)7147836SJohn.Forte@Sun.COM rdc_update_health(rdc_if_t *ip)
7157836SJohn.Forte@Sun.COM {
7167836SJohn.Forte@Sun.COM 	rdc_k_info_t *krdc;
7177836SJohn.Forte@Sun.COM 	rdc_u_info_t *urdc;
7187836SJohn.Forte@Sun.COM 	int index;
7197836SJohn.Forte@Sun.COM 	rdc_link_down_t *syncdp;
7207836SJohn.Forte@Sun.COM 
7217836SJohn.Forte@Sun.COM 	if (!ip->isprimary) {
7227836SJohn.Forte@Sun.COM #ifdef DEBUG
7237836SJohn.Forte@Sun.COM 		cmn_err(CE_WARN,
724*9093SRamana.Srikanth@Sun.COM 		    "!rdc_update_health: ip %p, isprimary %d, issecondary %d",
7257836SJohn.Forte@Sun.COM 		    (void *) ip, ip ? ip->isprimary : 0,
726*9093SRamana.Srikanth@Sun.COM 		    ip ? ip->issecondary : 0);
7277836SJohn.Forte@Sun.COM #endif
7287836SJohn.Forte@Sun.COM 		return;
7297836SJohn.Forte@Sun.COM 	}
7307836SJohn.Forte@Sun.COM 
7317836SJohn.Forte@Sun.COM 	if (!rdc_check_secondary(ip, TRUE)) {
7327836SJohn.Forte@Sun.COM 		/* interface down */
7337836SJohn.Forte@Sun.COM 		if (!ip->if_down) {
7347836SJohn.Forte@Sun.COM 			rdc_if_down(ip);
7357836SJohn.Forte@Sun.COM 			ip->if_down = 1;
7367836SJohn.Forte@Sun.COM 
7377836SJohn.Forte@Sun.COM 			/* scan rdc sets and update status */
7387836SJohn.Forte@Sun.COM 
7397836SJohn.Forte@Sun.COM 			for (index = 0; index < rdc_max_sets; index++) {
7407836SJohn.Forte@Sun.COM 				krdc = &rdc_k_info[index];
7417836SJohn.Forte@Sun.COM 				urdc = &rdc_u_info[index];
7427836SJohn.Forte@Sun.COM 
7437836SJohn.Forte@Sun.COM 				if (IS_ENABLED(urdc) && (krdc->intf == ip) &&
7447836SJohn.Forte@Sun.COM 				    (rdc_get_vflags(urdc) & RDC_PRIMARY) &&
7457836SJohn.Forte@Sun.COM 				    !(rdc_get_vflags(urdc) & RDC_LOGGING)) {
7467836SJohn.Forte@Sun.COM 					/* mark down */
7477836SJohn.Forte@Sun.COM 
7487836SJohn.Forte@Sun.COM 					rdc_group_enter(krdc);
7497836SJohn.Forte@Sun.COM 					/*
7507836SJohn.Forte@Sun.COM 					 * check for possible race with
7517836SJohn.Forte@Sun.COM 					 * with delete logic
7527836SJohn.Forte@Sun.COM 					 */
7537836SJohn.Forte@Sun.COM 					if (!IS_ENABLED(urdc)) {
7547836SJohn.Forte@Sun.COM 						rdc_group_exit(krdc);
7557836SJohn.Forte@Sun.COM 						continue;
7567836SJohn.Forte@Sun.COM 					}
757*9093SRamana.Srikanth@Sun.COM 					rdc_group_log(krdc, RDC_NOFLUSH |
758*9093SRamana.Srikanth@Sun.COM 					    RDC_NOREMOTE | RDC_QUEUING,
759*9093SRamana.Srikanth@Sun.COM 					    "hm detected secondary "
760*9093SRamana.Srikanth@Sun.COM 					    "interface down");
7617836SJohn.Forte@Sun.COM 
7627836SJohn.Forte@Sun.COM 					rdc_group_exit(krdc);
7637836SJohn.Forte@Sun.COM 
7647836SJohn.Forte@Sun.COM 					/* dump async queues */
7657836SJohn.Forte@Sun.COM 					rdc_dump_queue(index);
7667836SJohn.Forte@Sun.COM 				}
7677836SJohn.Forte@Sun.COM 			}
7687836SJohn.Forte@Sun.COM 
7697836SJohn.Forte@Sun.COM 			/* dump allocated bufs */
7707836SJohn.Forte@Sun.COM 			rdc_dump_alloc_bufs(ip);
7717836SJohn.Forte@Sun.COM 		}
7727836SJohn.Forte@Sun.COM 
7737836SJohn.Forte@Sun.COM 		syncdp = rdc_lookup_host(ip->srv->ri_hostname);
7747836SJohn.Forte@Sun.COM 		mutex_enter(&syncdp->syncd_mutex);
7757836SJohn.Forte@Sun.COM 		if (syncdp->link_down == 0) {
7767836SJohn.Forte@Sun.COM 			/* Link has gone down, notify rdcsyncd daemon */
7777836SJohn.Forte@Sun.COM 			syncdp->link_down = 1;
7787836SJohn.Forte@Sun.COM 			if (syncdp->waiting) {
7797836SJohn.Forte@Sun.COM 				syncdp->waiting = 0;
7807836SJohn.Forte@Sun.COM 				cv_signal(&syncdp->syncd_cv);
7817836SJohn.Forte@Sun.COM 			}
7827836SJohn.Forte@Sun.COM 		}
7837836SJohn.Forte@Sun.COM 		mutex_exit(&syncdp->syncd_mutex);
7847836SJohn.Forte@Sun.COM 	} else {
7857836SJohn.Forte@Sun.COM 		/* interface up */
7867836SJohn.Forte@Sun.COM 		if (ip->if_down && ip->isprimary) {
7877836SJohn.Forte@Sun.COM 			rdc_if_up(ip);
7887836SJohn.Forte@Sun.COM 			ip->if_down = 0;
7897836SJohn.Forte@Sun.COM 		}
7907836SJohn.Forte@Sun.COM 
7917836SJohn.Forte@Sun.COM 		syncdp = rdc_lookup_host(ip->srv->ri_hostname);
7927836SJohn.Forte@Sun.COM 		mutex_enter(&syncdp->syncd_mutex);
7937836SJohn.Forte@Sun.COM 		if (syncdp->link_down) {
7947836SJohn.Forte@Sun.COM 			/* Link has come back up */
7957836SJohn.Forte@Sun.COM 			syncdp->link_down = 0;
7967836SJohn.Forte@Sun.COM 		}
7977836SJohn.Forte@Sun.COM 		mutex_exit(&syncdp->syncd_mutex);
7987836SJohn.Forte@Sun.COM 	}
7997836SJohn.Forte@Sun.COM }
800