17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
57c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
67c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
77c478bd9Sstevel@tonic-gate  * with the License.
87c478bd9Sstevel@tonic-gate  *
97c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
107c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
117c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
127c478bd9Sstevel@tonic-gate  * and limitations under the License.
137c478bd9Sstevel@tonic-gate  *
147c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
157c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
167c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
177c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
187c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
197c478bd9Sstevel@tonic-gate  *
207c478bd9Sstevel@tonic-gate  * CDDL HEADER END
217c478bd9Sstevel@tonic-gate  */
227c478bd9Sstevel@tonic-gate /*
237c478bd9Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
25*b97d6ca7SMilan Jurik  * Copyright 2012 Milan Jurik. All rights reserved.
267c478bd9Sstevel@tonic-gate  */
277c478bd9Sstevel@tonic-gate 
287c478bd9Sstevel@tonic-gate /*
297c478bd9Sstevel@tonic-gate  * This module provides for the management of interconnect adapters
307c478bd9Sstevel@tonic-gate  * inter-node connections (aka paths), and IPC.  Adapter descriptors are
317c478bd9Sstevel@tonic-gate  * maintained on a linked list; one list per adapter devname.  Each
327c478bd9Sstevel@tonic-gate  * adapter descriptor heads a linked list of path descriptors.  There is
337c478bd9Sstevel@tonic-gate  * also a linked list of ipc_info descriptors; one for each node.  Each
347c478bd9Sstevel@tonic-gate  * ipc_info descriptor heads a circular list of ipc tokens (the tokens are
357c478bd9Sstevel@tonic-gate  * embedded within a path descriptor). The tokens are used in round robin
367c478bd9Sstevel@tonic-gate  * fashion.
377c478bd9Sstevel@tonic-gate  *
387c478bd9Sstevel@tonic-gate  *
397c478bd9Sstevel@tonic-gate  * The exported interface consists of the following functions:
407c478bd9Sstevel@tonic-gate  *	- rsmka_add_adapter
417c478bd9Sstevel@tonic-gate  *	- rsmka_remove_adapter
427c478bd9Sstevel@tonic-gate  *
437c478bd9Sstevel@tonic-gate  *      [add_path and remove_path only called for current adapters]
447c478bd9Sstevel@tonic-gate  *	- rsmka_add_path
457c478bd9Sstevel@tonic-gate  *	- rsmka_remove_path	[a path down request is implicit]
467c478bd9Sstevel@tonic-gate  *
477c478bd9Sstevel@tonic-gate  *	- rsmka_path_up           [called at clock ipl for Sun Cluster]
487c478bd9Sstevel@tonic-gate  *	- rsmka_path_down         [called at clock ipl for Sun Cluster]
497c478bd9Sstevel@tonic-gate  *	- rsmka_disconnect_node   [called at clock ipl for Sun Cluster;
507c478bd9Sstevel@tonic-gate  *				treat like path-down for all node paths;
517c478bd9Sstevel@tonic-gate  *				can be before node_alive; always before
527c478bd9Sstevel@tonic-gate  *				node_died.]
537c478bd9Sstevel@tonic-gate  *
547c478bd9Sstevel@tonic-gate  *	[node_alive and node_died are always paired]
557c478bd9Sstevel@tonic-gate  *	- rsmka_node_alive   called after the first cluster path is up
567c478bd9Sstevel@tonic-gate  *                           for this node
577c478bd9Sstevel@tonic-gate  *	- rsmka_node_died
587c478bd9Sstevel@tonic-gate  *
597c478bd9Sstevel@tonic-gate  *      [set the local node id]
607c478bd9Sstevel@tonic-gate  *      - rsmka_set_my_nodeid    called to set the variable my_nodeid to the
617c478bd9Sstevel@tonic-gate  *                           local node id
627c478bd9Sstevel@tonic-gate  *
637c478bd9Sstevel@tonic-gate  * Processing for these functions is setup as a state machine supported
647c478bd9Sstevel@tonic-gate  * by the data structures described above.
657c478bd9Sstevel@tonic-gate  *
667c478bd9Sstevel@tonic-gate  * For Sun Cluster these are called from the Path-Manager/Kernel-Agent
677c478bd9Sstevel@tonic-gate  * Interface (rsmka_pm_interface.cc).
687c478bd9Sstevel@tonic-gate  *
697c478bd9Sstevel@tonic-gate  * The functions rsm_path_up, rsm_path_down, and rsm_disconnect_node are
707c478bd9Sstevel@tonic-gate  * called at clock interrupt level from the Path-Manager/Kernel-Agent
717c478bd9Sstevel@tonic-gate  * Interface which precludes sleeping; so these functions may (optionally)
727c478bd9Sstevel@tonic-gate  * defer processing to an independent thread running at normal ipl.
737c478bd9Sstevel@tonic-gate  *
747c478bd9Sstevel@tonic-gate  *
757c478bd9Sstevel@tonic-gate  * lock definitions:
767c478bd9Sstevel@tonic-gate  *
777c478bd9Sstevel@tonic-gate  *	(mutex) work_queue.work_mutex
787c478bd9Sstevel@tonic-gate  *			protects linked list of work tokens and used
797c478bd9Sstevel@tonic-gate  *			with cv_wait/cv_signal thread synchronization.
807c478bd9Sstevel@tonic-gate  *			No other locks acquired when held.
817c478bd9Sstevel@tonic-gate  *
827c478bd9Sstevel@tonic-gate  *	(mutex) adapter_listhead_base.listlock
837c478bd9Sstevel@tonic-gate  *			protects linked list of adapter listheads
847c478bd9Sstevel@tonic-gate  *			Always acquired before listhead->mutex
857c478bd9Sstevel@tonic-gate  *
867c478bd9Sstevel@tonic-gate  *
877c478bd9Sstevel@tonic-gate  *	(mutex) ipc_info_lock
887c478bd9Sstevel@tonic-gate  *			protects ipc_info list and sendq token lists
897c478bd9Sstevel@tonic-gate  *			Always acquired before listhead->mutex
907c478bd9Sstevel@tonic-gate  *
917c478bd9Sstevel@tonic-gate  *      (mutex) listhead->mutex
927c478bd9Sstevel@tonic-gate  *			protects adapter listhead, linked list of
937c478bd9Sstevel@tonic-gate  *			adapters, and linked list of paths.
947c478bd9Sstevel@tonic-gate  *
957c478bd9Sstevel@tonic-gate  *      (mutex) path->mutex
967c478bd9Sstevel@tonic-gate  *			protects the path descriptor.
977c478bd9Sstevel@tonic-gate  *			work_queue.work_mutex may be acquired when holding
987c478bd9Sstevel@tonic-gate  *			this lock.
997c478bd9Sstevel@tonic-gate  *
1007c478bd9Sstevel@tonic-gate  *	(mutex) adapter->mutex
1017c478bd9Sstevel@tonic-gate  *			protects adapter descriptor contents.  used
1027c478bd9Sstevel@tonic-gate  *			mainly for ref_cnt update.
1037c478bd9Sstevel@tonic-gate  */
1047c478bd9Sstevel@tonic-gate 
1057c478bd9Sstevel@tonic-gate #include <sys/param.h>
1067c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
1077c478bd9Sstevel@tonic-gate #include <sys/errno.h>
1087c478bd9Sstevel@tonic-gate #include <sys/time.h>
1097c478bd9Sstevel@tonic-gate #include <sys/devops.h>
1107c478bd9Sstevel@tonic-gate #include <sys/ddi_impldefs.h>
1117c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
1127c478bd9Sstevel@tonic-gate #include <sys/ddi.h>
1137c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
1147c478bd9Sstevel@tonic-gate #include <sys/proc.h>
1157c478bd9Sstevel@tonic-gate #include <sys/thread.h>
1167c478bd9Sstevel@tonic-gate #include <sys/taskq.h>
1177c478bd9Sstevel@tonic-gate #include <sys/callb.h>
1187c478bd9Sstevel@tonic-gate 
1197c478bd9Sstevel@tonic-gate #include <sys/rsm/rsm.h>
1207c478bd9Sstevel@tonic-gate #include <rsm_in.h>
1217c478bd9Sstevel@tonic-gate #include <sys/rsm/rsmka_path_int.h>
1227c478bd9Sstevel@tonic-gate 
1237c478bd9Sstevel@tonic-gate extern void _cplpl_init();
1247c478bd9Sstevel@tonic-gate extern void _cplpl_fini();
1257c478bd9Sstevel@tonic-gate extern pri_t maxclsyspri;
1267c478bd9Sstevel@tonic-gate extern int   rsm_hash_size;
1277c478bd9Sstevel@tonic-gate 
1287c478bd9Sstevel@tonic-gate extern rsm_node_id_t my_nodeid;
1297c478bd9Sstevel@tonic-gate extern rsmhash_table_t rsm_import_segs;
130*b97d6ca7SMilan Jurik extern rsm_intr_hand_ret_t rsm_srv_func(rsm_controller_object_t *,
131*b97d6ca7SMilan Jurik     rsm_intr_q_op_t, rsm_addr_t, void *, size_t, rsm_intr_hand_arg_t);
1327c478bd9Sstevel@tonic-gate extern void rsmseg_unload(rsmseg_t *);
1337c478bd9Sstevel@tonic-gate extern void rsm_suspend_complete(rsm_node_id_t src_node, int flag);
1347c478bd9Sstevel@tonic-gate extern int rsmipc_send_controlmsg(path_t *path, int msgtype);
1357c478bd9Sstevel@tonic-gate extern void rsmka_path_monitor_initialize();
1367c478bd9Sstevel@tonic-gate extern void rsmka_path_monitor_terminate();
1377c478bd9Sstevel@tonic-gate 
1387c478bd9Sstevel@tonic-gate extern adapter_t loopback_adapter;
1397c478bd9Sstevel@tonic-gate /*
1407c478bd9Sstevel@tonic-gate  * Lint errors and warnings are displayed; informational messages
1417c478bd9Sstevel@tonic-gate  * are suppressed.
1427c478bd9Sstevel@tonic-gate  */
1437c478bd9Sstevel@tonic-gate /* lint -w2 */
1447c478bd9Sstevel@tonic-gate 
1457c478bd9Sstevel@tonic-gate 
1467c478bd9Sstevel@tonic-gate /*
1477c478bd9Sstevel@tonic-gate  * macros SQ_TOKEN_TO_PATH and WORK_TOKEN_TO_PATH use a null pointer
1487c478bd9Sstevel@tonic-gate  * for computational purposes.  Ignore the lint warning.
1497c478bd9Sstevel@tonic-gate  */
1507c478bd9Sstevel@tonic-gate /* lint -save -e413 */
1517c478bd9Sstevel@tonic-gate /* FUNCTION PROTOTYPES */
1527c478bd9Sstevel@tonic-gate static adapter_t *init_adapter(char *, int, rsm_addr_t,
1537c478bd9Sstevel@tonic-gate     rsm_controller_handle_t, rsm_ops_t *, srv_handler_arg_t *);
1547c478bd9Sstevel@tonic-gate adapter_t *rsmka_lookup_adapter(char *, int);
1557c478bd9Sstevel@tonic-gate static ipc_info_t *lookup_ipc_info(rsm_node_id_t);
1567c478bd9Sstevel@tonic-gate static ipc_info_t *init_ipc_info(rsm_node_id_t, boolean_t);
1577c478bd9Sstevel@tonic-gate static path_t *lookup_path(char *, int, rsm_node_id_t, rsm_addr_t);
1587c478bd9Sstevel@tonic-gate static void pathup_to_pathactive(ipc_info_t *, rsm_node_id_t);
1597c478bd9Sstevel@tonic-gate static void path_importer_disconnect(path_t *);
1607c478bd9Sstevel@tonic-gate boolean_t rsmka_do_path_active(path_t *, int);
1617c478bd9Sstevel@tonic-gate static boolean_t do_path_up(path_t *, int);
1627c478bd9Sstevel@tonic-gate static void do_path_down(path_t *, int);
1637c478bd9Sstevel@tonic-gate static void enqueue_work(work_token_t *);
1647c478bd9Sstevel@tonic-gate static boolean_t cancel_work(work_token_t *);
1657c478bd9Sstevel@tonic-gate static void link_path(path_t *);
1667c478bd9Sstevel@tonic-gate static void destroy_path(path_t *);
1677c478bd9Sstevel@tonic-gate static void link_sendq_token(sendq_token_t *, rsm_node_id_t);
1687c478bd9Sstevel@tonic-gate static void unlink_sendq_token(sendq_token_t *, rsm_node_id_t);
1697c478bd9Sstevel@tonic-gate boolean_t rsmka_check_node_alive(rsm_node_id_t);
1707c478bd9Sstevel@tonic-gate static void do_deferred_work(caddr_t);
1717c478bd9Sstevel@tonic-gate static int create_ipc_sendq(path_t *);
1727c478bd9Sstevel@tonic-gate static void destroy_ipc_info(ipc_info_t *);
1737c478bd9Sstevel@tonic-gate void rsmka_pathmanager_cleanup();
1747c478bd9Sstevel@tonic-gate void rsmka_release_adapter(adapter_t *);
1757c478bd9Sstevel@tonic-gate 
1767c478bd9Sstevel@tonic-gate kt_did_t rsm_thread_id;
1777c478bd9Sstevel@tonic-gate int rsmka_terminate_workthread_loop = 0;
1787c478bd9Sstevel@tonic-gate 
1797c478bd9Sstevel@tonic-gate static struct adapter_listhead_list adapter_listhead_base;
1807c478bd9Sstevel@tonic-gate static work_queue_t work_queue;
1817c478bd9Sstevel@tonic-gate 
1827c478bd9Sstevel@tonic-gate /* protect ipc_info descriptor manipulation */
1837c478bd9Sstevel@tonic-gate static kmutex_t ipc_info_lock;
1847c478bd9Sstevel@tonic-gate 
1857c478bd9Sstevel@tonic-gate static ipc_info_t *ipc_info_head = NULL;
1867c478bd9Sstevel@tonic-gate 
1877c478bd9Sstevel@tonic-gate static int category = RSM_PATH_MANAGER | RSM_KERNEL_AGENT;
1887c478bd9Sstevel@tonic-gate 
1897c478bd9Sstevel@tonic-gate /* for synchronization with rsmipc_send() in rsm.c */
1907c478bd9Sstevel@tonic-gate kmutex_t ipc_info_cvlock;
1917c478bd9Sstevel@tonic-gate kcondvar_t ipc_info_cv;
1927c478bd9Sstevel@tonic-gate 
1937c478bd9Sstevel@tonic-gate 
1947c478bd9Sstevel@tonic-gate 
1957c478bd9Sstevel@tonic-gate /*
1967c478bd9Sstevel@tonic-gate  * RSMKA PATHMANAGER INITIALIZATION AND CLEANUP ROUTINES
1977c478bd9Sstevel@tonic-gate  *
1987c478bd9Sstevel@tonic-gate  */
1997c478bd9Sstevel@tonic-gate 
2007c478bd9Sstevel@tonic-gate 
2017c478bd9Sstevel@tonic-gate /*
2027c478bd9Sstevel@tonic-gate  * Called from the rsm module (rsm.c)  _init() routine
2037c478bd9Sstevel@tonic-gate  */
2047c478bd9Sstevel@tonic-gate void
rsmka_pathmanager_init()2057c478bd9Sstevel@tonic-gate rsmka_pathmanager_init()
2067c478bd9Sstevel@tonic-gate {
2077c478bd9Sstevel@tonic-gate 	kthread_t *tp;
2087c478bd9Sstevel@tonic-gate 
2097c478bd9Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
2107c478bd9Sstevel@tonic-gate 	    "rsmka_pathmanager_init enter\n"));
2117c478bd9Sstevel@tonic-gate 
2127c478bd9Sstevel@tonic-gate 	/* initialization for locks and condition variables  */
2137c478bd9Sstevel@tonic-gate 	mutex_init(&work_queue.work_mutex, NULL, MUTEX_DEFAULT, NULL);
2147c478bd9Sstevel@tonic-gate 	mutex_init(&ipc_info_lock, NULL, MUTEX_DEFAULT, NULL);
2157c478bd9Sstevel@tonic-gate 	mutex_init(&ipc_info_cvlock, NULL, MUTEX_DEFAULT, NULL);
2167c478bd9Sstevel@tonic-gate 	mutex_init(&adapter_listhead_base.listlock, NULL,
2177c478bd9Sstevel@tonic-gate 	    MUTEX_DEFAULT, NULL);
2187c478bd9Sstevel@tonic-gate 
2197c478bd9Sstevel@tonic-gate 	cv_init(&work_queue.work_cv, NULL, CV_DEFAULT, NULL);
2207c478bd9Sstevel@tonic-gate 	cv_init(&ipc_info_cv, NULL, CV_DEFAULT, NULL);
2217c478bd9Sstevel@tonic-gate 
2227c478bd9Sstevel@tonic-gate 	tp = thread_create(NULL, 0, do_deferred_work, NULL, 0, &p0,
2237c478bd9Sstevel@tonic-gate 	    TS_RUN, maxclsyspri);
2247c478bd9Sstevel@tonic-gate 	rsm_thread_id = tp->t_did;
2257c478bd9Sstevel@tonic-gate 
2267c478bd9Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
2277c478bd9Sstevel@tonic-gate 	    "rsmka_pathmanager_init done\n"));
2287c478bd9Sstevel@tonic-gate }
2297c478bd9Sstevel@tonic-gate 
2307c478bd9Sstevel@tonic-gate void
rsmka_pathmanager_cleanup()2317c478bd9Sstevel@tonic-gate rsmka_pathmanager_cleanup()
2327c478bd9Sstevel@tonic-gate {
2337c478bd9Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
2347c478bd9Sstevel@tonic-gate 	    "rsmka_pathmanager_cleanup enter\n"));
2357c478bd9Sstevel@tonic-gate 
2367c478bd9Sstevel@tonic-gate 	ASSERT(work_queue.head == NULL);
2377c478bd9Sstevel@tonic-gate 
2387c478bd9Sstevel@tonic-gate 	/*
2397c478bd9Sstevel@tonic-gate 	 * In processing the remove path callbacks from the path monitor
2407c478bd9Sstevel@tonic-gate 	 * object, all deferred work will have been completed. So
2417c478bd9Sstevel@tonic-gate 	 * awaken the deferred work thread to give it a chance to exit
2427c478bd9Sstevel@tonic-gate 	 * the loop.
2437c478bd9Sstevel@tonic-gate 	 */
2447c478bd9Sstevel@tonic-gate 	mutex_enter(&work_queue.work_mutex);
2457c478bd9Sstevel@tonic-gate 	rsmka_terminate_workthread_loop++;
2467c478bd9Sstevel@tonic-gate 	cv_signal(&work_queue.work_cv);
2477c478bd9Sstevel@tonic-gate 	mutex_exit(&work_queue.work_mutex);
2487c478bd9Sstevel@tonic-gate 
2497c478bd9Sstevel@tonic-gate 	/*
2507c478bd9Sstevel@tonic-gate 	 * Wait for the deferred work thread to exit before
2517c478bd9Sstevel@tonic-gate 	 * destroying the locks and cleaning up other data
2527c478bd9Sstevel@tonic-gate 	 * structures.
2537c478bd9Sstevel@tonic-gate 	 */
2547c478bd9Sstevel@tonic-gate 	if (rsm_thread_id)
2557c478bd9Sstevel@tonic-gate 		thread_join(rsm_thread_id);
2567c478bd9Sstevel@tonic-gate 
2577c478bd9Sstevel@tonic-gate 	/*
2587c478bd9Sstevel@tonic-gate 	 * Destroy locks & condition variables
2597c478bd9Sstevel@tonic-gate 	 */
2607c478bd9Sstevel@tonic-gate 	mutex_destroy(&work_queue.work_mutex);
2617c478bd9Sstevel@tonic-gate 	cv_destroy(&work_queue.work_cv);
2627c478bd9Sstevel@tonic-gate 
2637c478bd9Sstevel@tonic-gate 	mutex_enter(&ipc_info_lock);
2647c478bd9Sstevel@tonic-gate 	while (ipc_info_head)
2657c478bd9Sstevel@tonic-gate 		destroy_ipc_info(ipc_info_head);
2667c478bd9Sstevel@tonic-gate 	mutex_exit(&ipc_info_lock);
2677c478bd9Sstevel@tonic-gate 
2687c478bd9Sstevel@tonic-gate 	mutex_destroy(&ipc_info_lock);
2697c478bd9Sstevel@tonic-gate 
2707c478bd9Sstevel@tonic-gate 	mutex_destroy(&ipc_info_cvlock);
2717c478bd9Sstevel@tonic-gate 	cv_destroy(&ipc_info_cv);
2727c478bd9Sstevel@tonic-gate 
2737c478bd9Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
2747c478bd9Sstevel@tonic-gate 	    "rsmka_pathmanager_cleanup done\n"));
2757c478bd9Sstevel@tonic-gate 
2767c478bd9Sstevel@tonic-gate }
2777c478bd9Sstevel@tonic-gate 
2787c478bd9Sstevel@tonic-gate void
rsmka_set_my_nodeid(rsm_node_id_t local_nodeid)2797c478bd9Sstevel@tonic-gate rsmka_set_my_nodeid(rsm_node_id_t local_nodeid)
2807c478bd9Sstevel@tonic-gate {
2817c478bd9Sstevel@tonic-gate 	my_nodeid = local_nodeid;
2827c478bd9Sstevel@tonic-gate 
2837c478bd9Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
2847c478bd9Sstevel@tonic-gate 	    "rsm: node %d \n", my_nodeid));
2857c478bd9Sstevel@tonic-gate 
2867c478bd9Sstevel@tonic-gate }
2877c478bd9Sstevel@tonic-gate 
2887c478bd9Sstevel@tonic-gate /*
2897c478bd9Sstevel@tonic-gate  * DEFERRED WORK THREAD AND WORK QUEUE SUPPORT ROUTINES
2907c478bd9Sstevel@tonic-gate  *
2917c478bd9Sstevel@tonic-gate  */
2927c478bd9Sstevel@tonic-gate 
2937c478bd9Sstevel@tonic-gate /*
2947c478bd9Sstevel@tonic-gate  * This function is the executable code of the thread which handles
2957c478bd9Sstevel@tonic-gate  * deferred work.  Work is deferred when a function is called at
2967c478bd9Sstevel@tonic-gate  * clock ipl and processing may require blocking.
2977c478bd9Sstevel@tonic-gate  *
2987c478bd9Sstevel@tonic-gate  *
2997c478bd9Sstevel@tonic-gate  * The thread is created by a call to taskq_create in rsmka_pathmanager_init.
3007c478bd9Sstevel@tonic-gate  * After creation, a call to taskq_dispatch causes this function to
3017c478bd9Sstevel@tonic-gate  * execute.  It loops forever - blocked until work is enqueued from
3027c478bd9Sstevel@tonic-gate  * rsmka_do_path_active, do_path_down, or rsmka_disconnect_node.
3037c478bd9Sstevel@tonic-gate  * rsmka_pathmanager_cleanup (called from _fini) will
3047c478bd9Sstevel@tonic-gate  * set rsmka_terminate_workthread_loop and the task processing will
3057c478bd9Sstevel@tonic-gate  * terminate.
3067c478bd9Sstevel@tonic-gate  */
3077c478bd9Sstevel@tonic-gate static void
do_deferred_work(caddr_t arg)3087c478bd9Sstevel@tonic-gate do_deferred_work(caddr_t arg /*ARGSUSED*/)
3097c478bd9Sstevel@tonic-gate {
3107c478bd9Sstevel@tonic-gate 
3117c478bd9Sstevel@tonic-gate 	adapter_t 			*adapter;
3127c478bd9Sstevel@tonic-gate 	path_t				*path;
3137c478bd9Sstevel@tonic-gate 	work_token_t			*work_token;
3147c478bd9Sstevel@tonic-gate 	int				work_opcode;
3157c478bd9Sstevel@tonic-gate 	rsm_send_q_handle_t		sendq_handle;
3167c478bd9Sstevel@tonic-gate 	int				error;
3177c478bd9Sstevel@tonic-gate 	timespec_t			tv;
3187c478bd9Sstevel@tonic-gate 	callb_cpr_t			cprinfo;
3197c478bd9Sstevel@tonic-gate 
3207c478bd9Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "do_deferred_work enter\n"));
3217c478bd9Sstevel@tonic-gate 
3227c478bd9Sstevel@tonic-gate 	CALLB_CPR_INIT(&cprinfo, &work_queue.work_mutex, callb_generic_cpr,
3237c478bd9Sstevel@tonic-gate 	    "rsm_deferred_work");
3247c478bd9Sstevel@tonic-gate 
3257c478bd9Sstevel@tonic-gate 	for (;;) {
3267c478bd9Sstevel@tonic-gate 		mutex_enter(&work_queue.work_mutex);
3277c478bd9Sstevel@tonic-gate 
3287c478bd9Sstevel@tonic-gate 		if (rsmka_terminate_workthread_loop) {
3297c478bd9Sstevel@tonic-gate 			goto exit;
3307c478bd9Sstevel@tonic-gate 		}
3317c478bd9Sstevel@tonic-gate 
3327c478bd9Sstevel@tonic-gate 		/* When there is no work to do, block here */
3337c478bd9Sstevel@tonic-gate 		while (work_queue.head == NULL) {
3347c478bd9Sstevel@tonic-gate 			/* Since no work to do, Safe to CPR */
3357c478bd9Sstevel@tonic-gate 			CALLB_CPR_SAFE_BEGIN(&cprinfo);
3367c478bd9Sstevel@tonic-gate 			cv_wait(&work_queue.work_cv, &work_queue.work_mutex);
3377c478bd9Sstevel@tonic-gate 			CALLB_CPR_SAFE_END(&cprinfo, &work_queue.work_mutex);
3387c478bd9Sstevel@tonic-gate 
3397c478bd9Sstevel@tonic-gate 			if (rsmka_terminate_workthread_loop) {
3407c478bd9Sstevel@tonic-gate 				goto exit;
3417c478bd9Sstevel@tonic-gate 			}
3427c478bd9Sstevel@tonic-gate 		}
3437c478bd9Sstevel@tonic-gate 
3447c478bd9Sstevel@tonic-gate 		/*
3457c478bd9Sstevel@tonic-gate 		 * Remove a work token and begin work
3467c478bd9Sstevel@tonic-gate 		 */
3477c478bd9Sstevel@tonic-gate 		work_token = work_queue.head;
3487c478bd9Sstevel@tonic-gate 		work_queue.head = work_token->next;
3497c478bd9Sstevel@tonic-gate 		if (work_queue.tail == work_token)
3507c478bd9Sstevel@tonic-gate 			work_queue.tail = NULL;
3517c478bd9Sstevel@tonic-gate 
3527c478bd9Sstevel@tonic-gate 		work_opcode = work_token->opcode;
3537c478bd9Sstevel@tonic-gate 		path = WORK_TOKEN_TO_PATH(work_token, work_opcode -1);
3547c478bd9Sstevel@tonic-gate 		work_token->next = NULL;
3557c478bd9Sstevel@tonic-gate 		mutex_exit(&work_queue.work_mutex);
3567c478bd9Sstevel@tonic-gate 
3577c478bd9Sstevel@tonic-gate 
3587c478bd9Sstevel@tonic-gate 		switch (work_opcode) {
3597c478bd9Sstevel@tonic-gate 		case RSMKA_IPC_UP:
3607c478bd9Sstevel@tonic-gate 			DBG_PRINTF((category, RSM_DEBUG,
3617c478bd9Sstevel@tonic-gate 			    "do_deferred_work:up,  path = %lx\n", path));
3627c478bd9Sstevel@tonic-gate 			error = create_ipc_sendq(path);
3637c478bd9Sstevel@tonic-gate 			mutex_enter(&path->mutex);
3647c478bd9Sstevel@tonic-gate 			if (path->state != RSMKA_PATH_UP) {
3657c478bd9Sstevel@tonic-gate 				/*
3667c478bd9Sstevel@tonic-gate 				 * path state has changed, if sendq was created,
3677c478bd9Sstevel@tonic-gate 				 * destroy it and return. Don't need to worry
3687c478bd9Sstevel@tonic-gate 				 * about sendq ref_cnt since no one starts
3697c478bd9Sstevel@tonic-gate 				 * using the sendq till path state becomes
3707c478bd9Sstevel@tonic-gate 				 * active
3717c478bd9Sstevel@tonic-gate 				 */
3727c478bd9Sstevel@tonic-gate 				if (error == RSM_SUCCESS) {
3737c478bd9Sstevel@tonic-gate 					sendq_handle = path->sendq_token.
3747c478bd9Sstevel@tonic-gate 					    rsmpi_sendq_handle;
3757c478bd9Sstevel@tonic-gate 					path->sendq_token.rsmpi_sendq_handle =
3767c478bd9Sstevel@tonic-gate 					    NULL;
3777c478bd9Sstevel@tonic-gate 					adapter = path->local_adapter;
3787c478bd9Sstevel@tonic-gate 					mutex_exit(&path->mutex);
3797c478bd9Sstevel@tonic-gate 
3807c478bd9Sstevel@tonic-gate 					if (sendq_handle != NULL) {
3817c478bd9Sstevel@tonic-gate 						adapter->rsmpi_ops->
3827c478bd9Sstevel@tonic-gate 						    rsm_sendq_destroy(
383*b97d6ca7SMilan Jurik 						    sendq_handle);
3847c478bd9Sstevel@tonic-gate 					}
3857c478bd9Sstevel@tonic-gate 					mutex_enter(&path->mutex);
3867c478bd9Sstevel@tonic-gate 				}
3877c478bd9Sstevel@tonic-gate 				/* free up work token */
3887c478bd9Sstevel@tonic-gate 				work_token->opcode = 0;
3897c478bd9Sstevel@tonic-gate 
3907c478bd9Sstevel@tonic-gate 				/*
3917c478bd9Sstevel@tonic-gate 				 * decrement reference count for the path
3927c478bd9Sstevel@tonic-gate 				 * descriptor and signal for synchronization
3937c478bd9Sstevel@tonic-gate 				 * with rsmka_remove_path. PATH_HOLD_NOLOCK was
3947c478bd9Sstevel@tonic-gate 				 * done by rsmka_path_up.
3957c478bd9Sstevel@tonic-gate 				 */
3967c478bd9Sstevel@tonic-gate 				PATH_RELE_NOLOCK(path);
3977c478bd9Sstevel@tonic-gate 				mutex_exit(&path->mutex);
3987c478bd9Sstevel@tonic-gate 				break;
3997c478bd9Sstevel@tonic-gate 			}
4007c478bd9Sstevel@tonic-gate 
4017c478bd9Sstevel@tonic-gate 			if (error == RSM_SUCCESS) {
4027c478bd9Sstevel@tonic-gate 				DBG_PRINTF((category, RSM_DEBUG,
4037c478bd9Sstevel@tonic-gate 				    "do_deferred_work:success on up\n"));
4047c478bd9Sstevel@tonic-gate 				/* clear flag since sendq_create succeeded */
4057c478bd9Sstevel@tonic-gate 				path->flags &= ~RSMKA_SQCREATE_PENDING;
4067c478bd9Sstevel@tonic-gate 				path->state = RSMKA_PATH_ACTIVE;
4077c478bd9Sstevel@tonic-gate 
4087c478bd9Sstevel@tonic-gate 				/*
4097c478bd9Sstevel@tonic-gate 				 * now that path is active we send the
4107c478bd9Sstevel@tonic-gate 				 * RSMIPC_MSG_SQREADY to the remote endpoint
4117c478bd9Sstevel@tonic-gate 				 */
4127c478bd9Sstevel@tonic-gate 				path->procmsg_cnt = 0;
4137c478bd9Sstevel@tonic-gate 				path->sendq_token.msgbuf_avail = 0;
4147c478bd9Sstevel@tonic-gate 
4157c478bd9Sstevel@tonic-gate 				/* Calculate local incarnation number */
4167c478bd9Sstevel@tonic-gate 				gethrestime(&tv);
4177c478bd9Sstevel@tonic-gate 				if (tv.tv_sec == RSM_UNKNOWN_INCN)
4187c478bd9Sstevel@tonic-gate 					tv.tv_sec = 1;
4197c478bd9Sstevel@tonic-gate 				path->local_incn = (int64_t)tv.tv_sec;
4207c478bd9Sstevel@tonic-gate 
4217c478bd9Sstevel@tonic-gate 				/*
4227c478bd9Sstevel@tonic-gate 				 * if send fails here its due to some
4237c478bd9Sstevel@tonic-gate 				 * non-transient error because QUEUE_FULL is
4247c478bd9Sstevel@tonic-gate 				 * not possible here since we are the first
4257c478bd9Sstevel@tonic-gate 				 * message on this sendq. The error will cause
4267c478bd9Sstevel@tonic-gate 				 * the path to go down anyways, so ignore
4277c478bd9Sstevel@tonic-gate 				 * the return value.
4287c478bd9Sstevel@tonic-gate 				 */
4297c478bd9Sstevel@tonic-gate 				(void) rsmipc_send_controlmsg(path,
4307c478bd9Sstevel@tonic-gate 				    RSMIPC_MSG_SQREADY);
4317c478bd9Sstevel@tonic-gate 				/* wait for SQREADY_ACK message */
4327c478bd9Sstevel@tonic-gate 				path->flags |= RSMKA_WAIT_FOR_SQACK;
4337c478bd9Sstevel@tonic-gate 			} else {
4347c478bd9Sstevel@tonic-gate 				/*
4357c478bd9Sstevel@tonic-gate 				 * sendq create failed possibly because
4367c478bd9Sstevel@tonic-gate 				 * the remote end is not yet ready eg.
4377c478bd9Sstevel@tonic-gate 				 * handler not registered, set a flag
4387c478bd9Sstevel@tonic-gate 				 * so that when there is an indication
4397c478bd9Sstevel@tonic-gate 				 * that the remote end is ready
4407c478bd9Sstevel@tonic-gate 				 * rsmka_do_path_active will be retried.
4417c478bd9Sstevel@tonic-gate 				 */
4427c478bd9Sstevel@tonic-gate 				path->flags |= RSMKA_SQCREATE_PENDING;
4437c478bd9Sstevel@tonic-gate 			}
4447c478bd9Sstevel@tonic-gate 
4457c478bd9Sstevel@tonic-gate 			/* free up work token */
4467c478bd9Sstevel@tonic-gate 			work_token->opcode = 0;
4477c478bd9Sstevel@tonic-gate 
4487c478bd9Sstevel@tonic-gate 			/*
4497c478bd9Sstevel@tonic-gate 			 * decrement reference count for the path
4507c478bd9Sstevel@tonic-gate 			 * descriptor and signal for synchronization with
4517c478bd9Sstevel@tonic-gate 			 * rsmka_remove_path. PATH_HOLD_NOLOCK was done
4527c478bd9Sstevel@tonic-gate 			 * by rsmka_path_up.
4537c478bd9Sstevel@tonic-gate 			 */
4547c478bd9Sstevel@tonic-gate 			PATH_RELE_NOLOCK(path);
4557c478bd9Sstevel@tonic-gate 			mutex_exit(&path->mutex);
4567c478bd9Sstevel@tonic-gate 
4577c478bd9Sstevel@tonic-gate 			break;
4587c478bd9Sstevel@tonic-gate 		case RSMKA_IPC_DOWN:
4597c478bd9Sstevel@tonic-gate 			DBG_PRINTF((category, RSM_DEBUG,
4607c478bd9Sstevel@tonic-gate 			    "do_deferred_work:down, path = %lx\n", path));
4617c478bd9Sstevel@tonic-gate 
4627c478bd9Sstevel@tonic-gate 			/*
4637c478bd9Sstevel@tonic-gate 			 * Unlike the processing of path_down in the case
4647c478bd9Sstevel@tonic-gate 			 * where the RSMKA_NO_SLEEP flag is not set, here,
4657c478bd9Sstevel@tonic-gate 			 * the state of the path is changed directly to
4667c478bd9Sstevel@tonic-gate 			 * RSMKA_PATH_DOWN. This is because in this case
4677c478bd9Sstevel@tonic-gate 			 * where the RSMKA_NO_SLEEP flag is set, any other
4687c478bd9Sstevel@tonic-gate 			 * calls referring this path will just queue up
4697c478bd9Sstevel@tonic-gate 			 * and will be processed only after the path
4707c478bd9Sstevel@tonic-gate 			 * down processing has completed.
4717c478bd9Sstevel@tonic-gate 			 */
4727c478bd9Sstevel@tonic-gate 			mutex_enter(&path->mutex);
4737c478bd9Sstevel@tonic-gate 			path->state = RSMKA_PATH_DOWN;
4747c478bd9Sstevel@tonic-gate 			/*
4757c478bd9Sstevel@tonic-gate 			 * clear the WAIT_FOR_SQACK flag since path is down.
4767c478bd9Sstevel@tonic-gate 			 */
4777c478bd9Sstevel@tonic-gate 			path->flags &= ~RSMKA_WAIT_FOR_SQACK;
4787c478bd9Sstevel@tonic-gate 
4797c478bd9Sstevel@tonic-gate 			/*
4807c478bd9Sstevel@tonic-gate 			 * this wakes up any thread waiting to receive credits
4817c478bd9Sstevel@tonic-gate 			 * in rsmipc_send to tell it that the path is down
4827c478bd9Sstevel@tonic-gate 			 * thus releasing the sendq.
4837c478bd9Sstevel@tonic-gate 			 */
4847c478bd9Sstevel@tonic-gate 			cv_broadcast(&path->sendq_token.sendq_cv);
4857c478bd9Sstevel@tonic-gate 
4867c478bd9Sstevel@tonic-gate 			mutex_exit(&path->mutex);
4877c478bd9Sstevel@tonic-gate 
4887c478bd9Sstevel@tonic-gate 			/* drain the messages from the receive msgbuf */
4897c478bd9Sstevel@tonic-gate 			taskq_wait(path->recv_taskq);
4907c478bd9Sstevel@tonic-gate 
4917c478bd9Sstevel@tonic-gate 			/*
4927c478bd9Sstevel@tonic-gate 			 * The path_importer_disconnect function has to
4937c478bd9Sstevel@tonic-gate 			 * be called after releasing the mutex on the path
4947c478bd9Sstevel@tonic-gate 			 * in order to avoid any recursive mutex enter panics
4957c478bd9Sstevel@tonic-gate 			 */
4967c478bd9Sstevel@tonic-gate 			path_importer_disconnect(path);
4977c478bd9Sstevel@tonic-gate 			DBG_PRINTF((category, RSM_DEBUG,
4987c478bd9Sstevel@tonic-gate 			    "do_deferred_work: success on down\n"));
4997c478bd9Sstevel@tonic-gate 			/*
5007c478bd9Sstevel@tonic-gate 			 * decrement reference count for the path
5017c478bd9Sstevel@tonic-gate 			 * descriptor and signal for synchronization with
5027c478bd9Sstevel@tonic-gate 			 * rsmka_remove_path. PATH_HOLD_NOLOCK was done
5037c478bd9Sstevel@tonic-gate 			 * by rsmka_path_down.
5047c478bd9Sstevel@tonic-gate 			 */
5057c478bd9Sstevel@tonic-gate 			mutex_enter(&path->mutex);
5067c478bd9Sstevel@tonic-gate 
5077c478bd9Sstevel@tonic-gate #ifdef DEBUG
5087c478bd9Sstevel@tonic-gate 			/*
5097c478bd9Sstevel@tonic-gate 			 * Some IPC messages left in the recv_buf,
5107c478bd9Sstevel@tonic-gate 			 * they'll be dropped
5117c478bd9Sstevel@tonic-gate 			 */
5127c478bd9Sstevel@tonic-gate 			if (path->msgbuf_cnt != 0)
5137c478bd9Sstevel@tonic-gate 				cmn_err(CE_NOTE,
5147c478bd9Sstevel@tonic-gate 				    "path=%lx msgbuf_cnt != 0\n",
5157c478bd9Sstevel@tonic-gate 				    (uintptr_t)path);
5167c478bd9Sstevel@tonic-gate #endif
5177c478bd9Sstevel@tonic-gate 
5187c478bd9Sstevel@tonic-gate 			/*
5197c478bd9Sstevel@tonic-gate 			 * Don't want to destroy a send queue when a token
5207c478bd9Sstevel@tonic-gate 			 * has been acquired; so wait 'til the token is
5217c478bd9Sstevel@tonic-gate 			 * no longer referenced (with a cv_wait).
5227c478bd9Sstevel@tonic-gate 			 */
5237c478bd9Sstevel@tonic-gate 			while (path->sendq_token.ref_cnt != 0)
5247c478bd9Sstevel@tonic-gate 				cv_wait(&path->sendq_token.sendq_cv,
5257c478bd9Sstevel@tonic-gate 				    &path->mutex);
5267c478bd9Sstevel@tonic-gate 
5277c478bd9Sstevel@tonic-gate 			sendq_handle = path->sendq_token.rsmpi_sendq_handle;
5287c478bd9Sstevel@tonic-gate 			path->sendq_token.rsmpi_sendq_handle = NULL;
5297c478bd9Sstevel@tonic-gate 
5307c478bd9Sstevel@tonic-gate 			/* destroy the send queue and release the handle */
5317c478bd9Sstevel@tonic-gate 			if (sendq_handle != NULL) {
5327c478bd9Sstevel@tonic-gate 				adapter = path->local_adapter;
5337c478bd9Sstevel@tonic-gate 				adapter->rsmpi_ops->rsm_sendq_destroy(
5347c478bd9Sstevel@tonic-gate 				    sendq_handle);
5357c478bd9Sstevel@tonic-gate 			}
5367c478bd9Sstevel@tonic-gate 
5377c478bd9Sstevel@tonic-gate 			work_token->opcode = 0;
5387c478bd9Sstevel@tonic-gate 			PATH_RELE_NOLOCK(path);
5397c478bd9Sstevel@tonic-gate 			mutex_exit(&path->mutex);
5407c478bd9Sstevel@tonic-gate 			break;
5417c478bd9Sstevel@tonic-gate 		default:
5427c478bd9Sstevel@tonic-gate 			DBG_PRINTF((category, RSM_DEBUG,
5437c478bd9Sstevel@tonic-gate 			    "do_deferred_work: bad work token opcode\n"));
5447c478bd9Sstevel@tonic-gate 			break;
5457c478bd9Sstevel@tonic-gate 		}
5467c478bd9Sstevel@tonic-gate 	}
5477c478bd9Sstevel@tonic-gate 
5487c478bd9Sstevel@tonic-gate exit:
5497c478bd9Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "do_deferred_work done\n"));
5507c478bd9Sstevel@tonic-gate 	/*
5517c478bd9Sstevel@tonic-gate 	 * CALLB_CPR_EXIT does a mutex_exit for
5527c478bd9Sstevel@tonic-gate 	 * the work_queue.work_mutex
5537c478bd9Sstevel@tonic-gate 	 */
5547c478bd9Sstevel@tonic-gate 	CALLB_CPR_EXIT(&cprinfo);
5557c478bd9Sstevel@tonic-gate }
5567c478bd9Sstevel@tonic-gate 
5577c478bd9Sstevel@tonic-gate /*
5587c478bd9Sstevel@tonic-gate  * Work is inserted at the tail of the list and processed from the
5597c478bd9Sstevel@tonic-gate  * head of the list.
5607c478bd9Sstevel@tonic-gate  */
5617c478bd9Sstevel@tonic-gate static void
enqueue_work(work_token_t * token)5627c478bd9Sstevel@tonic-gate enqueue_work(work_token_t *token)
5637c478bd9Sstevel@tonic-gate {
5647c478bd9Sstevel@tonic-gate 	work_token_t	*tail_token;
5657c478bd9Sstevel@tonic-gate 
5667c478bd9Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "enqueue_work enter\n"));
5677c478bd9Sstevel@tonic-gate 
5687c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&work_queue.work_mutex));
5697c478bd9Sstevel@tonic-gate 
5707c478bd9Sstevel@tonic-gate 	token->next = NULL;
5717c478bd9Sstevel@tonic-gate 	if (work_queue.head == NULL) {
5727c478bd9Sstevel@tonic-gate 		work_queue.head = work_queue.tail = token;
5737c478bd9Sstevel@tonic-gate 	} else {
5747c478bd9Sstevel@tonic-gate 		tail_token = work_queue.tail;
5757c478bd9Sstevel@tonic-gate 		work_queue.tail = tail_token->next = token;
5767c478bd9Sstevel@tonic-gate 	}
5777c478bd9Sstevel@tonic-gate 
5787c478bd9Sstevel@tonic-gate 	/* wake up deferred work thread */
5797c478bd9Sstevel@tonic-gate 	cv_signal(&work_queue.work_cv);
5807c478bd9Sstevel@tonic-gate 
5817c478bd9Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "enqueue_work done\n"));
5827c478bd9Sstevel@tonic-gate }
5837c478bd9Sstevel@tonic-gate 
5847c478bd9Sstevel@tonic-gate 
5857c478bd9Sstevel@tonic-gate /*
5867c478bd9Sstevel@tonic-gate  * If the work_token is found on the work queue, the work is cancelled
5877c478bd9Sstevel@tonic-gate  * by removing the token from the work queue.
5887c478bd9Sstevel@tonic-gate  *
5897c478bd9Sstevel@tonic-gate  * Return true if a work_token was found and cancelled, otherwise return false
5907c478bd9Sstevel@tonic-gate  *
5917c478bd9Sstevel@tonic-gate  * enqueue_work increments the path refcnt to make sure that the path doesn't
5927c478bd9Sstevel@tonic-gate  * go away, callers of cancel_work need to decrement the refcnt of the path to
5937c478bd9Sstevel@tonic-gate  * which this work_token belongs if a work_token is found in the work_queue
5947c478bd9Sstevel@tonic-gate  * and cancelled ie. when the return value is B_TRUE.
5957c478bd9Sstevel@tonic-gate  */
5967c478bd9Sstevel@tonic-gate static boolean_t
cancel_work(work_token_t * work_token)5977c478bd9Sstevel@tonic-gate cancel_work(work_token_t *work_token)
5987c478bd9Sstevel@tonic-gate {
5997c478bd9Sstevel@tonic-gate 	work_token_t	*current_token;
6007c478bd9Sstevel@tonic-gate 	work_token_t	*prev_token = NULL;
6017c478bd9Sstevel@tonic-gate 	boolean_t	cancelled = B_FALSE;
6027c478bd9Sstevel@tonic-gate 
6037c478bd9Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "cancel_work enter\n"));
6047c478bd9Sstevel@tonic-gate 
6057c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&work_queue.work_mutex));
6067c478bd9Sstevel@tonic-gate 
6077c478bd9Sstevel@tonic-gate 
6087c478bd9Sstevel@tonic-gate 	current_token = work_queue.head;
6097c478bd9Sstevel@tonic-gate 	while (current_token != NULL) {
6107c478bd9Sstevel@tonic-gate 		if (current_token == work_token) {
6117c478bd9Sstevel@tonic-gate 			if (work_token == work_queue.head)
6127c478bd9Sstevel@tonic-gate 				work_queue.head = work_token->next;
6137c478bd9Sstevel@tonic-gate 			else
6147c478bd9Sstevel@tonic-gate 				prev_token->next = work_token->next;
6157c478bd9Sstevel@tonic-gate 			if (work_token == work_queue.tail)
6167c478bd9Sstevel@tonic-gate 				work_queue.tail = prev_token;
6177c478bd9Sstevel@tonic-gate 
6187c478bd9Sstevel@tonic-gate 			current_token->opcode = 0;
6197c478bd9Sstevel@tonic-gate 			current_token->next = NULL;
6207c478bd9Sstevel@tonic-gate 			/* found and cancelled work */
6217c478bd9Sstevel@tonic-gate 			cancelled = B_TRUE;
6227c478bd9Sstevel@tonic-gate 			DBG_PRINTF((category, RSM_DEBUG,
6237c478bd9Sstevel@tonic-gate 			    "cancelled_work = 0x%p\n", work_token));
6247c478bd9Sstevel@tonic-gate 			break;
6257c478bd9Sstevel@tonic-gate 		}
6267c478bd9Sstevel@tonic-gate 		prev_token = current_token;
6277c478bd9Sstevel@tonic-gate 		current_token = current_token->next;
6287c478bd9Sstevel@tonic-gate 	}
6297c478bd9Sstevel@tonic-gate 
6307c478bd9Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "cancel_work done\n"));
6317c478bd9Sstevel@tonic-gate 	return (cancelled);
6327c478bd9Sstevel@tonic-gate }
6337c478bd9Sstevel@tonic-gate 
6347c478bd9Sstevel@tonic-gate /*
6357c478bd9Sstevel@tonic-gate  * EXTERNAL INTERFACES
6367c478bd9Sstevel@tonic-gate  *
6377c478bd9Sstevel@tonic-gate  * For Galileo Clustering, these routine are called from
6387c478bd9Sstevel@tonic-gate  * rsmka_pm_interface.cc
6397c478bd9Sstevel@tonic-gate  *
6407c478bd9Sstevel@tonic-gate  */
6417c478bd9Sstevel@tonic-gate 
6427c478bd9Sstevel@tonic-gate /*
6437c478bd9Sstevel@tonic-gate  *
6447c478bd9Sstevel@tonic-gate  * If the adapter is supported by rsmpi then initialize an adapter descriptor
6457c478bd9Sstevel@tonic-gate  * and link it to the list of adapters.  The adapter attributes are obtained
6467c478bd9Sstevel@tonic-gate  * from rsmpi and stored in the descriptor.  Finally, a service handler
6477c478bd9Sstevel@tonic-gate  * for incoming ipc on this adapter is registered with rsmpi.
6487c478bd9Sstevel@tonic-gate  * A pointer for the adapter descriptor is returned as a cookie to the
6497c478bd9Sstevel@tonic-gate  * caller.  The cookie may be use with subsequent calls to save the time of
6507c478bd9Sstevel@tonic-gate  * adapter descriptor lookup.
6517c478bd9Sstevel@tonic-gate  *
6527c478bd9Sstevel@tonic-gate  * The adapter descriptor maintains a reference count which is intialized
6537c478bd9Sstevel@tonic-gate  * to 1 and incremented on lookups; when a cookie is used in place of
6547c478bd9Sstevel@tonic-gate  * a lookup, an explicit ADAPTER_HOLD is required.
6557c478bd9Sstevel@tonic-gate  */
6567c478bd9Sstevel@tonic-gate 
6577c478bd9Sstevel@tonic-gate void *
rsmka_add_adapter(char * name,int instance,rsm_addr_t hwaddr)6587c478bd9Sstevel@tonic-gate rsmka_add_adapter(char *name, int instance, rsm_addr_t hwaddr)
6597c478bd9Sstevel@tonic-gate {
6607c478bd9Sstevel@tonic-gate 	adapter_t		*adapter;
6617c478bd9Sstevel@tonic-gate 	rsm_controller_object_t	rsmpi_adapter_object;
6627c478bd9Sstevel@tonic-gate 	rsm_controller_handle_t	rsmpi_adapter_handle;
6637c478bd9Sstevel@tonic-gate 	rsm_ops_t		*rsmpi_ops_vector;
6647c478bd9Sstevel@tonic-gate 	int			adapter_is_supported;
6657c478bd9Sstevel@tonic-gate 	rsm_controller_attr_t	*attr;
6667c478bd9Sstevel@tonic-gate 	srv_handler_arg_t	*srv_hdlr_argp;
6677c478bd9Sstevel@tonic-gate 	int result;
6687c478bd9Sstevel@tonic-gate 
6697c478bd9Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmka_add_adapter enter\n"));
6707c478bd9Sstevel@tonic-gate 
6717c478bd9Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG,
6727c478bd9Sstevel@tonic-gate 	    "rsmka_add_adapter: name = %s instance = %d hwaddr = %llx \n",
6737c478bd9Sstevel@tonic-gate 	    name, instance, hwaddr));
6747c478bd9Sstevel@tonic-gate 
6757c478bd9Sstevel@tonic-gate 	/* verify name length */
6767c478bd9Sstevel@tonic-gate 	if (strlen(name) >= MAXNAMELEN) {
6777c478bd9Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
6787c478bd9Sstevel@tonic-gate 		    "rsmka_add_adapter done: name too long\n"));
6797c478bd9Sstevel@tonic-gate 		return (NULL);
6807c478bd9Sstevel@tonic-gate 	}
6817c478bd9Sstevel@tonic-gate 
6827c478bd9Sstevel@tonic-gate 
6837c478bd9Sstevel@tonic-gate 	/* Check if rsmpi supports this adapter type */
6847c478bd9Sstevel@tonic-gate 	adapter_is_supported = rsm_get_controller(name, instance,
6857c478bd9Sstevel@tonic-gate 	    &rsmpi_adapter_object, RSM_VERSION);
6867c478bd9Sstevel@tonic-gate 
6877c478bd9Sstevel@tonic-gate 	if (adapter_is_supported != RSM_SUCCESS) {
6887c478bd9Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_ERR,
6897c478bd9Sstevel@tonic-gate 		    "rsmka_add_adapter done: adapter not supported\n"));
6907c478bd9Sstevel@tonic-gate 		return (NULL);
6917c478bd9Sstevel@tonic-gate 	}
6927c478bd9Sstevel@tonic-gate 
6937c478bd9Sstevel@tonic-gate 	rsmpi_adapter_handle = rsmpi_adapter_object.handle;
6947c478bd9Sstevel@tonic-gate 	rsmpi_ops_vector = rsmpi_adapter_object.ops;
6957c478bd9Sstevel@tonic-gate 
6967c478bd9Sstevel@tonic-gate 	/* Get adapter attributes */
6977c478bd9Sstevel@tonic-gate 	result = rsm_get_controller_attr(rsmpi_adapter_handle, &attr);
6987c478bd9Sstevel@tonic-gate 	if (result != RSM_SUCCESS) {
6997c478bd9Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_ERR,
7007c478bd9Sstevel@tonic-gate 		    "rsm: get_controller_attr(%d) Failed %x\n",
7017c478bd9Sstevel@tonic-gate 		    instance, result));
7027c478bd9Sstevel@tonic-gate 		(void) rsm_release_controller(name, instance,
7037c478bd9Sstevel@tonic-gate 		    &rsmpi_adapter_object);
7047c478bd9Sstevel@tonic-gate 		return (NULL);
7057c478bd9Sstevel@tonic-gate 	}
7067c478bd9Sstevel@tonic-gate 
7077c478bd9Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG,
7087c478bd9Sstevel@tonic-gate 	    "rsmka_add_adapter: register service offset = %d\n", hwaddr));
7097c478bd9Sstevel@tonic-gate 
7107c478bd9Sstevel@tonic-gate 	/*
7117c478bd9Sstevel@tonic-gate 	 * create a srv_handler_arg_t object, initialize it and register
7127c478bd9Sstevel@tonic-gate 	 * it along with rsm_srv_func. This get passed as the
7137c478bd9Sstevel@tonic-gate 	 * rsm_intr_hand_arg_t when the handler gets invoked.
7147c478bd9Sstevel@tonic-gate 	 */
7157c478bd9Sstevel@tonic-gate 	srv_hdlr_argp = kmem_zalloc(sizeof (srv_handler_arg_t), KM_SLEEP);
7167c478bd9Sstevel@tonic-gate 
7177c478bd9Sstevel@tonic-gate 	(void) strcpy(srv_hdlr_argp->adapter_name, name);
7187c478bd9Sstevel@tonic-gate 	srv_hdlr_argp->adapter_instance = instance;
7197c478bd9Sstevel@tonic-gate 	srv_hdlr_argp->adapter_hwaddr = hwaddr;
7207c478bd9Sstevel@tonic-gate 
7217c478bd9Sstevel@tonic-gate 	/* Have rsmpi register the ipc receive handler for this adapter */
7227c478bd9Sstevel@tonic-gate 	/*
7237c478bd9Sstevel@tonic-gate 	 * Currently, we need to pass in a separate service identifier for
7247c478bd9Sstevel@tonic-gate 	 * each adapter. In order to obtain a unique service identifier
7257c478bd9Sstevel@tonic-gate 	 * value for an adapter, we add the hardware address of the
7267c478bd9Sstevel@tonic-gate 	 * adapter to the base service identifier(RSM_SERVICE which is
7277c478bd9Sstevel@tonic-gate 	 * defined as RSM_INTR_T_KA as per the RSMPI specification).
7287c478bd9Sstevel@tonic-gate 	 * NOTE: This may result in using some of the service identifier
7297c478bd9Sstevel@tonic-gate 	 * values defined for RSM_INTR_T_XPORT(the Sun Cluster Transport).
7307c478bd9Sstevel@tonic-gate 	 */
7317c478bd9Sstevel@tonic-gate 	result = rsmpi_ops_vector->rsm_register_handler(
7327c478bd9Sstevel@tonic-gate 	    rsmpi_adapter_handle, &rsmpi_adapter_object,
7337c478bd9Sstevel@tonic-gate 	    RSM_SERVICE+(uint_t)hwaddr, rsm_srv_func,
7347c478bd9Sstevel@tonic-gate 	    (rsm_intr_hand_arg_t)srv_hdlr_argp, NULL, 0);
7357c478bd9Sstevel@tonic-gate 
7367c478bd9Sstevel@tonic-gate 	if (result != RSM_SUCCESS) {
7377c478bd9Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_ERR,
7387c478bd9Sstevel@tonic-gate 		    "rsmka_add_adapter done: rsm_register_handler"
7397c478bd9Sstevel@tonic-gate 		    "failed %d\n",
7407c478bd9Sstevel@tonic-gate 		    instance));
7417c478bd9Sstevel@tonic-gate 		return (NULL);
7427c478bd9Sstevel@tonic-gate 	}
7437c478bd9Sstevel@tonic-gate 
7447c478bd9Sstevel@tonic-gate 	/* Initialize an adapter descriptor and add it to the adapter list */
7457c478bd9Sstevel@tonic-gate 	adapter = init_adapter(name, instance, hwaddr,
7467c478bd9Sstevel@tonic-gate 	    rsmpi_adapter_handle, rsmpi_ops_vector, srv_hdlr_argp);
7477c478bd9Sstevel@tonic-gate 
7487c478bd9Sstevel@tonic-gate 	/* Copy over the attributes from the pointer returned to us */
7497c478bd9Sstevel@tonic-gate 	adapter->rsm_attr = *attr;
7507c478bd9Sstevel@tonic-gate 
7517c478bd9Sstevel@tonic-gate 	/*
7527c478bd9Sstevel@tonic-gate 	 * With the addition of the topology obtainment interface, applications
7537c478bd9Sstevel@tonic-gate 	 * now get the local nodeid from the topology data structure.
7547c478bd9Sstevel@tonic-gate 	 *
7557c478bd9Sstevel@tonic-gate 	 * adapter->rsm_attr.attr_node_id = my_nodeid;
7567c478bd9Sstevel@tonic-gate 	 */
7577c478bd9Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_ERR,
7587c478bd9Sstevel@tonic-gate 	    "rsmka_add_adapter: adapter = %lx\n", adapter));
7597c478bd9Sstevel@tonic-gate 
7607c478bd9Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmka_add_adapter done\n"));
7617c478bd9Sstevel@tonic-gate 
7627c478bd9Sstevel@tonic-gate 	/* return adapter pointer as a cookie for later fast access */
7637c478bd9Sstevel@tonic-gate 	return ((void *)adapter);
7647c478bd9Sstevel@tonic-gate }
7657c478bd9Sstevel@tonic-gate 
7667c478bd9Sstevel@tonic-gate 
7677c478bd9Sstevel@tonic-gate /*
7687c478bd9Sstevel@tonic-gate  * Unlink the adapter descriptor and call rsmka_release_adapter which
7697c478bd9Sstevel@tonic-gate  * will decrement the reference count and possibly free the desriptor.
7707c478bd9Sstevel@tonic-gate  */
7717c478bd9Sstevel@tonic-gate boolean_t
rsmka_remove_adapter(char * name,uint_t instance,void * cookie,int flags)7727c478bd9Sstevel@tonic-gate rsmka_remove_adapter(char *name, uint_t instance, void *cookie, int flags)
7737c478bd9Sstevel@tonic-gate {
7747c478bd9Sstevel@tonic-gate 	adapter_t		*adapter;
7757c478bd9Sstevel@tonic-gate 	adapter_listhead_t	*listhead;
7767c478bd9Sstevel@tonic-gate 	adapter_t		*prev, *current;
7777c478bd9Sstevel@tonic-gate 	rsm_controller_object_t	rsm_cntl_obj;
7787c478bd9Sstevel@tonic-gate 
7797c478bd9Sstevel@tonic-gate 
7807c478bd9Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
7817c478bd9Sstevel@tonic-gate 	    "rsmka_remove_adapter enter\n"));
7827c478bd9Sstevel@tonic-gate 
7837c478bd9Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
7847c478bd9Sstevel@tonic-gate 	    "rsmka_remove_adapter: cookie = %lx\n", cookie));
7857c478bd9Sstevel@tonic-gate 
7867c478bd9Sstevel@tonic-gate 	if (flags & RSMKA_USE_COOKIE) {
7877c478bd9Sstevel@tonic-gate 		adapter = (adapter_t *)cookie;
7887c478bd9Sstevel@tonic-gate 	} else {
7897c478bd9Sstevel@tonic-gate 		adapter = rsmka_lookup_adapter(name, instance);
7907c478bd9Sstevel@tonic-gate 		/*
7917c478bd9Sstevel@tonic-gate 		 * rsmka_lookup_adapter increments the ref_cnt; need
7927c478bd9Sstevel@tonic-gate 		 * to decrement here to get true count
7937c478bd9Sstevel@tonic-gate 		 */
7947c478bd9Sstevel@tonic-gate 		ADAPTER_RELE(adapter);
7957c478bd9Sstevel@tonic-gate 	}
7967c478bd9Sstevel@tonic-gate 	ASSERT(adapter->next_path == NULL);
7977c478bd9Sstevel@tonic-gate 
7987c478bd9Sstevel@tonic-gate 	listhead = adapter->listhead;
7997c478bd9Sstevel@tonic-gate 
8007c478bd9Sstevel@tonic-gate 	mutex_enter(&adapter_listhead_base.listlock);
8017c478bd9Sstevel@tonic-gate 
8027c478bd9Sstevel@tonic-gate 	mutex_enter(&listhead->mutex);
8037c478bd9Sstevel@tonic-gate 
8047c478bd9Sstevel@tonic-gate 	/* find the adapter in the list and remove it */
8057c478bd9Sstevel@tonic-gate 	prev = NULL;
8067c478bd9Sstevel@tonic-gate 	current = listhead->next_adapter;
8077c478bd9Sstevel@tonic-gate 	while (current != NULL) {
8087c478bd9Sstevel@tonic-gate 		if (adapter->instance == current->instance) {
8097c478bd9Sstevel@tonic-gate 			break;
8107c478bd9Sstevel@tonic-gate 		} else {
8117c478bd9Sstevel@tonic-gate 			prev = current;
8127c478bd9Sstevel@tonic-gate 			current = current->next;
8137c478bd9Sstevel@tonic-gate 		}
8147c478bd9Sstevel@tonic-gate 	}
8157c478bd9Sstevel@tonic-gate 	ASSERT(current != NULL);
8167c478bd9Sstevel@tonic-gate 
8177c478bd9Sstevel@tonic-gate 	if (prev == NULL)
8187c478bd9Sstevel@tonic-gate 		listhead->next_adapter = current->next;
8197c478bd9Sstevel@tonic-gate 	else
8207c478bd9Sstevel@tonic-gate 		prev->next = current->next;
8217c478bd9Sstevel@tonic-gate 
8227c478bd9Sstevel@tonic-gate 	listhead->adapter_count--;
8237c478bd9Sstevel@tonic-gate 
8247c478bd9Sstevel@tonic-gate 	mutex_exit(&listhead->mutex);
8257c478bd9Sstevel@tonic-gate 
8267c478bd9Sstevel@tonic-gate 	mutex_exit(&adapter_listhead_base.listlock);
8277c478bd9Sstevel@tonic-gate 
8287c478bd9Sstevel@tonic-gate 	mutex_enter(&current->mutex);
8297c478bd9Sstevel@tonic-gate 
8307c478bd9Sstevel@tonic-gate 	/*
8317c478bd9Sstevel@tonic-gate 	 * unregister the handler
8327c478bd9Sstevel@tonic-gate 	 */
8337c478bd9Sstevel@tonic-gate 	current->rsmpi_ops->rsm_unregister_handler(current->rsmpi_handle,
8347c478bd9Sstevel@tonic-gate 	    RSM_SERVICE+current->hwaddr, rsm_srv_func,
8357c478bd9Sstevel@tonic-gate 	    (rsm_intr_hand_arg_t)current->hdlr_argp);
8367c478bd9Sstevel@tonic-gate 
8377c478bd9Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG, "rsmka_remove_adapter: unreg hdlr "
8387c478bd9Sstevel@tonic-gate 	    ":adapter=%lx, hwaddr=%lx\n", current, current->hwaddr));
8397c478bd9Sstevel@tonic-gate 
8407c478bd9Sstevel@tonic-gate 	rsm_cntl_obj.handle = current->rsmpi_handle;
8417c478bd9Sstevel@tonic-gate 	rsm_cntl_obj.ops = current->rsmpi_ops;
8427c478bd9Sstevel@tonic-gate 
8437c478bd9Sstevel@tonic-gate 	(void) rsm_release_controller(current->listhead->adapter_devname,
8447c478bd9Sstevel@tonic-gate 	    current->instance, &rsm_cntl_obj);
8457c478bd9Sstevel@tonic-gate 
8467c478bd9Sstevel@tonic-gate 	mutex_exit(&current->mutex);
8477c478bd9Sstevel@tonic-gate 
8487c478bd9Sstevel@tonic-gate 	rsmka_release_adapter(current);
8497c478bd9Sstevel@tonic-gate 
8507c478bd9Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
8517c478bd9Sstevel@tonic-gate 	    "rsmka_remove_adapter done\n"));
8527c478bd9Sstevel@tonic-gate 
8537c478bd9Sstevel@tonic-gate 	return (B_TRUE);
8547c478bd9Sstevel@tonic-gate }
8557c478bd9Sstevel@tonic-gate 
8567c478bd9Sstevel@tonic-gate /*
8577c478bd9Sstevel@tonic-gate  * An adapter descriptor will exist from an earlier add_adapter. This
8587c478bd9Sstevel@tonic-gate  * function does:
8597c478bd9Sstevel@tonic-gate  *		initialize the path descriptor
8607c478bd9Sstevel@tonic-gate  *		initialize the ipc descriptor (it may already exist)
8617c478bd9Sstevel@tonic-gate  *		initialize and link a sendq token for this path
8627c478bd9Sstevel@tonic-gate  */
8637c478bd9Sstevel@tonic-gate void *
rsmka_add_path(char * adapter_name,int adapter_instance,rsm_node_id_t remote_node,rsm_addr_t remote_hwaddr,int rem_adapt_instance,void * cookie,int flags)8647c478bd9Sstevel@tonic-gate rsmka_add_path(char *adapter_name, int adapter_instance,
8657c478bd9Sstevel@tonic-gate     rsm_node_id_t remote_node,
8667c478bd9Sstevel@tonic-gate     rsm_addr_t remote_hwaddr, int rem_adapt_instance,
8677c478bd9Sstevel@tonic-gate     void *cookie, int flags)
8687c478bd9Sstevel@tonic-gate {
8697c478bd9Sstevel@tonic-gate 
8707c478bd9Sstevel@tonic-gate 	path_t			*path;
8717c478bd9Sstevel@tonic-gate 	adapter_t		*adapter;
8727c478bd9Sstevel@tonic-gate 	char			tq_name[TASKQ_NAMELEN];
8737c478bd9Sstevel@tonic-gate 
8747c478bd9Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmka_add_path enter\n"));
8757c478bd9Sstevel@tonic-gate 
8767c478bd9Sstevel@tonic-gate 	/* allocate new path descriptor */
8777c478bd9Sstevel@tonic-gate 	path = kmem_zalloc(sizeof (path_t), KM_SLEEP);
8787c478bd9Sstevel@tonic-gate 
8797c478bd9Sstevel@tonic-gate 	if (flags & RSMKA_USE_COOKIE) {
8807c478bd9Sstevel@tonic-gate 		adapter = (adapter_t *)cookie;
8817c478bd9Sstevel@tonic-gate 		ADAPTER_HOLD(adapter);
8827c478bd9Sstevel@tonic-gate 	} else {
8837c478bd9Sstevel@tonic-gate 		adapter = rsmka_lookup_adapter(adapter_name, adapter_instance);
8847c478bd9Sstevel@tonic-gate 	}
8857c478bd9Sstevel@tonic-gate 
8867c478bd9Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG,
8877c478bd9Sstevel@tonic-gate 	    "rsmka_add_path: adapter = %lx\n", adapter));
8887c478bd9Sstevel@tonic-gate 
8897c478bd9Sstevel@tonic-gate 	/*
8907c478bd9Sstevel@tonic-gate 	 * initialize path descriptor
8917c478bd9Sstevel@tonic-gate 	 * don't need to increment adapter reference count because
8927c478bd9Sstevel@tonic-gate 	 * it can't be removed if paths exist for it.
8937c478bd9Sstevel@tonic-gate 	 */
8947c478bd9Sstevel@tonic-gate 	mutex_init(&path->mutex, NULL, MUTEX_DEFAULT, NULL);
8957c478bd9Sstevel@tonic-gate 
8967c478bd9Sstevel@tonic-gate 	PATH_HOLD(path);
8977c478bd9Sstevel@tonic-gate 	path->state = RSMKA_PATH_DOWN;
8987c478bd9Sstevel@tonic-gate 	path->remote_node = remote_node;
8997c478bd9Sstevel@tonic-gate 	path->remote_hwaddr = remote_hwaddr;
9007c478bd9Sstevel@tonic-gate 	path->remote_devinst = rem_adapt_instance;
9017c478bd9Sstevel@tonic-gate 	path->local_adapter = adapter;
9027c478bd9Sstevel@tonic-gate 
9037c478bd9Sstevel@tonic-gate 	/* taskq is for sendq on adapter with remote_hwaddr on remote_node */
9047c478bd9Sstevel@tonic-gate 	(void) snprintf(tq_name, sizeof (tq_name), "%x_%llx",
9057c478bd9Sstevel@tonic-gate 	    remote_node, (unsigned long long) remote_hwaddr);
9067c478bd9Sstevel@tonic-gate 
9077c478bd9Sstevel@tonic-gate 	path->recv_taskq = taskq_create_instance(tq_name, adapter_instance,
9087c478bd9Sstevel@tonic-gate 	    RSMKA_ONE_THREAD, maxclsyspri, RSMIPC_MAX_MESSAGES,
9097c478bd9Sstevel@tonic-gate 	    RSMIPC_MAX_MESSAGES, TASKQ_PREPOPULATE);
9107c478bd9Sstevel@tonic-gate 
9117c478bd9Sstevel@tonic-gate 	/* allocate the message buffer array */
9127c478bd9Sstevel@tonic-gate 	path->msgbuf_queue = (msgbuf_elem_t *)kmem_zalloc(
9137c478bd9Sstevel@tonic-gate 	    RSMIPC_MAX_MESSAGES * sizeof (msgbuf_elem_t), KM_SLEEP);
9147c478bd9Sstevel@tonic-gate 
9157c478bd9Sstevel@tonic-gate 	/*
9167c478bd9Sstevel@tonic-gate 	 * init cond variables for synch with rsmipc_send()
9177c478bd9Sstevel@tonic-gate 	 * and rsmka_remove_path
9187c478bd9Sstevel@tonic-gate 	 */
9197c478bd9Sstevel@tonic-gate 	cv_init(&path->sendq_token.sendq_cv, NULL, CV_DEFAULT, NULL);
9207c478bd9Sstevel@tonic-gate 	cv_init(&path->hold_cv, NULL, CV_DEFAULT, NULL);
9217c478bd9Sstevel@tonic-gate 
9227c478bd9Sstevel@tonic-gate 	/* link path descriptor on adapter path list */
9237c478bd9Sstevel@tonic-gate 	link_path(path);
9247c478bd9Sstevel@tonic-gate 
9257c478bd9Sstevel@tonic-gate 	/* link the path sendq token on the ipc_info token list */
9267c478bd9Sstevel@tonic-gate 	link_sendq_token(&path->sendq_token, remote_node);
9277c478bd9Sstevel@tonic-gate 
9287c478bd9Sstevel@tonic-gate 	/* ADAPTER_HOLD done above by rsmka_lookup_adapter */
9297c478bd9Sstevel@tonic-gate 	ADAPTER_RELE(adapter);
9307c478bd9Sstevel@tonic-gate 
9317c478bd9Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG, "rsmka_add_path: path = %lx\n", path));
9327c478bd9Sstevel@tonic-gate 
9337c478bd9Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmka_add_path done\n"));
9347c478bd9Sstevel@tonic-gate 	return ((void *)path);
9357c478bd9Sstevel@tonic-gate }
9367c478bd9Sstevel@tonic-gate 
9377c478bd9Sstevel@tonic-gate /*
9387c478bd9Sstevel@tonic-gate  * Wait for the path descriptor reference count to become zero then
9397c478bd9Sstevel@tonic-gate  * directly call path down processing.  Finally, unlink the sendq token and
9407c478bd9Sstevel@tonic-gate  * free the path descriptor memory.
9417c478bd9Sstevel@tonic-gate  *
9427c478bd9Sstevel@tonic-gate  * Note: lookup_path locks the path and increments the path hold count
9437c478bd9Sstevel@tonic-gate  */
9447c478bd9Sstevel@tonic-gate void
rsmka_remove_path(char * adapter_name,int instance,rsm_node_id_t remote_node,rsm_addr_t remote_hwaddr,void * path_cookie,int flags)9457c478bd9Sstevel@tonic-gate rsmka_remove_path(char *adapter_name, int instance, rsm_node_id_t remote_node,
9467c478bd9Sstevel@tonic-gate     rsm_addr_t remote_hwaddr, void *path_cookie, int flags)
9477c478bd9Sstevel@tonic-gate {
9487c478bd9Sstevel@tonic-gate 	path_t		*path;
9497c478bd9Sstevel@tonic-gate 
9507c478bd9Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmka_remove_path enter\n"));
9517c478bd9Sstevel@tonic-gate 
9527c478bd9Sstevel@tonic-gate 	if (flags & RSMKA_USE_COOKIE) {
9537c478bd9Sstevel@tonic-gate 		path = (path_t *)path_cookie;
9547c478bd9Sstevel@tonic-gate 		mutex_enter(&path->mutex);
9557c478bd9Sstevel@tonic-gate 	} else {
9567c478bd9Sstevel@tonic-gate 		path = lookup_path(adapter_name, instance,  remote_node,
9577c478bd9Sstevel@tonic-gate 		    remote_hwaddr);
9587c478bd9Sstevel@tonic-gate 
9597c478bd9Sstevel@tonic-gate 		/*
9607c478bd9Sstevel@tonic-gate 		 * remember, lookup_path increments the reference
9617c478bd9Sstevel@tonic-gate 		 * count - so decrement now so we can get to zero
9627c478bd9Sstevel@tonic-gate 		 */
9637c478bd9Sstevel@tonic-gate 		PATH_RELE_NOLOCK(path);
9647c478bd9Sstevel@tonic-gate 	}
9657c478bd9Sstevel@tonic-gate 
9667c478bd9Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG,
9677c478bd9Sstevel@tonic-gate 	    "rsmka_remove_path: path = %lx\n", path));
9687c478bd9Sstevel@tonic-gate 
9697c478bd9Sstevel@tonic-gate 	while (path->state == RSMKA_PATH_GOING_DOWN)
9707c478bd9Sstevel@tonic-gate 		cv_wait(&path->hold_cv, &path->mutex);
9717c478bd9Sstevel@tonic-gate 
9727c478bd9Sstevel@tonic-gate 	/* attempt to cancel any possibly pending work */
9737c478bd9Sstevel@tonic-gate 	mutex_enter(&work_queue.work_mutex);
9747c478bd9Sstevel@tonic-gate 	if (cancel_work(&path->work_token[RSMKA_IPC_UP_INDEX])) {
9757c478bd9Sstevel@tonic-gate 		PATH_RELE_NOLOCK(path);
9767c478bd9Sstevel@tonic-gate 	}
9777c478bd9Sstevel@tonic-gate 	if (cancel_work(&path->work_token[RSMKA_IPC_DOWN_INDEX])) {
9787c478bd9Sstevel@tonic-gate 		PATH_RELE_NOLOCK(path);
9797c478bd9Sstevel@tonic-gate 	}
9807c478bd9Sstevel@tonic-gate 	mutex_exit(&work_queue.work_mutex);
9817c478bd9Sstevel@tonic-gate 
9827c478bd9Sstevel@tonic-gate 	/*
9837c478bd9Sstevel@tonic-gate 	 * The path descriptor ref cnt was set to 1 initially when
9847c478bd9Sstevel@tonic-gate 	 * the path was added.  So we need to do a decrement here to
9857c478bd9Sstevel@tonic-gate 	 * balance that.
9867c478bd9Sstevel@tonic-gate 	 */
9877c478bd9Sstevel@tonic-gate 	PATH_RELE_NOLOCK(path);
9887c478bd9Sstevel@tonic-gate 
9897c478bd9Sstevel@tonic-gate 	switch (path->state) {
9907c478bd9Sstevel@tonic-gate 	case RSMKA_PATH_UP:
9917c478bd9Sstevel@tonic-gate 		/* clear the flag */
9927c478bd9Sstevel@tonic-gate 		path->flags &= ~RSMKA_SQCREATE_PENDING;
9937c478bd9Sstevel@tonic-gate 		path->state = RSMKA_PATH_DOWN;
9947c478bd9Sstevel@tonic-gate 		break;
9957c478bd9Sstevel@tonic-gate 	case RSMKA_PATH_DOWN:
9967c478bd9Sstevel@tonic-gate 		break;
9977c478bd9Sstevel@tonic-gate 
9987c478bd9Sstevel@tonic-gate 	case RSMKA_PATH_ACTIVE:
9997c478bd9Sstevel@tonic-gate 		/*
10007c478bd9Sstevel@tonic-gate 		 * rsmka_remove_path should not call do_path_down
10017c478bd9Sstevel@tonic-gate 		 * with the RSMKA_NO_SLEEP flag set since for
10027c478bd9Sstevel@tonic-gate 		 * this code path, the deferred work would
10037c478bd9Sstevel@tonic-gate 		 * incorrectly do a PATH_RELE_NOLOCK.
10047c478bd9Sstevel@tonic-gate 		 */
10057c478bd9Sstevel@tonic-gate 		do_path_down(path, 0);
10067c478bd9Sstevel@tonic-gate 		break;
10077c478bd9Sstevel@tonic-gate 	default:
10087c478bd9Sstevel@tonic-gate 		mutex_exit(&path->mutex);
10097c478bd9Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_ERR,
10107c478bd9Sstevel@tonic-gate 		    "rsm_remove_path: invalid path state %d\n",
10117c478bd9Sstevel@tonic-gate 		    path->state));
10127c478bd9Sstevel@tonic-gate 		return;
10137c478bd9Sstevel@tonic-gate 
10147c478bd9Sstevel@tonic-gate 	}
10157c478bd9Sstevel@tonic-gate 
10167c478bd9Sstevel@tonic-gate 	/*
10177c478bd9Sstevel@tonic-gate 	 * wait for all references to the path to be released. If a thread
10187c478bd9Sstevel@tonic-gate 	 * was waiting to receive credits do_path_down should wake it up
10197c478bd9Sstevel@tonic-gate 	 * since the path is going down and that will cause the sleeping
10207c478bd9Sstevel@tonic-gate 	 * thread to release its hold on the path.
10217c478bd9Sstevel@tonic-gate 	 */
10227c478bd9Sstevel@tonic-gate 	while (path->ref_cnt != 0) {
10237c478bd9Sstevel@tonic-gate 		cv_wait(&path->hold_cv, &path->mutex);
10247c478bd9Sstevel@tonic-gate 	}
10257c478bd9Sstevel@tonic-gate 
10267c478bd9Sstevel@tonic-gate 	mutex_exit(&path->mutex);
10277c478bd9Sstevel@tonic-gate 
10287c478bd9Sstevel@tonic-gate 	/*
10297c478bd9Sstevel@tonic-gate 	 * remove from ipc token list
10307c478bd9Sstevel@tonic-gate 	 * NOTE: use the remote_node value from the path structure
10317c478bd9Sstevel@tonic-gate 	 * since for RSMKA_USE_COOKIE being set, the remote_node
10327c478bd9Sstevel@tonic-gate 	 * value passed into rsmka_remove_path is 0.
10337c478bd9Sstevel@tonic-gate 	 */
10347c478bd9Sstevel@tonic-gate 	unlink_sendq_token(&path->sendq_token, path->remote_node);
10357c478bd9Sstevel@tonic-gate 
10367c478bd9Sstevel@tonic-gate 	/* unlink from adapter path list and free path descriptor */
10377c478bd9Sstevel@tonic-gate 	destroy_path(path);
10387c478bd9Sstevel@tonic-gate 
10397c478bd9Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmka_remove_path done\n"));
10407c478bd9Sstevel@tonic-gate }
10417c478bd9Sstevel@tonic-gate 
10427c478bd9Sstevel@tonic-gate /*
10437c478bd9Sstevel@tonic-gate  *
10447c478bd9Sstevel@tonic-gate  * LOCKING:
10457c478bd9Sstevel@tonic-gate  * lookup_path locks the path and increments the path hold count. If the remote
10467c478bd9Sstevel@tonic-gate  * node is not in the alive state, do_path_up will release the lock and
10477c478bd9Sstevel@tonic-gate  * decrement the hold count.  Otherwise rsmka_do_path_active will release the
10487c478bd9Sstevel@tonic-gate  * lock prior to waking up the work thread.
10497c478bd9Sstevel@tonic-gate  *
10507c478bd9Sstevel@tonic-gate  * REF_CNT:
10517c478bd9Sstevel@tonic-gate  * The path descriptor ref_cnt is incremented here; it will be decremented
10527c478bd9Sstevel@tonic-gate  * when path up processing is completed in do_path_up or by the work thread
10537c478bd9Sstevel@tonic-gate  * if the path up is deferred.
10547c478bd9Sstevel@tonic-gate  *
10557c478bd9Sstevel@tonic-gate  */
10567c478bd9Sstevel@tonic-gate boolean_t
rsmka_path_up(char * adapter_name,uint_t adapter_instance,rsm_node_id_t remote_node,rsm_addr_t remote_hwaddr,void * path_cookie,int flags)10577c478bd9Sstevel@tonic-gate rsmka_path_up(char *adapter_name, uint_t adapter_instance,
10587c478bd9Sstevel@tonic-gate     rsm_node_id_t remote_node, rsm_addr_t remote_hwaddr,
10597c478bd9Sstevel@tonic-gate     void *path_cookie, int flags)
10607c478bd9Sstevel@tonic-gate {
10617c478bd9Sstevel@tonic-gate 
10627c478bd9Sstevel@tonic-gate 	path_t			*path;
10637c478bd9Sstevel@tonic-gate 	boolean_t		rval = B_TRUE;
10647c478bd9Sstevel@tonic-gate 
10657c478bd9Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmka_path_up enter\n"));
10667c478bd9Sstevel@tonic-gate 
10677c478bd9Sstevel@tonic-gate 	if (flags & RSMKA_USE_COOKIE) {
10687c478bd9Sstevel@tonic-gate 		path = (path_t *)path_cookie;
10697c478bd9Sstevel@tonic-gate 		mutex_enter(&path->mutex);
10707c478bd9Sstevel@tonic-gate 		PATH_HOLD_NOLOCK(path);
10717c478bd9Sstevel@tonic-gate 	} else {
10727c478bd9Sstevel@tonic-gate 		path = lookup_path(adapter_name, adapter_instance,
10737c478bd9Sstevel@tonic-gate 		    remote_node, remote_hwaddr);
10747c478bd9Sstevel@tonic-gate 	}
10757c478bd9Sstevel@tonic-gate 
10767c478bd9Sstevel@tonic-gate 	while (path->state == RSMKA_PATH_GOING_DOWN)
10777c478bd9Sstevel@tonic-gate 		cv_wait(&path->hold_cv, &path->mutex);
10787c478bd9Sstevel@tonic-gate 
10797c478bd9Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG, "rsmka_path_up: path = %lx\n", path));
10807c478bd9Sstevel@tonic-gate 	rval = do_path_up(path, flags);
10817c478bd9Sstevel@tonic-gate 	mutex_exit(&path->mutex);
10827c478bd9Sstevel@tonic-gate 
10837c478bd9Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmka_path_up done\n"));
10847c478bd9Sstevel@tonic-gate 	return (rval);
10857c478bd9Sstevel@tonic-gate }
10867c478bd9Sstevel@tonic-gate 
10877c478bd9Sstevel@tonic-gate /*
10887c478bd9Sstevel@tonic-gate  *
10897c478bd9Sstevel@tonic-gate  * LOCKING:
10907c478bd9Sstevel@tonic-gate  * lookup_path locks the path and increments the path hold count. If the
10917c478bd9Sstevel@tonic-gate  * current state is ACTIVE the path lock is release prior to waking up
10927c478bd9Sstevel@tonic-gate  * the work thread in do_path_down .  The work thread will decrement the hold
10937c478bd9Sstevel@tonic-gate  * count when the work for this is finished.
10947c478bd9Sstevel@tonic-gate  *
10957c478bd9Sstevel@tonic-gate  *
10967c478bd9Sstevel@tonic-gate  * REF_CNT:
10977c478bd9Sstevel@tonic-gate  * The path descriptor ref_cnt is incremented here; it will be decremented
10987c478bd9Sstevel@tonic-gate  * when path down processing is completed in do_path_down or by the work thread
10997c478bd9Sstevel@tonic-gate  * if the path down is deferred.
11007c478bd9Sstevel@tonic-gate  *
11017c478bd9Sstevel@tonic-gate  */
11027c478bd9Sstevel@tonic-gate boolean_t
rsmka_path_down(char * adapter_devname,int instance,rsm_node_id_t remote_node,rsm_addr_t remote_hwaddr,void * path_cookie,int flags)11037c478bd9Sstevel@tonic-gate rsmka_path_down(char *adapter_devname, int instance, rsm_node_id_t remote_node,
11047c478bd9Sstevel@tonic-gate     rsm_addr_t remote_hwaddr,  void *path_cookie, int flags)
11057c478bd9Sstevel@tonic-gate {
11067c478bd9Sstevel@tonic-gate 	path_t			*path;
11077c478bd9Sstevel@tonic-gate 	boolean_t		rval = B_TRUE;
11087c478bd9Sstevel@tonic-gate 
11097c478bd9Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmka_path_down enter\n"));
11107c478bd9Sstevel@tonic-gate 
11117c478bd9Sstevel@tonic-gate 	if (flags & RSMKA_USE_COOKIE) {
11127c478bd9Sstevel@tonic-gate 		path = (path_t *)path_cookie;
11137c478bd9Sstevel@tonic-gate 		mutex_enter(&path->mutex);
11147c478bd9Sstevel@tonic-gate 		PATH_HOLD_NOLOCK(path);
11157c478bd9Sstevel@tonic-gate 	} else {
11167c478bd9Sstevel@tonic-gate 		path = lookup_path(adapter_devname, instance, remote_node,
11177c478bd9Sstevel@tonic-gate 		    remote_hwaddr);
11187c478bd9Sstevel@tonic-gate 	}
11197c478bd9Sstevel@tonic-gate 
11207c478bd9Sstevel@tonic-gate 	while (path->state == RSMKA_PATH_GOING_DOWN)
11217c478bd9Sstevel@tonic-gate 		cv_wait(&path->hold_cv, &path->mutex);
11227c478bd9Sstevel@tonic-gate 
11237c478bd9Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG,
11247c478bd9Sstevel@tonic-gate 	    "rsmka_path_down: path = %lx\n", path));
11257c478bd9Sstevel@tonic-gate 
11267c478bd9Sstevel@tonic-gate 	switch (path->state) {
11277c478bd9Sstevel@tonic-gate 	case RSMKA_PATH_UP:
11287c478bd9Sstevel@tonic-gate 		/* clear the flag */
11297c478bd9Sstevel@tonic-gate 		path->flags &= ~RSMKA_SQCREATE_PENDING;
11307c478bd9Sstevel@tonic-gate 		path->state = RSMKA_PATH_GOING_DOWN;
11317c478bd9Sstevel@tonic-gate 		mutex_exit(&path->mutex);
11327c478bd9Sstevel@tonic-gate 
11337c478bd9Sstevel@tonic-gate 		/*
11347c478bd9Sstevel@tonic-gate 		 * release path->mutex since enqueued tasks acquire it.
11357c478bd9Sstevel@tonic-gate 		 * Drain all the enqueued tasks.
11367c478bd9Sstevel@tonic-gate 		 */
11377c478bd9Sstevel@tonic-gate 		taskq_wait(path->recv_taskq);
11387c478bd9Sstevel@tonic-gate 
11397c478bd9Sstevel@tonic-gate 		mutex_enter(&path->mutex);
11407c478bd9Sstevel@tonic-gate 		path->state = RSMKA_PATH_DOWN;
11417c478bd9Sstevel@tonic-gate 		PATH_RELE_NOLOCK(path);
11427c478bd9Sstevel@tonic-gate 		break;
11437c478bd9Sstevel@tonic-gate 	case RSMKA_PATH_DOWN:
11447c478bd9Sstevel@tonic-gate 		PATH_RELE_NOLOCK(path);
11457c478bd9Sstevel@tonic-gate 		break;
11467c478bd9Sstevel@tonic-gate 	case RSMKA_PATH_ACTIVE:
11477c478bd9Sstevel@tonic-gate 		do_path_down(path, flags);
11487c478bd9Sstevel@tonic-gate 		/*
11497c478bd9Sstevel@tonic-gate 		 * Need to release the path refcnt. Either done in do_path_down
11507c478bd9Sstevel@tonic-gate 		 * or do_deferred_work for RSMKA_NO_SLEEP being set. Has to be
11517c478bd9Sstevel@tonic-gate 		 * done here for RSMKA_NO_SLEEP not set.
11527c478bd9Sstevel@tonic-gate 		 */
11537c478bd9Sstevel@tonic-gate 		if (!(flags & RSMKA_NO_SLEEP))
11547c478bd9Sstevel@tonic-gate 			PATH_RELE_NOLOCK(path);
11557c478bd9Sstevel@tonic-gate 		break;
11567c478bd9Sstevel@tonic-gate 	default:
11577c478bd9Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_ERR,
11587c478bd9Sstevel@tonic-gate 		    "rsm_path_down: invalid path state %d\n", path->state));
11597c478bd9Sstevel@tonic-gate 		rval = B_FALSE;
11607c478bd9Sstevel@tonic-gate 	}
11617c478bd9Sstevel@tonic-gate 
11627c478bd9Sstevel@tonic-gate 	mutex_exit(&path->mutex);
11637c478bd9Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmka_path_down done\n"));
11647c478bd9Sstevel@tonic-gate 	return (rval);
11657c478bd9Sstevel@tonic-gate }
11667c478bd9Sstevel@tonic-gate 
11677c478bd9Sstevel@tonic-gate 
11687c478bd9Sstevel@tonic-gate /*
11697c478bd9Sstevel@tonic-gate  * Paths cannot become active until node_is_alive is marked true
11707c478bd9Sstevel@tonic-gate  * in the ipc_info descriptor for the node
11717c478bd9Sstevel@tonic-gate  *
11727c478bd9Sstevel@tonic-gate  * In the event this is called before any paths have been added,
11737c478bd9Sstevel@tonic-gate  * init_ipc_info if called here.
11747c478bd9Sstevel@tonic-gate  *
11757c478bd9Sstevel@tonic-gate  */
11767c478bd9Sstevel@tonic-gate boolean_t
rsmka_node_alive(rsm_node_id_t remote_node)11777c478bd9Sstevel@tonic-gate rsmka_node_alive(rsm_node_id_t remote_node)
11787c478bd9Sstevel@tonic-gate {
11797c478bd9Sstevel@tonic-gate 	ipc_info_t *ipc_info;
11807c478bd9Sstevel@tonic-gate 
11817c478bd9Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmka_node_alive enter\n"));
11827c478bd9Sstevel@tonic-gate 
11837c478bd9Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG,
11847c478bd9Sstevel@tonic-gate 	    "rsmka_node_alive: remote_node = %x\n", remote_node));
11857c478bd9Sstevel@tonic-gate 
11867c478bd9Sstevel@tonic-gate 	ipc_info = lookup_ipc_info(remote_node);
11877c478bd9Sstevel@tonic-gate 
11887c478bd9Sstevel@tonic-gate 	if (ipc_info == NULL) {
11897c478bd9Sstevel@tonic-gate 		ipc_info = init_ipc_info(remote_node, B_TRUE);
11907c478bd9Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_DEBUG,
11917c478bd9Sstevel@tonic-gate 		    "rsmka_node_alive: new ipc_info = %lx\n", ipc_info));
11927c478bd9Sstevel@tonic-gate 	} else {
11937c478bd9Sstevel@tonic-gate 		ASSERT(ipc_info->node_is_alive == B_FALSE);
11947c478bd9Sstevel@tonic-gate 		ipc_info->node_is_alive = B_TRUE;
11957c478bd9Sstevel@tonic-gate 	}
11967c478bd9Sstevel@tonic-gate 
11977c478bd9Sstevel@tonic-gate 	pathup_to_pathactive(ipc_info, remote_node);
11987c478bd9Sstevel@tonic-gate 
11997c478bd9Sstevel@tonic-gate 	mutex_exit(&ipc_info_lock);
12007c478bd9Sstevel@tonic-gate 
12017c478bd9Sstevel@tonic-gate 	/* rsmipc_send() may be waiting for a sendq_token */
12027c478bd9Sstevel@tonic-gate 	mutex_enter(&ipc_info_cvlock);
12037c478bd9Sstevel@tonic-gate 	cv_broadcast(&ipc_info_cv);
12047c478bd9Sstevel@tonic-gate 	mutex_exit(&ipc_info_cvlock);
12057c478bd9Sstevel@tonic-gate 
12067c478bd9Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmka_node_alive done\n"));
12077c478bd9Sstevel@tonic-gate 
12087c478bd9Sstevel@tonic-gate 	return (B_TRUE);
12097c478bd9Sstevel@tonic-gate }
12107c478bd9Sstevel@tonic-gate 
12117c478bd9Sstevel@tonic-gate 
12127c478bd9Sstevel@tonic-gate 
12137c478bd9Sstevel@tonic-gate /*
12147c478bd9Sstevel@tonic-gate  * Paths cannot become active when node_is_alive is marked false
12157c478bd9Sstevel@tonic-gate  * in the ipc_info descriptor for the node
12167c478bd9Sstevel@tonic-gate  */
12177c478bd9Sstevel@tonic-gate boolean_t
rsmka_node_died(rsm_node_id_t remote_node)12187c478bd9Sstevel@tonic-gate rsmka_node_died(rsm_node_id_t remote_node)
12197c478bd9Sstevel@tonic-gate {
12207c478bd9Sstevel@tonic-gate 	ipc_info_t *ipc_info;
12217c478bd9Sstevel@tonic-gate 
12227c478bd9Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmka_node_died enter\n"));
12237c478bd9Sstevel@tonic-gate 
12247c478bd9Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG,
12257c478bd9Sstevel@tonic-gate 	    "rsmka_node_died: remote_node = %x\n", remote_node));
12267c478bd9Sstevel@tonic-gate 
12277c478bd9Sstevel@tonic-gate 	ipc_info = lookup_ipc_info(remote_node);
12287c478bd9Sstevel@tonic-gate 	if (ipc_info == NULL)
12297c478bd9Sstevel@tonic-gate 		return (B_FALSE);
12307c478bd9Sstevel@tonic-gate 
12317c478bd9Sstevel@tonic-gate 	ASSERT(ipc_info->node_is_alive == B_TRUE);
12327c478bd9Sstevel@tonic-gate 	ipc_info->node_is_alive = B_FALSE;
12337c478bd9Sstevel@tonic-gate 
12347c478bd9Sstevel@tonic-gate 	rsm_suspend_complete(remote_node, RSM_SUSPEND_NODEDEAD);
12357c478bd9Sstevel@tonic-gate 
12367c478bd9Sstevel@tonic-gate 	mutex_exit(&ipc_info_lock);
12377c478bd9Sstevel@tonic-gate 
12387c478bd9Sstevel@tonic-gate 	/* rsmipc_send() may be waiting for a sendq_token */
12397c478bd9Sstevel@tonic-gate 	mutex_enter(&ipc_info_cvlock);
12407c478bd9Sstevel@tonic-gate 	cv_broadcast(&ipc_info_cv);
12417c478bd9Sstevel@tonic-gate 	mutex_exit(&ipc_info_cvlock);
12427c478bd9Sstevel@tonic-gate 
12437c478bd9Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmka_node_died done\n"));
12447c478bd9Sstevel@tonic-gate 
12457c478bd9Sstevel@tonic-gate 	return (B_TRUE);
12467c478bd9Sstevel@tonic-gate }
12477c478bd9Sstevel@tonic-gate 
12487c478bd9Sstevel@tonic-gate /*
12497c478bd9Sstevel@tonic-gate  * Treat like path_down for all paths for the specified remote node.
12507c478bd9Sstevel@tonic-gate  * Always invoked before node died.
12517c478bd9Sstevel@tonic-gate  *
12527c478bd9Sstevel@tonic-gate  * NOTE: This routine is not called from the cluster path interface; the
12537c478bd9Sstevel@tonic-gate  * rsmka_path_down is called directly for each path.
12547c478bd9Sstevel@tonic-gate  */
12557c478bd9Sstevel@tonic-gate void
rsmka_disconnect_node(rsm_node_id_t remote_node,int flags)12567c478bd9Sstevel@tonic-gate rsmka_disconnect_node(rsm_node_id_t remote_node, int flags)
12577c478bd9Sstevel@tonic-gate {
12587c478bd9Sstevel@tonic-gate 	ipc_info_t	*ipc_info;
12597c478bd9Sstevel@tonic-gate 	path_t		*path;
12607c478bd9Sstevel@tonic-gate 	sendq_token_t	*sendq_token;
12617c478bd9Sstevel@tonic-gate 	work_token_t 	*up_token;
12627c478bd9Sstevel@tonic-gate 	work_token_t 	*down_token;
12637c478bd9Sstevel@tonic-gate 	boolean_t	do_work = B_FALSE;
12647c478bd9Sstevel@tonic-gate 	boolean_t	cancelled = B_FALSE;
12657c478bd9Sstevel@tonic-gate 
12667c478bd9Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
12677c478bd9Sstevel@tonic-gate 	    "rsmka_disconnect_node enter\n"));
12687c478bd9Sstevel@tonic-gate 
12697c478bd9Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG,
12707c478bd9Sstevel@tonic-gate 	    "rsmka_disconnect_node: node = %d\n", remote_node));
12717c478bd9Sstevel@tonic-gate 
12727c478bd9Sstevel@tonic-gate 	if (flags & RSMKA_NO_SLEEP) {
12737c478bd9Sstevel@tonic-gate 		ipc_info = lookup_ipc_info(remote_node);
12747c478bd9Sstevel@tonic-gate 
12757c478bd9Sstevel@tonic-gate 		sendq_token = ipc_info->token_list;
12767c478bd9Sstevel@tonic-gate 
12777c478bd9Sstevel@tonic-gate 		while (sendq_token != NULL) {
12787c478bd9Sstevel@tonic-gate 			path = SQ_TOKEN_TO_PATH(sendq_token);
12797c478bd9Sstevel@tonic-gate 			PATH_HOLD(path);
12807c478bd9Sstevel@tonic-gate 			up_token = &path->work_token[RSMKA_IPC_UP_INDEX];
12817c478bd9Sstevel@tonic-gate 			down_token = &path->work_token[RSMKA_IPC_DOWN_INDEX];
12827c478bd9Sstevel@tonic-gate 
12837c478bd9Sstevel@tonic-gate 			mutex_enter(&work_queue.work_mutex);
12847c478bd9Sstevel@tonic-gate 
12857c478bd9Sstevel@tonic-gate 			/* if an up token is enqueued, remove it */
12867c478bd9Sstevel@tonic-gate 			cancelled = cancel_work(up_token);
12877c478bd9Sstevel@tonic-gate 
12887c478bd9Sstevel@tonic-gate 			/*
12897c478bd9Sstevel@tonic-gate 			 * If the path is active and down work hasn't
12907c478bd9Sstevel@tonic-gate 			 * already been setup then down work is needed.
12917c478bd9Sstevel@tonic-gate 			 * else
12927c478bd9Sstevel@tonic-gate 			 * if up work wasn't canceled because it was
12937c478bd9Sstevel@tonic-gate 			 * already being processed then down work is needed
12947c478bd9Sstevel@tonic-gate 			 */
12957c478bd9Sstevel@tonic-gate 			if (path->state == RSMKA_PATH_ACTIVE) {
12967c478bd9Sstevel@tonic-gate 				if (down_token->opcode == 0)
12977c478bd9Sstevel@tonic-gate 					do_work = B_TRUE;
12987c478bd9Sstevel@tonic-gate 			} else
12997c478bd9Sstevel@tonic-gate 				if (up_token->opcode == RSMKA_IPC_UP)
13007c478bd9Sstevel@tonic-gate 					do_work = B_TRUE;
13017c478bd9Sstevel@tonic-gate 
13027c478bd9Sstevel@tonic-gate 			if (do_work == B_TRUE) {
13037c478bd9Sstevel@tonic-gate 				down_token->opcode = RSMKA_IPC_DOWN;
13047c478bd9Sstevel@tonic-gate 				enqueue_work(down_token);
13057c478bd9Sstevel@tonic-gate 			}
13067c478bd9Sstevel@tonic-gate 			mutex_exit(&work_queue.work_mutex);
13077c478bd9Sstevel@tonic-gate 
13087c478bd9Sstevel@tonic-gate 			if (do_work == B_FALSE)
13097c478bd9Sstevel@tonic-gate 				PATH_RELE(path);
13107c478bd9Sstevel@tonic-gate 
13117c478bd9Sstevel@tonic-gate 			if (cancelled) {
13127c478bd9Sstevel@tonic-gate 				PATH_RELE(path);
13137c478bd9Sstevel@tonic-gate 			}
13147c478bd9Sstevel@tonic-gate 			sendq_token = sendq_token->next;
13157c478bd9Sstevel@tonic-gate 		}
13167c478bd9Sstevel@tonic-gate 
13177c478bd9Sstevel@tonic-gate 		/*
13187c478bd9Sstevel@tonic-gate 		 * Now that all the work is enqueued, wakeup the work
13197c478bd9Sstevel@tonic-gate 		 * thread.
13207c478bd9Sstevel@tonic-gate 		 */
13217c478bd9Sstevel@tonic-gate 		mutex_enter(&work_queue.work_mutex);
13227c478bd9Sstevel@tonic-gate 		cv_signal(&work_queue.work_cv);
13237c478bd9Sstevel@tonic-gate 		mutex_exit(&work_queue.work_mutex);
13247c478bd9Sstevel@tonic-gate 
13257c478bd9Sstevel@tonic-gate 		IPCINFO_RELE_NOLOCK(ipc_info);
13267c478bd9Sstevel@tonic-gate 		mutex_exit(&ipc_info_lock);
13277c478bd9Sstevel@tonic-gate 
13287c478bd9Sstevel@tonic-gate 	} else {
13297c478bd9Sstevel@tonic-gate 		/* get locked ipc_info descriptor */
13307c478bd9Sstevel@tonic-gate 		ipc_info = lookup_ipc_info(remote_node);
13317c478bd9Sstevel@tonic-gate 
13327c478bd9Sstevel@tonic-gate 		sendq_token = ipc_info->token_list;
13337c478bd9Sstevel@tonic-gate 		while (sendq_token != NULL) {
13347c478bd9Sstevel@tonic-gate 			path = SQ_TOKEN_TO_PATH(sendq_token);
13357c478bd9Sstevel@tonic-gate 			DBG_PRINTF((category, RSM_DEBUG,
13367c478bd9Sstevel@tonic-gate 			    "rsmka_disconnect_node: path_down"
13377c478bd9Sstevel@tonic-gate 			    "for path = %x\n",
13387c478bd9Sstevel@tonic-gate 			    path));
13397c478bd9Sstevel@tonic-gate 			(void) rsmka_path_down(0, 0, 0, 0,
13407c478bd9Sstevel@tonic-gate 			    path, RSMKA_USE_COOKIE);
13417c478bd9Sstevel@tonic-gate 			sendq_token = sendq_token->next;
13427c478bd9Sstevel@tonic-gate 			if (sendq_token == ipc_info->token_list)
13437c478bd9Sstevel@tonic-gate 				break;
13447c478bd9Sstevel@tonic-gate 		}
13457c478bd9Sstevel@tonic-gate 		mutex_exit(&ipc_info_lock);
13467c478bd9Sstevel@tonic-gate 	}
13477c478bd9Sstevel@tonic-gate 
13487c478bd9Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
13497c478bd9Sstevel@tonic-gate 	    "rsmka_disconnect_node done\n"));
13507c478bd9Sstevel@tonic-gate }
13517c478bd9Sstevel@tonic-gate 
13527c478bd9Sstevel@tonic-gate 
13537c478bd9Sstevel@tonic-gate /*
13547c478bd9Sstevel@tonic-gate  * Called from rsm_node_alive - if a path to a remote node is in
13557c478bd9Sstevel@tonic-gate  * state RSMKA_PATH_UP, transition the state to RSMKA_PATH_ACTIVE with a
13567c478bd9Sstevel@tonic-gate  * call to rsmka_do_path_active.
13577c478bd9Sstevel@tonic-gate  *
13587c478bd9Sstevel@tonic-gate  * REF_CNT:
13597c478bd9Sstevel@tonic-gate  * The path descriptor ref_cnt is incremented here; it will be decremented
13607c478bd9Sstevel@tonic-gate  * when path up processing is completed in rsmka_do_path_active or by the work
13617c478bd9Sstevel@tonic-gate  * thread if the path up is deferred.
13627c478bd9Sstevel@tonic-gate  */
13637c478bd9Sstevel@tonic-gate static void
pathup_to_pathactive(ipc_info_t * ipc_info,rsm_node_id_t remote_node)13647c478bd9Sstevel@tonic-gate pathup_to_pathactive(ipc_info_t *ipc_info, rsm_node_id_t remote_node)
13657c478bd9Sstevel@tonic-gate {
13667c478bd9Sstevel@tonic-gate 	path_t		*path;
13677c478bd9Sstevel@tonic-gate 	sendq_token_t	*token;
13687c478bd9Sstevel@tonic-gate 
13697c478bd9Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
13707c478bd9Sstevel@tonic-gate 	    "pathup_to_pathactive enter\n"));
13717c478bd9Sstevel@tonic-gate 
13727c478bd9Sstevel@tonic-gate 	remote_node = remote_node;
13737c478bd9Sstevel@tonic-gate 
13747c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&ipc_info_lock));
13757c478bd9Sstevel@tonic-gate 
13767c478bd9Sstevel@tonic-gate 	token = ipc_info->token_list;
13777c478bd9Sstevel@tonic-gate 	while (token != NULL) {
13787c478bd9Sstevel@tonic-gate 		path = SQ_TOKEN_TO_PATH(token);
13797c478bd9Sstevel@tonic-gate 		mutex_enter(&path->mutex);
13807c478bd9Sstevel@tonic-gate 		if (path->state == RSMKA_PATH_UP)  {
13817c478bd9Sstevel@tonic-gate 			PATH_HOLD_NOLOCK(path);
13827c478bd9Sstevel@tonic-gate 			(void) rsmka_do_path_active(path, 0);
13837c478bd9Sstevel@tonic-gate 		}
13847c478bd9Sstevel@tonic-gate 		mutex_exit(&path->mutex);
13857c478bd9Sstevel@tonic-gate 		token = token->next;
13867c478bd9Sstevel@tonic-gate 		if (token == ipc_info->token_list)
13877c478bd9Sstevel@tonic-gate 			break;
13887c478bd9Sstevel@tonic-gate 	}
13897c478bd9Sstevel@tonic-gate 
13907c478bd9Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
13917c478bd9Sstevel@tonic-gate 	    "pathup_to_pathactive done\n"));
13927c478bd9Sstevel@tonic-gate }
13937c478bd9Sstevel@tonic-gate 
13947c478bd9Sstevel@tonic-gate /*
13957c478bd9Sstevel@tonic-gate  * Called from pathup_to_pathactive and do_path_up. The objective is to
13967c478bd9Sstevel@tonic-gate  * create an ipc send queue and transition to state RSMKA_PATH_ACTIVE.
13977c478bd9Sstevel@tonic-gate  * For the no sleep case we may need to defer the work using a token.
13987c478bd9Sstevel@tonic-gate  *
13997c478bd9Sstevel@tonic-gate  */
14007c478bd9Sstevel@tonic-gate boolean_t
rsmka_do_path_active(path_t * path,int flags)14017c478bd9Sstevel@tonic-gate rsmka_do_path_active(path_t *path, int flags)
14027c478bd9Sstevel@tonic-gate {
14037c478bd9Sstevel@tonic-gate 	work_token_t	*up_token = &path->work_token[RSMKA_IPC_UP_INDEX];
14047c478bd9Sstevel@tonic-gate 	work_token_t	*down_token = &path->work_token[RSMKA_IPC_DOWN_INDEX];
14057c478bd9Sstevel@tonic-gate 	boolean_t	do_work = B_FALSE;
14067c478bd9Sstevel@tonic-gate 	int		error;
14077c478bd9Sstevel@tonic-gate 	timespec_t	tv;
14087c478bd9Sstevel@tonic-gate 	adapter_t	*adapter;
14097c478bd9Sstevel@tonic-gate 	rsm_send_q_handle_t	sqhdl;
14107c478bd9Sstevel@tonic-gate 
14117c478bd9Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
14127c478bd9Sstevel@tonic-gate 	    "rsmka_do_path_active enter\n"));
14137c478bd9Sstevel@tonic-gate 
14147c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&path->mutex));
14157c478bd9Sstevel@tonic-gate 
14167c478bd9Sstevel@tonic-gate 	if (flags & RSMKA_NO_SLEEP) {
14177c478bd9Sstevel@tonic-gate 		mutex_enter(&work_queue.work_mutex);
14187c478bd9Sstevel@tonic-gate 
14197c478bd9Sstevel@tonic-gate 		/* if a down token is enqueued, remove it */
14207c478bd9Sstevel@tonic-gate 		if (cancel_work(down_token)) {
14217c478bd9Sstevel@tonic-gate 			PATH_RELE_NOLOCK(path);
14227c478bd9Sstevel@tonic-gate 		}
14237c478bd9Sstevel@tonic-gate 
14247c478bd9Sstevel@tonic-gate 		/*
14257c478bd9Sstevel@tonic-gate 		 * If the path is not active and up work hasn't
14267c478bd9Sstevel@tonic-gate 		 * already been setup then up work is needed.
14277c478bd9Sstevel@tonic-gate 		 * else
14287c478bd9Sstevel@tonic-gate 		 * if down work wasn't canceled because it was
14297c478bd9Sstevel@tonic-gate 		 * already being processed then up work is needed
14307c478bd9Sstevel@tonic-gate 		 */
14317c478bd9Sstevel@tonic-gate 		if (path->state != RSMKA_PATH_ACTIVE) {
14327c478bd9Sstevel@tonic-gate 			if (up_token->opcode == 0)
14337c478bd9Sstevel@tonic-gate 				do_work = B_TRUE;
14347c478bd9Sstevel@tonic-gate 		} else
14357c478bd9Sstevel@tonic-gate 			if (down_token->opcode == RSMKA_IPC_DOWN)
14367c478bd9Sstevel@tonic-gate 				do_work = B_TRUE;
14377c478bd9Sstevel@tonic-gate 
14387c478bd9Sstevel@tonic-gate 		if (do_work == B_TRUE) {
14397c478bd9Sstevel@tonic-gate 			up_token->opcode = RSMKA_IPC_UP;
14407c478bd9Sstevel@tonic-gate 			enqueue_work(up_token);
14417c478bd9Sstevel@tonic-gate 		}
14427c478bd9Sstevel@tonic-gate 		else
14437c478bd9Sstevel@tonic-gate 			PATH_RELE_NOLOCK(path);
14447c478bd9Sstevel@tonic-gate 
14457c478bd9Sstevel@tonic-gate 		mutex_exit(&work_queue.work_mutex);
14467c478bd9Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
14477c478bd9Sstevel@tonic-gate 		    "rsmka_do_path_active done\n"));
14487c478bd9Sstevel@tonic-gate 		return (B_TRUE);
14497c478bd9Sstevel@tonic-gate 	} else {
14507c478bd9Sstevel@tonic-gate 		/*
14517c478bd9Sstevel@tonic-gate 		 * Drop the path lock before calling create_ipc_sendq, shouldn't
14527c478bd9Sstevel@tonic-gate 		 * hold locks across calls to RSMPI routines.
14537c478bd9Sstevel@tonic-gate 		 */
14547c478bd9Sstevel@tonic-gate 		mutex_exit(&path->mutex);
14557c478bd9Sstevel@tonic-gate 
14567c478bd9Sstevel@tonic-gate 		error = create_ipc_sendq(path);
14577c478bd9Sstevel@tonic-gate 
14587c478bd9Sstevel@tonic-gate 		mutex_enter(&path->mutex);
14597c478bd9Sstevel@tonic-gate 		if (path->state != RSMKA_PATH_UP) {
14607c478bd9Sstevel@tonic-gate 			/*
14617c478bd9Sstevel@tonic-gate 			 * path state has changed, if sendq was created,
14627c478bd9Sstevel@tonic-gate 			 * destroy it and return
14637c478bd9Sstevel@tonic-gate 			 */
14647c478bd9Sstevel@tonic-gate 			if (error == RSM_SUCCESS) {
14657c478bd9Sstevel@tonic-gate 				sqhdl = path->sendq_token.rsmpi_sendq_handle;
14667c478bd9Sstevel@tonic-gate 				path->sendq_token.rsmpi_sendq_handle = NULL;
14677c478bd9Sstevel@tonic-gate 				adapter = path->local_adapter;
14687c478bd9Sstevel@tonic-gate 				mutex_exit(&path->mutex);
14697c478bd9Sstevel@tonic-gate 
14707c478bd9Sstevel@tonic-gate 				if (sqhdl != NULL) {
14717c478bd9Sstevel@tonic-gate 					adapter->rsmpi_ops->rsm_sendq_destroy(
1472*b97d6ca7SMilan Jurik 					    sqhdl);
14737c478bd9Sstevel@tonic-gate 				}
14747c478bd9Sstevel@tonic-gate 				mutex_enter(&path->mutex);
14757c478bd9Sstevel@tonic-gate 			}
14767c478bd9Sstevel@tonic-gate 			PATH_RELE_NOLOCK(path);
14777c478bd9Sstevel@tonic-gate 
14787c478bd9Sstevel@tonic-gate 			DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
14797c478bd9Sstevel@tonic-gate 			    "rsmka_do_path_active done: path=%lx not UP\n",
14807c478bd9Sstevel@tonic-gate 			    (uintptr_t)path));
14817c478bd9Sstevel@tonic-gate 			return (error ? B_FALSE : B_TRUE);
14827c478bd9Sstevel@tonic-gate 		}
14837c478bd9Sstevel@tonic-gate 
14847c478bd9Sstevel@tonic-gate 		if (error == RSM_SUCCESS) {
14857c478bd9Sstevel@tonic-gate 			/* clear flag since sendq_create succeeded */
14867c478bd9Sstevel@tonic-gate 			path->flags &= ~RSMKA_SQCREATE_PENDING;
14877c478bd9Sstevel@tonic-gate 			path->state = RSMKA_PATH_ACTIVE;
14887c478bd9Sstevel@tonic-gate 			/*
14897c478bd9Sstevel@tonic-gate 			 * now that path is active we send the
14907c478bd9Sstevel@tonic-gate 			 * RSMIPC_MSG_SQREADY to the remote endpoint
14917c478bd9Sstevel@tonic-gate 			 */
14927c478bd9Sstevel@tonic-gate 			path->procmsg_cnt = 0;
14937c478bd9Sstevel@tonic-gate 			path->sendq_token.msgbuf_avail = 0;
14947c478bd9Sstevel@tonic-gate 
14957c478bd9Sstevel@tonic-gate 			/* Calculate local incarnation number */
14967c478bd9Sstevel@tonic-gate 			gethrestime(&tv);
14977c478bd9Sstevel@tonic-gate 			if (tv.tv_sec == RSM_UNKNOWN_INCN)
14987c478bd9Sstevel@tonic-gate 				tv.tv_sec = 1;
14997c478bd9Sstevel@tonic-gate 			path->local_incn = (int64_t)tv.tv_sec;
15007c478bd9Sstevel@tonic-gate 
15017c478bd9Sstevel@tonic-gate 			/*
15027c478bd9Sstevel@tonic-gate 			 * if send fails here its due to some non-transient
15037c478bd9Sstevel@tonic-gate 			 * error because QUEUE_FULL is not possible here since
15047c478bd9Sstevel@tonic-gate 			 * we are the first message on this sendq. The error
15057c478bd9Sstevel@tonic-gate 			 * will cause the path to go down anyways so ignore
15067c478bd9Sstevel@tonic-gate 			 * the return value
15077c478bd9Sstevel@tonic-gate 			 */
15087c478bd9Sstevel@tonic-gate 			(void) rsmipc_send_controlmsg(path, RSMIPC_MSG_SQREADY);
15097c478bd9Sstevel@tonic-gate 			/* wait for SQREADY_ACK message */
15107c478bd9Sstevel@tonic-gate 			path->flags |= RSMKA_WAIT_FOR_SQACK;
15117c478bd9Sstevel@tonic-gate 
15127c478bd9Sstevel@tonic-gate 			DBG_PRINTF((category, RSM_DEBUG,
15137c478bd9Sstevel@tonic-gate 			    "rsmka_do_path_active success\n"));
15147c478bd9Sstevel@tonic-gate 		} else {
15157c478bd9Sstevel@tonic-gate 			/*
15167c478bd9Sstevel@tonic-gate 			 * sendq create failed possibly because
15177c478bd9Sstevel@tonic-gate 			 * the remote end is not yet ready eg.
15187c478bd9Sstevel@tonic-gate 			 * handler not registered, set a flag
15197c478bd9Sstevel@tonic-gate 			 * so that when there is an indication
15207c478bd9Sstevel@tonic-gate 			 * that the remote end is ready rsmka_do_path_active
15217c478bd9Sstevel@tonic-gate 			 * will be retried.
15227c478bd9Sstevel@tonic-gate 			 */
15237c478bd9Sstevel@tonic-gate 			path->flags |= RSMKA_SQCREATE_PENDING;
15247c478bd9Sstevel@tonic-gate 		}
15257c478bd9Sstevel@tonic-gate 
15267c478bd9Sstevel@tonic-gate 		PATH_RELE_NOLOCK(path);
15277c478bd9Sstevel@tonic-gate 
15287c478bd9Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
15297c478bd9Sstevel@tonic-gate 		    "rsmka_do_path_active done\n"));
15307c478bd9Sstevel@tonic-gate 		return (error ? B_FALSE : B_TRUE);
15317c478bd9Sstevel@tonic-gate 	}
15327c478bd9Sstevel@tonic-gate 
15337c478bd9Sstevel@tonic-gate }
15347c478bd9Sstevel@tonic-gate 
15357c478bd9Sstevel@tonic-gate /*
15367c478bd9Sstevel@tonic-gate  * Called from rsm_path_up.
15377c478bd9Sstevel@tonic-gate  * If the remote node state is "alive" then call rsmka_do_path_active
15387c478bd9Sstevel@tonic-gate  * otherwise just transition path state to RSMKA_PATH_UP.
15397c478bd9Sstevel@tonic-gate  */
15407c478bd9Sstevel@tonic-gate static boolean_t
do_path_up(path_t * path,int flags)15417c478bd9Sstevel@tonic-gate do_path_up(path_t *path, int flags)
15427c478bd9Sstevel@tonic-gate {
15437c478bd9Sstevel@tonic-gate 	boolean_t	rval;
15447c478bd9Sstevel@tonic-gate 	boolean_t	node_alive;
15457c478bd9Sstevel@tonic-gate 
15467c478bd9Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "do_path_up enter\n"));
15477c478bd9Sstevel@tonic-gate 
15487c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&path->mutex));
15497c478bd9Sstevel@tonic-gate 
15507c478bd9Sstevel@tonic-gate 	/* path moved to ACTIVE by rsm_sqcreateop_callback - just return */
15517c478bd9Sstevel@tonic-gate 	if (path->state == RSMKA_PATH_ACTIVE) {
15527c478bd9Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
1553*b97d6ca7SMilan Jurik 		    "do_path_up done: already ACTIVE\n"));
15547c478bd9Sstevel@tonic-gate 		PATH_RELE_NOLOCK(path);
15557c478bd9Sstevel@tonic-gate 		return (B_TRUE);
15567c478bd9Sstevel@tonic-gate 	}
15577c478bd9Sstevel@tonic-gate 
15587c478bd9Sstevel@tonic-gate 	path->state = RSMKA_PATH_UP;
15597c478bd9Sstevel@tonic-gate 
15607c478bd9Sstevel@tonic-gate 	/* initialize the receive msgbuf counters */
15617c478bd9Sstevel@tonic-gate 	path->msgbuf_head = 0;
15627c478bd9Sstevel@tonic-gate 	path->msgbuf_tail = RSMIPC_MAX_MESSAGES - 1;
15637c478bd9Sstevel@tonic-gate 	path->msgbuf_cnt = 0;
15647c478bd9Sstevel@tonic-gate 	path->procmsg_cnt = 0;
15657c478bd9Sstevel@tonic-gate 	/*
15667c478bd9Sstevel@tonic-gate 	 * rsmka_check_node_alive acquires ipc_info_lock, in order to maintain
15677c478bd9Sstevel@tonic-gate 	 * correct lock ordering drop the path lock before calling it.
15687c478bd9Sstevel@tonic-gate 	 */
15697c478bd9Sstevel@tonic-gate 	mutex_exit(&path->mutex);
15707c478bd9Sstevel@tonic-gate 
15717c478bd9Sstevel@tonic-gate 	node_alive = rsmka_check_node_alive(path->remote_node);
15727c478bd9Sstevel@tonic-gate 
15737c478bd9Sstevel@tonic-gate 	mutex_enter(&path->mutex);
15747c478bd9Sstevel@tonic-gate 	if (node_alive == B_TRUE)
15757c478bd9Sstevel@tonic-gate 		rval = rsmka_do_path_active(path, flags);
15767c478bd9Sstevel@tonic-gate 	else {
15777c478bd9Sstevel@tonic-gate 		PATH_RELE_NOLOCK(path);
15787c478bd9Sstevel@tonic-gate 		rval = B_TRUE;
15797c478bd9Sstevel@tonic-gate 	}
15807c478bd9Sstevel@tonic-gate 
15817c478bd9Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "do_path_up done\n"));
15827c478bd9Sstevel@tonic-gate 	return (rval);
15837c478bd9Sstevel@tonic-gate }
15847c478bd9Sstevel@tonic-gate 
15857c478bd9Sstevel@tonic-gate 
15867c478bd9Sstevel@tonic-gate 
15877c478bd9Sstevel@tonic-gate /*
15887c478bd9Sstevel@tonic-gate  * Called from rsm_remove_path, rsm_path_down, deferred_work.
15897c478bd9Sstevel@tonic-gate  * Destroy the send queue on this path.
15907c478bd9Sstevel@tonic-gate  * Disconnect segments being imported from the remote node
15917c478bd9Sstevel@tonic-gate  * Disconnect segments being imported by the remote node
15927c478bd9Sstevel@tonic-gate  *
15937c478bd9Sstevel@tonic-gate  */
15947c478bd9Sstevel@tonic-gate static void
do_path_down(path_t * path,int flags)15957c478bd9Sstevel@tonic-gate do_path_down(path_t *path, int flags)
15967c478bd9Sstevel@tonic-gate {
15977c478bd9Sstevel@tonic-gate 	work_token_t *up_token = &path->work_token[RSMKA_IPC_UP_INDEX];
15987c478bd9Sstevel@tonic-gate 	work_token_t *down_token = &path->work_token[RSMKA_IPC_DOWN_INDEX];
15997c478bd9Sstevel@tonic-gate 	boolean_t do_work = B_FALSE;
16007c478bd9Sstevel@tonic-gate 
16017c478bd9Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "do_path_down enter\n"));
16027c478bd9Sstevel@tonic-gate 
16037c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&path->mutex));
16047c478bd9Sstevel@tonic-gate 
16057c478bd9Sstevel@tonic-gate 	if (flags & RSMKA_NO_SLEEP) {
16067c478bd9Sstevel@tonic-gate 		mutex_enter(&work_queue.work_mutex);
16077c478bd9Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_DEBUG,
16087c478bd9Sstevel@tonic-gate 		    "do_path_down: after work_mutex\n"));
16097c478bd9Sstevel@tonic-gate 
16107c478bd9Sstevel@tonic-gate 		/* if an up token is enqueued, remove it */
16117c478bd9Sstevel@tonic-gate 		if (cancel_work(up_token)) {
16127c478bd9Sstevel@tonic-gate 			PATH_RELE_NOLOCK(path);
16137c478bd9Sstevel@tonic-gate 		}
16147c478bd9Sstevel@tonic-gate 
16157c478bd9Sstevel@tonic-gate 		/*
16167c478bd9Sstevel@tonic-gate 		 * If the path is active and down work hasn't
16177c478bd9Sstevel@tonic-gate 		 * already been setup then down work is needed.
16187c478bd9Sstevel@tonic-gate 		 * else
16197c478bd9Sstevel@tonic-gate 		 * if up work wasn't canceled because it was
16207c478bd9Sstevel@tonic-gate 		 * already being processed then down work is needed
16217c478bd9Sstevel@tonic-gate 		 */
16227c478bd9Sstevel@tonic-gate 		if (path->state == RSMKA_PATH_ACTIVE) {
16237c478bd9Sstevel@tonic-gate 			if (down_token->opcode == 0)
16247c478bd9Sstevel@tonic-gate 				do_work = B_TRUE;
16257c478bd9Sstevel@tonic-gate 		} else
16267c478bd9Sstevel@tonic-gate 			if (up_token->opcode == RSMKA_IPC_UP)
16277c478bd9Sstevel@tonic-gate 				do_work = B_TRUE;
16287c478bd9Sstevel@tonic-gate 
16297c478bd9Sstevel@tonic-gate 		if (do_work == B_TRUE) {
16307c478bd9Sstevel@tonic-gate 			down_token->opcode = RSMKA_IPC_DOWN;
16317c478bd9Sstevel@tonic-gate 			enqueue_work(down_token);
16327c478bd9Sstevel@tonic-gate 		} else
16337c478bd9Sstevel@tonic-gate 			PATH_RELE_NOLOCK(path);
16347c478bd9Sstevel@tonic-gate 
16357c478bd9Sstevel@tonic-gate 
16367c478bd9Sstevel@tonic-gate 		mutex_exit(&work_queue.work_mutex);
16377c478bd9Sstevel@tonic-gate 
16387c478bd9Sstevel@tonic-gate 	} else {
16397c478bd9Sstevel@tonic-gate 
16407c478bd9Sstevel@tonic-gate 		/*
16417c478bd9Sstevel@tonic-gate 		 * Change state of the path to RSMKA_PATH_GOING_DOWN and
16427c478bd9Sstevel@tonic-gate 		 * release the path mutex. Any other thread referring
16437c478bd9Sstevel@tonic-gate 		 * this path would cv_wait till the state of the path
16447c478bd9Sstevel@tonic-gate 		 * remains RSMKA_PATH_GOING_DOWN.
16457c478bd9Sstevel@tonic-gate 		 * On completing the path down processing, change the
16467c478bd9Sstevel@tonic-gate 		 * state of RSMKA_PATH_DOWN indicating that the path
16477c478bd9Sstevel@tonic-gate 		 * is indeed down.
16487c478bd9Sstevel@tonic-gate 		 */
16497c478bd9Sstevel@tonic-gate 		path->state = RSMKA_PATH_GOING_DOWN;
16507c478bd9Sstevel@tonic-gate 
16517c478bd9Sstevel@tonic-gate 		/*
16527c478bd9Sstevel@tonic-gate 		 * clear the WAIT_FOR_SQACK flag since path is going down.
16537c478bd9Sstevel@tonic-gate 		 */
16547c478bd9Sstevel@tonic-gate 		path->flags &= ~RSMKA_WAIT_FOR_SQACK;
16557c478bd9Sstevel@tonic-gate 
16567c478bd9Sstevel@tonic-gate 		/*
16577c478bd9Sstevel@tonic-gate 		 * this wakes up any thread waiting to receive credits
16587c478bd9Sstevel@tonic-gate 		 * in rsmipc_send to tell it that the path is going down
16597c478bd9Sstevel@tonic-gate 		 */
16607c478bd9Sstevel@tonic-gate 		cv_broadcast(&path->sendq_token.sendq_cv);
16617c478bd9Sstevel@tonic-gate 
16627c478bd9Sstevel@tonic-gate 		mutex_exit(&path->mutex);
16637c478bd9Sstevel@tonic-gate 
16647c478bd9Sstevel@tonic-gate 		/*
16657c478bd9Sstevel@tonic-gate 		 * drain the messages from the receive msgbuf, the
16667c478bd9Sstevel@tonic-gate 		 * tasks in the taskq_thread acquire the path->mutex
16677c478bd9Sstevel@tonic-gate 		 * so we drop the path mutex before taskq_wait.
16687c478bd9Sstevel@tonic-gate 		 */
16697c478bd9Sstevel@tonic-gate 		taskq_wait(path->recv_taskq);
16707c478bd9Sstevel@tonic-gate 
16717c478bd9Sstevel@tonic-gate 		/*
16727c478bd9Sstevel@tonic-gate 		 * Disconnect segments being imported from the remote node
16737c478bd9Sstevel@tonic-gate 		 * The path_importer_disconnect function needs to be called
16747c478bd9Sstevel@tonic-gate 		 * only after releasing the mutex on the path. This is to
16757c478bd9Sstevel@tonic-gate 		 * avoid a recursive mutex enter when doing the
16767c478bd9Sstevel@tonic-gate 		 * rsmka_get_sendq_token.
16777c478bd9Sstevel@tonic-gate 		 */
16787c478bd9Sstevel@tonic-gate 		path_importer_disconnect(path);
16797c478bd9Sstevel@tonic-gate 
16807c478bd9Sstevel@tonic-gate 		/*
16817c478bd9Sstevel@tonic-gate 		 * Get the path mutex, change the state of the path to
16827c478bd9Sstevel@tonic-gate 		 * RSMKA_PATH_DOWN since the path down processing has
16837c478bd9Sstevel@tonic-gate 		 * completed and cv_signal anyone who was waiting since
16847c478bd9Sstevel@tonic-gate 		 * the state was RSMKA_PATH_GOING_DOWN.
16857c478bd9Sstevel@tonic-gate 		 * NOTE: Do not do a mutex_exit here. We entered this
16867c478bd9Sstevel@tonic-gate 		 * routine with the path lock held by the caller. The
16877c478bd9Sstevel@tonic-gate 		 * caller eventually releases the path lock by doing a
16887c478bd9Sstevel@tonic-gate 		 * mutex_exit.
16897c478bd9Sstevel@tonic-gate 		 */
16907c478bd9Sstevel@tonic-gate 		mutex_enter(&path->mutex);
16917c478bd9Sstevel@tonic-gate 
16927c478bd9Sstevel@tonic-gate #ifdef DEBUG
16937c478bd9Sstevel@tonic-gate 		/*
16947c478bd9Sstevel@tonic-gate 		 * Some IPC messages left in the recv_buf,
16957c478bd9Sstevel@tonic-gate 		 * they'll be dropped
16967c478bd9Sstevel@tonic-gate 		 */
16977c478bd9Sstevel@tonic-gate 		if (path->msgbuf_cnt != 0)
16987c478bd9Sstevel@tonic-gate 			cmn_err(CE_NOTE, "path=%lx msgbuf_cnt != 0\n",
16997c478bd9Sstevel@tonic-gate 			    (uintptr_t)path);
17007c478bd9Sstevel@tonic-gate #endif
17017c478bd9Sstevel@tonic-gate 		while (path->sendq_token.ref_cnt != 0)
17027c478bd9Sstevel@tonic-gate 			cv_wait(&path->sendq_token.sendq_cv,
17037c478bd9Sstevel@tonic-gate 			    &path->mutex);
17047c478bd9Sstevel@tonic-gate 
17057c478bd9Sstevel@tonic-gate 		/* release the rsmpi handle */
17067c478bd9Sstevel@tonic-gate 		if (path->sendq_token.rsmpi_sendq_handle != NULL)
17077c478bd9Sstevel@tonic-gate 			path->local_adapter->rsmpi_ops->rsm_sendq_destroy(
17087c478bd9Sstevel@tonic-gate 			    path->sendq_token.rsmpi_sendq_handle);
17097c478bd9Sstevel@tonic-gate 
17107c478bd9Sstevel@tonic-gate 		path->sendq_token.rsmpi_sendq_handle = NULL;
17117c478bd9Sstevel@tonic-gate 
17127c478bd9Sstevel@tonic-gate 		path->state = RSMKA_PATH_DOWN;
17137c478bd9Sstevel@tonic-gate 
17147c478bd9Sstevel@tonic-gate 		cv_signal(&path->hold_cv);
17157c478bd9Sstevel@tonic-gate 
17167c478bd9Sstevel@tonic-gate 	}
17177c478bd9Sstevel@tonic-gate 
17187c478bd9Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "do_path_down done\n"));
17197c478bd9Sstevel@tonic-gate 
17207c478bd9Sstevel@tonic-gate }
17217c478bd9Sstevel@tonic-gate 
17227c478bd9Sstevel@tonic-gate /*
17237c478bd9Sstevel@tonic-gate  * Search through the list of imported segments for segments using this path
17247c478bd9Sstevel@tonic-gate  * and unload the memory mappings for each one.  The application will
17257c478bd9Sstevel@tonic-gate  * get an error return when a barrier close is invoked.
17267c478bd9Sstevel@tonic-gate  * NOTE: This function has to be called only after releasing the mutex on
17277c478bd9Sstevel@tonic-gate  * the path. This is to avoid any recursive mutex panics on the path mutex
17287c478bd9Sstevel@tonic-gate  * since the path_importer_disconnect function would end up calling
17297c478bd9Sstevel@tonic-gate  * rsmka_get_sendq_token which requires the path mutex.
17307c478bd9Sstevel@tonic-gate  */
17317c478bd9Sstevel@tonic-gate 
17327c478bd9Sstevel@tonic-gate static void
path_importer_disconnect(path_t * path)17337c478bd9Sstevel@tonic-gate path_importer_disconnect(path_t *path)
17347c478bd9Sstevel@tonic-gate {
17357c478bd9Sstevel@tonic-gate 	int i;
17367c478bd9Sstevel@tonic-gate 	adapter_t *adapter = path->local_adapter;
17377c478bd9Sstevel@tonic-gate 	rsm_node_id_t remote_node = path->remote_node;
17387c478bd9Sstevel@tonic-gate 	rsmresource_t		*p = NULL;
17397c478bd9Sstevel@tonic-gate 	rsmseg_t *seg;
17407c478bd9Sstevel@tonic-gate 
17417c478bd9Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
17427c478bd9Sstevel@tonic-gate 	    "path_importer_disconnect enter\n"));
17437c478bd9Sstevel@tonic-gate 
17447c478bd9Sstevel@tonic-gate 	rw_enter(&rsm_import_segs.rsmhash_rw, RW_READER);
17457c478bd9Sstevel@tonic-gate 
17467c478bd9Sstevel@tonic-gate 	if (rsm_import_segs.bucket != NULL) {
17477c478bd9Sstevel@tonic-gate 		for (i = 0; i < rsm_hash_size; i++) {
17487c478bd9Sstevel@tonic-gate 			p = rsm_import_segs.bucket[i];
17497c478bd9Sstevel@tonic-gate 			for (; p; p = p->rsmrc_next) {
17507c478bd9Sstevel@tonic-gate 				if ((p->rsmrc_node == remote_node) &&
17517c478bd9Sstevel@tonic-gate 				    (p->rsmrc_adapter == adapter)) {
17527c478bd9Sstevel@tonic-gate 					seg = (rsmseg_t *)p;
17537c478bd9Sstevel@tonic-gate 			/*
17547c478bd9Sstevel@tonic-gate 			 * In order to make rsmseg_unload and
17557c478bd9Sstevel@tonic-gate 			 * path_importer_disconnect thread safe, acquire the
17567c478bd9Sstevel@tonic-gate 			 * segment lock here. rsmseg_unload is responsible for
17577c478bd9Sstevel@tonic-gate 			 * releasing the lock. rsmseg_unload releases the lock
17587c478bd9Sstevel@tonic-gate 			 * just before a call to rsmipc_send or in case of an
17597c478bd9Sstevel@tonic-gate 			 * early exit which occurs if the segment was in the
17607c478bd9Sstevel@tonic-gate 			 * state RSM_STATE_CONNECTING or RSM_STATE_NEW.
17617c478bd9Sstevel@tonic-gate 			 */
17627c478bd9Sstevel@tonic-gate 					rsmseglock_acquire(seg);
17637c478bd9Sstevel@tonic-gate 					seg->s_flags |= RSM_FORCE_DISCONNECT;
17647c478bd9Sstevel@tonic-gate 					rsmseg_unload(seg);
17657c478bd9Sstevel@tonic-gate 				}
17667c478bd9Sstevel@tonic-gate 			}
17677c478bd9Sstevel@tonic-gate 		}
17687c478bd9Sstevel@tonic-gate 	}
17697c478bd9Sstevel@tonic-gate 	rw_exit(&rsm_import_segs.rsmhash_rw);
17707c478bd9Sstevel@tonic-gate 
17717c478bd9Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
17727c478bd9Sstevel@tonic-gate 	    "path_importer_disconnect done\n"));
17737c478bd9Sstevel@tonic-gate }
17747c478bd9Sstevel@tonic-gate 
17757c478bd9Sstevel@tonic-gate 
17767c478bd9Sstevel@tonic-gate 
17777c478bd9Sstevel@tonic-gate 
17787c478bd9Sstevel@tonic-gate /*
17797c478bd9Sstevel@tonic-gate  *
17807c478bd9Sstevel@tonic-gate  * ADAPTER UTILITY FUNCTIONS
17817c478bd9Sstevel@tonic-gate  *
17827c478bd9Sstevel@tonic-gate  */
17837c478bd9Sstevel@tonic-gate 
17847c478bd9Sstevel@tonic-gate 
17857c478bd9Sstevel@tonic-gate 
17867c478bd9Sstevel@tonic-gate /*
17877c478bd9Sstevel@tonic-gate  * Allocate new adapter list head structure and add it to the beginning of
17887c478bd9Sstevel@tonic-gate  * the list of adapter list heads.  There is one list for each adapter
17897c478bd9Sstevel@tonic-gate  * device name (or type).
17907c478bd9Sstevel@tonic-gate  */
17917c478bd9Sstevel@tonic-gate static adapter_listhead_t *
init_listhead(char * name)17927c478bd9Sstevel@tonic-gate init_listhead(char *name)
17937c478bd9Sstevel@tonic-gate {
17947c478bd9Sstevel@tonic-gate 	adapter_listhead_t *listhead;
17957c478bd9Sstevel@tonic-gate 
17967c478bd9Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "init_listhead enter\n"));
17977c478bd9Sstevel@tonic-gate 
17987c478bd9Sstevel@tonic-gate 	/* allocation and initialization */
17997c478bd9Sstevel@tonic-gate 	listhead = kmem_zalloc(sizeof (adapter_listhead_t), KM_SLEEP);
18007c478bd9Sstevel@tonic-gate 	mutex_init(&listhead->mutex, NULL, MUTEX_DEFAULT, NULL);
18017c478bd9Sstevel@tonic-gate 	(void) strcpy(listhead->adapter_devname, name);
18027c478bd9Sstevel@tonic-gate 
18037c478bd9Sstevel@tonic-gate 	/* link into list of listheads */
18047c478bd9Sstevel@tonic-gate 	mutex_enter(&adapter_listhead_base.listlock);
18057c478bd9Sstevel@tonic-gate 	if (adapter_listhead_base.next == NULL) {
18067c478bd9Sstevel@tonic-gate 		adapter_listhead_base.next = listhead;
18077c478bd9Sstevel@tonic-gate 		listhead->next_listhead = NULL;
18087c478bd9Sstevel@tonic-gate 	} else {
18097c478bd9Sstevel@tonic-gate 		listhead->next_listhead = adapter_listhead_base.next;
18107c478bd9Sstevel@tonic-gate 		adapter_listhead_base.next = listhead;
18117c478bd9Sstevel@tonic-gate 	}
18127c478bd9Sstevel@tonic-gate 	mutex_exit(&adapter_listhead_base.listlock);
18137c478bd9Sstevel@tonic-gate 
18147c478bd9Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "init_listhead done\n"));
18157c478bd9Sstevel@tonic-gate 
18167c478bd9Sstevel@tonic-gate 	return (listhead);
18177c478bd9Sstevel@tonic-gate }
18187c478bd9Sstevel@tonic-gate 
18197c478bd9Sstevel@tonic-gate 
18207c478bd9Sstevel@tonic-gate /*
18217c478bd9Sstevel@tonic-gate  * Search the list of adapter list heads for a match on name.
18227c478bd9Sstevel@tonic-gate  *
18237c478bd9Sstevel@tonic-gate  */
18247c478bd9Sstevel@tonic-gate static adapter_listhead_t *
lookup_adapter_listhead(char * name)18257c478bd9Sstevel@tonic-gate lookup_adapter_listhead(char *name)
18267c478bd9Sstevel@tonic-gate {
18277c478bd9Sstevel@tonic-gate 	adapter_listhead_t *listhead;
18287c478bd9Sstevel@tonic-gate 
18297c478bd9Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
18307c478bd9Sstevel@tonic-gate 	    "lookup_adapter_listhead enter\n"));
18317c478bd9Sstevel@tonic-gate 
18327c478bd9Sstevel@tonic-gate 	mutex_enter(&adapter_listhead_base.listlock);
18337c478bd9Sstevel@tonic-gate 	listhead = adapter_listhead_base.next;
18347c478bd9Sstevel@tonic-gate 	while (listhead != NULL) {
18357c478bd9Sstevel@tonic-gate 		if (strcmp(name, listhead->adapter_devname) == 0)
18367c478bd9Sstevel@tonic-gate 			break;
18377c478bd9Sstevel@tonic-gate 		listhead = listhead->next_listhead;
18387c478bd9Sstevel@tonic-gate 	}
18397c478bd9Sstevel@tonic-gate 	mutex_exit(&adapter_listhead_base.listlock);
18407c478bd9Sstevel@tonic-gate 
18417c478bd9Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
18427c478bd9Sstevel@tonic-gate 	    "lookup_adapter_listhead done\n"));
18437c478bd9Sstevel@tonic-gate 
18447c478bd9Sstevel@tonic-gate 	return (listhead);
18457c478bd9Sstevel@tonic-gate }
18467c478bd9Sstevel@tonic-gate 
18477c478bd9Sstevel@tonic-gate 
18487c478bd9Sstevel@tonic-gate /*
18497c478bd9Sstevel@tonic-gate  * Get the adapter list head corresponding to devname and search for
18507c478bd9Sstevel@tonic-gate  * an adapter descriptor with a match on the instance number. If
18517c478bd9Sstevel@tonic-gate  * successful, increment the descriptor reference count and return
18527c478bd9Sstevel@tonic-gate  * the descriptor pointer to the caller.
18537c478bd9Sstevel@tonic-gate  *
18547c478bd9Sstevel@tonic-gate  */
18557c478bd9Sstevel@tonic-gate adapter_t *
rsmka_lookup_adapter(char * devname,int instance)18567c478bd9Sstevel@tonic-gate rsmka_lookup_adapter(char *devname, int instance)
18577c478bd9Sstevel@tonic-gate {
18587c478bd9Sstevel@tonic-gate 	adapter_listhead_t *listhead;
18597c478bd9Sstevel@tonic-gate 	adapter_t *current = NULL;
18607c478bd9Sstevel@tonic-gate 
18617c478bd9Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
18627c478bd9Sstevel@tonic-gate 	    "rsmka_lookup_adapter enter\n"));
18637c478bd9Sstevel@tonic-gate 
18647c478bd9Sstevel@tonic-gate 	listhead = lookup_adapter_listhead(devname);
18657c478bd9Sstevel@tonic-gate 	if (listhead != NULL) {
18667c478bd9Sstevel@tonic-gate 		mutex_enter(&listhead->mutex);
18677c478bd9Sstevel@tonic-gate 
18687c478bd9Sstevel@tonic-gate 		current = listhead->next_adapter;
18697c478bd9Sstevel@tonic-gate 		while (current != NULL) {
18707c478bd9Sstevel@tonic-gate 			if (current->instance == instance) {
18717c478bd9Sstevel@tonic-gate 				ADAPTER_HOLD(current);
18727c478bd9Sstevel@tonic-gate 				break;
18737c478bd9Sstevel@tonic-gate 			} else
18747c478bd9Sstevel@tonic-gate 				current = current->next;
18757c478bd9Sstevel@tonic-gate 		}
18767c478bd9Sstevel@tonic-gate 
18777c478bd9Sstevel@tonic-gate 		mutex_exit(&listhead->mutex);
18787c478bd9Sstevel@tonic-gate 	}
18797c478bd9Sstevel@tonic-gate 
18807c478bd9Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
18817c478bd9Sstevel@tonic-gate 	    "rsmka_lookup_adapter done\n"));
18827c478bd9Sstevel@tonic-gate 
18837c478bd9Sstevel@tonic-gate 	return (current);
18847c478bd9Sstevel@tonic-gate }
18857c478bd9Sstevel@tonic-gate 
18867c478bd9Sstevel@tonic-gate /*
18877c478bd9Sstevel@tonic-gate  * Called from rsmka_remove_adapter or rsmseg_free.
18887c478bd9Sstevel@tonic-gate  * rsm_bind() and rsm_connect() store the adapter pointer returned
18897c478bd9Sstevel@tonic-gate  * from rsmka_getadapter.  The pointer is kept in the segment descriptor.
18907c478bd9Sstevel@tonic-gate  * When the segment is freed, this routine is called by rsmseg_free to decrement
18917c478bd9Sstevel@tonic-gate  * the adapter descriptor reference count and possibly free the
18927c478bd9Sstevel@tonic-gate  * descriptor.
18937c478bd9Sstevel@tonic-gate  */
18947c478bd9Sstevel@tonic-gate void
rsmka_release_adapter(adapter_t * adapter)18957c478bd9Sstevel@tonic-gate rsmka_release_adapter(adapter_t *adapter)
18967c478bd9Sstevel@tonic-gate {
18977c478bd9Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
18987c478bd9Sstevel@tonic-gate 	    "rsmka_release_adapter enter\n"));
18997c478bd9Sstevel@tonic-gate 
19007c478bd9Sstevel@tonic-gate 	if (adapter == &loopback_adapter) {
19017c478bd9Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
19027c478bd9Sstevel@tonic-gate 		    "rsmka_release_adapter done\n"));
19037c478bd9Sstevel@tonic-gate 		return;
19047c478bd9Sstevel@tonic-gate 	}
19057c478bd9Sstevel@tonic-gate 
19067c478bd9Sstevel@tonic-gate 	mutex_enter(&adapter->mutex);
19077c478bd9Sstevel@tonic-gate 
19087c478bd9Sstevel@tonic-gate 	/* decrement reference count */
19097c478bd9Sstevel@tonic-gate 	ADAPTER_RELE_NOLOCK(adapter);
19107c478bd9Sstevel@tonic-gate 
19117c478bd9Sstevel@tonic-gate 	/*
19127c478bd9Sstevel@tonic-gate 	 * if the adapter descriptor reference count is equal to the
19137c478bd9Sstevel@tonic-gate 	 * initialization value of one, then the descriptor has been
19147c478bd9Sstevel@tonic-gate 	 * unlinked and can now be freed.
19157c478bd9Sstevel@tonic-gate 	 */
19167c478bd9Sstevel@tonic-gate 	if (adapter->ref_cnt == 1) {
19177c478bd9Sstevel@tonic-gate 		mutex_exit(&adapter->mutex);
19187c478bd9Sstevel@tonic-gate 
19197c478bd9Sstevel@tonic-gate 		mutex_destroy(&adapter->mutex);
19207c478bd9Sstevel@tonic-gate 		kmem_free(adapter->hdlr_argp, sizeof (srv_handler_arg_t));
19217c478bd9Sstevel@tonic-gate 		kmem_free(adapter, sizeof (adapter_t));
19227c478bd9Sstevel@tonic-gate 	}
19237c478bd9Sstevel@tonic-gate 	else
19247c478bd9Sstevel@tonic-gate 		mutex_exit(&adapter->mutex);
19257c478bd9Sstevel@tonic-gate 
19267c478bd9Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
19277c478bd9Sstevel@tonic-gate 	    "rsmka_release_adapter done\n"));
19287c478bd9Sstevel@tonic-gate 
19297c478bd9Sstevel@tonic-gate }
19307c478bd9Sstevel@tonic-gate 
19317c478bd9Sstevel@tonic-gate 
19327c478bd9Sstevel@tonic-gate 
19337c478bd9Sstevel@tonic-gate /*
19347c478bd9Sstevel@tonic-gate  * Singly linked list. Add to the front.
19357c478bd9Sstevel@tonic-gate  */
19367c478bd9Sstevel@tonic-gate static void
link_adapter(adapter_t * adapter)19377c478bd9Sstevel@tonic-gate link_adapter(adapter_t *adapter)
19387c478bd9Sstevel@tonic-gate {
19397c478bd9Sstevel@tonic-gate 
19407c478bd9Sstevel@tonic-gate 	adapter_listhead_t *listhead;
19417c478bd9Sstevel@tonic-gate 	adapter_t *current;
19427c478bd9Sstevel@tonic-gate 
19437c478bd9Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "link_adapter enter\n"));
19447c478bd9Sstevel@tonic-gate 
19457c478bd9Sstevel@tonic-gate 	mutex_enter(&adapter_listhead_base.listlock);
19467c478bd9Sstevel@tonic-gate 
19477c478bd9Sstevel@tonic-gate 	mutex_enter(&adapter->listhead->mutex);
19487c478bd9Sstevel@tonic-gate 
19497c478bd9Sstevel@tonic-gate 	listhead = adapter->listhead;
19507c478bd9Sstevel@tonic-gate 	current = listhead->next_adapter;
19517c478bd9Sstevel@tonic-gate 	listhead->next_adapter = adapter;
19527c478bd9Sstevel@tonic-gate 	adapter->next = current;
19537c478bd9Sstevel@tonic-gate 	ADAPTER_HOLD(adapter);
19547c478bd9Sstevel@tonic-gate 
19557c478bd9Sstevel@tonic-gate 	adapter->listhead->adapter_count++;
19567c478bd9Sstevel@tonic-gate 
19577c478bd9Sstevel@tonic-gate 	mutex_exit(&adapter->listhead->mutex);
19587c478bd9Sstevel@tonic-gate 
19597c478bd9Sstevel@tonic-gate 	mutex_exit(&adapter_listhead_base.listlock);
19607c478bd9Sstevel@tonic-gate 
19617c478bd9Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "link_adapter done\n"));
19627c478bd9Sstevel@tonic-gate }
19637c478bd9Sstevel@tonic-gate 
19647c478bd9Sstevel@tonic-gate 
19657c478bd9Sstevel@tonic-gate /*
19667c478bd9Sstevel@tonic-gate  * Return adapter descriptor
19677c478bd9Sstevel@tonic-gate  *
19687c478bd9Sstevel@tonic-gate  * lookup_adapter_listhead returns with the the list of adapter listheads
19697c478bd9Sstevel@tonic-gate  * locked.  After adding the adapter descriptor, the adapter listhead list
19707c478bd9Sstevel@tonic-gate  * lock is dropped.
19717c478bd9Sstevel@tonic-gate  */
19727c478bd9Sstevel@tonic-gate static adapter_t *
init_adapter(char * name,int instance,rsm_addr_t hwaddr,rsm_controller_handle_t handle,rsm_ops_t * ops,srv_handler_arg_t * hdlr_argp)19737c478bd9Sstevel@tonic-gate init_adapter(char *name, int instance, rsm_addr_t hwaddr,
19747c478bd9Sstevel@tonic-gate     rsm_controller_handle_t handle, rsm_ops_t *ops,
19757c478bd9Sstevel@tonic-gate     srv_handler_arg_t *hdlr_argp)
19767c478bd9Sstevel@tonic-gate {
19777c478bd9Sstevel@tonic-gate 	adapter_t *adapter;
19787c478bd9Sstevel@tonic-gate 	adapter_listhead_t *listhead;
19797c478bd9Sstevel@tonic-gate 
19807c478bd9Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "init_adapter enter\n"));
19817c478bd9Sstevel@tonic-gate 
19827c478bd9Sstevel@tonic-gate 	adapter = kmem_zalloc(sizeof (adapter_t), KM_SLEEP);
19837c478bd9Sstevel@tonic-gate 	adapter->instance = instance;
19847c478bd9Sstevel@tonic-gate 	adapter->hwaddr = hwaddr;
19857c478bd9Sstevel@tonic-gate 	adapter->rsmpi_handle = handle;
19867c478bd9Sstevel@tonic-gate 	adapter->rsmpi_ops = ops;
19877c478bd9Sstevel@tonic-gate 	adapter->hdlr_argp = hdlr_argp;
19887c478bd9Sstevel@tonic-gate 	mutex_init(&adapter->mutex, NULL, MUTEX_DEFAULT, NULL);
19897c478bd9Sstevel@tonic-gate 	ADAPTER_HOLD(adapter);
19907c478bd9Sstevel@tonic-gate 
19917c478bd9Sstevel@tonic-gate 
19927c478bd9Sstevel@tonic-gate 	listhead = lookup_adapter_listhead(name);
19937c478bd9Sstevel@tonic-gate 	if (listhead == NULL)  {
19947c478bd9Sstevel@tonic-gate 		listhead = init_listhead(name);
19957c478bd9Sstevel@tonic-gate 	}
19967c478bd9Sstevel@tonic-gate 
19977c478bd9Sstevel@tonic-gate 	adapter->listhead = listhead;
19987c478bd9Sstevel@tonic-gate 
19997c478bd9Sstevel@tonic-gate 	link_adapter(adapter);
20007c478bd9Sstevel@tonic-gate 
20017c478bd9Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "init_adapter done\n"));
20027c478bd9Sstevel@tonic-gate 
20037c478bd9Sstevel@tonic-gate 	return (adapter);
20047c478bd9Sstevel@tonic-gate }
20057c478bd9Sstevel@tonic-gate 
20067c478bd9Sstevel@tonic-gate /*
20077c478bd9Sstevel@tonic-gate  *
20087c478bd9Sstevel@tonic-gate  * PATH UTILITY FUNCTIONS
20097c478bd9Sstevel@tonic-gate  *
20107c478bd9Sstevel@tonic-gate  */
20117c478bd9Sstevel@tonic-gate 
20127c478bd9Sstevel@tonic-gate 
20137c478bd9Sstevel@tonic-gate /*
20147c478bd9Sstevel@tonic-gate  * Search the per adapter path list for a match on remote node and
20157c478bd9Sstevel@tonic-gate  * hwaddr.  The path ref_cnt must be greater than zero or the path
20167c478bd9Sstevel@tonic-gate  * is in the process of being removed.
20177c478bd9Sstevel@tonic-gate  *
20187c478bd9Sstevel@tonic-gate  * Acquire the path lock and increment the path hold count.
20197c478bd9Sstevel@tonic-gate  */
20207c478bd9Sstevel@tonic-gate static path_t *
lookup_path(char * adapter_devname,int adapter_instance,rsm_node_id_t remote_node,rsm_addr_t hwaddr)20217c478bd9Sstevel@tonic-gate lookup_path(char *adapter_devname, int adapter_instance,
20227c478bd9Sstevel@tonic-gate     rsm_node_id_t remote_node, rsm_addr_t hwaddr)
20237c478bd9Sstevel@tonic-gate {
20247c478bd9Sstevel@tonic-gate 	path_t		*current;
20257c478bd9Sstevel@tonic-gate 	adapter_t	*adapter;
20267c478bd9Sstevel@tonic-gate 
20277c478bd9Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "lookup_path enter\n"));
20287c478bd9Sstevel@tonic-gate 
20297c478bd9Sstevel@tonic-gate 	adapter = rsmka_lookup_adapter(adapter_devname, adapter_instance);
20307c478bd9Sstevel@tonic-gate 	ASSERT(adapter != NULL);
20317c478bd9Sstevel@tonic-gate 
20327c478bd9Sstevel@tonic-gate 	mutex_enter(&adapter->listhead->mutex);
20337c478bd9Sstevel@tonic-gate 
20347c478bd9Sstevel@tonic-gate 	/* start at the list head */
20357c478bd9Sstevel@tonic-gate 	current = adapter->next_path;
20367c478bd9Sstevel@tonic-gate 
20377c478bd9Sstevel@tonic-gate 	while (current != NULL) {
20387c478bd9Sstevel@tonic-gate 		if ((current->remote_node == remote_node) &&
20397c478bd9Sstevel@tonic-gate 		    (current->remote_hwaddr == hwaddr) &&
20407c478bd9Sstevel@tonic-gate 		    (current->ref_cnt > 0))
20417c478bd9Sstevel@tonic-gate 			break;
20427c478bd9Sstevel@tonic-gate 		else
20437c478bd9Sstevel@tonic-gate 			current = current->next_path;
20447c478bd9Sstevel@tonic-gate 	}
20457c478bd9Sstevel@tonic-gate 	if (current != NULL) {
20467c478bd9Sstevel@tonic-gate 		mutex_enter(&current->mutex);
20477c478bd9Sstevel@tonic-gate 		PATH_HOLD_NOLOCK(current);
20487c478bd9Sstevel@tonic-gate 	}
20497c478bd9Sstevel@tonic-gate 
20507c478bd9Sstevel@tonic-gate 	mutex_exit(&adapter->listhead->mutex);
20517c478bd9Sstevel@tonic-gate 	ADAPTER_RELE(adapter);
20527c478bd9Sstevel@tonic-gate 
20537c478bd9Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "lookup_path done\n"));
20547c478bd9Sstevel@tonic-gate 
20557c478bd9Sstevel@tonic-gate 	return (current);
20567c478bd9Sstevel@tonic-gate }
20577c478bd9Sstevel@tonic-gate 
20587c478bd9Sstevel@tonic-gate /*
20597c478bd9Sstevel@tonic-gate  * This interface is similar to lookup_path but takes only the local
20607c478bd9Sstevel@tonic-gate  * adapter name, instance and remote adapters hwaddr to identify the
20617c478bd9Sstevel@tonic-gate  * path. This is used in the interrupt handler routines where nodeid
20627c478bd9Sstevel@tonic-gate  * is not always available.
20637c478bd9Sstevel@tonic-gate  */
20647c478bd9Sstevel@tonic-gate path_t *
rsm_find_path(char * adapter_devname,int adapter_instance,rsm_addr_t hwaddr)20657c478bd9Sstevel@tonic-gate rsm_find_path(char *adapter_devname, int adapter_instance, rsm_addr_t hwaddr)
20667c478bd9Sstevel@tonic-gate {
20677c478bd9Sstevel@tonic-gate 	path_t		*current;
20687c478bd9Sstevel@tonic-gate 	adapter_t	*adapter;
20697c478bd9Sstevel@tonic-gate 
20707c478bd9Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_find_path enter\n"));
20717c478bd9Sstevel@tonic-gate 
20727c478bd9Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
20737c478bd9Sstevel@tonic-gate 	    "rsm_find_path:adapter=%s:%d,rem=%llx\n",
20747c478bd9Sstevel@tonic-gate 	    adapter_devname, adapter_instance, hwaddr));
20757c478bd9Sstevel@tonic-gate 
20767c478bd9Sstevel@tonic-gate 	adapter = rsmka_lookup_adapter(adapter_devname, adapter_instance);
20777c478bd9Sstevel@tonic-gate 
20787c478bd9Sstevel@tonic-gate 	/*
20797c478bd9Sstevel@tonic-gate 	 * its possible that we are here due to an interrupt but the adapter
20807c478bd9Sstevel@tonic-gate 	 * has been removed after we received the callback.
20817c478bd9Sstevel@tonic-gate 	 */
20827c478bd9Sstevel@tonic-gate 	if (adapter == NULL)
20837c478bd9Sstevel@tonic-gate 		return (NULL);
20847c478bd9Sstevel@tonic-gate 
20857c478bd9Sstevel@tonic-gate 	mutex_enter(&adapter->listhead->mutex);
20867c478bd9Sstevel@tonic-gate 
20877c478bd9Sstevel@tonic-gate 	/* start at the list head */
20887c478bd9Sstevel@tonic-gate 	current = adapter->next_path;
20897c478bd9Sstevel@tonic-gate 
20907c478bd9Sstevel@tonic-gate 	while (current != NULL) {
20917c478bd9Sstevel@tonic-gate 		if ((current->remote_hwaddr == hwaddr) &&
20927c478bd9Sstevel@tonic-gate 		    (current->ref_cnt > 0))
20937c478bd9Sstevel@tonic-gate 			break;
20947c478bd9Sstevel@tonic-gate 		else
20957c478bd9Sstevel@tonic-gate 			current = current->next_path;
20967c478bd9Sstevel@tonic-gate 	}
20977c478bd9Sstevel@tonic-gate 	if (current != NULL) {
20987c478bd9Sstevel@tonic-gate 		mutex_enter(&current->mutex);
20997c478bd9Sstevel@tonic-gate 		PATH_HOLD_NOLOCK(current);
21007c478bd9Sstevel@tonic-gate 	}
21017c478bd9Sstevel@tonic-gate 
21027c478bd9Sstevel@tonic-gate 	mutex_exit(&adapter->listhead->mutex);
21037c478bd9Sstevel@tonic-gate 
21047c478bd9Sstevel@tonic-gate 	rsmka_release_adapter(adapter);
21057c478bd9Sstevel@tonic-gate 
21067c478bd9Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_find_path done\n"));
21077c478bd9Sstevel@tonic-gate 
21087c478bd9Sstevel@tonic-gate 	return (current);
21097c478bd9Sstevel@tonic-gate }
21107c478bd9Sstevel@tonic-gate 
21117c478bd9Sstevel@tonic-gate 
21127c478bd9Sstevel@tonic-gate /*
21137c478bd9Sstevel@tonic-gate  * Add the path to the head of the (per adapter) list of paths
21147c478bd9Sstevel@tonic-gate  */
21157c478bd9Sstevel@tonic-gate static void
link_path(path_t * path)21167c478bd9Sstevel@tonic-gate link_path(path_t *path)
21177c478bd9Sstevel@tonic-gate {
21187c478bd9Sstevel@tonic-gate 
21197c478bd9Sstevel@tonic-gate 	adapter_t *adapter = path->local_adapter;
21207c478bd9Sstevel@tonic-gate 	path_t *first_path;
21217c478bd9Sstevel@tonic-gate 
21227c478bd9Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "link_path enter\n"));
21237c478bd9Sstevel@tonic-gate 
21247c478bd9Sstevel@tonic-gate 	mutex_enter(&adapter_listhead_base.listlock);
21257c478bd9Sstevel@tonic-gate 
21267c478bd9Sstevel@tonic-gate 	mutex_enter(&adapter->listhead->mutex);
21277c478bd9Sstevel@tonic-gate 
21287c478bd9Sstevel@tonic-gate 	first_path = adapter->next_path;
21297c478bd9Sstevel@tonic-gate 	adapter->next_path = path;
21307c478bd9Sstevel@tonic-gate 	path->next_path = first_path;
21317c478bd9Sstevel@tonic-gate 
21327c478bd9Sstevel@tonic-gate 	adapter->listhead->path_count++;
21337c478bd9Sstevel@tonic-gate 
21347c478bd9Sstevel@tonic-gate 	mutex_exit(&adapter->listhead->mutex);
21357c478bd9Sstevel@tonic-gate 
21367c478bd9Sstevel@tonic-gate 	mutex_exit(&adapter_listhead_base.listlock);
21377c478bd9Sstevel@tonic-gate 
21387c478bd9Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "link_path done\n"));
21397c478bd9Sstevel@tonic-gate }
21407c478bd9Sstevel@tonic-gate 
21417c478bd9Sstevel@tonic-gate /*
21427c478bd9Sstevel@tonic-gate  * Search the per-adapter list of paths for the specified path, beginning
21437c478bd9Sstevel@tonic-gate  * at the head of the list.  Unlink the path and free the descriptor
21447c478bd9Sstevel@tonic-gate  * memory.
21457c478bd9Sstevel@tonic-gate  */
21467c478bd9Sstevel@tonic-gate static void
destroy_path(path_t * path)21477c478bd9Sstevel@tonic-gate destroy_path(path_t *path)
21487c478bd9Sstevel@tonic-gate {
21497c478bd9Sstevel@tonic-gate 
21507c478bd9Sstevel@tonic-gate 	adapter_t *adapter = path->local_adapter;
21517c478bd9Sstevel@tonic-gate 	path_t *prev, *current;
21527c478bd9Sstevel@tonic-gate 
21537c478bd9Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "destroy_path enter\n"));
21547c478bd9Sstevel@tonic-gate 
21557c478bd9Sstevel@tonic-gate 	mutex_enter(&adapter_listhead_base.listlock);
21567c478bd9Sstevel@tonic-gate 
21577c478bd9Sstevel@tonic-gate 	mutex_enter(&path->local_adapter->listhead->mutex);
21587c478bd9Sstevel@tonic-gate 	ASSERT(path->ref_cnt == 0);
21597c478bd9Sstevel@tonic-gate 
21607c478bd9Sstevel@tonic-gate 	/* start at the list head */
21617c478bd9Sstevel@tonic-gate 	prev = NULL;
21627c478bd9Sstevel@tonic-gate 	current =  adapter->next_path;
21637c478bd9Sstevel@tonic-gate 
21647c478bd9Sstevel@tonic-gate 	while (current != NULL) {
21657c478bd9Sstevel@tonic-gate 		if (path->remote_node == current->remote_node &&
21667c478bd9Sstevel@tonic-gate 		    path->remote_hwaddr == current->remote_hwaddr)
21677c478bd9Sstevel@tonic-gate 			break;
21687c478bd9Sstevel@tonic-gate 		else {
21697c478bd9Sstevel@tonic-gate 			prev = current;
21707c478bd9Sstevel@tonic-gate 			current = current->next_path;
21717c478bd9Sstevel@tonic-gate 		}
21727c478bd9Sstevel@tonic-gate 	}
21737c478bd9Sstevel@tonic-gate 
21747c478bd9Sstevel@tonic-gate 	if (prev == NULL)
21757c478bd9Sstevel@tonic-gate 		adapter->next_path = current->next_path;
21767c478bd9Sstevel@tonic-gate 	else
21777c478bd9Sstevel@tonic-gate 		prev->next_path = current->next_path;
21787c478bd9Sstevel@tonic-gate 
21797c478bd9Sstevel@tonic-gate 	path->local_adapter->listhead->path_count--;
21807c478bd9Sstevel@tonic-gate 
21817c478bd9Sstevel@tonic-gate 	mutex_exit(&path->local_adapter->listhead->mutex);
21827c478bd9Sstevel@tonic-gate 
21837c478bd9Sstevel@tonic-gate 	mutex_exit(&adapter_listhead_base.listlock);
21847c478bd9Sstevel@tonic-gate 
21857c478bd9Sstevel@tonic-gate 	taskq_destroy(path->recv_taskq);
21867c478bd9Sstevel@tonic-gate 
21877c478bd9Sstevel@tonic-gate 	kmem_free(path->msgbuf_queue,
21887c478bd9Sstevel@tonic-gate 	    RSMIPC_MAX_MESSAGES * sizeof (msgbuf_elem_t));
21897c478bd9Sstevel@tonic-gate 
21907c478bd9Sstevel@tonic-gate 	mutex_destroy(&current->mutex);
21917c478bd9Sstevel@tonic-gate 	cv_destroy(&current->sendq_token.sendq_cv);
21927c478bd9Sstevel@tonic-gate 	cv_destroy(&path->hold_cv);
21937c478bd9Sstevel@tonic-gate 	kmem_free(current, sizeof (path_t));
21947c478bd9Sstevel@tonic-gate 
21957c478bd9Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "destroy_path done\n"));
21967c478bd9Sstevel@tonic-gate }
21977c478bd9Sstevel@tonic-gate 
21987c478bd9Sstevel@tonic-gate void
rsmka_enqueue_msgbuf(path_t * path,void * data)21997c478bd9Sstevel@tonic-gate rsmka_enqueue_msgbuf(path_t *path, void *data)
22007c478bd9Sstevel@tonic-gate {
22017c478bd9Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
22027c478bd9Sstevel@tonic-gate 	    "rsmka_enqueue_msgbuf enter\n"));
22037c478bd9Sstevel@tonic-gate 
22047c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&path->mutex));
22057c478bd9Sstevel@tonic-gate 
22067c478bd9Sstevel@tonic-gate 	ASSERT(path->msgbuf_cnt < RSMIPC_MAX_MESSAGES);
22077c478bd9Sstevel@tonic-gate 
22087c478bd9Sstevel@tonic-gate 	/* increment the count and advance the tail */
22097c478bd9Sstevel@tonic-gate 
22107c478bd9Sstevel@tonic-gate 	path->msgbuf_cnt++;
22117c478bd9Sstevel@tonic-gate 
22127c478bd9Sstevel@tonic-gate 	if (path->msgbuf_tail == RSMIPC_MAX_MESSAGES - 1) {
22137c478bd9Sstevel@tonic-gate 		path->msgbuf_tail = 0;
22147c478bd9Sstevel@tonic-gate 	} else {
22157c478bd9Sstevel@tonic-gate 		path->msgbuf_tail++;
22167c478bd9Sstevel@tonic-gate 	}
22177c478bd9Sstevel@tonic-gate 
22187c478bd9Sstevel@tonic-gate 	path->msgbuf_queue[path->msgbuf_tail].active = B_TRUE;
22197c478bd9Sstevel@tonic-gate 
22207c478bd9Sstevel@tonic-gate 	bcopy(data, &(path->msgbuf_queue[path->msgbuf_tail].msg),
22217c478bd9Sstevel@tonic-gate 	    sizeof (rsmipc_request_t));
22227c478bd9Sstevel@tonic-gate 
22237c478bd9Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
22247c478bd9Sstevel@tonic-gate 	    "rsmka_enqueue_msgbuf done\n"));
22257c478bd9Sstevel@tonic-gate 
22267c478bd9Sstevel@tonic-gate }
22277c478bd9Sstevel@tonic-gate 
22287c478bd9Sstevel@tonic-gate /*
22297c478bd9Sstevel@tonic-gate  * get the head of the queue using rsmka_gethead_msgbuf and then call
22307c478bd9Sstevel@tonic-gate  * rsmka_dequeue_msgbuf to remove it.
22317c478bd9Sstevel@tonic-gate  */
22327c478bd9Sstevel@tonic-gate void
rsmka_dequeue_msgbuf(path_t * path)22337c478bd9Sstevel@tonic-gate rsmka_dequeue_msgbuf(path_t *path)
22347c478bd9Sstevel@tonic-gate {
22357c478bd9Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
22367c478bd9Sstevel@tonic-gate 	    "rsmka_dequeue_msgbuf enter\n"));
22377c478bd9Sstevel@tonic-gate 
22387c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&path->mutex));
22397c478bd9Sstevel@tonic-gate 
22407c478bd9Sstevel@tonic-gate 	if (path->msgbuf_cnt == 0)
22417c478bd9Sstevel@tonic-gate 		return;
22427c478bd9Sstevel@tonic-gate 
22437c478bd9Sstevel@tonic-gate 	path->msgbuf_cnt--;
22447c478bd9Sstevel@tonic-gate 
22457c478bd9Sstevel@tonic-gate 	path->msgbuf_queue[path->msgbuf_head].active = B_FALSE;
22467c478bd9Sstevel@tonic-gate 
22477c478bd9Sstevel@tonic-gate 	if (path->msgbuf_head == RSMIPC_MAX_MESSAGES - 1) {
22487c478bd9Sstevel@tonic-gate 		path->msgbuf_head = 0;
22497c478bd9Sstevel@tonic-gate 	} else {
22507c478bd9Sstevel@tonic-gate 		path->msgbuf_head++;
22517c478bd9Sstevel@tonic-gate 	}
22527c478bd9Sstevel@tonic-gate 
22537c478bd9Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
22547c478bd9Sstevel@tonic-gate 	    "rsmka_dequeue_msgbuf done\n"));
22557c478bd9Sstevel@tonic-gate 
22567c478bd9Sstevel@tonic-gate }
22577c478bd9Sstevel@tonic-gate 
22587c478bd9Sstevel@tonic-gate msgbuf_elem_t *
rsmka_gethead_msgbuf(path_t * path)22597c478bd9Sstevel@tonic-gate rsmka_gethead_msgbuf(path_t *path)
22607c478bd9Sstevel@tonic-gate {
22617c478bd9Sstevel@tonic-gate 	msgbuf_elem_t	*head;
22627c478bd9Sstevel@tonic-gate 
22637c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&path->mutex));
22647c478bd9Sstevel@tonic-gate 
22657c478bd9Sstevel@tonic-gate 	if (path->msgbuf_cnt == 0)
22667c478bd9Sstevel@tonic-gate 		return (NULL);
22677c478bd9Sstevel@tonic-gate 
22687c478bd9Sstevel@tonic-gate 	head = &path->msgbuf_queue[path->msgbuf_head];
22697c478bd9Sstevel@tonic-gate 
22707c478bd9Sstevel@tonic-gate 	return (head);
22717c478bd9Sstevel@tonic-gate 
22727c478bd9Sstevel@tonic-gate }
22737c478bd9Sstevel@tonic-gate /*
22747c478bd9Sstevel@tonic-gate  * Called by rsm_connect which needs the hardware address of the
22757c478bd9Sstevel@tonic-gate  * remote adapter.  A search is done through the paths for the local
22767c478bd9Sstevel@tonic-gate  * adapter for a match on the specified remote node.
22777c478bd9Sstevel@tonic-gate  */
22787c478bd9Sstevel@tonic-gate rsm_node_id_t
get_remote_nodeid(adapter_t * adapter,rsm_addr_t remote_hwaddr)22797c478bd9Sstevel@tonic-gate get_remote_nodeid(adapter_t *adapter, rsm_addr_t remote_hwaddr)
22807c478bd9Sstevel@tonic-gate {
22817c478bd9Sstevel@tonic-gate 
22827c478bd9Sstevel@tonic-gate 	rsm_node_id_t remote_node;
22837c478bd9Sstevel@tonic-gate 	path_t	   *current = adapter->next_path;
22847c478bd9Sstevel@tonic-gate 
22857c478bd9Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "get_remote_nodeid enter\n"));
22867c478bd9Sstevel@tonic-gate 
22877c478bd9Sstevel@tonic-gate 	mutex_enter(&adapter->listhead->mutex);
22887c478bd9Sstevel@tonic-gate 	while (current != NULL) {
22897c478bd9Sstevel@tonic-gate 		if (current->remote_hwaddr == remote_hwaddr) {
22907c478bd9Sstevel@tonic-gate 			remote_node = current->remote_node;
22917c478bd9Sstevel@tonic-gate 			break;
22927c478bd9Sstevel@tonic-gate 		}
22937c478bd9Sstevel@tonic-gate 		current = current->next_path;
22947c478bd9Sstevel@tonic-gate 	}
22957c478bd9Sstevel@tonic-gate 
22967c478bd9Sstevel@tonic-gate 	if (current == NULL)
22977c478bd9Sstevel@tonic-gate 		remote_node = (rsm_node_id_t)-1;
22987c478bd9Sstevel@tonic-gate 
22997c478bd9Sstevel@tonic-gate 	mutex_exit(&adapter->listhead->mutex);
23007c478bd9Sstevel@tonic-gate 
23017c478bd9Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "get_remote_nodeid done\n"));
23027c478bd9Sstevel@tonic-gate 
23037c478bd9Sstevel@tonic-gate 	return (remote_node);
23047c478bd9Sstevel@tonic-gate }
23057c478bd9Sstevel@tonic-gate 
23067c478bd9Sstevel@tonic-gate /*
23077c478bd9Sstevel@tonic-gate  * Called by rsm_connect which needs the hardware address of the
23087c478bd9Sstevel@tonic-gate  * remote adapter.  A search is done through the paths for the local
23097c478bd9Sstevel@tonic-gate  * adapter for a match on the specified remote node.
23107c478bd9Sstevel@tonic-gate  */
23117c478bd9Sstevel@tonic-gate rsm_addr_t
get_remote_hwaddr(adapter_t * adapter,rsm_node_id_t remote_node)23127c478bd9Sstevel@tonic-gate get_remote_hwaddr(adapter_t *adapter, rsm_node_id_t remote_node)
23137c478bd9Sstevel@tonic-gate {
23147c478bd9Sstevel@tonic-gate 
23157c478bd9Sstevel@tonic-gate 	rsm_addr_t remote_hwaddr;
23167c478bd9Sstevel@tonic-gate 	path_t	   *current = adapter->next_path;
23177c478bd9Sstevel@tonic-gate 
23187c478bd9Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "get_remote_hwaddr enter\n"));
23197c478bd9Sstevel@tonic-gate 
23207c478bd9Sstevel@tonic-gate 	mutex_enter(&adapter->listhead->mutex);
23217c478bd9Sstevel@tonic-gate 	while (current != NULL) {
23227c478bd9Sstevel@tonic-gate 		if (current->remote_node == remote_node) {
23237c478bd9Sstevel@tonic-gate 			remote_hwaddr = current->remote_hwaddr;
23247c478bd9Sstevel@tonic-gate 			break;
23257c478bd9Sstevel@tonic-gate 		}
23267c478bd9Sstevel@tonic-gate 		current = current->next_path;
23277c478bd9Sstevel@tonic-gate 	}
23287c478bd9Sstevel@tonic-gate 	if (current == NULL)
23297c478bd9Sstevel@tonic-gate 		remote_hwaddr = -1;
23307c478bd9Sstevel@tonic-gate 	mutex_exit(&adapter->listhead->mutex);
23317c478bd9Sstevel@tonic-gate 
23327c478bd9Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "get_remote_hwaddr done\n"));
23337c478bd9Sstevel@tonic-gate 
23347c478bd9Sstevel@tonic-gate 	return (remote_hwaddr);
23357c478bd9Sstevel@tonic-gate }
23367c478bd9Sstevel@tonic-gate /*
23377c478bd9Sstevel@tonic-gate  * IPC UTILITY FUNCTIONS
23387c478bd9Sstevel@tonic-gate  */
23397c478bd9Sstevel@tonic-gate 
23407c478bd9Sstevel@tonic-gate 
23417c478bd9Sstevel@tonic-gate /*
23427c478bd9Sstevel@tonic-gate  * If an entry exists, return with the ipc_info_lock held
23437c478bd9Sstevel@tonic-gate  */
23447c478bd9Sstevel@tonic-gate static ipc_info_t *
lookup_ipc_info(rsm_node_id_t remote_node)23457c478bd9Sstevel@tonic-gate lookup_ipc_info(rsm_node_id_t remote_node)
23467c478bd9Sstevel@tonic-gate {
23477c478bd9Sstevel@tonic-gate 	ipc_info_t  *ipc_info;
23487c478bd9Sstevel@tonic-gate 
23497c478bd9Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "lookup_ipc_info enter\n"));
23507c478bd9Sstevel@tonic-gate 
23517c478bd9Sstevel@tonic-gate 	mutex_enter(&ipc_info_lock);
23527c478bd9Sstevel@tonic-gate 
23537c478bd9Sstevel@tonic-gate 	ipc_info = ipc_info_head;
23547c478bd9Sstevel@tonic-gate 	if (ipc_info == NULL) {
23557c478bd9Sstevel@tonic-gate 		mutex_exit(&ipc_info_lock);
23567c478bd9Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
23577c478bd9Sstevel@tonic-gate 		    "lookup_ipc_info done: ipc_info is NULL\n"));
23587c478bd9Sstevel@tonic-gate 		return (NULL);
23597c478bd9Sstevel@tonic-gate 	}
23607c478bd9Sstevel@tonic-gate 
23617c478bd9Sstevel@tonic-gate 	while (ipc_info->remote_node != remote_node) {
23627c478bd9Sstevel@tonic-gate 		ipc_info = ipc_info->next;
23637c478bd9Sstevel@tonic-gate 		if (ipc_info == NULL) {
23647c478bd9Sstevel@tonic-gate 			DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
23657c478bd9Sstevel@tonic-gate 			    "lookup_ipc_info: ipc_info not found\n"));
23667c478bd9Sstevel@tonic-gate 			mutex_exit(&ipc_info_lock);
23677c478bd9Sstevel@tonic-gate 			break;
23687c478bd9Sstevel@tonic-gate 		}
23697c478bd9Sstevel@tonic-gate 	}
23707c478bd9Sstevel@tonic-gate 
23717c478bd9Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "lookup_ipc_info done\n"));
23727c478bd9Sstevel@tonic-gate 
23737c478bd9Sstevel@tonic-gate 	return (ipc_info);
23747c478bd9Sstevel@tonic-gate }
23757c478bd9Sstevel@tonic-gate 
23767c478bd9Sstevel@tonic-gate /*
23777c478bd9Sstevel@tonic-gate  * Create an ipc_info descriptor and return with ipc_info_lock held
23787c478bd9Sstevel@tonic-gate  */
23797c478bd9Sstevel@tonic-gate static ipc_info_t *
init_ipc_info(rsm_node_id_t remote_node,boolean_t state)23807c478bd9Sstevel@tonic-gate init_ipc_info(rsm_node_id_t remote_node, boolean_t state)
23817c478bd9Sstevel@tonic-gate {
23827c478bd9Sstevel@tonic-gate 	ipc_info_t *ipc_info;
23837c478bd9Sstevel@tonic-gate 
23847c478bd9Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "init_ipc_info enter\n"));
23857c478bd9Sstevel@tonic-gate 
23867c478bd9Sstevel@tonic-gate 	/*
23877c478bd9Sstevel@tonic-gate 	 * allocate an ipc_info descriptor and add it to a
23887c478bd9Sstevel@tonic-gate 	 * singly linked list
23897c478bd9Sstevel@tonic-gate 	 */
23907c478bd9Sstevel@tonic-gate 
23917c478bd9Sstevel@tonic-gate 	ipc_info = kmem_zalloc(sizeof (ipc_info_t), KM_SLEEP);
23927c478bd9Sstevel@tonic-gate 	ipc_info->remote_node = remote_node;
23937c478bd9Sstevel@tonic-gate 	ipc_info->node_is_alive = state;
23947c478bd9Sstevel@tonic-gate 
23957c478bd9Sstevel@tonic-gate 	mutex_enter(&ipc_info_lock);
23967c478bd9Sstevel@tonic-gate 	if (ipc_info_head == NULL) {
23977c478bd9Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_DEBUG,
23987c478bd9Sstevel@tonic-gate 		    "init_ipc_info:ipc_info_head = %lx\n", ipc_info));
23997c478bd9Sstevel@tonic-gate 		ipc_info_head = ipc_info;
24007c478bd9Sstevel@tonic-gate 		ipc_info->next = NULL;
24017c478bd9Sstevel@tonic-gate 	} else {
24027c478bd9Sstevel@tonic-gate 		ipc_info->next = ipc_info_head;
24037c478bd9Sstevel@tonic-gate 		ipc_info_head = ipc_info;
24047c478bd9Sstevel@tonic-gate 	}
24057c478bd9Sstevel@tonic-gate 
24067c478bd9Sstevel@tonic-gate 	ipc_info->remote_node = remote_node;
24077c478bd9Sstevel@tonic-gate 
24087c478bd9Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "init_ipc_info done\n"));
24097c478bd9Sstevel@tonic-gate 
24107c478bd9Sstevel@tonic-gate 	return (ipc_info);
24117c478bd9Sstevel@tonic-gate }
24127c478bd9Sstevel@tonic-gate 
24137c478bd9Sstevel@tonic-gate static void
destroy_ipc_info(ipc_info_t * ipc_info)24147c478bd9Sstevel@tonic-gate destroy_ipc_info(ipc_info_t *ipc_info)
24157c478bd9Sstevel@tonic-gate {
24167c478bd9Sstevel@tonic-gate 	ipc_info_t *current = ipc_info_head;
24177c478bd9Sstevel@tonic-gate 	ipc_info_t *prev;
24187c478bd9Sstevel@tonic-gate 
24197c478bd9Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "destroy_ipc_info enter\n"));
24207c478bd9Sstevel@tonic-gate 
24217c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&ipc_info_lock));
24227c478bd9Sstevel@tonic-gate 
24237c478bd9Sstevel@tonic-gate 	while (current != ipc_info) {
24247c478bd9Sstevel@tonic-gate 		prev = current;
24257c478bd9Sstevel@tonic-gate 		current = current->next;
24267c478bd9Sstevel@tonic-gate 	}
24277c478bd9Sstevel@tonic-gate 	ASSERT(current != NULL);
24287c478bd9Sstevel@tonic-gate 
24297c478bd9Sstevel@tonic-gate 	if (current != ipc_info_head)
24307c478bd9Sstevel@tonic-gate 		prev->next = current->next;
24317c478bd9Sstevel@tonic-gate 	else
24327c478bd9Sstevel@tonic-gate 		ipc_info_head = current->next;
24337c478bd9Sstevel@tonic-gate 
24347c478bd9Sstevel@tonic-gate 	kmem_free(current, sizeof (ipc_info_t));
24357c478bd9Sstevel@tonic-gate 
24367c478bd9Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "destroy_ipc_info done\n"));
24377c478bd9Sstevel@tonic-gate 
24387c478bd9Sstevel@tonic-gate }
24397c478bd9Sstevel@tonic-gate 
24407c478bd9Sstevel@tonic-gate /*
24417c478bd9Sstevel@tonic-gate  * Sendq tokens are kept on a circular list.  If tokens A, B, C, & D are
24427c478bd9Sstevel@tonic-gate  * on the list headed by ipc_info, then ipc_info points to A, A points to
24437c478bd9Sstevel@tonic-gate  * D, D to C, C to B, and B to A.
24447c478bd9Sstevel@tonic-gate  */
24457c478bd9Sstevel@tonic-gate static void
link_sendq_token(sendq_token_t * token,rsm_node_id_t remote_node)24467c478bd9Sstevel@tonic-gate link_sendq_token(sendq_token_t *token, rsm_node_id_t remote_node)
24477c478bd9Sstevel@tonic-gate {
24487c478bd9Sstevel@tonic-gate 	ipc_info_t *ipc_info;
24497c478bd9Sstevel@tonic-gate 
24507c478bd9Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "link_sendq_token enter\n"));
24517c478bd9Sstevel@tonic-gate 
24527c478bd9Sstevel@tonic-gate 	ipc_info = lookup_ipc_info(remote_node);
24537c478bd9Sstevel@tonic-gate 	if (ipc_info == NULL) {
24547c478bd9Sstevel@tonic-gate 		ipc_info = init_ipc_info(remote_node, B_FALSE);
24557c478bd9Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_DEBUG,
24567c478bd9Sstevel@tonic-gate 		    "link_sendq_token: new ipc_info = %lx\n", ipc_info));
24577c478bd9Sstevel@tonic-gate 	}
24587c478bd9Sstevel@tonic-gate 	else
24597c478bd9Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_DEBUG,
24607c478bd9Sstevel@tonic-gate 		    "link_sendq_token: ipc_info = %lx\n", ipc_info));
24617c478bd9Sstevel@tonic-gate 
24627c478bd9Sstevel@tonic-gate 	if (ipc_info->token_list == NULL) {
24637c478bd9Sstevel@tonic-gate 		ipc_info->token_list = token;
24647c478bd9Sstevel@tonic-gate 		ipc_info->current_token = token;
24657c478bd9Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_DEBUG,
24667c478bd9Sstevel@tonic-gate 		    "link_sendq_token: current = %lx\n", token));
24677c478bd9Sstevel@tonic-gate 		token->next = token;
24687c478bd9Sstevel@tonic-gate 	} else {
24697c478bd9Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_DEBUG,
24707c478bd9Sstevel@tonic-gate 		    "link_sendq_token: token = %lx\n", token));
24717c478bd9Sstevel@tonic-gate 		token->next = ipc_info->token_list->next;
24727c478bd9Sstevel@tonic-gate 		ipc_info->token_list->next = token;
24737c478bd9Sstevel@tonic-gate 		ipc_info->token_list = token;
24747c478bd9Sstevel@tonic-gate 	}
24757c478bd9Sstevel@tonic-gate 
24767c478bd9Sstevel@tonic-gate 
24777c478bd9Sstevel@tonic-gate 	mutex_exit(&ipc_info_lock);
24787c478bd9Sstevel@tonic-gate 
24797c478bd9Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "link_sendq_token done\n"));
24807c478bd9Sstevel@tonic-gate 
24817c478bd9Sstevel@tonic-gate }
24827c478bd9Sstevel@tonic-gate 
24837c478bd9Sstevel@tonic-gate static void
unlink_sendq_token(sendq_token_t * token,rsm_node_id_t remote_node)24847c478bd9Sstevel@tonic-gate unlink_sendq_token(sendq_token_t *token, rsm_node_id_t remote_node)
24857c478bd9Sstevel@tonic-gate {
24867c478bd9Sstevel@tonic-gate 	sendq_token_t *prev, *start,  *current;
24877c478bd9Sstevel@tonic-gate 	ipc_info_t *ipc_info;
24887c478bd9Sstevel@tonic-gate 	path_t *path = SQ_TOKEN_TO_PATH(token);
24897c478bd9Sstevel@tonic-gate 
24907c478bd9Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
24917c478bd9Sstevel@tonic-gate 	    "unlink_sendq_token enter\n"));
24927c478bd9Sstevel@tonic-gate 
24937c478bd9Sstevel@tonic-gate 	ASSERT(path->ref_cnt == 0);
24947c478bd9Sstevel@tonic-gate 
24957c478bd9Sstevel@tonic-gate 	ipc_info = lookup_ipc_info(remote_node);
24967c478bd9Sstevel@tonic-gate 	if (ipc_info == NULL) {
24977c478bd9Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_DEBUG,
24987c478bd9Sstevel@tonic-gate 		    "ipc_info for %d not found\n", remote_node));
24997c478bd9Sstevel@tonic-gate 		return;
25007c478bd9Sstevel@tonic-gate 	}
25017c478bd9Sstevel@tonic-gate 
25027c478bd9Sstevel@tonic-gate 	prev = ipc_info->token_list;
25037c478bd9Sstevel@tonic-gate 	start = current = ipc_info->token_list->next;
25047c478bd9Sstevel@tonic-gate 
25057c478bd9Sstevel@tonic-gate 	for (;;) {
25067c478bd9Sstevel@tonic-gate 		if (current == token) {
25077c478bd9Sstevel@tonic-gate 			if (current->next != current) {
25087c478bd9Sstevel@tonic-gate 				DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
25097c478bd9Sstevel@tonic-gate 				    "found token, removed it\n"));
25107c478bd9Sstevel@tonic-gate 				prev->next = token->next;
25117c478bd9Sstevel@tonic-gate 				if (ipc_info->token_list == token)
25127c478bd9Sstevel@tonic-gate 					ipc_info->token_list = prev;
25137c478bd9Sstevel@tonic-gate 				ipc_info->current_token = token->next;
25147c478bd9Sstevel@tonic-gate 			} else {
25157c478bd9Sstevel@tonic-gate 				/* list will be empty  */
25167c478bd9Sstevel@tonic-gate 				DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
25177c478bd9Sstevel@tonic-gate 				    "removed token, list empty\n"));
25187c478bd9Sstevel@tonic-gate 				ipc_info->token_list = NULL;
25197c478bd9Sstevel@tonic-gate 				ipc_info->current_token = NULL;
25207c478bd9Sstevel@tonic-gate 			}
25217c478bd9Sstevel@tonic-gate 			break;
25227c478bd9Sstevel@tonic-gate 		}
25237c478bd9Sstevel@tonic-gate 		prev = current;
25247c478bd9Sstevel@tonic-gate 		current = current->next;
25257c478bd9Sstevel@tonic-gate 		if (current == start) {
25267c478bd9Sstevel@tonic-gate 			DBG_PRINTF((category, RSM_DEBUG,
25277c478bd9Sstevel@tonic-gate 			    "unlink_sendq_token: token not found\n"));
25287c478bd9Sstevel@tonic-gate 			break;
25297c478bd9Sstevel@tonic-gate 		}
25307c478bd9Sstevel@tonic-gate 	}
25317c478bd9Sstevel@tonic-gate 	mutex_exit(&ipc_info_lock);
25327c478bd9Sstevel@tonic-gate 
25337c478bd9Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "unlink_sendq_token done\n"));
25347c478bd9Sstevel@tonic-gate }
25357c478bd9Sstevel@tonic-gate 
25367c478bd9Sstevel@tonic-gate 
25377c478bd9Sstevel@tonic-gate void
rele_sendq_token(sendq_token_t * token)25387c478bd9Sstevel@tonic-gate rele_sendq_token(sendq_token_t *token)
25397c478bd9Sstevel@tonic-gate {
25407c478bd9Sstevel@tonic-gate 	path_t *path;
25417c478bd9Sstevel@tonic-gate 
25427c478bd9Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rele_sendq_token enter\n"));
25437c478bd9Sstevel@tonic-gate 
25447c478bd9Sstevel@tonic-gate 	path = SQ_TOKEN_TO_PATH(token);
25457c478bd9Sstevel@tonic-gate 	mutex_enter(&path->mutex);
25467c478bd9Sstevel@tonic-gate 	PATH_RELE_NOLOCK(path);
25477c478bd9Sstevel@tonic-gate 	SENDQ_TOKEN_RELE(path);
25487c478bd9Sstevel@tonic-gate 	mutex_exit(&path->mutex);
25497c478bd9Sstevel@tonic-gate 
25507c478bd9Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rele_sendq_token done\n"));
25517c478bd9Sstevel@tonic-gate 
25527c478bd9Sstevel@tonic-gate }
25537c478bd9Sstevel@tonic-gate 
25547c478bd9Sstevel@tonic-gate /*
25557c478bd9Sstevel@tonic-gate  * A valid ipc token can only be returned if the remote node is alive.
25567c478bd9Sstevel@tonic-gate  * Tokens are on a circular list.  Starting with the current token
25577c478bd9Sstevel@tonic-gate  * search for a token with an endpoint in state RSM_PATH_ACTIVE.
25587c478bd9Sstevel@tonic-gate  * rsmipc_send which calls rsmka_get_sendq_token expects that if there are
25597c478bd9Sstevel@tonic-gate  * multiple paths available between a node-pair then consecutive calls from
25607c478bd9Sstevel@tonic-gate  * a particular invocation of rsmipc_send will return a sendq that is
25617c478bd9Sstevel@tonic-gate  * different from the one that was used in the previous iteration. When
25627c478bd9Sstevel@tonic-gate  * prev_used is NULL it indicates that this is the first interation in a
25637c478bd9Sstevel@tonic-gate  * specific rsmipc_send invocation.
25647c478bd9Sstevel@tonic-gate  *
25657c478bd9Sstevel@tonic-gate  * Updating the current token provides round robin selection and this
25667c478bd9Sstevel@tonic-gate  * is done only in the first iteration ie. when prev_used is NULL
25677c478bd9Sstevel@tonic-gate  */
25687c478bd9Sstevel@tonic-gate sendq_token_t *
rsmka_get_sendq_token(rsm_node_id_t remote_node,sendq_token_t * prev_used)25697c478bd9Sstevel@tonic-gate rsmka_get_sendq_token(rsm_node_id_t remote_node, sendq_token_t *prev_used)
25707c478bd9Sstevel@tonic-gate {
25717c478bd9Sstevel@tonic-gate 	sendq_token_t *token, *first_token;
25727c478bd9Sstevel@tonic-gate 	path_t *path;
25737c478bd9Sstevel@tonic-gate 	ipc_info_t *ipc_info;
25747c478bd9Sstevel@tonic-gate 
25757c478bd9Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
25767c478bd9Sstevel@tonic-gate 	    "rsmka_get_sendq_token enter\n"));
25777c478bd9Sstevel@tonic-gate 
25787c478bd9Sstevel@tonic-gate 	ipc_info = lookup_ipc_info(remote_node);
25797c478bd9Sstevel@tonic-gate 	if (ipc_info == NULL) {
25807c478bd9Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
25817c478bd9Sstevel@tonic-gate 		    "rsmka_get_sendq_token done: ipc_info is NULL\n"));
25827c478bd9Sstevel@tonic-gate 		return (NULL);
25837c478bd9Sstevel@tonic-gate 	}
25847c478bd9Sstevel@tonic-gate 
25857c478bd9Sstevel@tonic-gate 	if (ipc_info->node_is_alive == B_TRUE) {
25867c478bd9Sstevel@tonic-gate 		token = first_token = ipc_info->current_token;
25877c478bd9Sstevel@tonic-gate 		if (token == NULL) {
25887c478bd9Sstevel@tonic-gate 			mutex_exit(&ipc_info_lock);
25897c478bd9Sstevel@tonic-gate 			DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
25907c478bd9Sstevel@tonic-gate 			    "rsmka_get_sendq_token done: token=NULL\n"));
25917c478bd9Sstevel@tonic-gate 			return (NULL);
25927c478bd9Sstevel@tonic-gate 		}
25937c478bd9Sstevel@tonic-gate 
25947c478bd9Sstevel@tonic-gate 		for (;;) {
25957c478bd9Sstevel@tonic-gate 			path = SQ_TOKEN_TO_PATH(token);
25967c478bd9Sstevel@tonic-gate 			DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
25977c478bd9Sstevel@tonic-gate 			    "path %lx\n", path));
25987c478bd9Sstevel@tonic-gate 			mutex_enter(&path->mutex);
25997c478bd9Sstevel@tonic-gate 			if (path->state != RSMKA_PATH_ACTIVE ||
26007c478bd9Sstevel@tonic-gate 			    path->ref_cnt == 0) {
26017c478bd9Sstevel@tonic-gate 				mutex_exit(&path->mutex);
26027c478bd9Sstevel@tonic-gate 			} else {
26037c478bd9Sstevel@tonic-gate 				if (token != prev_used) {
26047c478bd9Sstevel@tonic-gate 					/* found a new token */
26057c478bd9Sstevel@tonic-gate 					break;
26067c478bd9Sstevel@tonic-gate 				}
26077c478bd9Sstevel@tonic-gate 				mutex_exit(&path->mutex);
26087c478bd9Sstevel@tonic-gate 			}
26097c478bd9Sstevel@tonic-gate 
26107c478bd9Sstevel@tonic-gate 			token = token->next;
26117c478bd9Sstevel@tonic-gate 			if (token == first_token) {
26127c478bd9Sstevel@tonic-gate 				/*
26137c478bd9Sstevel@tonic-gate 				 * we didn't find a new token reuse prev_used
26147c478bd9Sstevel@tonic-gate 				 * if the corresponding path is still up
26157c478bd9Sstevel@tonic-gate 				 */
26167c478bd9Sstevel@tonic-gate 				if (prev_used) {
26177c478bd9Sstevel@tonic-gate 					path = SQ_TOKEN_TO_PATH(prev_used);
26187c478bd9Sstevel@tonic-gate 					DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
26197c478bd9Sstevel@tonic-gate 					    "path %lx\n", path));
26207c478bd9Sstevel@tonic-gate 					mutex_enter(&path->mutex);
26217c478bd9Sstevel@tonic-gate 					if (path->state != RSMKA_PATH_ACTIVE ||
26227c478bd9Sstevel@tonic-gate 					    path->ref_cnt == 0) {
26237c478bd9Sstevel@tonic-gate 						mutex_exit(&path->mutex);
26247c478bd9Sstevel@tonic-gate 					} else {
26257c478bd9Sstevel@tonic-gate 						token = prev_used;
26267c478bd9Sstevel@tonic-gate 						break;
26277c478bd9Sstevel@tonic-gate 					}
26287c478bd9Sstevel@tonic-gate 				}
26297c478bd9Sstevel@tonic-gate 				mutex_exit(&ipc_info_lock);
26307c478bd9Sstevel@tonic-gate 				DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
26317c478bd9Sstevel@tonic-gate 				    "rsmka_get_sendq_token: token=NULL\n"));
26327c478bd9Sstevel@tonic-gate 				return (NULL);
26337c478bd9Sstevel@tonic-gate 			}
26347c478bd9Sstevel@tonic-gate 		}
26357c478bd9Sstevel@tonic-gate 
26367c478bd9Sstevel@tonic-gate 		PATH_HOLD_NOLOCK(path);
26377c478bd9Sstevel@tonic-gate 		SENDQ_TOKEN_HOLD(path);
26387c478bd9Sstevel@tonic-gate 		if (prev_used == NULL) {
26397c478bd9Sstevel@tonic-gate 			/* change current_token only the first time */
26407c478bd9Sstevel@tonic-gate 			ipc_info->current_token = token->next;
26417c478bd9Sstevel@tonic-gate 		}
26427c478bd9Sstevel@tonic-gate 
26437c478bd9Sstevel@tonic-gate 		mutex_exit(&path->mutex);
26447c478bd9Sstevel@tonic-gate 		mutex_exit(&ipc_info_lock);
26457c478bd9Sstevel@tonic-gate 
26467c478bd9Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
26477c478bd9Sstevel@tonic-gate 		    "rsmka_get_sendq_token done\n"));
26487c478bd9Sstevel@tonic-gate 		return (token);
26497c478bd9Sstevel@tonic-gate 	} else {
26507c478bd9Sstevel@tonic-gate 		mutex_exit(&ipc_info_lock);
26517c478bd9Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
26527c478bd9Sstevel@tonic-gate 		    "rsmka_get_sendq_token done\n"));
26537c478bd9Sstevel@tonic-gate 		return (NULL);
26547c478bd9Sstevel@tonic-gate 	}
26557c478bd9Sstevel@tonic-gate }
26567c478bd9Sstevel@tonic-gate 
26577c478bd9Sstevel@tonic-gate 
26587c478bd9Sstevel@tonic-gate 
26597c478bd9Sstevel@tonic-gate /*
26607c478bd9Sstevel@tonic-gate  */
26617c478bd9Sstevel@tonic-gate static int
create_ipc_sendq(path_t * path)26627c478bd9Sstevel@tonic-gate create_ipc_sendq(path_t *path)
26637c478bd9Sstevel@tonic-gate {
26647c478bd9Sstevel@tonic-gate 	int		rval;
26657c478bd9Sstevel@tonic-gate 	sendq_token_t	*token;
26667c478bd9Sstevel@tonic-gate 	adapter_t 	*adapter;
26677c478bd9Sstevel@tonic-gate 	int64_t		srvc_offset;
26687c478bd9Sstevel@tonic-gate 
26697c478bd9Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "create_ipc_sendq enter\n"));
26707c478bd9Sstevel@tonic-gate 
26717c478bd9Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG, "create_ipc_sendq: path = %lx\n",
26727c478bd9Sstevel@tonic-gate 	    path));
26737c478bd9Sstevel@tonic-gate 
26747c478bd9Sstevel@tonic-gate 	adapter = path->local_adapter;
26757c478bd9Sstevel@tonic-gate 	token = &path->sendq_token;
26767c478bd9Sstevel@tonic-gate 
26777c478bd9Sstevel@tonic-gate 	srvc_offset = path->remote_hwaddr;
26787c478bd9Sstevel@tonic-gate 
26797c478bd9Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG,
26807c478bd9Sstevel@tonic-gate 	    "create_ipc_sendq: srvc_offset = %lld\n",
26817c478bd9Sstevel@tonic-gate 	    srvc_offset));
26827c478bd9Sstevel@tonic-gate 
26837c478bd9Sstevel@tonic-gate 	rval = adapter->rsmpi_ops->rsm_sendq_create(adapter->rsmpi_handle,
26847c478bd9Sstevel@tonic-gate 	    path->remote_hwaddr,
26857c478bd9Sstevel@tonic-gate 	    (rsm_intr_service_t)(RSM_SERVICE+srvc_offset),
26867c478bd9Sstevel@tonic-gate 	    (rsm_intr_pri_t)RSM_PRI, (size_t)RSM_QUEUE_SZ,
26877c478bd9Sstevel@tonic-gate 	    RSM_INTR_SEND_Q_NO_FENCE,
26887c478bd9Sstevel@tonic-gate 	    RSM_RESOURCE_SLEEP, NULL, &token->rsmpi_sendq_handle);
26897c478bd9Sstevel@tonic-gate 	if (rval == RSM_SUCCESS) {
26907c478bd9Sstevel@tonic-gate 		/* rsmipc_send() may be waiting for a sendq_token */
26917c478bd9Sstevel@tonic-gate 		mutex_enter(&ipc_info_cvlock);
26927c478bd9Sstevel@tonic-gate 		cv_broadcast(&ipc_info_cv);
26937c478bd9Sstevel@tonic-gate 		mutex_exit(&ipc_info_cvlock);
26947c478bd9Sstevel@tonic-gate 	}
26957c478bd9Sstevel@tonic-gate 
26967c478bd9Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG, "create_ipc_sendq: handle = %lx\n",
26977c478bd9Sstevel@tonic-gate 	    token->rsmpi_sendq_handle));
26987c478bd9Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG, "create_ipc_sendq: rval = %d\n",
26997c478bd9Sstevel@tonic-gate 	    rval));
27007c478bd9Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "create_ipc_sendq done\n"));
27017c478bd9Sstevel@tonic-gate 
27027c478bd9Sstevel@tonic-gate 	return (rval);
27037c478bd9Sstevel@tonic-gate }
27047c478bd9Sstevel@tonic-gate 
27057c478bd9Sstevel@tonic-gate 
27067c478bd9Sstevel@tonic-gate boolean_t
rsmka_check_node_alive(rsm_node_id_t remote_node)27077c478bd9Sstevel@tonic-gate rsmka_check_node_alive(rsm_node_id_t remote_node)
27087c478bd9Sstevel@tonic-gate {
27097c478bd9Sstevel@tonic-gate 	ipc_info_t *ipc_info;
27107c478bd9Sstevel@tonic-gate 
27117c478bd9Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG, "rsmka_check_node_alive enter\n"));
27127c478bd9Sstevel@tonic-gate 
27137c478bd9Sstevel@tonic-gate 	ipc_info = lookup_ipc_info(remote_node);
27147c478bd9Sstevel@tonic-gate 	if (ipc_info == NULL) {
27157c478bd9Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_DEBUG,
27167c478bd9Sstevel@tonic-gate 		    "rsmka_check_node_alive done: ipc_info NULL\n"));
27177c478bd9Sstevel@tonic-gate 		return (B_FALSE);
27187c478bd9Sstevel@tonic-gate 	}
27197c478bd9Sstevel@tonic-gate 
27207c478bd9Sstevel@tonic-gate 	if (ipc_info->node_is_alive == B_TRUE) {
27217c478bd9Sstevel@tonic-gate 		mutex_exit(&ipc_info_lock);
27227c478bd9Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_DEBUG,
27237c478bd9Sstevel@tonic-gate 		    "rsmka_check_node_alive done: node is alive\n"));
27247c478bd9Sstevel@tonic-gate 		return (B_TRUE);
27257c478bd9Sstevel@tonic-gate 	} else {
27267c478bd9Sstevel@tonic-gate 		mutex_exit(&ipc_info_lock);
27277c478bd9Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_DEBUG,
27287c478bd9Sstevel@tonic-gate 		    "rsmka_check_node_alive done: node is not alive\n"));
27297c478bd9Sstevel@tonic-gate 		return (B_FALSE);
27307c478bd9Sstevel@tonic-gate 	}
27317c478bd9Sstevel@tonic-gate }
27327c478bd9Sstevel@tonic-gate 
27337c478bd9Sstevel@tonic-gate 
27347c478bd9Sstevel@tonic-gate 
27357c478bd9Sstevel@tonic-gate 
27367c478bd9Sstevel@tonic-gate /*
27377c478bd9Sstevel@tonic-gate  *  TOPOLOGY IOCTL SUPPORT
27387c478bd9Sstevel@tonic-gate  */
27397c478bd9Sstevel@tonic-gate 
27407c478bd9Sstevel@tonic-gate static uint32_t
get_topology_size(int mode)27417c478bd9Sstevel@tonic-gate get_topology_size(int mode)
27427c478bd9Sstevel@tonic-gate {
27437c478bd9Sstevel@tonic-gate 	uint32_t	topology_size;
27447c478bd9Sstevel@tonic-gate 	int		pointer_area_size;
27457c478bd9Sstevel@tonic-gate 	adapter_listhead_t	*listhead;
27467c478bd9Sstevel@tonic-gate 	int		total_num_of_adapters;
27477c478bd9Sstevel@tonic-gate 	int		total_num_of_paths;
27487c478bd9Sstevel@tonic-gate 
27497c478bd9Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "get_topology_size enter\n"));
27507c478bd9Sstevel@tonic-gate 
27517c478bd9Sstevel@tonic-gate 	/*
27527c478bd9Sstevel@tonic-gate 	 * Find the total number of adapters and paths by adding up the
27537c478bd9Sstevel@tonic-gate 	 * individual adapter and path counts from all the listheads
27547c478bd9Sstevel@tonic-gate 	 */
27557c478bd9Sstevel@tonic-gate 	total_num_of_adapters = 0;
27567c478bd9Sstevel@tonic-gate 	total_num_of_paths = 0;
27577c478bd9Sstevel@tonic-gate 	listhead = adapter_listhead_base.next;
27587c478bd9Sstevel@tonic-gate 	while (listhead != NULL) {
27597c478bd9Sstevel@tonic-gate 		total_num_of_adapters += listhead->adapter_count;
27607c478bd9Sstevel@tonic-gate 		total_num_of_paths += listhead->path_count;
27617c478bd9Sstevel@tonic-gate 		listhead = listhead->next_listhead;
27627c478bd9Sstevel@tonic-gate 	}
27637c478bd9Sstevel@tonic-gate 
27647c478bd9Sstevel@tonic-gate #ifdef	_MULTI_DATAMODEL
27657c478bd9Sstevel@tonic-gate 	if ((mode & DATAMODEL_MASK) == DATAMODEL_ILP32)
27667c478bd9Sstevel@tonic-gate 		/*
27677c478bd9Sstevel@tonic-gate 		 * Add extra 4-bytes to make sure connections header
27687c478bd9Sstevel@tonic-gate 		 * is double-word aligned
27697c478bd9Sstevel@tonic-gate 		 */
27707c478bd9Sstevel@tonic-gate 		pointer_area_size =
27717c478bd9Sstevel@tonic-gate 		    (total_num_of_adapters + total_num_of_adapters%2) *
27727c478bd9Sstevel@tonic-gate 		    sizeof (caddr32_t);
27737c478bd9Sstevel@tonic-gate 	else
27747c478bd9Sstevel@tonic-gate 		pointer_area_size = total_num_of_adapters * sizeof (caddr_t);
27757c478bd9Sstevel@tonic-gate #else	/* _MULTI_DATAMODEL */
27767c478bd9Sstevel@tonic-gate 	mode = mode;
27777c478bd9Sstevel@tonic-gate 	pointer_area_size = total_num_of_adapters * sizeof (caddr_t);
27787c478bd9Sstevel@tonic-gate #endif	/* _MULTI_DATAMODEL */
27797c478bd9Sstevel@tonic-gate 
27807c478bd9Sstevel@tonic-gate 
27817c478bd9Sstevel@tonic-gate 	topology_size = sizeof (rsmka_topology_hdr_t) +
27827c478bd9Sstevel@tonic-gate 	    pointer_area_size +
27837c478bd9Sstevel@tonic-gate 	    (total_num_of_adapters * sizeof (rsmka_connections_hdr_t)) +
27847c478bd9Sstevel@tonic-gate 	    (total_num_of_paths * sizeof (rsmka_remote_cntlr_t));
27857c478bd9Sstevel@tonic-gate 
27867c478bd9Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "get_topology_size done\n"));
27877c478bd9Sstevel@tonic-gate 
27887c478bd9Sstevel@tonic-gate 	return (topology_size);
27897c478bd9Sstevel@tonic-gate }
27907c478bd9Sstevel@tonic-gate 
27917c478bd9Sstevel@tonic-gate 
27927c478bd9Sstevel@tonic-gate 
27937c478bd9Sstevel@tonic-gate static void
get_topology(caddr_t arg,char * bufp,int mode)27947c478bd9Sstevel@tonic-gate get_topology(caddr_t arg, char *bufp, int mode)
27957c478bd9Sstevel@tonic-gate {
27967c478bd9Sstevel@tonic-gate 
27977c478bd9Sstevel@tonic-gate 	rsmka_topology_t	*tp = (rsmka_topology_t *)bufp;
27987c478bd9Sstevel@tonic-gate 	adapter_listhead_t	*listhead;
27997c478bd9Sstevel@tonic-gate 	adapter_t		*adapter;
28007c478bd9Sstevel@tonic-gate 	path_t			*path;
28017c478bd9Sstevel@tonic-gate 	int			cntlr = 0;
28027c478bd9Sstevel@tonic-gate 	rsmka_connections_t	*connection;
28037c478bd9Sstevel@tonic-gate 	rsmka_remote_cntlr_t	*rem_cntlr;
28047c478bd9Sstevel@tonic-gate 	int			total_num_of_adapters;
28057c478bd9Sstevel@tonic-gate 
28067c478bd9Sstevel@tonic-gate #ifdef	_MULTI_DATAMODEL
28077c478bd9Sstevel@tonic-gate 	rsmka_topology32_t	*tp32 = (rsmka_topology32_t *)bufp;
28087c478bd9Sstevel@tonic-gate #else
28097c478bd9Sstevel@tonic-gate 	mode = mode;
28107c478bd9Sstevel@tonic-gate #endif	/* _MULTI_DATAMODEL */
28117c478bd9Sstevel@tonic-gate 
28127c478bd9Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "get_topology enter\n"));
28137c478bd9Sstevel@tonic-gate 
28147c478bd9Sstevel@tonic-gate 	/*
28157c478bd9Sstevel@tonic-gate 	 * Find the total number of adapters by adding up the
28167c478bd9Sstevel@tonic-gate 	 * individual adapter counts from all the listheads
28177c478bd9Sstevel@tonic-gate 	 */
28187c478bd9Sstevel@tonic-gate 	total_num_of_adapters = 0;
28197c478bd9Sstevel@tonic-gate 	listhead = adapter_listhead_base.next;
28207c478bd9Sstevel@tonic-gate 	while (listhead != NULL) {
28217c478bd9Sstevel@tonic-gate 		total_num_of_adapters += listhead->adapter_count;
28227c478bd9Sstevel@tonic-gate 		listhead = listhead->next_listhead;
28237c478bd9Sstevel@tonic-gate 	}
28247c478bd9Sstevel@tonic-gate 
28257c478bd9Sstevel@tonic-gate 	/* fill topology header and adjust bufp */
28267c478bd9Sstevel@tonic-gate 	tp->topology_hdr.local_nodeid = my_nodeid;
28277c478bd9Sstevel@tonic-gate 	tp->topology_hdr.local_cntlr_count = total_num_of_adapters;
28287c478bd9Sstevel@tonic-gate 	bufp = (char *)&tp->connections[0];
28297c478bd9Sstevel@tonic-gate 
28307c478bd9Sstevel@tonic-gate 	/* leave room for connection pointer area */
28317c478bd9Sstevel@tonic-gate #ifdef	_MULTI_DATAMODEL
28327c478bd9Sstevel@tonic-gate 	if ((mode & DATAMODEL_MASK) == DATAMODEL_ILP32)
28337c478bd9Sstevel@tonic-gate 		/* make sure bufp is double-word aligned */
28347c478bd9Sstevel@tonic-gate 		bufp += (total_num_of_adapters + total_num_of_adapters%2) *
28357c478bd9Sstevel@tonic-gate 		    sizeof (caddr32_t);
28367c478bd9Sstevel@tonic-gate 	else
28377c478bd9Sstevel@tonic-gate 		bufp += total_num_of_adapters * sizeof (caddr_t);
28387c478bd9Sstevel@tonic-gate #else	/* _MULTI_DATAMODEL */
28397c478bd9Sstevel@tonic-gate 	bufp += total_num_of_adapters * sizeof (caddr_t);
28407c478bd9Sstevel@tonic-gate #endif	/* _MULTI_DATAMODEL */
28417c478bd9Sstevel@tonic-gate 
28427c478bd9Sstevel@tonic-gate 	/* fill topology from the adapter and path data */
28437c478bd9Sstevel@tonic-gate 	listhead = adapter_listhead_base.next;
28447c478bd9Sstevel@tonic-gate 	while (listhead != NULL) {
28457c478bd9Sstevel@tonic-gate 		adapter = listhead->next_adapter;
28467c478bd9Sstevel@tonic-gate 		while (adapter != NULL) {
28477c478bd9Sstevel@tonic-gate 			/* fill in user based connection pointer */
28487c478bd9Sstevel@tonic-gate #ifdef	_MULTI_DATAMODEL
28497c478bd9Sstevel@tonic-gate 			if ((mode & DATAMODEL_MASK) == DATAMODEL_ILP32) {
28507c478bd9Sstevel@tonic-gate 				ulong_t delta = (ulong_t)bufp - (ulong_t)tp32;
28517c478bd9Sstevel@tonic-gate 				caddr32_t userbase = (caddr32_t)((ulong_t)arg &
28527c478bd9Sstevel@tonic-gate 				    0xffffffff);
28537c478bd9Sstevel@tonic-gate 				tp32->connections[cntlr++] = userbase + delta;
28547c478bd9Sstevel@tonic-gate 			} else {
28557c478bd9Sstevel@tonic-gate 				tp->connections[cntlr++] = arg +
28567c478bd9Sstevel@tonic-gate 				    (ulong_t)bufp -
28577c478bd9Sstevel@tonic-gate 				    (ulong_t)tp;
28587c478bd9Sstevel@tonic-gate 			}
28597c478bd9Sstevel@tonic-gate #else	/* _MULTI_DATAMODEL */
28607c478bd9Sstevel@tonic-gate 				tp->connections[cntlr++] = arg +
28617c478bd9Sstevel@tonic-gate 				    (ulong_t)bufp -
28627c478bd9Sstevel@tonic-gate 				    (ulong_t)tp;
28637c478bd9Sstevel@tonic-gate #endif	/* _MULTI_DATAMODEL */
28647c478bd9Sstevel@tonic-gate 			connection = (rsmka_connections_t *)bufp;
28657c478bd9Sstevel@tonic-gate 			(void) snprintf(connection->hdr.cntlr_name,
28667c478bd9Sstevel@tonic-gate 			    MAXNAMELEN, "%s%d",
28677c478bd9Sstevel@tonic-gate 			    listhead->adapter_devname,
28687c478bd9Sstevel@tonic-gate 			    adapter->instance);
28697c478bd9Sstevel@tonic-gate 			connection->hdr.local_hwaddr = adapter->hwaddr;
28707c478bd9Sstevel@tonic-gate 			connection->hdr.remote_cntlr_count = 0;
28717c478bd9Sstevel@tonic-gate 			bufp += sizeof (rsmka_connections_hdr_t);
28727c478bd9Sstevel@tonic-gate 			rem_cntlr = (rsmka_remote_cntlr_t *)bufp;
28737c478bd9Sstevel@tonic-gate 			path = adapter->next_path;
28747c478bd9Sstevel@tonic-gate 			while (path != NULL) {
28757c478bd9Sstevel@tonic-gate 				connection->hdr.remote_cntlr_count++;
28767c478bd9Sstevel@tonic-gate 				rem_cntlr->remote_nodeid = path->remote_node;
28777c478bd9Sstevel@tonic-gate 				(void) snprintf(rem_cntlr->remote_cntlrname,
28787c478bd9Sstevel@tonic-gate 				    MAXNAMELEN, "%s%d",
28797c478bd9Sstevel@tonic-gate 				    listhead->adapter_devname,
28807c478bd9Sstevel@tonic-gate 				    path->remote_devinst);
28817c478bd9Sstevel@tonic-gate 				rem_cntlr->remote_hwaddr = path->remote_hwaddr;
28827c478bd9Sstevel@tonic-gate 				rem_cntlr->connection_state = path->state;
28837c478bd9Sstevel@tonic-gate 				++rem_cntlr;
28847c478bd9Sstevel@tonic-gate 				path = path->next_path;
28857c478bd9Sstevel@tonic-gate 			}
28867c478bd9Sstevel@tonic-gate 			adapter = adapter->next;
28877c478bd9Sstevel@tonic-gate 			bufp = (char *)rem_cntlr;
28887c478bd9Sstevel@tonic-gate 		}
28897c478bd9Sstevel@tonic-gate 		listhead = listhead->next_listhead;
28907c478bd9Sstevel@tonic-gate 	}
28917c478bd9Sstevel@tonic-gate 
28927c478bd9Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "get_topology done\n"));
28937c478bd9Sstevel@tonic-gate 
28947c478bd9Sstevel@tonic-gate }
28957c478bd9Sstevel@tonic-gate 
28967c478bd9Sstevel@tonic-gate 
28977c478bd9Sstevel@tonic-gate /*
28987c478bd9Sstevel@tonic-gate  * Called from rsm_ioctl() in rsm.c
28997c478bd9Sstevel@tonic-gate  * Make sure there is no possiblity of blocking while holding
29007c478bd9Sstevel@tonic-gate  * adapter_listhead_base.lock
29017c478bd9Sstevel@tonic-gate  */
29027c478bd9Sstevel@tonic-gate int
rsmka_topology_ioctl(caddr_t arg,int cmd,int mode)29037c478bd9Sstevel@tonic-gate rsmka_topology_ioctl(caddr_t arg, int cmd, int mode)
29047c478bd9Sstevel@tonic-gate {
29057c478bd9Sstevel@tonic-gate 	uint32_t	topology_size;
29067c478bd9Sstevel@tonic-gate 	uint32_t 	request_size;
29077c478bd9Sstevel@tonic-gate 	char		*bufp;
29087c478bd9Sstevel@tonic-gate 	int		error = RSM_SUCCESS;
29097c478bd9Sstevel@tonic-gate 	size_t		max_toposize;
29107c478bd9Sstevel@tonic-gate 
29117c478bd9Sstevel@tonic-gate 	DBG_PRINTF((category | RSM_IOCTL, RSM_DEBUG_VERBOSE,
29127c478bd9Sstevel@tonic-gate 	    "rsmka_topology_ioctl enter\n"));
29137c478bd9Sstevel@tonic-gate 
29147c478bd9Sstevel@tonic-gate 	switch (cmd) {
29157c478bd9Sstevel@tonic-gate 	case RSM_IOCTL_TOPOLOGY_SIZE:
29167c478bd9Sstevel@tonic-gate 		mutex_enter(&adapter_listhead_base.listlock);
29177c478bd9Sstevel@tonic-gate 		topology_size = get_topology_size(mode);
29187c478bd9Sstevel@tonic-gate 		mutex_exit(&adapter_listhead_base.listlock);
29197c478bd9Sstevel@tonic-gate 		if (ddi_copyout((caddr_t)&topology_size,
29207c478bd9Sstevel@tonic-gate 		    (caddr_t)arg, sizeof (uint32_t), mode))
29217c478bd9Sstevel@tonic-gate 			error = RSMERR_BAD_ADDR;
29227c478bd9Sstevel@tonic-gate 		break;
29237c478bd9Sstevel@tonic-gate 	case RSM_IOCTL_TOPOLOGY_DATA:
29247c478bd9Sstevel@tonic-gate 		/*
29257c478bd9Sstevel@tonic-gate 		 * The size of the buffer which the caller has allocated
29267c478bd9Sstevel@tonic-gate 		 * is passed in.  If the size needed for the topology data
29277c478bd9Sstevel@tonic-gate 		 * is not sufficient, E2BIG is returned
29287c478bd9Sstevel@tonic-gate 		 */
29297c478bd9Sstevel@tonic-gate 		if (ddi_copyin(arg, &request_size, sizeof (uint32_t), mode)) {
29307c478bd9Sstevel@tonic-gate 			DBG_PRINTF((category | RSM_IOCTL, RSM_DEBUG_VERBOSE,
29317c478bd9Sstevel@tonic-gate 			    "rsmka_topology_ioctl done: BAD_ADDR\n"));
29327c478bd9Sstevel@tonic-gate 			return (RSMERR_BAD_ADDR);
29337c478bd9Sstevel@tonic-gate 		}
29347c478bd9Sstevel@tonic-gate 		/* calculate the max size of the topology structure */
29357c478bd9Sstevel@tonic-gate 		max_toposize = sizeof (rsmka_topology_hdr_t) +
29367c478bd9Sstevel@tonic-gate 		    RSM_MAX_CTRL * (sizeof (caddr_t) +
2937*b97d6ca7SMilan Jurik 		    sizeof (rsmka_connections_hdr_t)) +
29387c478bd9Sstevel@tonic-gate 		    RSM_MAX_NODE * sizeof (rsmka_remote_cntlr_t);
29397c478bd9Sstevel@tonic-gate 
29407c478bd9Sstevel@tonic-gate 		if (request_size > max_toposize) { /* validate request_size */
29417c478bd9Sstevel@tonic-gate 			DBG_PRINTF((category | RSM_IOCTL, RSM_DEBUG_VERBOSE,
29427c478bd9Sstevel@tonic-gate 			    "rsmka_topology_ioctl done: size too large\n"));
29437c478bd9Sstevel@tonic-gate 			return (EINVAL);
29447c478bd9Sstevel@tonic-gate 		}
29457c478bd9Sstevel@tonic-gate 		bufp = kmem_zalloc(request_size, KM_SLEEP);
29467c478bd9Sstevel@tonic-gate 		mutex_enter(&adapter_listhead_base.listlock);
29477c478bd9Sstevel@tonic-gate 		topology_size = get_topology_size(mode);
29487c478bd9Sstevel@tonic-gate 		if (request_size < topology_size) {
29497c478bd9Sstevel@tonic-gate 			kmem_free(bufp, request_size);
29507c478bd9Sstevel@tonic-gate 			mutex_exit(&adapter_listhead_base.listlock);
29517c478bd9Sstevel@tonic-gate 			DBG_PRINTF((category | RSM_IOCTL, RSM_DEBUG_VERBOSE,
29527c478bd9Sstevel@tonic-gate 			    "rsmka_topology_ioctl done: E2BIG\n"));
29537c478bd9Sstevel@tonic-gate 			return (E2BIG);
29547c478bd9Sstevel@tonic-gate 		}
29557c478bd9Sstevel@tonic-gate 
29567c478bd9Sstevel@tonic-gate 		/* get the topology data and copyout to the caller */
29577c478bd9Sstevel@tonic-gate 		get_topology(arg, bufp, mode);
29587c478bd9Sstevel@tonic-gate 		mutex_exit(&adapter_listhead_base.listlock);
29597c478bd9Sstevel@tonic-gate 		if (ddi_copyout((caddr_t)bufp, (caddr_t)arg,
29607c478bd9Sstevel@tonic-gate 		    topology_size, mode))
29617c478bd9Sstevel@tonic-gate 			error = RSMERR_BAD_ADDR;
29627c478bd9Sstevel@tonic-gate 
29637c478bd9Sstevel@tonic-gate 		kmem_free(bufp, request_size);
29647c478bd9Sstevel@tonic-gate 		break;
29657c478bd9Sstevel@tonic-gate 	default:
29667c478bd9Sstevel@tonic-gate 		DBG_PRINTF((category | RSM_IOCTL, RSM_DEBUG,
29677c478bd9Sstevel@tonic-gate 		    "rsmka_topology_ioctl: cmd not supported\n"));
29687c478bd9Sstevel@tonic-gate 		error = DDI_FAILURE;
29697c478bd9Sstevel@tonic-gate 	}
29707c478bd9Sstevel@tonic-gate 
29717c478bd9Sstevel@tonic-gate 	DBG_PRINTF((category | RSM_IOCTL, RSM_DEBUG_VERBOSE,
29727c478bd9Sstevel@tonic-gate 	    "rsmka_topology_ioctl done: %d\n", error));
29737c478bd9Sstevel@tonic-gate 	return (error);
29747c478bd9Sstevel@tonic-gate }
2975