xref: /onnv-gate/usr/src/uts/common/io/rsm/rsm.c (revision 11066:cebb50cbe4f9)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
55116Sjg97986  * Common Development and Distribution License (the "License").
65116Sjg97986  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
22*11066Srafael.vanoni@sun.com  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate 
270Sstevel@tonic-gate /*
280Sstevel@tonic-gate  * Overview of the RSM Kernel Agent:
290Sstevel@tonic-gate  * ---------------------------------
300Sstevel@tonic-gate  *
310Sstevel@tonic-gate  * rsm.c constitutes the implementation of the RSM kernel agent. The RSM
320Sstevel@tonic-gate  * kernel agent is a pseudo device driver which makes use of the RSMPI
330Sstevel@tonic-gate  * interface on behalf of the RSMAPI user library.
340Sstevel@tonic-gate  *
350Sstevel@tonic-gate  * The kernel agent functionality can be categorized into the following
360Sstevel@tonic-gate  * components:
370Sstevel@tonic-gate  * 1. Driver Infrastructure
380Sstevel@tonic-gate  * 2. Export/Import Segment Management
390Sstevel@tonic-gate  * 3. Internal resource allocation/deallocation
400Sstevel@tonic-gate  *
410Sstevel@tonic-gate  * The driver infrastructure includes the basic module loading entry points
420Sstevel@tonic-gate  * like _init, _info, _fini to load, unload and report information about
430Sstevel@tonic-gate  * the driver module. The driver infrastructure also includes the
440Sstevel@tonic-gate  * autoconfiguration entry points namely, attach, detach and getinfo for
450Sstevel@tonic-gate  * the device autoconfiguration.
460Sstevel@tonic-gate  *
470Sstevel@tonic-gate  * The kernel agent is a pseudo character device driver and exports
480Sstevel@tonic-gate  * a cb_ops structure which defines the driver entry points for character
490Sstevel@tonic-gate  * device access. This includes the open and close entry points. The
500Sstevel@tonic-gate  * other entry points provided include ioctl, devmap and segmap and chpoll.
510Sstevel@tonic-gate  * read and write entry points are not used since the device is memory
520Sstevel@tonic-gate  * mapped. Also ddi_prop_op is used for the prop_op entry point.
530Sstevel@tonic-gate  *
540Sstevel@tonic-gate  * The ioctl entry point supports a number of commands, which are used by
550Sstevel@tonic-gate  * the RSMAPI library in order to export and import segments. These
560Sstevel@tonic-gate  * commands include commands for binding and rebinding the physical pages
570Sstevel@tonic-gate  * allocated to the virtual address range, publishing the export segment,
580Sstevel@tonic-gate  * unpublishing and republishing an export segment, creating an
590Sstevel@tonic-gate  * import segment and a virtual connection from this import segment to
600Sstevel@tonic-gate  * an export segment, performing scatter-gather data transfer, barrier
610Sstevel@tonic-gate  * operations.
620Sstevel@tonic-gate  *
630Sstevel@tonic-gate  *
640Sstevel@tonic-gate  * Export and Import segments:
650Sstevel@tonic-gate  * ---------------------------
660Sstevel@tonic-gate  *
670Sstevel@tonic-gate  * In order to create an RSM export segment a process allocates a range in its
680Sstevel@tonic-gate  * virtual address space for the segment using standard Solaris interfaces.
690Sstevel@tonic-gate  * The process then calls RSMAPI, which in turn makes an ioctl call to the
700Sstevel@tonic-gate  * RSM kernel agent for an allocation of physical memory pages and for
710Sstevel@tonic-gate  * creation of the export segment by binding these pages to the virtual
720Sstevel@tonic-gate  * address range. These pages are locked in memory so that remote accesses
730Sstevel@tonic-gate  * are always applied to the correct page. Then the RSM segment is published,
740Sstevel@tonic-gate  * again via RSMAPI making an ioctl to the RSM kernel agent, and a segment id
750Sstevel@tonic-gate  * is assigned to it.
760Sstevel@tonic-gate  *
770Sstevel@tonic-gate  * In order to import a published RSM segment, RSMAPI creates an import
780Sstevel@tonic-gate  * segment and forms a virtual connection across the interconnect to the
790Sstevel@tonic-gate  * export segment, via an ioctl into the kernel agent with the connect
800Sstevel@tonic-gate  * command. The import segment setup is completed by mapping the
810Sstevel@tonic-gate  * local device memory into the importers virtual address space. The
820Sstevel@tonic-gate  * mapping of the import segment is handled by the segmap/devmap
830Sstevel@tonic-gate  * infrastructure described as follows.
840Sstevel@tonic-gate  *
850Sstevel@tonic-gate  * Segmap and Devmap interfaces:
860Sstevel@tonic-gate  *
870Sstevel@tonic-gate  * The RSM kernel agent allows device memory to be directly accessed by user
880Sstevel@tonic-gate  * threads via memory mapping. In order to do so, the RSM kernel agent
890Sstevel@tonic-gate  * supports the devmap and segmap entry points.
900Sstevel@tonic-gate  *
910Sstevel@tonic-gate  * The segmap entry point(rsm_segmap) is responsible for setting up a memory
920Sstevel@tonic-gate  * mapping as requested by mmap. The devmap entry point(rsm_devmap) is
930Sstevel@tonic-gate  * responsible for exporting the device memory to the user applications.
940Sstevel@tonic-gate  * rsm_segmap calls RSMPI rsm_map to allocate device memory. Then the
950Sstevel@tonic-gate  * control is transfered to the devmap_setup call which calls rsm_devmap.
960Sstevel@tonic-gate  *
970Sstevel@tonic-gate  * rsm_devmap validates the user mapping to the device or kernel memory
980Sstevel@tonic-gate  * and passes the information to the system for setting up the mapping. The
990Sstevel@tonic-gate  * actual setting up of the mapping is done by devmap_devmem_setup(for
1000Sstevel@tonic-gate  * device memory) or devmap_umem_setup(for kernel memory). Callbacks are
1010Sstevel@tonic-gate  * registered for device context management via the devmap_devmem_setup
1020Sstevel@tonic-gate  * or devmap_umem_setup calls. The callbacks are rsmmap_map, rsmmap_unmap,
1030Sstevel@tonic-gate  * rsmmap_access, rsmmap_dup. The callbacks are called when a new mapping
1040Sstevel@tonic-gate  * is created, a mapping is freed, a mapping is accessed or an existing
1050Sstevel@tonic-gate  * mapping is duplicated respectively. These callbacks allow the RSM kernel
1060Sstevel@tonic-gate  * agent to maintain state information associated with the mappings.
1070Sstevel@tonic-gate  * The state information is mainly in the form of a cookie list for the import
1080Sstevel@tonic-gate  * segment for which mapping has been done.
1090Sstevel@tonic-gate  *
1100Sstevel@tonic-gate  * Forced disconnect of import segments:
1110Sstevel@tonic-gate  *
1120Sstevel@tonic-gate  * When an exported segment is unpublished, the exporter sends a forced
1130Sstevel@tonic-gate  * disconnect message to all its importers. The importer segments are
1140Sstevel@tonic-gate  * unloaded and disconnected. This involves unloading the original
1150Sstevel@tonic-gate  * mappings and remapping to a preallocated kernel trash page. This is
1160Sstevel@tonic-gate  * done by devmap_umem_remap. The trash/dummy page is a kernel page,
1170Sstevel@tonic-gate  * preallocated by the kernel agent during attach using ddi_umem_alloc with
1180Sstevel@tonic-gate  * the DDI_UMEM_TRASH flag set. This avoids a core dump in the application
1190Sstevel@tonic-gate  * due to unloading of the original mappings.
1200Sstevel@tonic-gate  *
1210Sstevel@tonic-gate  * Additionally every segment has a mapping generation number associated
1220Sstevel@tonic-gate  * with it. This is an entry in the barrier generation page, created
1230Sstevel@tonic-gate  * during attach time. This mapping generation number for the import
1240Sstevel@tonic-gate  * segments is incremented on a force disconnect to notify the application
1250Sstevel@tonic-gate  * of the force disconnect. On this notification, the application needs
1260Sstevel@tonic-gate  * to reconnect the segment to establish a new legitimate mapping.
1270Sstevel@tonic-gate  *
1280Sstevel@tonic-gate  *
1290Sstevel@tonic-gate  * Locks used in the kernel agent:
1300Sstevel@tonic-gate  * -------------------------------
1310Sstevel@tonic-gate  *
1320Sstevel@tonic-gate  * The kernel agent uses a variety of mutexes and condition variables for
1330Sstevel@tonic-gate  * mutual exclusion of the shared data structures and for synchronization
1340Sstevel@tonic-gate  * between the various threads. Some of the locks are described as follows.
1350Sstevel@tonic-gate  *
1360Sstevel@tonic-gate  * Each resource structure, which represents either an export/import segment
1370Sstevel@tonic-gate  * has a lock associated with it. The lock is the resource mutex, rsmrc_lock.
1380Sstevel@tonic-gate  * This is used directly by RSMRC_LOCK and RSMRC_UNLOCK macros and in the
1390Sstevel@tonic-gate  * rsmseglock_acquire and rsmseglock_release macros. An additional
1400Sstevel@tonic-gate  * lock called the rsmsi_lock is used for the shared import data structure
1410Sstevel@tonic-gate  * that is relevant for resources representing import segments. There is
1420Sstevel@tonic-gate  * also a condition variable associated with the resource called s_cv. This
1430Sstevel@tonic-gate  * is used to wait for events like the segment state change etc.
1440Sstevel@tonic-gate  *
1450Sstevel@tonic-gate  * The resource structures are allocated from a pool of resource structures,
1460Sstevel@tonic-gate  * called rsm_resource. This pool is protected via a reader-writer lock,
1470Sstevel@tonic-gate  * called rsmrc_lock.
1480Sstevel@tonic-gate  *
1490Sstevel@tonic-gate  * There are two separate hash tables, one for the export segments and
1500Sstevel@tonic-gate  * one for the import segments. The export segments are inserted into the
1510Sstevel@tonic-gate  * export segment hash table only after they have been published and the
1520Sstevel@tonic-gate  * import segments are inserted in the import segments list only after they
1530Sstevel@tonic-gate  * have successfully connected to an exported segment. These tables are
1540Sstevel@tonic-gate  * protected via reader-writer locks.
1550Sstevel@tonic-gate  *
1560Sstevel@tonic-gate  * Debug Support in the kernel agent:
1570Sstevel@tonic-gate  * ----------------------------------
1580Sstevel@tonic-gate  *
1590Sstevel@tonic-gate  * Debugging support in the kernel agent is provided by the following
1600Sstevel@tonic-gate  * macros.
1610Sstevel@tonic-gate  *
1620Sstevel@tonic-gate  * DBG_PRINTF((category, level, message)) is a macro which logs a debug
1630Sstevel@tonic-gate  * message to the kernel agents debug buffer, rsmka_dbg. This debug buffer
1640Sstevel@tonic-gate  * can be viewed in kmdb as *rsmka_dbg/s. The message is logged based
1650Sstevel@tonic-gate  * on the definition of the category and level. All messages that belong to
1660Sstevel@tonic-gate  * the specified category(rsmdbg_category) and are of an equal or greater
1670Sstevel@tonic-gate  * severity than the specified level(rsmdbg_level) are logged. The message
1680Sstevel@tonic-gate  * is a string which uses the same formatting rules as the strings used in
1690Sstevel@tonic-gate  * printf.
1700Sstevel@tonic-gate  *
1710Sstevel@tonic-gate  * The category defines which component of the kernel agent has logged this
1720Sstevel@tonic-gate  * message. There are a number of categories that have been defined such as
1730Sstevel@tonic-gate  * RSM_KERNEL_AGENT, RSM_OPS, RSM_IMPORT, RSM_EXPORT etc. A macro,
1740Sstevel@tonic-gate  * DBG_ADDCATEGORY is used to add in another category to the currently
1750Sstevel@tonic-gate  * specified category value so that the component using this new category
1760Sstevel@tonic-gate  * can also effectively log debug messages. Thus, the category of a specific
1770Sstevel@tonic-gate  * message is some combination of the available categories and we can define
1780Sstevel@tonic-gate  * sub-categories if we want a finer level of granularity.
1790Sstevel@tonic-gate  *
1800Sstevel@tonic-gate  * The level defines the severity of the message. Different level values are
1810Sstevel@tonic-gate  * defined, with RSM_ERR being the most severe and RSM_DEBUG_VERBOSE being
1820Sstevel@tonic-gate  * the least severe(debug level is 0).
1830Sstevel@tonic-gate  *
1840Sstevel@tonic-gate  * DBG_DEFINE and DBG_DEFINE_STR are macros provided to declare a debug
1850Sstevel@tonic-gate  * variable or a string respectively.
1860Sstevel@tonic-gate  *
1870Sstevel@tonic-gate  *
1880Sstevel@tonic-gate  * NOTES:
1890Sstevel@tonic-gate  *
1900Sstevel@tonic-gate  * Special Fork and Exec Handling:
1910Sstevel@tonic-gate  * -------------------------------
1920Sstevel@tonic-gate  *
1930Sstevel@tonic-gate  * The backing physical pages of an exported segment are always locked down.
1940Sstevel@tonic-gate  * Thus, there are two cases in which a process having exported segments
1950Sstevel@tonic-gate  * will cause a cpu to hang: (1) the process invokes exec; (2) a process
1960Sstevel@tonic-gate  * forks and invokes exit before the duped file descriptors for the export
1970Sstevel@tonic-gate  * segments are closed in the child process. The hang is caused because the
1980Sstevel@tonic-gate  * address space release algorithm in Solaris VM subsystem is based on a
1990Sstevel@tonic-gate  * non-blocking loop which does not terminate while segments are locked
2000Sstevel@tonic-gate  * down. In addition to this, Solaris VM subsystem lacks a callback
2010Sstevel@tonic-gate  * mechanism to the rsm kernel agent to allow unlocking these export
2020Sstevel@tonic-gate  * segment pages.
2030Sstevel@tonic-gate  *
2040Sstevel@tonic-gate  * In order to circumvent this problem, the kernel agent does the following.
2050Sstevel@tonic-gate  * The Solaris VM subsystem keeps memory segments in increasing order of
2060Sstevel@tonic-gate  * virtual addressses. Thus a special page(special_exit_offset) is allocated
2070Sstevel@tonic-gate  * by the kernel agent and is mmapped into the heap area of the process address
2080Sstevel@tonic-gate  * space(the mmap is done by the RSMAPI library). During the mmap processing
2090Sstevel@tonic-gate  * of this special page by the devmap infrastructure, a callback(the same
2100Sstevel@tonic-gate  * devmap context management callbacks discussed above) is registered for an
2110Sstevel@tonic-gate  * unmap.
2120Sstevel@tonic-gate  *
2130Sstevel@tonic-gate  * As discussed above, this page is processed by the Solaris address space
2140Sstevel@tonic-gate  * release code before any of the exported segments pages(which are allocated
2150Sstevel@tonic-gate  * from high memory). It is during this processing that the unmap callback gets
2160Sstevel@tonic-gate  * called and this callback is responsible for force destroying the exported
2170Sstevel@tonic-gate  * segments and thus eliminating the problem of locked pages.
2180Sstevel@tonic-gate  *
2190Sstevel@tonic-gate  * Flow-control:
2200Sstevel@tonic-gate  * ------------
2210Sstevel@tonic-gate  *
2220Sstevel@tonic-gate  * A credit based flow control algorithm is used for messages whose
2230Sstevel@tonic-gate  * processing cannot be done in the interrupt context because it might
2240Sstevel@tonic-gate  * involve invoking rsmpi calls, or might take a long time to complete
2250Sstevel@tonic-gate  * or might need to allocate resources. The algorithm operates on a per
2260Sstevel@tonic-gate  * path basis. To send a message the pathend needs to have a credit and
2270Sstevel@tonic-gate  * it consumes one for every message that is flow controlled. On the
2280Sstevel@tonic-gate  * receiving pathend the message is put on a msgbuf_queue and a task is
2290Sstevel@tonic-gate  * dispatched on the worker thread - recv_taskq where it is processed.
2300Sstevel@tonic-gate  * After processing the message, the receiving pathend dequeues the message,
2310Sstevel@tonic-gate  * and if it has processed > RSMIPC_LOTSFREE_MSGBUFS messages sends
2320Sstevel@tonic-gate  * credits to the sender pathend.
2330Sstevel@tonic-gate  *
2340Sstevel@tonic-gate  * RSM_DRTEST:
2350Sstevel@tonic-gate  * -----------
2360Sstevel@tonic-gate  *
2370Sstevel@tonic-gate  * This is used to enable the DR testing using a test driver on test
2380Sstevel@tonic-gate  * platforms which do not supported DR.
2390Sstevel@tonic-gate  *
2400Sstevel@tonic-gate  */
2410Sstevel@tonic-gate 
2420Sstevel@tonic-gate #include <sys/types.h>
2430Sstevel@tonic-gate #include <sys/param.h>
2440Sstevel@tonic-gate #include <sys/user.h>
2450Sstevel@tonic-gate #include <sys/buf.h>
2460Sstevel@tonic-gate #include <sys/systm.h>
2470Sstevel@tonic-gate #include <sys/cred.h>
2480Sstevel@tonic-gate #include <sys/vm.h>
2490Sstevel@tonic-gate #include <sys/uio.h>
2500Sstevel@tonic-gate #include <vm/seg.h>
2510Sstevel@tonic-gate #include <vm/page.h>
2520Sstevel@tonic-gate #include <sys/stat.h>
2530Sstevel@tonic-gate 
2540Sstevel@tonic-gate #include <sys/time.h>
2550Sstevel@tonic-gate #include <sys/errno.h>
2560Sstevel@tonic-gate 
2570Sstevel@tonic-gate #include <sys/file.h>
2580Sstevel@tonic-gate #include <sys/uio.h>
2590Sstevel@tonic-gate #include <sys/proc.h>
2600Sstevel@tonic-gate #include <sys/mman.h>
2610Sstevel@tonic-gate #include <sys/open.h>
2620Sstevel@tonic-gate #include <sys/atomic.h>
2630Sstevel@tonic-gate #include <sys/mem_config.h>
2640Sstevel@tonic-gate 
2650Sstevel@tonic-gate 
2660Sstevel@tonic-gate #include <sys/ddi.h>
2670Sstevel@tonic-gate #include <sys/devops.h>
2680Sstevel@tonic-gate #include <sys/ddidevmap.h>
2690Sstevel@tonic-gate #include <sys/sunddi.h>
2700Sstevel@tonic-gate #include <sys/esunddi.h>
2710Sstevel@tonic-gate #include <sys/ddi_impldefs.h>
2720Sstevel@tonic-gate 
2730Sstevel@tonic-gate #include <sys/kmem.h>
2740Sstevel@tonic-gate #include <sys/conf.h>
2750Sstevel@tonic-gate #include <sys/devops.h>
2760Sstevel@tonic-gate #include <sys/ddi_impldefs.h>
2770Sstevel@tonic-gate 
2780Sstevel@tonic-gate #include <sys/modctl.h>
2790Sstevel@tonic-gate 
2800Sstevel@tonic-gate #include <sys/policy.h>
2810Sstevel@tonic-gate #include <sys/types.h>
2820Sstevel@tonic-gate #include <sys/conf.h>
2830Sstevel@tonic-gate #include <sys/param.h>
2840Sstevel@tonic-gate 
2850Sstevel@tonic-gate #include <sys/taskq.h>
2860Sstevel@tonic-gate 
2870Sstevel@tonic-gate #include <sys/rsm/rsm_common.h>
2880Sstevel@tonic-gate #include <sys/rsm/rsmapi_common.h>
2890Sstevel@tonic-gate #include <sys/rsm/rsm.h>
2900Sstevel@tonic-gate #include <rsm_in.h>
2910Sstevel@tonic-gate #include <sys/rsm/rsmka_path_int.h>
2920Sstevel@tonic-gate #include <sys/rsm/rsmpi.h>
2930Sstevel@tonic-gate 
2940Sstevel@tonic-gate #include <sys/modctl.h>
2950Sstevel@tonic-gate #include <sys/debug.h>
2960Sstevel@tonic-gate 
2970Sstevel@tonic-gate #include <sys/tuneable.h>
2980Sstevel@tonic-gate 
2990Sstevel@tonic-gate #ifdef	RSM_DRTEST
3000Sstevel@tonic-gate extern int rsm_kphysm_setup_func_register(kphysm_setup_vector_t *vec,
3010Sstevel@tonic-gate 		void *arg);
3020Sstevel@tonic-gate extern void rsm_kphysm_setup_func_unregister(kphysm_setup_vector_t *vec,
3030Sstevel@tonic-gate 		void *arg);
3040Sstevel@tonic-gate #endif
3050Sstevel@tonic-gate 
3060Sstevel@tonic-gate extern void dbg_printf(int category, int level, char *fmt, ...);
3070Sstevel@tonic-gate extern void rsmka_pathmanager_init();
3080Sstevel@tonic-gate extern void rsmka_pathmanager_cleanup();
3090Sstevel@tonic-gate extern void rele_sendq_token();
3100Sstevel@tonic-gate extern rsm_addr_t get_remote_hwaddr(adapter_t *, rsm_node_id_t);
3110Sstevel@tonic-gate extern rsm_node_id_t get_remote_nodeid(adapter_t *, rsm_addr_t);
3120Sstevel@tonic-gate extern int rsmka_topology_ioctl(caddr_t, int, int);
3130Sstevel@tonic-gate 
3140Sstevel@tonic-gate extern pri_t maxclsyspri;
3150Sstevel@tonic-gate extern work_queue_t work_queue;
3160Sstevel@tonic-gate extern kmutex_t ipc_info_lock;
3170Sstevel@tonic-gate extern kmutex_t ipc_info_cvlock;
3180Sstevel@tonic-gate extern kcondvar_t ipc_info_cv;
3190Sstevel@tonic-gate extern kmutex_t path_hold_cvlock;
3200Sstevel@tonic-gate extern kcondvar_t path_hold_cv;
3210Sstevel@tonic-gate 
3220Sstevel@tonic-gate extern kmutex_t rsmka_buf_lock;
3230Sstevel@tonic-gate 
3240Sstevel@tonic-gate extern path_t *rsm_find_path(char *, int, rsm_addr_t);
3250Sstevel@tonic-gate extern adapter_t *rsmka_lookup_adapter(char *, int);
3260Sstevel@tonic-gate extern sendq_token_t *rsmka_get_sendq_token(rsm_node_id_t, sendq_token_t *);
3270Sstevel@tonic-gate extern boolean_t rsmka_do_path_active(path_t *, int);
3280Sstevel@tonic-gate extern boolean_t rsmka_check_node_alive(rsm_node_id_t);
3290Sstevel@tonic-gate extern void rsmka_release_adapter(adapter_t *);
3300Sstevel@tonic-gate extern void rsmka_enqueue_msgbuf(path_t *path, void *data);
3310Sstevel@tonic-gate extern void rsmka_dequeue_msgbuf(path_t *path);
3320Sstevel@tonic-gate extern msgbuf_elem_t *rsmka_gethead_msgbuf(path_t *path);
3330Sstevel@tonic-gate /* lint -w2 */
3340Sstevel@tonic-gate 
3350Sstevel@tonic-gate static int rsm_open(dev_t *, int, int, cred_t *);
3360Sstevel@tonic-gate static int rsm_close(dev_t, int, int, cred_t *);
3370Sstevel@tonic-gate static int rsm_ioctl(dev_t dev, int cmd, intptr_t arg, int mode,
3380Sstevel@tonic-gate     cred_t *credp, int *rvalp);
3390Sstevel@tonic-gate static int rsm_devmap(dev_t, devmap_cookie_t, offset_t, size_t, size_t *,
3400Sstevel@tonic-gate     uint_t);
3410Sstevel@tonic-gate static int rsm_segmap(dev_t, off_t, struct as *, caddr_t *, off_t, uint_t,
3420Sstevel@tonic-gate     uint_t, uint_t, cred_t *);
3430Sstevel@tonic-gate static int rsm_chpoll(dev_t dev, short events, int anyyet, short *reventsp,
3440Sstevel@tonic-gate     struct pollhead **phpp);
3450Sstevel@tonic-gate 
3460Sstevel@tonic-gate static int rsm_info(dev_info_t *, ddi_info_cmd_t, void *, void **);
3470Sstevel@tonic-gate static int rsm_attach(dev_info_t *, ddi_attach_cmd_t);
3480Sstevel@tonic-gate static int rsm_detach(dev_info_t *, ddi_detach_cmd_t);
3490Sstevel@tonic-gate 
3500Sstevel@tonic-gate static int rsmipc_send(rsm_node_id_t, rsmipc_request_t *, rsmipc_reply_t *);
3510Sstevel@tonic-gate static void rsm_force_unload(rsm_node_id_t, rsm_memseg_id_t, boolean_t);
3520Sstevel@tonic-gate static void rsm_send_importer_disconnects(rsm_memseg_id_t, rsm_node_id_t);
3530Sstevel@tonic-gate static void rsm_send_republish(rsm_memseg_id_t, rsmapi_access_entry_t *, int,
3540Sstevel@tonic-gate 				rsm_permission_t);
3550Sstevel@tonic-gate static void rsm_export_force_destroy(ddi_umem_cookie_t *);
3560Sstevel@tonic-gate static void rsmacl_free(rsmapi_access_entry_t *, int);
3570Sstevel@tonic-gate static void rsmpiacl_free(rsm_access_entry_t *, int);
3580Sstevel@tonic-gate 
3590Sstevel@tonic-gate static int rsm_inc_pgcnt(pgcnt_t);
3600Sstevel@tonic-gate static void rsm_dec_pgcnt(pgcnt_t);
3610Sstevel@tonic-gate static void rsm_free_mapinfo(rsm_mapinfo_t *mapinfop);
3620Sstevel@tonic-gate static rsm_mapinfo_t *rsm_get_mapinfo(rsmseg_t *, off_t, size_t, off_t *,
3630Sstevel@tonic-gate 					size_t *);
3640Sstevel@tonic-gate static void exporter_quiesce();
3650Sstevel@tonic-gate static void rsmseg_suspend(rsmseg_t *, int *);
3660Sstevel@tonic-gate static void rsmsegshare_suspend(rsmseg_t *);
3670Sstevel@tonic-gate static int rsmseg_resume(rsmseg_t *, void **);
3680Sstevel@tonic-gate static int rsmsegshare_resume(rsmseg_t *);
3690Sstevel@tonic-gate 
3700Sstevel@tonic-gate static struct cb_ops rsm_cb_ops = {
3710Sstevel@tonic-gate 	rsm_open,		/* open */
3720Sstevel@tonic-gate 	rsm_close,		/* close */
3730Sstevel@tonic-gate 	nodev,			/* strategy */
3740Sstevel@tonic-gate 	nodev,			/* print */
3750Sstevel@tonic-gate 	nodev,			/* dump */
3760Sstevel@tonic-gate 	nodev,			/* read */
3770Sstevel@tonic-gate 	nodev,			/* write */
3780Sstevel@tonic-gate 	rsm_ioctl,		/* ioctl */
3790Sstevel@tonic-gate 	rsm_devmap,		/* devmap */
3800Sstevel@tonic-gate 	NULL,			/* mmap */
3810Sstevel@tonic-gate 	rsm_segmap,		/* segmap */
3820Sstevel@tonic-gate 	rsm_chpoll,		/* poll */
3830Sstevel@tonic-gate 	ddi_prop_op,		/* cb_prop_op */
3840Sstevel@tonic-gate 	0,			/* streamtab  */
3850Sstevel@tonic-gate 	D_NEW|D_MP|D_DEVMAP,	/* Driver compatibility flag */
3860Sstevel@tonic-gate 	0,
3870Sstevel@tonic-gate 	0,
3880Sstevel@tonic-gate 	0
3890Sstevel@tonic-gate };
3900Sstevel@tonic-gate 
3910Sstevel@tonic-gate static struct dev_ops rsm_ops = {
3920Sstevel@tonic-gate 	DEVO_REV,		/* devo_rev, */
3930Sstevel@tonic-gate 	0,			/* refcnt  */
3940Sstevel@tonic-gate 	rsm_info,		/* get_dev_info */
3950Sstevel@tonic-gate 	nulldev,		/* identify */
3960Sstevel@tonic-gate 	nulldev,		/* probe */
3970Sstevel@tonic-gate 	rsm_attach,		/* attach */
3980Sstevel@tonic-gate 	rsm_detach,		/* detach */
3990Sstevel@tonic-gate 	nodev,			/* reset */
4000Sstevel@tonic-gate 	&rsm_cb_ops,		/* driver operations */
4010Sstevel@tonic-gate 	(struct bus_ops *)0,	/* bus operations */
4027656SSherry.Moore@Sun.COM 	0,
4037656SSherry.Moore@Sun.COM 	ddi_quiesce_not_needed,		/* quiesce */
4040Sstevel@tonic-gate };
4050Sstevel@tonic-gate 
4060Sstevel@tonic-gate /*
4070Sstevel@tonic-gate  * Module linkage information for the kernel.
4080Sstevel@tonic-gate  */
4090Sstevel@tonic-gate 
4100Sstevel@tonic-gate static struct modldrv modldrv = {
4110Sstevel@tonic-gate 	&mod_driverops, /* Type of module.  This one is a pseudo driver */
4127656SSherry.Moore@Sun.COM 	"Remote Shared Memory Driver",
4130Sstevel@tonic-gate 	&rsm_ops,	/* driver ops */
4140Sstevel@tonic-gate };
4150Sstevel@tonic-gate 
4160Sstevel@tonic-gate static struct modlinkage modlinkage = {
4170Sstevel@tonic-gate 	MODREV_1,
4180Sstevel@tonic-gate 	(void *)&modldrv,
4190Sstevel@tonic-gate 	0,
4200Sstevel@tonic-gate 	0,
4210Sstevel@tonic-gate 	0
4220Sstevel@tonic-gate };
4230Sstevel@tonic-gate 
4240Sstevel@tonic-gate static void rsm_dr_callback_post_add(void *arg, pgcnt_t delta);
4250Sstevel@tonic-gate static int rsm_dr_callback_pre_del(void *arg, pgcnt_t delta);
4260Sstevel@tonic-gate static void rsm_dr_callback_post_del(void *arg, pgcnt_t delta, int cancelled);
4270Sstevel@tonic-gate 
4280Sstevel@tonic-gate static kphysm_setup_vector_t rsm_dr_callback_vec = {
4290Sstevel@tonic-gate 	KPHYSM_SETUP_VECTOR_VERSION,
4300Sstevel@tonic-gate 	rsm_dr_callback_post_add,
4310Sstevel@tonic-gate 	rsm_dr_callback_pre_del,
4320Sstevel@tonic-gate 	rsm_dr_callback_post_del
4330Sstevel@tonic-gate };
4340Sstevel@tonic-gate 
4350Sstevel@tonic-gate /* This flag can be changed to 0 to help with PIT testing */
4360Sstevel@tonic-gate int rsmka_modunloadok = 1;
4370Sstevel@tonic-gate int no_reply_cnt = 0;
4380Sstevel@tonic-gate 
4390Sstevel@tonic-gate uint64_t rsm_ctrlmsg_errcnt = 0;
4400Sstevel@tonic-gate uint64_t rsm_ipcsend_errcnt = 0;
4410Sstevel@tonic-gate 
4420Sstevel@tonic-gate #define	MAX_NODES 64
4430Sstevel@tonic-gate 
4440Sstevel@tonic-gate static struct rsm_driver_data rsm_drv_data;
4450Sstevel@tonic-gate static struct rsmresource_table rsm_resource;
4460Sstevel@tonic-gate 
4470Sstevel@tonic-gate static void rsmresource_insert(minor_t, rsmresource_t *, rsm_resource_type_t);
4480Sstevel@tonic-gate static void rsmresource_destroy(void);
4490Sstevel@tonic-gate static int rsmresource_alloc(minor_t *);
4500Sstevel@tonic-gate static rsmresource_t *rsmresource_free(minor_t rnum);
4510Sstevel@tonic-gate static int rsm_closeconnection(rsmseg_t *seg, void **cookie);
4520Sstevel@tonic-gate static int rsm_unpublish(rsmseg_t *seg, int mode);
4530Sstevel@tonic-gate static int rsm_unbind(rsmseg_t *seg);
4540Sstevel@tonic-gate static uint_t rsmhash(rsm_memseg_id_t key);
4550Sstevel@tonic-gate static void rsmhash_alloc(rsmhash_table_t *rhash, int size);
4560Sstevel@tonic-gate static void rsmhash_free(rsmhash_table_t *rhash, int size);
4570Sstevel@tonic-gate static void *rsmhash_getbkt(rsmhash_table_t *rhash, uint_t hashval);
4580Sstevel@tonic-gate static void **rsmhash_bktaddr(rsmhash_table_t *rhash, uint_t hashval);
4590Sstevel@tonic-gate static int rsm_send_notimporting(rsm_node_id_t dest, rsm_memseg_id_t segid,
4600Sstevel@tonic-gate 					void *cookie);
4610Sstevel@tonic-gate int rsm_disconnect(rsmseg_t *seg);
4620Sstevel@tonic-gate void rsmseg_unload(rsmseg_t *);
4630Sstevel@tonic-gate void rsm_suspend_complete(rsm_node_id_t src_node, int flag);
4640Sstevel@tonic-gate 
4650Sstevel@tonic-gate rsm_intr_hand_ret_t rsm_srv_func(rsm_controller_object_t *chd,
4660Sstevel@tonic-gate     rsm_intr_q_op_t opcode, rsm_addr_t src,
4670Sstevel@tonic-gate     void *data, size_t size, rsm_intr_hand_arg_t arg);
4680Sstevel@tonic-gate 
4690Sstevel@tonic-gate static void rsm_intr_callback(void *, rsm_addr_t, rsm_intr_hand_arg_t);
4700Sstevel@tonic-gate 
4710Sstevel@tonic-gate rsm_node_id_t my_nodeid;
4720Sstevel@tonic-gate 
4730Sstevel@tonic-gate /* cookie, va, offsets and length for the barrier */
4740Sstevel@tonic-gate static rsm_gnum_t		*bar_va;
4750Sstevel@tonic-gate static ddi_umem_cookie_t	bar_cookie;
4760Sstevel@tonic-gate static off_t			barrier_offset;
4770Sstevel@tonic-gate static size_t			barrier_size;
4780Sstevel@tonic-gate static int			max_segs;
4790Sstevel@tonic-gate 
4800Sstevel@tonic-gate /* cookie for the trash memory */
4810Sstevel@tonic-gate static ddi_umem_cookie_t	remap_cookie;
4820Sstevel@tonic-gate 
4830Sstevel@tonic-gate static rsm_memseg_id_t	rsm_nextavail_segmentid;
4840Sstevel@tonic-gate 
4850Sstevel@tonic-gate extern taskq_t *work_taskq;
4860Sstevel@tonic-gate extern char *taskq_name;
4870Sstevel@tonic-gate 
4880Sstevel@tonic-gate static dev_info_t *rsm_dip;	/* private copy of devinfo pointer */
4890Sstevel@tonic-gate 
4900Sstevel@tonic-gate static rsmhash_table_t rsm_export_segs;		/* list of exported segs */
4910Sstevel@tonic-gate rsmhash_table_t rsm_import_segs;		/* list of imported segs */
4920Sstevel@tonic-gate static rsmhash_table_t rsm_event_queues;	/* list of event queues */
4930Sstevel@tonic-gate 
4940Sstevel@tonic-gate static	rsm_ipc_t	rsm_ipc;		/* ipc info */
4950Sstevel@tonic-gate 
4960Sstevel@tonic-gate /* list of nodes to which RSMIPC_MSG_SUSPEND has been sent */
4970Sstevel@tonic-gate static list_head_t	rsm_suspend_list;
4980Sstevel@tonic-gate 
4990Sstevel@tonic-gate /* list of descriptors for remote importers */
5000Sstevel@tonic-gate static importers_table_t importer_list;
5010Sstevel@tonic-gate 
5020Sstevel@tonic-gate kmutex_t rsm_suspend_cvlock;
5030Sstevel@tonic-gate kcondvar_t rsm_suspend_cv;
5040Sstevel@tonic-gate 
5050Sstevel@tonic-gate static kmutex_t rsm_lock;
5060Sstevel@tonic-gate 
5070Sstevel@tonic-gate adapter_t loopback_adapter;
5080Sstevel@tonic-gate rsm_controller_attr_t loopback_attr;
5090Sstevel@tonic-gate 
5100Sstevel@tonic-gate int rsmipc_send_controlmsg(path_t *path, int msgtype);
5110Sstevel@tonic-gate 
5120Sstevel@tonic-gate void rsmka_init_loopback();
5130Sstevel@tonic-gate 
5140Sstevel@tonic-gate int rsmka_null_seg_create(
5150Sstevel@tonic-gate     rsm_controller_handle_t,
5160Sstevel@tonic-gate     rsm_memseg_export_handle_t *,
5170Sstevel@tonic-gate     size_t,
5180Sstevel@tonic-gate     uint_t,
5190Sstevel@tonic-gate     rsm_memory_local_t *,
5200Sstevel@tonic-gate     rsm_resource_callback_t,
5210Sstevel@tonic-gate     rsm_resource_callback_arg_t);
5220Sstevel@tonic-gate 
5230Sstevel@tonic-gate int rsmka_null_seg_destroy(
5240Sstevel@tonic-gate     rsm_memseg_export_handle_t);
5250Sstevel@tonic-gate 
5260Sstevel@tonic-gate int rsmka_null_bind(
5270Sstevel@tonic-gate     rsm_memseg_export_handle_t,
5280Sstevel@tonic-gate     off_t,
5290Sstevel@tonic-gate     rsm_memory_local_t *,
5300Sstevel@tonic-gate     rsm_resource_callback_t,
5310Sstevel@tonic-gate     rsm_resource_callback_arg_t);
5320Sstevel@tonic-gate 
5330Sstevel@tonic-gate int rsmka_null_unbind(
5340Sstevel@tonic-gate     rsm_memseg_export_handle_t,
5350Sstevel@tonic-gate     off_t,
5360Sstevel@tonic-gate     size_t);
5370Sstevel@tonic-gate 
5380Sstevel@tonic-gate int rsmka_null_rebind(
5390Sstevel@tonic-gate     rsm_memseg_export_handle_t,
5400Sstevel@tonic-gate     off_t,
5410Sstevel@tonic-gate     rsm_memory_local_t *,
5420Sstevel@tonic-gate     rsm_resource_callback_t,
5430Sstevel@tonic-gate     rsm_resource_callback_arg_t);
5440Sstevel@tonic-gate 
5450Sstevel@tonic-gate int rsmka_null_publish(
5460Sstevel@tonic-gate     rsm_memseg_export_handle_t,
5470Sstevel@tonic-gate     rsm_access_entry_t [],
5480Sstevel@tonic-gate     uint_t,
5490Sstevel@tonic-gate     rsm_memseg_id_t,
5500Sstevel@tonic-gate     rsm_resource_callback_t,
5510Sstevel@tonic-gate     rsm_resource_callback_arg_t);
5520Sstevel@tonic-gate 
5530Sstevel@tonic-gate 
5540Sstevel@tonic-gate int rsmka_null_republish(
5550Sstevel@tonic-gate     rsm_memseg_export_handle_t,
5560Sstevel@tonic-gate     rsm_access_entry_t [],
5570Sstevel@tonic-gate     uint_t,
5580Sstevel@tonic-gate     rsm_resource_callback_t,
5590Sstevel@tonic-gate     rsm_resource_callback_arg_t);
5600Sstevel@tonic-gate 
5610Sstevel@tonic-gate int rsmka_null_unpublish(
5620Sstevel@tonic-gate     rsm_memseg_export_handle_t);
5630Sstevel@tonic-gate 
5640Sstevel@tonic-gate rsm_ops_t null_rsmpi_ops;
5650Sstevel@tonic-gate 
5660Sstevel@tonic-gate /*
5670Sstevel@tonic-gate  * data and locks to keep track of total amount of exported memory
5680Sstevel@tonic-gate  */
5690Sstevel@tonic-gate static	pgcnt_t		rsm_pgcnt;
5700Sstevel@tonic-gate static	pgcnt_t		rsm_pgcnt_max;	/* max allowed */
5710Sstevel@tonic-gate static	kmutex_t	rsm_pgcnt_lock;
5720Sstevel@tonic-gate 
5730Sstevel@tonic-gate static	int		rsm_enable_dr;
5740Sstevel@tonic-gate 
5750Sstevel@tonic-gate static	char		loopback_str[] = "loopback";
5760Sstevel@tonic-gate 
5770Sstevel@tonic-gate int		rsm_hash_size;
5780Sstevel@tonic-gate 
5790Sstevel@tonic-gate /*
5800Sstevel@tonic-gate  * The locking model is as follows:
5810Sstevel@tonic-gate  *
5820Sstevel@tonic-gate  * Local operations:
5830Sstevel@tonic-gate  *		find resource - grab reader lock on resouce list
5840Sstevel@tonic-gate  *		insert rc     - grab writer lock
5850Sstevel@tonic-gate  *		delete rc     - grab writer lock and resource mutex
5860Sstevel@tonic-gate  *		read/write    - no lock
5870Sstevel@tonic-gate  *
5880Sstevel@tonic-gate  * Remote invocations:
5890Sstevel@tonic-gate  *		find resource - grab read lock and resource mutex
5900Sstevel@tonic-gate  *
5910Sstevel@tonic-gate  * State:
5920Sstevel@tonic-gate  *		resource state - grab resource mutex
5930Sstevel@tonic-gate  */
5940Sstevel@tonic-gate 
5950Sstevel@tonic-gate int
_init(void)5960Sstevel@tonic-gate _init(void)
5970Sstevel@tonic-gate {
5980Sstevel@tonic-gate 	int e;
5990Sstevel@tonic-gate 
6000Sstevel@tonic-gate 	e = mod_install(&modlinkage);
6010Sstevel@tonic-gate 	if (e != 0) {
6020Sstevel@tonic-gate 		return (e);
6030Sstevel@tonic-gate 	}
6040Sstevel@tonic-gate 
6050Sstevel@tonic-gate 	mutex_init(&rsm_lock, NULL, MUTEX_DRIVER, NULL);
6060Sstevel@tonic-gate 
6070Sstevel@tonic-gate 	mutex_init(&rsmka_buf_lock, NULL, MUTEX_DEFAULT, NULL);
6080Sstevel@tonic-gate 
6090Sstevel@tonic-gate 
6100Sstevel@tonic-gate 	rw_init(&rsm_resource.rsmrc_lock, NULL, RW_DRIVER, NULL);
6110Sstevel@tonic-gate 
6120Sstevel@tonic-gate 	rsm_hash_size = RSM_HASHSZ;
6130Sstevel@tonic-gate 
6140Sstevel@tonic-gate 	rw_init(&rsm_export_segs.rsmhash_rw, NULL, RW_DRIVER, NULL);
6150Sstevel@tonic-gate 
6160Sstevel@tonic-gate 	rw_init(&rsm_import_segs.rsmhash_rw, NULL, RW_DRIVER, NULL);
6170Sstevel@tonic-gate 
6180Sstevel@tonic-gate 	mutex_init(&importer_list.lock, NULL, MUTEX_DRIVER, NULL);
6190Sstevel@tonic-gate 
6200Sstevel@tonic-gate 	mutex_init(&rsm_ipc.lock, NULL, MUTEX_DRIVER, NULL);
6210Sstevel@tonic-gate 	cv_init(&rsm_ipc.cv, NULL, CV_DRIVER, 0);
6220Sstevel@tonic-gate 
6230Sstevel@tonic-gate 	mutex_init(&rsm_suspend_cvlock, NULL, MUTEX_DRIVER, NULL);
6240Sstevel@tonic-gate 	cv_init(&rsm_suspend_cv, NULL, CV_DRIVER, 0);
6250Sstevel@tonic-gate 
6260Sstevel@tonic-gate 	mutex_init(&rsm_drv_data.drv_lock, NULL, MUTEX_DRIVER, NULL);
6270Sstevel@tonic-gate 	cv_init(&rsm_drv_data.drv_cv, NULL, CV_DRIVER, 0);
6280Sstevel@tonic-gate 
6290Sstevel@tonic-gate 	rsm_ipc.count = RSMIPC_SZ;
6300Sstevel@tonic-gate 	rsm_ipc.wanted = 0;
6310Sstevel@tonic-gate 	rsm_ipc.sequence = 0;
6320Sstevel@tonic-gate 
6330Sstevel@tonic-gate 	(void) mutex_init(&rsm_pgcnt_lock, NULL, MUTEX_DRIVER, NULL);
6340Sstevel@tonic-gate 
6350Sstevel@tonic-gate 	for (e = 0; e < RSMIPC_SZ; e++) {
6360Sstevel@tonic-gate 		rsmipc_slot_t *slot = &rsm_ipc.slots[e];
6370Sstevel@tonic-gate 
6380Sstevel@tonic-gate 		RSMIPC_SET(slot, RSMIPC_FREE);
6390Sstevel@tonic-gate 		mutex_init(&slot->rsmipc_lock, NULL, MUTEX_DRIVER, NULL);
6400Sstevel@tonic-gate 		cv_init(&slot->rsmipc_cv, NULL, CV_DRIVER, 0);
6410Sstevel@tonic-gate 	}
6420Sstevel@tonic-gate 
6430Sstevel@tonic-gate 	/*
6440Sstevel@tonic-gate 	 * Initialize the suspend message list
6450Sstevel@tonic-gate 	 */
6460Sstevel@tonic-gate 	rsm_suspend_list.list_head = NULL;
6470Sstevel@tonic-gate 	mutex_init(&rsm_suspend_list.list_lock, NULL, MUTEX_DRIVER, NULL);
6480Sstevel@tonic-gate 
6490Sstevel@tonic-gate 	/*
6500Sstevel@tonic-gate 	 * It is assumed here that configuration data is available
6510Sstevel@tonic-gate 	 * during system boot since _init may be called at that time.
6520Sstevel@tonic-gate 	 */
6530Sstevel@tonic-gate 
6540Sstevel@tonic-gate 	rsmka_pathmanager_init();
6550Sstevel@tonic-gate 
6560Sstevel@tonic-gate 	DBG_PRINTF((RSM_KERNEL_AGENT, RSM_DEBUG_VERBOSE,
6570Sstevel@tonic-gate 	    "rsm: _init done\n"));
6580Sstevel@tonic-gate 
6590Sstevel@tonic-gate 	return (DDI_SUCCESS);
6600Sstevel@tonic-gate 
6610Sstevel@tonic-gate }
6620Sstevel@tonic-gate 
6630Sstevel@tonic-gate int
_info(struct modinfo * modinfop)6640Sstevel@tonic-gate _info(struct modinfo *modinfop)
6650Sstevel@tonic-gate {
6660Sstevel@tonic-gate 
6670Sstevel@tonic-gate 	return (mod_info(&modlinkage, modinfop));
6680Sstevel@tonic-gate }
6690Sstevel@tonic-gate 
6700Sstevel@tonic-gate int
_fini(void)6710Sstevel@tonic-gate _fini(void)
6720Sstevel@tonic-gate {
6730Sstevel@tonic-gate 	int e;
6740Sstevel@tonic-gate 
6750Sstevel@tonic-gate 	DBG_PRINTF((RSM_KERNEL_AGENT, RSM_DEBUG_VERBOSE,
6760Sstevel@tonic-gate 	    "rsm: _fini enter\n"));
6770Sstevel@tonic-gate 
6780Sstevel@tonic-gate 	/*
6790Sstevel@tonic-gate 	 * The rsmka_modunloadok flag is simply used to help with
6800Sstevel@tonic-gate 	 * the PIT testing. Make this flag 0 to disallow modunload.
6810Sstevel@tonic-gate 	 */
6820Sstevel@tonic-gate 	if (rsmka_modunloadok == 0)
6830Sstevel@tonic-gate 		return (EBUSY);
6840Sstevel@tonic-gate 
6850Sstevel@tonic-gate 	/* rsm_detach will be called as a result of mod_remove */
6860Sstevel@tonic-gate 	e = mod_remove(&modlinkage);
6870Sstevel@tonic-gate 	if (e) {
6880Sstevel@tonic-gate 		DBG_PRINTF((RSM_KERNEL_AGENT, RSM_ERR,
6890Sstevel@tonic-gate 		    "Unable to fini RSM %x\n", e));
6900Sstevel@tonic-gate 		return (e);
6910Sstevel@tonic-gate 	}
6920Sstevel@tonic-gate 
6930Sstevel@tonic-gate 	rsmka_pathmanager_cleanup();
6940Sstevel@tonic-gate 
6950Sstevel@tonic-gate 	rw_destroy(&rsm_resource.rsmrc_lock);
6960Sstevel@tonic-gate 
6970Sstevel@tonic-gate 	rw_destroy(&rsm_export_segs.rsmhash_rw);
6980Sstevel@tonic-gate 	rw_destroy(&rsm_import_segs.rsmhash_rw);
6990Sstevel@tonic-gate 	rw_destroy(&rsm_event_queues.rsmhash_rw);
7000Sstevel@tonic-gate 
7010Sstevel@tonic-gate 	mutex_destroy(&importer_list.lock);
7020Sstevel@tonic-gate 
7030Sstevel@tonic-gate 	mutex_destroy(&rsm_ipc.lock);
7040Sstevel@tonic-gate 	cv_destroy(&rsm_ipc.cv);
7050Sstevel@tonic-gate 
7060Sstevel@tonic-gate 	(void) mutex_destroy(&rsm_suspend_list.list_lock);
7070Sstevel@tonic-gate 
7080Sstevel@tonic-gate 	(void) mutex_destroy(&rsm_pgcnt_lock);
7090Sstevel@tonic-gate 
7100Sstevel@tonic-gate 	DBG_PRINTF((RSM_KERNEL_AGENT, RSM_DEBUG_VERBOSE, "_fini done\n"));
7110Sstevel@tonic-gate 
7120Sstevel@tonic-gate 	return (DDI_SUCCESS);
7130Sstevel@tonic-gate 
7140Sstevel@tonic-gate }
7150Sstevel@tonic-gate 
7160Sstevel@tonic-gate /*ARGSUSED1*/
7170Sstevel@tonic-gate static int
rsm_attach(dev_info_t * devi,ddi_attach_cmd_t cmd)7180Sstevel@tonic-gate rsm_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
7190Sstevel@tonic-gate {
7200Sstevel@tonic-gate 	minor_t	rnum;
7210Sstevel@tonic-gate 	int	percent;
7220Sstevel@tonic-gate 	int	ret;
7230Sstevel@tonic-gate 	DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_DDI);
7240Sstevel@tonic-gate 
7250Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_attach enter\n"));
7260Sstevel@tonic-gate 
7270Sstevel@tonic-gate 	switch (cmd) {
7280Sstevel@tonic-gate 	case DDI_ATTACH:
7290Sstevel@tonic-gate 		break;
7300Sstevel@tonic-gate 	case DDI_RESUME:
7310Sstevel@tonic-gate 	default:
7320Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_ERR,
7330Sstevel@tonic-gate 		    "rsm:rsm_attach - cmd not supported\n"));
7340Sstevel@tonic-gate 		return (DDI_FAILURE);
7350Sstevel@tonic-gate 	}
7360Sstevel@tonic-gate 
7370Sstevel@tonic-gate 	if (rsm_dip != NULL) {
7380Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_ERR,
7390Sstevel@tonic-gate 		    "rsm:rsm_attach - supports only "
7400Sstevel@tonic-gate 		    "one instance\n"));
7410Sstevel@tonic-gate 		return (DDI_FAILURE);
7420Sstevel@tonic-gate 	}
7430Sstevel@tonic-gate 
7440Sstevel@tonic-gate 	rsm_enable_dr = ddi_prop_get_int(DDI_DEV_T_ANY, devi,
7457656SSherry.Moore@Sun.COM 	    DDI_PROP_DONTPASS | DDI_PROP_NOTPROM,
7467656SSherry.Moore@Sun.COM 	    "enable-dynamic-reconfiguration", 1);
7470Sstevel@tonic-gate 
7480Sstevel@tonic-gate 	mutex_enter(&rsm_drv_data.drv_lock);
7490Sstevel@tonic-gate 	rsm_drv_data.drv_state = RSM_DRV_REG_PROCESSING;
7500Sstevel@tonic-gate 	mutex_exit(&rsm_drv_data.drv_lock);
7510Sstevel@tonic-gate 
7520Sstevel@tonic-gate 	if (rsm_enable_dr) {
7530Sstevel@tonic-gate #ifdef	RSM_DRTEST
7540Sstevel@tonic-gate 		ret = rsm_kphysm_setup_func_register(&rsm_dr_callback_vec,
7550Sstevel@tonic-gate 		    (void *)NULL);
7560Sstevel@tonic-gate #else
7570Sstevel@tonic-gate 		ret = kphysm_setup_func_register(&rsm_dr_callback_vec,
7580Sstevel@tonic-gate 		    (void *)NULL);
7590Sstevel@tonic-gate #endif
7600Sstevel@tonic-gate 		if (ret != 0) {
7610Sstevel@tonic-gate 			mutex_exit(&rsm_drv_data.drv_lock);
7620Sstevel@tonic-gate 			cmn_err(CE_CONT, "rsm:rsm_attach - Dynamic "
7630Sstevel@tonic-gate 			    "reconfiguration setup failed\n");
7640Sstevel@tonic-gate 			return (DDI_FAILURE);
7650Sstevel@tonic-gate 		}
7660Sstevel@tonic-gate 	}
7670Sstevel@tonic-gate 
7680Sstevel@tonic-gate 	mutex_enter(&rsm_drv_data.drv_lock);
7690Sstevel@tonic-gate 	ASSERT(rsm_drv_data.drv_state == RSM_DRV_REG_PROCESSING);
7700Sstevel@tonic-gate 	rsm_drv_data.drv_state = RSM_DRV_OK;
7710Sstevel@tonic-gate 	cv_broadcast(&rsm_drv_data.drv_cv);
7720Sstevel@tonic-gate 	mutex_exit(&rsm_drv_data.drv_lock);
7730Sstevel@tonic-gate 
7740Sstevel@tonic-gate 	/*
7750Sstevel@tonic-gate 	 * page_list_read_lock();
7760Sstevel@tonic-gate 	 * xx_setup();
7770Sstevel@tonic-gate 	 * page_list_read_unlock();
7780Sstevel@tonic-gate 	 */
7790Sstevel@tonic-gate 
7800Sstevel@tonic-gate 	rsm_hash_size = ddi_prop_get_int(DDI_DEV_T_ANY, devi,
7817656SSherry.Moore@Sun.COM 	    DDI_PROP_DONTPASS | DDI_PROP_NOTPROM,
7827656SSherry.Moore@Sun.COM 	    "segment-hashtable-size", RSM_HASHSZ);
7830Sstevel@tonic-gate 	if (rsm_hash_size == 0) {
7840Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
7850Sstevel@tonic-gate 		    "rsm: segment-hashtable-size in rsm.conf "
7860Sstevel@tonic-gate 		    "must be greater than 0, defaulting to 128\n"));
7870Sstevel@tonic-gate 		rsm_hash_size = RSM_HASHSZ;
7880Sstevel@tonic-gate 	}
7890Sstevel@tonic-gate 
7900Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG, "rsm_attach rsm_hash_size: %d\n",
7910Sstevel@tonic-gate 	    rsm_hash_size));
7920Sstevel@tonic-gate 
7930Sstevel@tonic-gate 	rsm_pgcnt = 0;
7940Sstevel@tonic-gate 
7950Sstevel@tonic-gate 	percent = ddi_prop_get_int(DDI_DEV_T_ANY, devi,
7960Sstevel@tonic-gate 	    DDI_PROP_DONTPASS | DDI_PROP_NOTPROM,
7970Sstevel@tonic-gate 	    "max-exported-memory", 0);
7980Sstevel@tonic-gate 	if (percent < 0) {
7990Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_ERR,
8000Sstevel@tonic-gate 		    "rsm:rsm_attach not enough memory available to "
8010Sstevel@tonic-gate 		    "export, or max-exported-memory set incorrectly.\n"));
8020Sstevel@tonic-gate 		return (DDI_FAILURE);
8030Sstevel@tonic-gate 	}
8040Sstevel@tonic-gate 	/* 0 indicates no fixed upper limit. maxmem is the max	*/
8050Sstevel@tonic-gate 	/* available pageable physical mem			*/
8060Sstevel@tonic-gate 	rsm_pgcnt_max = (percent*maxmem)/100;
8070Sstevel@tonic-gate 
8080Sstevel@tonic-gate 	if (rsm_pgcnt_max > 0) {
8090Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
8100Sstevel@tonic-gate 		    "rsm: Available physical memory = %lu pages, "
8110Sstevel@tonic-gate 		    "Max exportable memory = %lu pages",
8120Sstevel@tonic-gate 		    maxmem, rsm_pgcnt_max));
8130Sstevel@tonic-gate 	}
8140Sstevel@tonic-gate 
8150Sstevel@tonic-gate 	/*
8160Sstevel@tonic-gate 	 * Create minor number
8170Sstevel@tonic-gate 	 */
8180Sstevel@tonic-gate 	if (rsmresource_alloc(&rnum) != RSM_SUCCESS) {
8190Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_ERR,
8200Sstevel@tonic-gate 		    "rsm: rsm_attach - Unable to get "
8210Sstevel@tonic-gate 		    "minor number\n"));
8220Sstevel@tonic-gate 		return (DDI_FAILURE);
8230Sstevel@tonic-gate 	}
8240Sstevel@tonic-gate 
8250Sstevel@tonic-gate 	ASSERT(rnum == RSM_DRIVER_MINOR);
8260Sstevel@tonic-gate 
8270Sstevel@tonic-gate 	if (ddi_create_minor_node(devi, DRIVER_NAME, S_IFCHR,
8280Sstevel@tonic-gate 	    rnum, DDI_PSEUDO, NULL) == DDI_FAILURE) {
8290Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_ERR,
8300Sstevel@tonic-gate 		    "rsm: rsm_attach - unable to allocate "
8310Sstevel@tonic-gate 		    "minor #\n"));
8320Sstevel@tonic-gate 		return (DDI_FAILURE);
8330Sstevel@tonic-gate 	}
8340Sstevel@tonic-gate 
8350Sstevel@tonic-gate 	rsm_dip = devi;
8360Sstevel@tonic-gate 	/*
8370Sstevel@tonic-gate 	 * Allocate the hashtables
8380Sstevel@tonic-gate 	 */
8390Sstevel@tonic-gate 	rsmhash_alloc(&rsm_export_segs, rsm_hash_size);
8400Sstevel@tonic-gate 	rsmhash_alloc(&rsm_import_segs, rsm_hash_size);
8410Sstevel@tonic-gate 
8420Sstevel@tonic-gate 	importer_list.bucket = (importing_token_t **)
8437656SSherry.Moore@Sun.COM 	    kmem_zalloc(rsm_hash_size * sizeof (importing_token_t *), KM_SLEEP);
8440Sstevel@tonic-gate 
8450Sstevel@tonic-gate 	/*
8460Sstevel@tonic-gate 	 * Allocate a resource struct
8470Sstevel@tonic-gate 	 */
8480Sstevel@tonic-gate 	{
8490Sstevel@tonic-gate 		rsmresource_t *p;
8500Sstevel@tonic-gate 
8510Sstevel@tonic-gate 		p = (rsmresource_t *)kmem_zalloc(sizeof (*p), KM_SLEEP);
8520Sstevel@tonic-gate 
8530Sstevel@tonic-gate 		mutex_init(&p->rsmrc_lock, NULL, MUTEX_DRIVER, (void *) NULL);
8540Sstevel@tonic-gate 
8550Sstevel@tonic-gate 		rsmresource_insert(rnum, p, RSM_RESOURCE_BAR);
8560Sstevel@tonic-gate 	}
8570Sstevel@tonic-gate 
8580Sstevel@tonic-gate 	/*
8590Sstevel@tonic-gate 	 * Based on the rsm.conf property max-segments, determine the maximum
8600Sstevel@tonic-gate 	 * number of segments that can be exported/imported. This is then used
8610Sstevel@tonic-gate 	 * to determine the size for barrier failure pages.
8620Sstevel@tonic-gate 	 */
8630Sstevel@tonic-gate 
8640Sstevel@tonic-gate 	/* First get the max number of segments from the rsm.conf file */
8650Sstevel@tonic-gate 	max_segs = ddi_prop_get_int(DDI_DEV_T_ANY, devi,
8667656SSherry.Moore@Sun.COM 	    DDI_PROP_DONTPASS | DDI_PROP_NOTPROM,
8677656SSherry.Moore@Sun.COM 	    "max-segments", 0);
8680Sstevel@tonic-gate 	if (max_segs == 0) {
8690Sstevel@tonic-gate 		/* Use default number of segments */
8700Sstevel@tonic-gate 		max_segs = RSM_MAX_NUM_SEG;
8710Sstevel@tonic-gate 	}
8720Sstevel@tonic-gate 
8730Sstevel@tonic-gate 	/*
8740Sstevel@tonic-gate 	 * Based on the max number of segments allowed, determine the barrier
8750Sstevel@tonic-gate 	 * page size. add 1 to max_segs since the barrier page itself uses
8760Sstevel@tonic-gate 	 * a slot
8770Sstevel@tonic-gate 	 */
8780Sstevel@tonic-gate 	barrier_size = roundup((max_segs + 1) * sizeof (rsm_gnum_t),
8797656SSherry.Moore@Sun.COM 	    PAGESIZE);
8800Sstevel@tonic-gate 
8810Sstevel@tonic-gate 	/*
8820Sstevel@tonic-gate 	 * allocation of the barrier failure page
8830Sstevel@tonic-gate 	 */
8840Sstevel@tonic-gate 	bar_va = (rsm_gnum_t *)ddi_umem_alloc(barrier_size,
8857656SSherry.Moore@Sun.COM 	    DDI_UMEM_SLEEP, &bar_cookie);
8860Sstevel@tonic-gate 
8870Sstevel@tonic-gate 	/*
8880Sstevel@tonic-gate 	 * Set the barrier_offset
8890Sstevel@tonic-gate 	 */
8900Sstevel@tonic-gate 	barrier_offset = 0;
8910Sstevel@tonic-gate 
8920Sstevel@tonic-gate 	/*
8930Sstevel@tonic-gate 	 * Allocate a trash memory and get a cookie for it. This will be used
8940Sstevel@tonic-gate 	 * when remapping segments during force disconnects. Allocate the
8950Sstevel@tonic-gate 	 * trash memory with a large size which is page aligned.
8960Sstevel@tonic-gate 	 */
8970Sstevel@tonic-gate 	(void) ddi_umem_alloc((size_t)TRASHSIZE,
8987656SSherry.Moore@Sun.COM 	    DDI_UMEM_TRASH, &remap_cookie);
8990Sstevel@tonic-gate 
9000Sstevel@tonic-gate 	/* initialize user segment id allocation variable */
9010Sstevel@tonic-gate 	rsm_nextavail_segmentid = (rsm_memseg_id_t)RSM_USER_APP_ID_BASE;
9020Sstevel@tonic-gate 
9030Sstevel@tonic-gate 	/*
9040Sstevel@tonic-gate 	 * initialize the null_rsmpi_ops vector and the loopback adapter
9050Sstevel@tonic-gate 	 */
9060Sstevel@tonic-gate 	rsmka_init_loopback();
9070Sstevel@tonic-gate 
9080Sstevel@tonic-gate 
9090Sstevel@tonic-gate 	ddi_report_dev(devi);
9100Sstevel@tonic-gate 
9110Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_attach done\n"));
9120Sstevel@tonic-gate 
9130Sstevel@tonic-gate 	return (DDI_SUCCESS);
9140Sstevel@tonic-gate }
9150Sstevel@tonic-gate 
9160Sstevel@tonic-gate /*
9170Sstevel@tonic-gate  * The call to mod_remove in the _fine routine will cause the system
9180Sstevel@tonic-gate  * to call rsm_detach
9190Sstevel@tonic-gate  */
9200Sstevel@tonic-gate /*ARGSUSED*/
9210Sstevel@tonic-gate static int
rsm_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)9220Sstevel@tonic-gate rsm_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
9230Sstevel@tonic-gate {
9240Sstevel@tonic-gate 	DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_DDI);
9250Sstevel@tonic-gate 
9260Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_detach enter\n"));
9270Sstevel@tonic-gate 
9280Sstevel@tonic-gate 	switch (cmd) {
9290Sstevel@tonic-gate 	case DDI_DETACH:
9300Sstevel@tonic-gate 		break;
9310Sstevel@tonic-gate 	default:
9320Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_ERR,
9330Sstevel@tonic-gate 		    "rsm:rsm_detach - cmd %x not supported\n",
9340Sstevel@tonic-gate 		    cmd));
9350Sstevel@tonic-gate 		return (DDI_FAILURE);
9360Sstevel@tonic-gate 	}
9370Sstevel@tonic-gate 
9380Sstevel@tonic-gate 	mutex_enter(&rsm_drv_data.drv_lock);
9390Sstevel@tonic-gate 	while (rsm_drv_data.drv_state != RSM_DRV_OK)
9400Sstevel@tonic-gate 		cv_wait(&rsm_drv_data.drv_cv, &rsm_drv_data.drv_lock);
9410Sstevel@tonic-gate 	rsm_drv_data.drv_state = RSM_DRV_UNREG_PROCESSING;
9420Sstevel@tonic-gate 	mutex_exit(&rsm_drv_data.drv_lock);
9430Sstevel@tonic-gate 
9440Sstevel@tonic-gate 	/*
9450Sstevel@tonic-gate 	 * Unregister the DR callback functions
9460Sstevel@tonic-gate 	 */
9470Sstevel@tonic-gate 	if (rsm_enable_dr) {
9480Sstevel@tonic-gate #ifdef	RSM_DRTEST
9490Sstevel@tonic-gate 		rsm_kphysm_setup_func_unregister(&rsm_dr_callback_vec,
9500Sstevel@tonic-gate 		    (void *)NULL);
9510Sstevel@tonic-gate #else
9520Sstevel@tonic-gate 		kphysm_setup_func_unregister(&rsm_dr_callback_vec,
9530Sstevel@tonic-gate 		    (void *)NULL);
9540Sstevel@tonic-gate #endif
9550Sstevel@tonic-gate 	}
9560Sstevel@tonic-gate 
9570Sstevel@tonic-gate 	mutex_enter(&rsm_drv_data.drv_lock);
9580Sstevel@tonic-gate 	ASSERT(rsm_drv_data.drv_state == RSM_DRV_UNREG_PROCESSING);
9590Sstevel@tonic-gate 	rsm_drv_data.drv_state = RSM_DRV_NEW;
9600Sstevel@tonic-gate 	mutex_exit(&rsm_drv_data.drv_lock);
9610Sstevel@tonic-gate 
9620Sstevel@tonic-gate 	ASSERT(rsm_suspend_list.list_head == NULL);
9630Sstevel@tonic-gate 
9640Sstevel@tonic-gate 	/*
9650Sstevel@tonic-gate 	 * Release all resources, seglist, controller, ...
9660Sstevel@tonic-gate 	 */
9670Sstevel@tonic-gate 
9680Sstevel@tonic-gate 	/* remove intersend queues */
9690Sstevel@tonic-gate 	/* remove registered services */
9700Sstevel@tonic-gate 
9710Sstevel@tonic-gate 
9720Sstevel@tonic-gate 	ddi_remove_minor_node(dip, DRIVER_NAME);
9730Sstevel@tonic-gate 	rsm_dip = NULL;
9740Sstevel@tonic-gate 
9750Sstevel@tonic-gate 	/*
9760Sstevel@tonic-gate 	 * Free minor zero resource
9770Sstevel@tonic-gate 	 */
9780Sstevel@tonic-gate 	{
9790Sstevel@tonic-gate 		rsmresource_t *p;
9800Sstevel@tonic-gate 
9810Sstevel@tonic-gate 		p = rsmresource_free(RSM_DRIVER_MINOR);
9820Sstevel@tonic-gate 		if (p) {
9830Sstevel@tonic-gate 			mutex_destroy(&p->rsmrc_lock);
9840Sstevel@tonic-gate 			kmem_free((void *)p, sizeof (*p));
9850Sstevel@tonic-gate 		}
9860Sstevel@tonic-gate 	}
9870Sstevel@tonic-gate 
9880Sstevel@tonic-gate 	/*
9890Sstevel@tonic-gate 	 * Free resource table
9900Sstevel@tonic-gate 	 */
9910Sstevel@tonic-gate 
9920Sstevel@tonic-gate 	rsmresource_destroy();
9930Sstevel@tonic-gate 
9940Sstevel@tonic-gate 	/*
9950Sstevel@tonic-gate 	 * Free the hash tables
9960Sstevel@tonic-gate 	 */
9970Sstevel@tonic-gate 	rsmhash_free(&rsm_export_segs, rsm_hash_size);
9980Sstevel@tonic-gate 	rsmhash_free(&rsm_import_segs, rsm_hash_size);
9990Sstevel@tonic-gate 
10000Sstevel@tonic-gate 	kmem_free((void *)importer_list.bucket,
10010Sstevel@tonic-gate 	    rsm_hash_size * sizeof (importing_token_t *));
10020Sstevel@tonic-gate 	importer_list.bucket = NULL;
10030Sstevel@tonic-gate 
10040Sstevel@tonic-gate 
10050Sstevel@tonic-gate 	/* free barrier page */
10060Sstevel@tonic-gate 	if (bar_cookie != NULL) {
10070Sstevel@tonic-gate 		ddi_umem_free(bar_cookie);
10080Sstevel@tonic-gate 	}
10090Sstevel@tonic-gate 	bar_va = NULL;
10100Sstevel@tonic-gate 	bar_cookie = NULL;
10110Sstevel@tonic-gate 
10120Sstevel@tonic-gate 	/*
10130Sstevel@tonic-gate 	 * Free the memory allocated for the trash
10140Sstevel@tonic-gate 	 */
10150Sstevel@tonic-gate 	if (remap_cookie != NULL) {
10160Sstevel@tonic-gate 		ddi_umem_free(remap_cookie);
10170Sstevel@tonic-gate 	}
10180Sstevel@tonic-gate 	remap_cookie = NULL;
10190Sstevel@tonic-gate 
10200Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_detach done\n"));
10210Sstevel@tonic-gate 
10220Sstevel@tonic-gate 	return (DDI_SUCCESS);
10230Sstevel@tonic-gate }
10240Sstevel@tonic-gate 
10250Sstevel@tonic-gate /*ARGSUSED*/
10260Sstevel@tonic-gate static int
rsm_info(dev_info_t * dip,ddi_info_cmd_t infocmd,void * arg,void ** result)10270Sstevel@tonic-gate rsm_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
10280Sstevel@tonic-gate {
10290Sstevel@tonic-gate 	register int error;
10300Sstevel@tonic-gate 	DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_DDI);
10310Sstevel@tonic-gate 
10320Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_info enter\n"));
10330Sstevel@tonic-gate 
10340Sstevel@tonic-gate 	switch (infocmd) {
10350Sstevel@tonic-gate 	case DDI_INFO_DEVT2DEVINFO:
10360Sstevel@tonic-gate 		if (rsm_dip == NULL)
10370Sstevel@tonic-gate 			error = DDI_FAILURE;
10380Sstevel@tonic-gate 		else {
10390Sstevel@tonic-gate 			*result = (void *)rsm_dip;
10400Sstevel@tonic-gate 			error = DDI_SUCCESS;
10410Sstevel@tonic-gate 		}
10420Sstevel@tonic-gate 		break;
10430Sstevel@tonic-gate 	case DDI_INFO_DEVT2INSTANCE:
10440Sstevel@tonic-gate 		*result = (void *)0;
10450Sstevel@tonic-gate 		error = DDI_SUCCESS;
10460Sstevel@tonic-gate 		break;
10470Sstevel@tonic-gate 	default:
10480Sstevel@tonic-gate 		error = DDI_FAILURE;
10490Sstevel@tonic-gate 	}
10500Sstevel@tonic-gate 
10510Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_info done\n"));
10520Sstevel@tonic-gate 	return (error);
10530Sstevel@tonic-gate }
10540Sstevel@tonic-gate 
10550Sstevel@tonic-gate adapter_t *
rsm_getadapter(rsm_ioctlmsg_t * msg,int mode)10560Sstevel@tonic-gate rsm_getadapter(rsm_ioctlmsg_t *msg, int mode)
10570Sstevel@tonic-gate {
10580Sstevel@tonic-gate 	adapter_t *adapter;
10590Sstevel@tonic-gate 	char adapter_devname[MAXNAMELEN];
10600Sstevel@tonic-gate 	int instance;
10610Sstevel@tonic-gate 	DBG_DEFINE(category,
10620Sstevel@tonic-gate 	    RSM_KERNEL_AGENT | RSM_IMPORT | RSM_EXPORT | RSM_IOCTL);
10630Sstevel@tonic-gate 
10640Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_getadapter enter\n"));
10650Sstevel@tonic-gate 
10660Sstevel@tonic-gate 	instance = msg->cnum;
10670Sstevel@tonic-gate 
10680Sstevel@tonic-gate 	if ((msg->cname_len <= 0) || (msg->cname_len > MAXNAMELEN)) {
10690Sstevel@tonic-gate 		return (NULL);
10700Sstevel@tonic-gate 	}
10710Sstevel@tonic-gate 
10720Sstevel@tonic-gate 	if (ddi_copyin(msg->cname, adapter_devname, msg->cname_len, mode))
10730Sstevel@tonic-gate 		return (NULL);
10740Sstevel@tonic-gate 
10750Sstevel@tonic-gate 	if (strcmp(adapter_devname, "loopback") == 0)
10760Sstevel@tonic-gate 		return (&loopback_adapter);
10770Sstevel@tonic-gate 
10780Sstevel@tonic-gate 	adapter = rsmka_lookup_adapter(adapter_devname, instance);
10790Sstevel@tonic-gate 
10800Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_getadapter done\n"));
10810Sstevel@tonic-gate 
10820Sstevel@tonic-gate 	return (adapter);
10830Sstevel@tonic-gate }
10840Sstevel@tonic-gate 
10850Sstevel@tonic-gate 
10860Sstevel@tonic-gate /*
10870Sstevel@tonic-gate  * *********************** Resource Number Management ********************
10880Sstevel@tonic-gate  * All resources are stored in a simple hash table. The table is an array
10890Sstevel@tonic-gate  * of pointers to resource blks. Each blk contains:
10900Sstevel@tonic-gate  *	base	- base number of this blk
10910Sstevel@tonic-gate  *	used	- number of used slots in this blk.
10920Sstevel@tonic-gate  *	blks    - array of pointers to resource items.
10930Sstevel@tonic-gate  * An entry in a resource blk is empty if it's NULL.
10940Sstevel@tonic-gate  *
10950Sstevel@tonic-gate  * We start with no resource array. Each time we run out of slots, we
10960Sstevel@tonic-gate  * reallocate a new larger array and copy the pointer to the new array and
10970Sstevel@tonic-gate  * a new resource blk is allocated and added to the hash table.
10980Sstevel@tonic-gate  *
10990Sstevel@tonic-gate  * The resource control block contains:
11000Sstevel@tonic-gate  *      root    - array of pointer of resource blks
11010Sstevel@tonic-gate  *      sz      - current size of array.
11020Sstevel@tonic-gate  *      len     - last valid entry in array.
11030Sstevel@tonic-gate  *
11040Sstevel@tonic-gate  * A search operation based on a resource number is as follows:
11050Sstevel@tonic-gate  *      index = rnum / RESOURCE_BLKSZ;
11060Sstevel@tonic-gate  *      ASSERT(index < resource_block.len);
11070Sstevel@tonic-gate  *      ASSERT(index < resource_block.sz);
11080Sstevel@tonic-gate  *	offset = rnum % RESOURCE_BLKSZ;
11090Sstevel@tonic-gate  *      ASSERT(offset >= resource_block.root[index]->base);
11100Sstevel@tonic-gate  *	ASSERT(offset < resource_block.root[index]->base + RESOURCE_BLKSZ);
11110Sstevel@tonic-gate  *	return resource_block.root[index]->blks[offset];
11120Sstevel@tonic-gate  *
11130Sstevel@tonic-gate  * A resource blk is freed with its used count reachs zero.
11140Sstevel@tonic-gate  */
11150Sstevel@tonic-gate static int
rsmresource_alloc(minor_t * rnum)11160Sstevel@tonic-gate rsmresource_alloc(minor_t *rnum)
11170Sstevel@tonic-gate {
11180Sstevel@tonic-gate 
11190Sstevel@tonic-gate 	/* search for available resource slot */
11200Sstevel@tonic-gate 	int i, j, empty = -1;
11210Sstevel@tonic-gate 	rsmresource_blk_t *blk;
11220Sstevel@tonic-gate 
11230Sstevel@tonic-gate 	DBG_PRINTF((RSM_KERNEL_ALL, RSM_DEBUG_VERBOSE,
11240Sstevel@tonic-gate 	    "rsmresource_alloc enter\n"));
11250Sstevel@tonic-gate 
11260Sstevel@tonic-gate 	rw_enter(&rsm_resource.rsmrc_lock, RW_WRITER);
11270Sstevel@tonic-gate 
11280Sstevel@tonic-gate 	/* Try to find an empty slot */
11290Sstevel@tonic-gate 	for (i = 0; i < rsm_resource.rsmrc_len; i++) {
11300Sstevel@tonic-gate 		blk = rsm_resource.rsmrc_root[i];
11310Sstevel@tonic-gate 		if (blk != NULL && blk->rsmrcblk_avail > 0) {
11320Sstevel@tonic-gate 			/* found an empty slot in this blk */
11330Sstevel@tonic-gate 			for (j = 0; j < RSMRC_BLKSZ; j++) {
11340Sstevel@tonic-gate 				if (blk->rsmrcblk_blks[j] == NULL) {
11350Sstevel@tonic-gate 					*rnum = (minor_t)
11360Sstevel@tonic-gate 					    (j + (i * RSMRC_BLKSZ));
11370Sstevel@tonic-gate 					/*
11380Sstevel@tonic-gate 					 * obey gen page limits
11390Sstevel@tonic-gate 					 */
11400Sstevel@tonic-gate 					if (*rnum >= max_segs + 1) {
11410Sstevel@tonic-gate 						if (empty < 0) {
11420Sstevel@tonic-gate 							rw_exit(&rsm_resource.
11430Sstevel@tonic-gate 							    rsmrc_lock);
11440Sstevel@tonic-gate 							DBG_PRINTF((
11450Sstevel@tonic-gate 							    RSM_KERNEL_ALL,
11460Sstevel@tonic-gate 							    RSM_ERR,
11470Sstevel@tonic-gate 							    "rsmresource"
11480Sstevel@tonic-gate 							    "_alloc failed:"
11490Sstevel@tonic-gate 							    "not enough res"
11500Sstevel@tonic-gate 							    "%d\n", *rnum));
11517656SSherry.Moore@Sun.COM 					return (RSMERR_INSUFFICIENT_RESOURCES);
11520Sstevel@tonic-gate 						} else {
11530Sstevel@tonic-gate 							/* use empty slot */
11540Sstevel@tonic-gate 							break;
11550Sstevel@tonic-gate 						}
11560Sstevel@tonic-gate 
11570Sstevel@tonic-gate 					}
11580Sstevel@tonic-gate 
11590Sstevel@tonic-gate 					blk->rsmrcblk_blks[j] = RSMRC_RESERVED;
11600Sstevel@tonic-gate 					blk->rsmrcblk_avail--;
11610Sstevel@tonic-gate 					rw_exit(&rsm_resource.rsmrc_lock);
11620Sstevel@tonic-gate 					DBG_PRINTF((RSM_KERNEL_ALL,
11630Sstevel@tonic-gate 					    RSM_DEBUG_VERBOSE,
11640Sstevel@tonic-gate 					    "rsmresource_alloc done\n"));
11650Sstevel@tonic-gate 					return (RSM_SUCCESS);
11660Sstevel@tonic-gate 				}
11670Sstevel@tonic-gate 			}
11680Sstevel@tonic-gate 		} else if (blk == NULL && empty < 0) {
11690Sstevel@tonic-gate 			/* remember first empty slot */
11700Sstevel@tonic-gate 			empty = i;
11710Sstevel@tonic-gate 		}
11720Sstevel@tonic-gate 	}
11730Sstevel@tonic-gate 
11740Sstevel@tonic-gate 	/* Couldn't find anything, allocate a new blk */
11750Sstevel@tonic-gate 	/*
11760Sstevel@tonic-gate 	 * Do we need to reallocate the root array
11770Sstevel@tonic-gate 	 */
11780Sstevel@tonic-gate 	if (empty < 0) {
11790Sstevel@tonic-gate 		if (rsm_resource.rsmrc_len == rsm_resource.rsmrc_sz) {
11800Sstevel@tonic-gate 			/*
11810Sstevel@tonic-gate 			 * Allocate new array and copy current stuff into it
11820Sstevel@tonic-gate 			 */
11830Sstevel@tonic-gate 			rsmresource_blk_t	**p;
11840Sstevel@tonic-gate 			uint_t newsz = (uint_t)rsm_resource.rsmrc_sz +
11857656SSherry.Moore@Sun.COM 			    RSMRC_BLKSZ;
11860Sstevel@tonic-gate 			/*
11870Sstevel@tonic-gate 			 * Don't allocate more that max valid rnum
11880Sstevel@tonic-gate 			 */
11890Sstevel@tonic-gate 			if (rsm_resource.rsmrc_len*RSMRC_BLKSZ >=
11900Sstevel@tonic-gate 			    max_segs + 1) {
11910Sstevel@tonic-gate 				rw_exit(&rsm_resource.rsmrc_lock);
11920Sstevel@tonic-gate 				return (RSMERR_INSUFFICIENT_RESOURCES);
11930Sstevel@tonic-gate 			}
11940Sstevel@tonic-gate 
11950Sstevel@tonic-gate 			p = (rsmresource_blk_t **)kmem_zalloc(
11960Sstevel@tonic-gate 			    newsz * sizeof (*p),
11970Sstevel@tonic-gate 			    KM_SLEEP);
11980Sstevel@tonic-gate 
11990Sstevel@tonic-gate 			if (rsm_resource.rsmrc_root) {
12000Sstevel@tonic-gate 				uint_t oldsz;
12010Sstevel@tonic-gate 
12020Sstevel@tonic-gate 				oldsz = (uint_t)(rsm_resource.rsmrc_sz *
12030Sstevel@tonic-gate 				    (int)sizeof (*p));
12040Sstevel@tonic-gate 
12050Sstevel@tonic-gate 				/*
12060Sstevel@tonic-gate 				 * Copy old data into new space and
12070Sstevel@tonic-gate 				 * free old stuff
12080Sstevel@tonic-gate 				 */
12090Sstevel@tonic-gate 				bcopy(rsm_resource.rsmrc_root, p, oldsz);
12100Sstevel@tonic-gate 				kmem_free(rsm_resource.rsmrc_root, oldsz);
12110Sstevel@tonic-gate 			}
12120Sstevel@tonic-gate 
12130Sstevel@tonic-gate 			rsm_resource.rsmrc_root = p;
12140Sstevel@tonic-gate 			rsm_resource.rsmrc_sz = (int)newsz;
12150Sstevel@tonic-gate 		}
12160Sstevel@tonic-gate 
12170Sstevel@tonic-gate 		empty = rsm_resource.rsmrc_len;
12180Sstevel@tonic-gate 		rsm_resource.rsmrc_len++;
12190Sstevel@tonic-gate 	}
12200Sstevel@tonic-gate 
12210Sstevel@tonic-gate 	/*
12220Sstevel@tonic-gate 	 * Allocate a new blk
12230Sstevel@tonic-gate 	 */
12240Sstevel@tonic-gate 	blk = (rsmresource_blk_t *)kmem_zalloc(sizeof (*blk), KM_SLEEP);
12250Sstevel@tonic-gate 	ASSERT(rsm_resource.rsmrc_root[empty] == NULL);
12260Sstevel@tonic-gate 	rsm_resource.rsmrc_root[empty] = blk;
12270Sstevel@tonic-gate 	blk->rsmrcblk_avail = RSMRC_BLKSZ - 1;
12280Sstevel@tonic-gate 
12290Sstevel@tonic-gate 	/*
12300Sstevel@tonic-gate 	 * Allocate slot
12310Sstevel@tonic-gate 	 */
12320Sstevel@tonic-gate 
12330Sstevel@tonic-gate 	*rnum = (minor_t)(empty * RSMRC_BLKSZ);
12340Sstevel@tonic-gate 
12350Sstevel@tonic-gate 	/*
12360Sstevel@tonic-gate 	 * watch out not to exceed bounds of barrier page
12370Sstevel@tonic-gate 	 */
12380Sstevel@tonic-gate 	if (*rnum >= max_segs + 1) {
12390Sstevel@tonic-gate 		rw_exit(&rsm_resource.rsmrc_lock);
12400Sstevel@tonic-gate 		DBG_PRINTF((RSM_KERNEL_ALL, RSM_ERR,
12410Sstevel@tonic-gate 		    "rsmresource_alloc failed %d\n", *rnum));
12420Sstevel@tonic-gate 
12430Sstevel@tonic-gate 		return (RSMERR_INSUFFICIENT_RESOURCES);
12440Sstevel@tonic-gate 	}
12450Sstevel@tonic-gate 	blk->rsmrcblk_blks[0] = RSMRC_RESERVED;
12460Sstevel@tonic-gate 
12470Sstevel@tonic-gate 
12480Sstevel@tonic-gate 	rw_exit(&rsm_resource.rsmrc_lock);
12490Sstevel@tonic-gate 
12500Sstevel@tonic-gate 	DBG_PRINTF((RSM_KERNEL_ALL, RSM_DEBUG_VERBOSE,
12510Sstevel@tonic-gate 	    "rsmresource_alloc done\n"));
12520Sstevel@tonic-gate 
12530Sstevel@tonic-gate 	return (RSM_SUCCESS);
12540Sstevel@tonic-gate }
12550Sstevel@tonic-gate 
12560Sstevel@tonic-gate static rsmresource_t *
rsmresource_free(minor_t rnum)12570Sstevel@tonic-gate rsmresource_free(minor_t rnum)
12580Sstevel@tonic-gate {
12590Sstevel@tonic-gate 
12600Sstevel@tonic-gate 	/* search for available resource slot */
12610Sstevel@tonic-gate 	int i, j;
12620Sstevel@tonic-gate 	rsmresource_blk_t *blk;
12630Sstevel@tonic-gate 	rsmresource_t *p;
12640Sstevel@tonic-gate 
12650Sstevel@tonic-gate 	DBG_PRINTF((RSM_KERNEL_ALL, RSM_DEBUG_VERBOSE,
12660Sstevel@tonic-gate 	    "rsmresource_free enter\n"));
12670Sstevel@tonic-gate 
12680Sstevel@tonic-gate 	i = (int)(rnum / RSMRC_BLKSZ);
12690Sstevel@tonic-gate 	j = (int)(rnum % RSMRC_BLKSZ);
12700Sstevel@tonic-gate 
12710Sstevel@tonic-gate 	if (i >= rsm_resource.rsmrc_len) {
12720Sstevel@tonic-gate 		DBG_PRINTF((RSM_KERNEL_ALL, RSM_DEBUG_VERBOSE,
12730Sstevel@tonic-gate 		    "rsmresource_free done\n"));
12740Sstevel@tonic-gate 		return (NULL);
12750Sstevel@tonic-gate 	}
12760Sstevel@tonic-gate 
12770Sstevel@tonic-gate 	rw_enter(&rsm_resource.rsmrc_lock, RW_WRITER);
12780Sstevel@tonic-gate 
12790Sstevel@tonic-gate 	ASSERT(rsm_resource.rsmrc_root);
12800Sstevel@tonic-gate 	ASSERT(i < rsm_resource.rsmrc_len);
12810Sstevel@tonic-gate 	ASSERT(i < rsm_resource.rsmrc_sz);
12820Sstevel@tonic-gate 	blk = rsm_resource.rsmrc_root[i];
12830Sstevel@tonic-gate 	if (blk == NULL) {
12840Sstevel@tonic-gate 		rw_exit(&rsm_resource.rsmrc_lock);
12850Sstevel@tonic-gate 		DBG_PRINTF((RSM_KERNEL_ALL, RSM_DEBUG_VERBOSE,
12860Sstevel@tonic-gate 		    "rsmresource_free done\n"));
12870Sstevel@tonic-gate 		return (NULL);
12880Sstevel@tonic-gate 	}
12890Sstevel@tonic-gate 
12900Sstevel@tonic-gate 	ASSERT(blk->rsmrcblk_blks[j]); /* reserved or full */
12910Sstevel@tonic-gate 
12920Sstevel@tonic-gate 	p = blk->rsmrcblk_blks[j];
12930Sstevel@tonic-gate 	if (p == RSMRC_RESERVED) {
12940Sstevel@tonic-gate 		p = NULL;
12950Sstevel@tonic-gate 	}
12960Sstevel@tonic-gate 
12970Sstevel@tonic-gate 	blk->rsmrcblk_blks[j] = NULL;
12980Sstevel@tonic-gate 	blk->rsmrcblk_avail++;
12990Sstevel@tonic-gate 	if (blk->rsmrcblk_avail == RSMRC_BLKSZ) {
13000Sstevel@tonic-gate 		/* free this blk */
13010Sstevel@tonic-gate 		kmem_free(blk, sizeof (*blk));
13020Sstevel@tonic-gate 		rsm_resource.rsmrc_root[i] = NULL;
13030Sstevel@tonic-gate 	}
13040Sstevel@tonic-gate 
13050Sstevel@tonic-gate 	rw_exit(&rsm_resource.rsmrc_lock);
13060Sstevel@tonic-gate 
13070Sstevel@tonic-gate 	DBG_PRINTF((RSM_KERNEL_ALL, RSM_DEBUG_VERBOSE,
13080Sstevel@tonic-gate 	    "rsmresource_free done\n"));
13090Sstevel@tonic-gate 
13100Sstevel@tonic-gate 	return (p);
13110Sstevel@tonic-gate }
13120Sstevel@tonic-gate 
13130Sstevel@tonic-gate static rsmresource_t *
rsmresource_lookup(minor_t rnum,int lock)13140Sstevel@tonic-gate rsmresource_lookup(minor_t rnum, int lock)
13150Sstevel@tonic-gate {
13160Sstevel@tonic-gate 	int i, j;
13170Sstevel@tonic-gate 	rsmresource_blk_t *blk;
13180Sstevel@tonic-gate 	rsmresource_t *p;
13190Sstevel@tonic-gate 
13200Sstevel@tonic-gate 	DBG_PRINTF((RSM_KERNEL_ALL, RSM_DEBUG_VERBOSE,
13210Sstevel@tonic-gate 	    "rsmresource_lookup enter\n"));
13220Sstevel@tonic-gate 
13230Sstevel@tonic-gate 	/* Find resource and lock it in READER mode */
13240Sstevel@tonic-gate 	/* search for available resource slot */
13250Sstevel@tonic-gate 
13260Sstevel@tonic-gate 	i = (int)(rnum / RSMRC_BLKSZ);
13270Sstevel@tonic-gate 	j = (int)(rnum % RSMRC_BLKSZ);
13280Sstevel@tonic-gate 
13290Sstevel@tonic-gate 	if (i >= rsm_resource.rsmrc_len) {
13300Sstevel@tonic-gate 		DBG_PRINTF((RSM_KERNEL_ALL, RSM_DEBUG_VERBOSE,
13310Sstevel@tonic-gate 		    "rsmresource_lookup done\n"));
13320Sstevel@tonic-gate 		return (NULL);
13330Sstevel@tonic-gate 	}
13340Sstevel@tonic-gate 
13350Sstevel@tonic-gate 	rw_enter(&rsm_resource.rsmrc_lock, RW_READER);
13360Sstevel@tonic-gate 
13370Sstevel@tonic-gate 	blk = rsm_resource.rsmrc_root[i];
13380Sstevel@tonic-gate 	if (blk != NULL) {
13390Sstevel@tonic-gate 		ASSERT(i < rsm_resource.rsmrc_len);
13400Sstevel@tonic-gate 		ASSERT(i < rsm_resource.rsmrc_sz);
13410Sstevel@tonic-gate 
13420Sstevel@tonic-gate 		p = blk->rsmrcblk_blks[j];
13430Sstevel@tonic-gate 		if (lock == RSM_LOCK) {
13440Sstevel@tonic-gate 			if (p != RSMRC_RESERVED) {
13450Sstevel@tonic-gate 				mutex_enter(&p->rsmrc_lock);
13460Sstevel@tonic-gate 			} else {
13470Sstevel@tonic-gate 				p = NULL;
13480Sstevel@tonic-gate 			}
13490Sstevel@tonic-gate 		}
13500Sstevel@tonic-gate 	} else {
13510Sstevel@tonic-gate 		p = NULL;
13520Sstevel@tonic-gate 	}
13530Sstevel@tonic-gate 	rw_exit(&rsm_resource.rsmrc_lock);
13540Sstevel@tonic-gate 
13550Sstevel@tonic-gate 	DBG_PRINTF((RSM_KERNEL_ALL, RSM_DEBUG_VERBOSE,
13560Sstevel@tonic-gate 	    "rsmresource_lookup done\n"));
13570Sstevel@tonic-gate 
13580Sstevel@tonic-gate 	return (p);
13590Sstevel@tonic-gate }
13600Sstevel@tonic-gate 
13610Sstevel@tonic-gate static void
rsmresource_insert(minor_t rnum,rsmresource_t * p,rsm_resource_type_t type)13620Sstevel@tonic-gate rsmresource_insert(minor_t rnum, rsmresource_t *p, rsm_resource_type_t type)
13630Sstevel@tonic-gate {
13640Sstevel@tonic-gate 	/* Find resource and lock it in READER mode */
13650Sstevel@tonic-gate 	/* Caller can upgrade if need be */
13660Sstevel@tonic-gate 	/* search for available resource slot */
13670Sstevel@tonic-gate 	int i, j;
13680Sstevel@tonic-gate 	rsmresource_blk_t *blk;
13690Sstevel@tonic-gate 
13700Sstevel@tonic-gate 	DBG_PRINTF((RSM_KERNEL_ALL, RSM_DEBUG_VERBOSE,
13710Sstevel@tonic-gate 	    "rsmresource_insert enter\n"));
13720Sstevel@tonic-gate 
13730Sstevel@tonic-gate 	i = (int)(rnum / RSMRC_BLKSZ);
13740Sstevel@tonic-gate 	j = (int)(rnum % RSMRC_BLKSZ);
13750Sstevel@tonic-gate 
13760Sstevel@tonic-gate 	p->rsmrc_type = type;
13770Sstevel@tonic-gate 	p->rsmrc_num = rnum;
13780Sstevel@tonic-gate 
13790Sstevel@tonic-gate 	rw_enter(&rsm_resource.rsmrc_lock, RW_READER);
13800Sstevel@tonic-gate 
13810Sstevel@tonic-gate 	ASSERT(rsm_resource.rsmrc_root);
13820Sstevel@tonic-gate 	ASSERT(i < rsm_resource.rsmrc_len);
13830Sstevel@tonic-gate 	ASSERT(i < rsm_resource.rsmrc_sz);
13840Sstevel@tonic-gate 
13850Sstevel@tonic-gate 	blk = rsm_resource.rsmrc_root[i];
13860Sstevel@tonic-gate 	ASSERT(blk);
13870Sstevel@tonic-gate 
13880Sstevel@tonic-gate 	ASSERT(blk->rsmrcblk_blks[j] == RSMRC_RESERVED);
13890Sstevel@tonic-gate 
13900Sstevel@tonic-gate 	blk->rsmrcblk_blks[j] = p;
13910Sstevel@tonic-gate 
13920Sstevel@tonic-gate 	DBG_PRINTF((RSM_KERNEL_ALL, RSM_DEBUG_VERBOSE,
13930Sstevel@tonic-gate 	    "rsmresource_insert done\n"));
13940Sstevel@tonic-gate 
13950Sstevel@tonic-gate 	rw_exit(&rsm_resource.rsmrc_lock);
13960Sstevel@tonic-gate }
13970Sstevel@tonic-gate 
13980Sstevel@tonic-gate static void
rsmresource_destroy()13990Sstevel@tonic-gate rsmresource_destroy()
14000Sstevel@tonic-gate {
14010Sstevel@tonic-gate 	int i, j;
14020Sstevel@tonic-gate 
14030Sstevel@tonic-gate 	DBG_PRINTF((RSM_KERNEL_ALL, RSM_DEBUG_VERBOSE,
14040Sstevel@tonic-gate 	    "rsmresource_destroy enter\n"));
14050Sstevel@tonic-gate 
14060Sstevel@tonic-gate 	rw_enter(&rsm_resource.rsmrc_lock, RW_WRITER);
14070Sstevel@tonic-gate 
14080Sstevel@tonic-gate 	for (i = 0; i < rsm_resource.rsmrc_len; i++) {
14090Sstevel@tonic-gate 		rsmresource_blk_t	*blk;
14100Sstevel@tonic-gate 
14110Sstevel@tonic-gate 		blk = rsm_resource.rsmrc_root[i];
14120Sstevel@tonic-gate 		if (blk == NULL) {
14130Sstevel@tonic-gate 			continue;
14140Sstevel@tonic-gate 		}
14150Sstevel@tonic-gate 		for (j = 0; j < RSMRC_BLKSZ; j++) {
14160Sstevel@tonic-gate 			if (blk->rsmrcblk_blks[j] != NULL) {
14170Sstevel@tonic-gate 				DBG_PRINTF((RSM_KERNEL_ALL, RSM_DEBUG_VERBOSE,
14180Sstevel@tonic-gate 				    "Not null slot %d, %lx\n", j,
14190Sstevel@tonic-gate 				    (size_t)blk->rsmrcblk_blks[j]));
14200Sstevel@tonic-gate 			}
14210Sstevel@tonic-gate 		}
14220Sstevel@tonic-gate 		kmem_free(blk, sizeof (*blk));
14230Sstevel@tonic-gate 		rsm_resource.rsmrc_root[i] = NULL;
14240Sstevel@tonic-gate 	}
14250Sstevel@tonic-gate 	if (rsm_resource.rsmrc_root) {
14260Sstevel@tonic-gate 		i = rsm_resource.rsmrc_sz * (int)sizeof (rsmresource_blk_t *);
14270Sstevel@tonic-gate 		kmem_free(rsm_resource.rsmrc_root, (uint_t)i);
14280Sstevel@tonic-gate 		rsm_resource.rsmrc_root = NULL;
14290Sstevel@tonic-gate 		rsm_resource.rsmrc_len = 0;
14300Sstevel@tonic-gate 		rsm_resource.rsmrc_sz = 0;
14310Sstevel@tonic-gate 	}
14320Sstevel@tonic-gate 
14330Sstevel@tonic-gate 	DBG_PRINTF((RSM_KERNEL_ALL, RSM_DEBUG_VERBOSE,
14340Sstevel@tonic-gate 	    "rsmresource_destroy done\n"));
14350Sstevel@tonic-gate 
14360Sstevel@tonic-gate 	rw_exit(&rsm_resource.rsmrc_lock);
14370Sstevel@tonic-gate }
14380Sstevel@tonic-gate 
14390Sstevel@tonic-gate 
14400Sstevel@tonic-gate /* ******************** Generic Key Hash Table Management ********* */
14410Sstevel@tonic-gate static rsmresource_t *
rsmhash_lookup(rsmhash_table_t * rhash,rsm_memseg_id_t key,rsm_resource_state_t state)14420Sstevel@tonic-gate rsmhash_lookup(rsmhash_table_t *rhash, rsm_memseg_id_t key,
14430Sstevel@tonic-gate     rsm_resource_state_t state)
14440Sstevel@tonic-gate {
14450Sstevel@tonic-gate 	rsmresource_t	*p;
14460Sstevel@tonic-gate 	uint_t		hashval;
14470Sstevel@tonic-gate 	DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_FUNC_ALL);
14480Sstevel@tonic-gate 
14490Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmhash_lookup enter\n"));
14500Sstevel@tonic-gate 
14510Sstevel@tonic-gate 	hashval = rsmhash(key);
14520Sstevel@tonic-gate 
14530Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_LVL2, "rsmhash_lookup %u=%d\n",
14540Sstevel@tonic-gate 	    key, hashval));
14550Sstevel@tonic-gate 
14560Sstevel@tonic-gate 	rw_enter(&rhash->rsmhash_rw, RW_READER);
14570Sstevel@tonic-gate 
14580Sstevel@tonic-gate 	p = (rsmresource_t *)rsmhash_getbkt(rhash, hashval);
14590Sstevel@tonic-gate 
14600Sstevel@tonic-gate 	for (; p; p = p->rsmrc_next) {
14610Sstevel@tonic-gate 		if (p->rsmrc_key == key) {
14620Sstevel@tonic-gate 			/* acquire resource lock */
14630Sstevel@tonic-gate 			RSMRC_LOCK(p);
14640Sstevel@tonic-gate 			break;
14650Sstevel@tonic-gate 		}
14660Sstevel@tonic-gate 	}
14670Sstevel@tonic-gate 
14680Sstevel@tonic-gate 	rw_exit(&rhash->rsmhash_rw);
14690Sstevel@tonic-gate 
14700Sstevel@tonic-gate 	if (p != NULL && p->rsmrc_state != state) {
14710Sstevel@tonic-gate 		/* state changed, release lock and return null */
14720Sstevel@tonic-gate 		RSMRC_UNLOCK(p);
14730Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
14740Sstevel@tonic-gate 		    "rsmhash_lookup done: state changed\n"));
14750Sstevel@tonic-gate 		return (NULL);
14760Sstevel@tonic-gate 	}
14770Sstevel@tonic-gate 
14780Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmhash_lookup done\n"));
14790Sstevel@tonic-gate 
14800Sstevel@tonic-gate 	return (p);
14810Sstevel@tonic-gate }
14820Sstevel@tonic-gate 
14830Sstevel@tonic-gate static void
rsmhash_rm(rsmhash_table_t * rhash,rsmresource_t * rcelm)14840Sstevel@tonic-gate rsmhash_rm(rsmhash_table_t *rhash, rsmresource_t *rcelm)
14850Sstevel@tonic-gate {
14860Sstevel@tonic-gate 	rsmresource_t		*p, **back;
14870Sstevel@tonic-gate 	uint_t			hashval;
14880Sstevel@tonic-gate 	DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_FUNC_ALL);
14890Sstevel@tonic-gate 
14900Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmhash_rm enter\n"));
14910Sstevel@tonic-gate 
14920Sstevel@tonic-gate 	hashval = rsmhash(rcelm->rsmrc_key);
14930Sstevel@tonic-gate 
14940Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_LVL2, "rsmhash_rm %u=%d\n",
14950Sstevel@tonic-gate 	    rcelm->rsmrc_key, hashval));
14960Sstevel@tonic-gate 
14970Sstevel@tonic-gate 	/*
14980Sstevel@tonic-gate 	 * It's ok not to find the segment.
14990Sstevel@tonic-gate 	 */
15000Sstevel@tonic-gate 	rw_enter(&rhash->rsmhash_rw, RW_WRITER);
15010Sstevel@tonic-gate 
15020Sstevel@tonic-gate 	back = (rsmresource_t **)rsmhash_bktaddr(rhash, hashval);
15030Sstevel@tonic-gate 
15040Sstevel@tonic-gate 	for (; (p = *back) != NULL;  back = &p->rsmrc_next) {
15050Sstevel@tonic-gate 		if (p == rcelm) {
15060Sstevel@tonic-gate 			*back = rcelm->rsmrc_next;
15070Sstevel@tonic-gate 			break;
15080Sstevel@tonic-gate 		}
15090Sstevel@tonic-gate 	}
15100Sstevel@tonic-gate 
15110Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmhash_rm done\n"));
15120Sstevel@tonic-gate 
15130Sstevel@tonic-gate 	rw_exit(&rhash->rsmhash_rw);
15140Sstevel@tonic-gate }
15150Sstevel@tonic-gate 
15160Sstevel@tonic-gate static int
rsmhash_add(rsmhash_table_t * rhash,rsmresource_t * new,rsm_memseg_id_t key,int dup_check,rsm_resource_state_t state)15170Sstevel@tonic-gate rsmhash_add(rsmhash_table_t *rhash, rsmresource_t *new, rsm_memseg_id_t key,
15180Sstevel@tonic-gate     int dup_check, rsm_resource_state_t state)
15190Sstevel@tonic-gate {
15200Sstevel@tonic-gate 	rsmresource_t	*p = NULL, **bktp;
15210Sstevel@tonic-gate 	uint_t		hashval;
15220Sstevel@tonic-gate 	DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_FUNC_ALL);
15230Sstevel@tonic-gate 
15240Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmhash_add enter\n"));
15250Sstevel@tonic-gate 
15260Sstevel@tonic-gate 	/* lock table */
15270Sstevel@tonic-gate 	rw_enter(&rhash->rsmhash_rw, RW_WRITER);
15280Sstevel@tonic-gate 
15290Sstevel@tonic-gate 	/*
15300Sstevel@tonic-gate 	 * If the current resource state is other than the state passed in
15310Sstevel@tonic-gate 	 * then the resource is (probably) already on the list. eg. for an
15320Sstevel@tonic-gate 	 * import segment if the state is not RSM_STATE_NEW then it's on the
15330Sstevel@tonic-gate 	 * list already.
15340Sstevel@tonic-gate 	 */
15350Sstevel@tonic-gate 	RSMRC_LOCK(new);
15360Sstevel@tonic-gate 	if (new->rsmrc_state != state) {
15370Sstevel@tonic-gate 		RSMRC_UNLOCK(new);
15380Sstevel@tonic-gate 		rw_exit(&rhash->rsmhash_rw);
15390Sstevel@tonic-gate 		return (RSMERR_BAD_SEG_HNDL);
15400Sstevel@tonic-gate 	}
15410Sstevel@tonic-gate 
15420Sstevel@tonic-gate 	hashval = rsmhash(key);
15430Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_LVL2, "rsmhash_add %d\n", hashval));
15440Sstevel@tonic-gate 
15450Sstevel@tonic-gate 	if (dup_check) {
15460Sstevel@tonic-gate 		/*
15470Sstevel@tonic-gate 		 * Used for checking export segments; don't want to have
15480Sstevel@tonic-gate 		 * the same key used for multiple segments.
15490Sstevel@tonic-gate 		 */
15500Sstevel@tonic-gate 
15510Sstevel@tonic-gate 		p = (rsmresource_t *)rsmhash_getbkt(rhash, hashval);
15520Sstevel@tonic-gate 
15530Sstevel@tonic-gate 		for (; p; p = p->rsmrc_next) {
15540Sstevel@tonic-gate 			if (p->rsmrc_key == key) {
15550Sstevel@tonic-gate 				RSMRC_UNLOCK(new);
15560Sstevel@tonic-gate 				break;
15570Sstevel@tonic-gate 			}
15580Sstevel@tonic-gate 		}
15590Sstevel@tonic-gate 	}
15600Sstevel@tonic-gate 
15610Sstevel@tonic-gate 	if (p == NULL) {
15620Sstevel@tonic-gate 		/* Key doesn't exist, add it */
15630Sstevel@tonic-gate 
15640Sstevel@tonic-gate 		bktp = (rsmresource_t **)rsmhash_bktaddr(rhash, hashval);
15650Sstevel@tonic-gate 
15660Sstevel@tonic-gate 		new->rsmrc_key = key;
15670Sstevel@tonic-gate 		new->rsmrc_next = *bktp;
15680Sstevel@tonic-gate 		*bktp = new;
15690Sstevel@tonic-gate 	}
15700Sstevel@tonic-gate 
15710Sstevel@tonic-gate 	rw_exit(&rhash->rsmhash_rw);
15720Sstevel@tonic-gate 
15730Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmhash_add done\n"));
15740Sstevel@tonic-gate 
15750Sstevel@tonic-gate 	return (p == NULL ? RSM_SUCCESS : RSMERR_SEGID_IN_USE);
15760Sstevel@tonic-gate }
15770Sstevel@tonic-gate 
15780Sstevel@tonic-gate /*
15790Sstevel@tonic-gate  * XOR each byte of the key.
15800Sstevel@tonic-gate  */
15810Sstevel@tonic-gate static uint_t
rsmhash(rsm_memseg_id_t key)15820Sstevel@tonic-gate rsmhash(rsm_memseg_id_t key)
15830Sstevel@tonic-gate {
15840Sstevel@tonic-gate 	uint_t	hash = key;
15850Sstevel@tonic-gate 
15860Sstevel@tonic-gate 	hash ^=  (key >> 8);
15870Sstevel@tonic-gate 	hash ^=  (key >> 16);
15880Sstevel@tonic-gate 	hash ^=  (key >> 24);
15890Sstevel@tonic-gate 
15900Sstevel@tonic-gate 	return (hash % rsm_hash_size);
15910Sstevel@tonic-gate 
15920Sstevel@tonic-gate }
15930Sstevel@tonic-gate 
15940Sstevel@tonic-gate /*
15950Sstevel@tonic-gate  * generic function to get a specific bucket
15960Sstevel@tonic-gate  */
15970Sstevel@tonic-gate static void *
rsmhash_getbkt(rsmhash_table_t * rhash,uint_t hashval)15980Sstevel@tonic-gate rsmhash_getbkt(rsmhash_table_t *rhash, uint_t hashval)
15990Sstevel@tonic-gate {
16000Sstevel@tonic-gate 
16010Sstevel@tonic-gate 	if (rhash->bucket == NULL)
16020Sstevel@tonic-gate 		return (NULL);
16030Sstevel@tonic-gate 	else
16040Sstevel@tonic-gate 		return ((void *)rhash->bucket[hashval]);
16050Sstevel@tonic-gate }
16060Sstevel@tonic-gate 
16070Sstevel@tonic-gate /*
16080Sstevel@tonic-gate  * generic function to get a specific bucket's address
16090Sstevel@tonic-gate  */
16100Sstevel@tonic-gate static void **
rsmhash_bktaddr(rsmhash_table_t * rhash,uint_t hashval)16110Sstevel@tonic-gate rsmhash_bktaddr(rsmhash_table_t *rhash, uint_t hashval)
16120Sstevel@tonic-gate {
16130Sstevel@tonic-gate 	if (rhash->bucket == NULL)
16140Sstevel@tonic-gate 		return (NULL);
16150Sstevel@tonic-gate 	else
16160Sstevel@tonic-gate 		return ((void **)&(rhash->bucket[hashval]));
16170Sstevel@tonic-gate }
16180Sstevel@tonic-gate 
16190Sstevel@tonic-gate /*
16200Sstevel@tonic-gate  * generic function to alloc a hash table
16210Sstevel@tonic-gate  */
16220Sstevel@tonic-gate static void
rsmhash_alloc(rsmhash_table_t * rhash,int size)16230Sstevel@tonic-gate rsmhash_alloc(rsmhash_table_t *rhash, int size)
16240Sstevel@tonic-gate {
16250Sstevel@tonic-gate 	rhash->bucket = (rsmresource_t **)
16260Sstevel@tonic-gate 	    kmem_zalloc(size * sizeof (rsmresource_t *), KM_SLEEP);
16270Sstevel@tonic-gate }
16280Sstevel@tonic-gate 
16290Sstevel@tonic-gate /*
16300Sstevel@tonic-gate  * generic function to free a hash table
16310Sstevel@tonic-gate  */
16320Sstevel@tonic-gate static void
rsmhash_free(rsmhash_table_t * rhash,int size)16330Sstevel@tonic-gate rsmhash_free(rsmhash_table_t *rhash, int size)
16340Sstevel@tonic-gate {
16350Sstevel@tonic-gate 
16360Sstevel@tonic-gate 	kmem_free((void *)rhash->bucket, size * sizeof (caddr_t));
16370Sstevel@tonic-gate 	rhash->bucket = NULL;
16380Sstevel@tonic-gate 
16390Sstevel@tonic-gate }
16400Sstevel@tonic-gate /* *********************** Exported Segment Key Management ************ */
16410Sstevel@tonic-gate 
16420Sstevel@tonic-gate #define	rsmexport_add(new, key)		\
16430Sstevel@tonic-gate 	rsmhash_add(&rsm_export_segs, (rsmresource_t *)new, key, 1, \
16440Sstevel@tonic-gate 	    RSM_STATE_BIND)
16450Sstevel@tonic-gate 
16460Sstevel@tonic-gate #define	rsmexport_rm(arg)	\
16470Sstevel@tonic-gate 	rsmhash_rm(&rsm_export_segs, (rsmresource_t *)(arg))
16480Sstevel@tonic-gate 
16490Sstevel@tonic-gate #define	rsmexport_lookup(key)	\
16500Sstevel@tonic-gate 	(rsmseg_t *)rsmhash_lookup(&rsm_export_segs, key, RSM_STATE_EXPORT)
16510Sstevel@tonic-gate 
16520Sstevel@tonic-gate /* ************************** Import Segment List Management ********** */
16530Sstevel@tonic-gate 
16540Sstevel@tonic-gate /*
16550Sstevel@tonic-gate  *  Add segment to import list. This will be useful for paging and loopback
16560Sstevel@tonic-gate  * segment unloading.
16570Sstevel@tonic-gate  */
16580Sstevel@tonic-gate #define	rsmimport_add(arg, key)	\
16590Sstevel@tonic-gate 	rsmhash_add(&rsm_import_segs, (rsmresource_t *)(arg), (key), 0, \
16600Sstevel@tonic-gate 	    RSM_STATE_NEW)
16610Sstevel@tonic-gate 
16620Sstevel@tonic-gate #define	rsmimport_rm(arg)	\
16630Sstevel@tonic-gate 	rsmhash_rm(&rsm_import_segs, (rsmresource_t *)(arg))
16640Sstevel@tonic-gate 
16650Sstevel@tonic-gate /*
16660Sstevel@tonic-gate  *	#define	rsmimport_lookup(key)	\
16670Sstevel@tonic-gate  *	(rsmseg_t *)rsmhash_lookup(&rsm_import_segs, (key), RSM_STATE_CONNECT)
16680Sstevel@tonic-gate  */
16690Sstevel@tonic-gate 
16700Sstevel@tonic-gate /*
16710Sstevel@tonic-gate  * increase the ref count and make the import segment point to the
16720Sstevel@tonic-gate  * shared data structure. Return a pointer to the share data struct
16730Sstevel@tonic-gate  * and the shared data struct is locked upon return
16740Sstevel@tonic-gate  */
16750Sstevel@tonic-gate static rsm_import_share_t *
rsmshare_get(rsm_memseg_id_t key,rsm_node_id_t node,adapter_t * adapter,rsmseg_t * segp)16760Sstevel@tonic-gate rsmshare_get(rsm_memseg_id_t key, rsm_node_id_t node, adapter_t *adapter,
16770Sstevel@tonic-gate     rsmseg_t *segp)
16780Sstevel@tonic-gate {
16790Sstevel@tonic-gate 	uint_t		hash;
16800Sstevel@tonic-gate 	rsmresource_t		*p;
16810Sstevel@tonic-gate 	rsm_import_share_t	*shdatap;
16820Sstevel@tonic-gate 	DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_FUNC_ALL);
16830Sstevel@tonic-gate 
16840Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmshare_get enter\n"));
16850Sstevel@tonic-gate 
16860Sstevel@tonic-gate 	hash = rsmhash(key);
16870Sstevel@tonic-gate 	/* lock table */
16880Sstevel@tonic-gate 	rw_enter(&rsm_import_segs.rsmhash_rw, RW_WRITER);
16890Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_LVL2, "rsmshare_get:key=%u, hash=%d\n",
16900Sstevel@tonic-gate 	    key, hash));
16910Sstevel@tonic-gate 
16920Sstevel@tonic-gate 	p = (rsmresource_t *)rsmhash_getbkt(&rsm_import_segs, hash);
16930Sstevel@tonic-gate 
16940Sstevel@tonic-gate 	for (; p; p = p->rsmrc_next) {
16950Sstevel@tonic-gate 		/*
16960Sstevel@tonic-gate 		 * Look for an entry that is importing the same exporter
16970Sstevel@tonic-gate 		 * with the share data structure allocated.
16980Sstevel@tonic-gate 		 */
16990Sstevel@tonic-gate 		if ((p->rsmrc_key == key) &&
17000Sstevel@tonic-gate 		    (p->rsmrc_node == node) &&
17010Sstevel@tonic-gate 		    (p->rsmrc_adapter == adapter) &&
17020Sstevel@tonic-gate 		    (((rsmseg_t *)p)->s_share != NULL)) {
17030Sstevel@tonic-gate 			shdatap = ((rsmseg_t *)p)->s_share;
17040Sstevel@tonic-gate 			break;
17050Sstevel@tonic-gate 		}
17060Sstevel@tonic-gate 	}
17070Sstevel@tonic-gate 
17080Sstevel@tonic-gate 	if (p == NULL) {
17090Sstevel@tonic-gate 		/* we are the first importer, create the shared data struct */
17100Sstevel@tonic-gate 		shdatap = kmem_zalloc(sizeof (rsm_import_share_t), KM_SLEEP);
17110Sstevel@tonic-gate 		shdatap->rsmsi_state = RSMSI_STATE_NEW;
17120Sstevel@tonic-gate 		shdatap->rsmsi_segid = key;
17130Sstevel@tonic-gate 		shdatap->rsmsi_node = node;
17140Sstevel@tonic-gate 		mutex_init(&shdatap->rsmsi_lock, NULL, MUTEX_DRIVER, NULL);
17150Sstevel@tonic-gate 		cv_init(&shdatap->rsmsi_cv, NULL, CV_DRIVER, 0);
17160Sstevel@tonic-gate 	}
17170Sstevel@tonic-gate 
17180Sstevel@tonic-gate 	rsmseglock_acquire(segp);
17190Sstevel@tonic-gate 
17200Sstevel@tonic-gate 	/* we grab the shared lock before returning from this function */
17210Sstevel@tonic-gate 	mutex_enter(&shdatap->rsmsi_lock);
17220Sstevel@tonic-gate 
17230Sstevel@tonic-gate 	shdatap->rsmsi_refcnt++;
17240Sstevel@tonic-gate 	segp->s_share = shdatap;
17250Sstevel@tonic-gate 
17260Sstevel@tonic-gate 	rsmseglock_release(segp);
17270Sstevel@tonic-gate 
17280Sstevel@tonic-gate 	rw_exit(&rsm_import_segs.rsmhash_rw);
17290Sstevel@tonic-gate 
17300Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmshare_get done\n"));
17310Sstevel@tonic-gate 
17320Sstevel@tonic-gate 	return (shdatap);
17330Sstevel@tonic-gate }
17340Sstevel@tonic-gate 
17350Sstevel@tonic-gate /*
17360Sstevel@tonic-gate  * the shared data structure should be locked before calling
17370Sstevel@tonic-gate  * rsmsharecv_signal().
17380Sstevel@tonic-gate  * Change the state and signal any waiting segments.
17390Sstevel@tonic-gate  */
17400Sstevel@tonic-gate void
rsmsharecv_signal(rsmseg_t * seg,int oldstate,int newstate)17410Sstevel@tonic-gate rsmsharecv_signal(rsmseg_t *seg, int oldstate, int newstate)
17420Sstevel@tonic-gate {
17430Sstevel@tonic-gate 	ASSERT(rsmsharelock_held(seg));
17440Sstevel@tonic-gate 
17450Sstevel@tonic-gate 	if (seg->s_share->rsmsi_state == oldstate) {
17460Sstevel@tonic-gate 		seg->s_share->rsmsi_state = newstate;
17470Sstevel@tonic-gate 		cv_broadcast(&seg->s_share->rsmsi_cv);
17480Sstevel@tonic-gate 	}
17490Sstevel@tonic-gate }
17500Sstevel@tonic-gate 
17510Sstevel@tonic-gate /*
17520Sstevel@tonic-gate  * Add to the hash table
17530Sstevel@tonic-gate  */
17540Sstevel@tonic-gate static void
importer_list_add(rsm_node_id_t node,rsm_memseg_id_t key,rsm_addr_t hwaddr,void * cookie)17550Sstevel@tonic-gate importer_list_add(rsm_node_id_t node, rsm_memseg_id_t key, rsm_addr_t hwaddr,
17560Sstevel@tonic-gate     void *cookie)
17570Sstevel@tonic-gate {
17580Sstevel@tonic-gate 
17590Sstevel@tonic-gate 	importing_token_t	*head;
17600Sstevel@tonic-gate 	importing_token_t	*new_token;
17610Sstevel@tonic-gate 	int			index;
17620Sstevel@tonic-gate 
17630Sstevel@tonic-gate 	DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_FUNC_ALL);
17640Sstevel@tonic-gate 
17650Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "importer_list_add enter\n"));
17660Sstevel@tonic-gate 
17670Sstevel@tonic-gate 	new_token = kmem_zalloc(sizeof (importing_token_t), KM_SLEEP);
17680Sstevel@tonic-gate 	new_token->importing_node = node;
17690Sstevel@tonic-gate 	new_token->key = key;
17700Sstevel@tonic-gate 	new_token->import_segment_cookie = cookie;
17710Sstevel@tonic-gate 	new_token->importing_adapter_hwaddr = hwaddr;
17720Sstevel@tonic-gate 
17730Sstevel@tonic-gate 	index = rsmhash(key);
17740Sstevel@tonic-gate 
17750Sstevel@tonic-gate 	mutex_enter(&importer_list.lock);
17760Sstevel@tonic-gate 
17770Sstevel@tonic-gate 	head = importer_list.bucket[index];
17780Sstevel@tonic-gate 	importer_list.bucket[index] = new_token;
17790Sstevel@tonic-gate 	new_token->next = head;
17800Sstevel@tonic-gate 	mutex_exit(&importer_list.lock);
17810Sstevel@tonic-gate 
17820Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "importer_list_add done\n"));
17830Sstevel@tonic-gate }
17840Sstevel@tonic-gate 
17850Sstevel@tonic-gate static void
importer_list_rm(rsm_node_id_t node,rsm_memseg_id_t key,void * cookie)17860Sstevel@tonic-gate importer_list_rm(rsm_node_id_t node,  rsm_memseg_id_t key, void *cookie)
17870Sstevel@tonic-gate {
17880Sstevel@tonic-gate 
17890Sstevel@tonic-gate 	importing_token_t	*prev, *token = NULL;
17900Sstevel@tonic-gate 	int			index;
17910Sstevel@tonic-gate 	DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_FUNC_ALL);
17920Sstevel@tonic-gate 
17930Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "importer_list_rm enter\n"));
17940Sstevel@tonic-gate 
17950Sstevel@tonic-gate 	index = rsmhash(key);
17960Sstevel@tonic-gate 
17970Sstevel@tonic-gate 	mutex_enter(&importer_list.lock);
17980Sstevel@tonic-gate 
17990Sstevel@tonic-gate 	token = importer_list.bucket[index];
18000Sstevel@tonic-gate 
18010Sstevel@tonic-gate 	prev = token;
18020Sstevel@tonic-gate 	while (token != NULL) {
18030Sstevel@tonic-gate 		if (token->importing_node == node &&
18040Sstevel@tonic-gate 		    token->import_segment_cookie == cookie) {
18050Sstevel@tonic-gate 			if (prev == token)
18060Sstevel@tonic-gate 				importer_list.bucket[index] = token->next;
18070Sstevel@tonic-gate 			else
18080Sstevel@tonic-gate 				prev->next = token->next;
18090Sstevel@tonic-gate 			kmem_free((void *)token, sizeof (*token));
18100Sstevel@tonic-gate 			break;
18110Sstevel@tonic-gate 		} else {
18120Sstevel@tonic-gate 			prev = token;
18130Sstevel@tonic-gate 			token = token->next;
18140Sstevel@tonic-gate 		}
18150Sstevel@tonic-gate 	}
18160Sstevel@tonic-gate 
18170Sstevel@tonic-gate 	mutex_exit(&importer_list.lock);
18180Sstevel@tonic-gate 
18190Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "importer_list_rm done\n"));
18200Sstevel@tonic-gate 
18210Sstevel@tonic-gate 
18220Sstevel@tonic-gate }
18230Sstevel@tonic-gate 
18240Sstevel@tonic-gate /* **************************Segment Structure Management ************* */
18250Sstevel@tonic-gate 
18260Sstevel@tonic-gate /*
18270Sstevel@tonic-gate  * Free segment structure
18280Sstevel@tonic-gate  */
18290Sstevel@tonic-gate static void
rsmseg_free(rsmseg_t * seg)18300Sstevel@tonic-gate rsmseg_free(rsmseg_t *seg)
18310Sstevel@tonic-gate {
18320Sstevel@tonic-gate 
18330Sstevel@tonic-gate 	DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_FUNC_ALL);
18340Sstevel@tonic-gate 
18350Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmseg_free enter\n"));
18360Sstevel@tonic-gate 
18370Sstevel@tonic-gate 	/* need to take seglock here to avoid race with rsmmap_unmap() */
18380Sstevel@tonic-gate 	rsmseglock_acquire(seg);
18390Sstevel@tonic-gate 	if (seg->s_ckl != NULL) {
18400Sstevel@tonic-gate 		/* Segment is still busy */
18410Sstevel@tonic-gate 		seg->s_state = RSM_STATE_END;
18420Sstevel@tonic-gate 		rsmseglock_release(seg);
18430Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
18440Sstevel@tonic-gate 		    "rsmseg_free done\n"));
18450Sstevel@tonic-gate 		return;
18460Sstevel@tonic-gate 	}
18470Sstevel@tonic-gate 
18480Sstevel@tonic-gate 	rsmseglock_release(seg);
18490Sstevel@tonic-gate 
18500Sstevel@tonic-gate 	ASSERT(seg->s_state == RSM_STATE_END || seg->s_state == RSM_STATE_NEW);
18510Sstevel@tonic-gate 
18520Sstevel@tonic-gate 	/*
18530Sstevel@tonic-gate 	 * If it's an importer decrement the refcount
18540Sstevel@tonic-gate 	 * and if its down to zero free the shared data structure.
18550Sstevel@tonic-gate 	 * This is where failures during rsm_connect() are unrefcounted
18560Sstevel@tonic-gate 	 */
18570Sstevel@tonic-gate 	if (seg->s_share != NULL) {
18580Sstevel@tonic-gate 
18590Sstevel@tonic-gate 		ASSERT(seg->s_type == RSM_RESOURCE_IMPORT_SEGMENT);
18600Sstevel@tonic-gate 
18610Sstevel@tonic-gate 		rsmsharelock_acquire(seg);
18620Sstevel@tonic-gate 
18630Sstevel@tonic-gate 		ASSERT(seg->s_share->rsmsi_refcnt > 0);
18640Sstevel@tonic-gate 
18650Sstevel@tonic-gate 		seg->s_share->rsmsi_refcnt--;
18660Sstevel@tonic-gate 
18670Sstevel@tonic-gate 		if (seg->s_share->rsmsi_refcnt == 0) {
18680Sstevel@tonic-gate 			rsmsharelock_release(seg);
18690Sstevel@tonic-gate 			mutex_destroy(&seg->s_share->rsmsi_lock);
18700Sstevel@tonic-gate 			cv_destroy(&seg->s_share->rsmsi_cv);
18710Sstevel@tonic-gate 			kmem_free((void *)(seg->s_share),
18720Sstevel@tonic-gate 			    sizeof (rsm_import_share_t));
18730Sstevel@tonic-gate 		} else {
18740Sstevel@tonic-gate 			rsmsharelock_release(seg);
18750Sstevel@tonic-gate 		}
18760Sstevel@tonic-gate 		/*
18770Sstevel@tonic-gate 		 * The following needs to be done after any
18780Sstevel@tonic-gate 		 * rsmsharelock calls which use seg->s_share.
18790Sstevel@tonic-gate 		 */
18800Sstevel@tonic-gate 		seg->s_share = NULL;
18810Sstevel@tonic-gate 	}
18820Sstevel@tonic-gate 
18830Sstevel@tonic-gate 	cv_destroy(&seg->s_cv);
18840Sstevel@tonic-gate 	mutex_destroy(&seg->s_lock);
18850Sstevel@tonic-gate 	rsmacl_free(seg->s_acl, seg->s_acl_len);
18860Sstevel@tonic-gate 	rsmpiacl_free(seg->s_acl_in, seg->s_acl_len);
18870Sstevel@tonic-gate 	if (seg->s_adapter)
18880Sstevel@tonic-gate 		rsmka_release_adapter(seg->s_adapter);
18890Sstevel@tonic-gate 
18900Sstevel@tonic-gate 	kmem_free((void *)seg, sizeof (*seg));
18910Sstevel@tonic-gate 
18920Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmseg_free done\n"));
18930Sstevel@tonic-gate 
18940Sstevel@tonic-gate }
18950Sstevel@tonic-gate 
18960Sstevel@tonic-gate 
18970Sstevel@tonic-gate static rsmseg_t *
rsmseg_alloc(minor_t num,struct cred * cred)18980Sstevel@tonic-gate rsmseg_alloc(minor_t num, struct cred *cred)
18990Sstevel@tonic-gate {
19000Sstevel@tonic-gate 	rsmseg_t	*new;
19010Sstevel@tonic-gate 	DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_FUNC_ALL);
19020Sstevel@tonic-gate 
19030Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmseg_alloc enter\n"));
19040Sstevel@tonic-gate 	/*
19050Sstevel@tonic-gate 	 * allocate memory for new segment. This should be a segkmem cache.
19060Sstevel@tonic-gate 	 */
19070Sstevel@tonic-gate 	new = (rsmseg_t *)kmem_zalloc(sizeof (*new), KM_SLEEP);
19080Sstevel@tonic-gate 
19090Sstevel@tonic-gate 	new->s_state = RSM_STATE_NEW;
19100Sstevel@tonic-gate 	new->s_minor	= num;
19110Sstevel@tonic-gate 	new->s_acl_len	= 0;
19120Sstevel@tonic-gate 	new->s_cookie = NULL;
19130Sstevel@tonic-gate 	new->s_adapter = NULL;
19140Sstevel@tonic-gate 
19150Sstevel@tonic-gate 	new->s_mode = 0777 & ~PTOU((ttoproc(curthread)))->u_cmask;
19160Sstevel@tonic-gate 	/* we don't have a key yet, will set at export/connect */
19170Sstevel@tonic-gate 	new->s_uid  = crgetuid(cred);
19180Sstevel@tonic-gate 	new->s_gid  = crgetgid(cred);
19190Sstevel@tonic-gate 
19200Sstevel@tonic-gate 	mutex_init(&new->s_lock, NULL, MUTEX_DRIVER, (void *)NULL);
19210Sstevel@tonic-gate 	cv_init(&new->s_cv, NULL, CV_DRIVER, 0);
19220Sstevel@tonic-gate 
19230Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmseg_alloc done\n"));
19240Sstevel@tonic-gate 
19250Sstevel@tonic-gate 	return (new);
19260Sstevel@tonic-gate }
19270Sstevel@tonic-gate 
19280Sstevel@tonic-gate /* ******************************** Driver Open/Close/Poll *************** */
19290Sstevel@tonic-gate 
19300Sstevel@tonic-gate /*ARGSUSED1*/
19310Sstevel@tonic-gate static int
rsm_open(dev_t * devp,int flag,int otyp,struct cred * cred)19320Sstevel@tonic-gate rsm_open(dev_t *devp, int flag, int otyp, struct cred *cred)
19330Sstevel@tonic-gate {
19340Sstevel@tonic-gate 	minor_t rnum;
19350Sstevel@tonic-gate 	DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_FUNC_ALL| RSM_DDI);
19360Sstevel@tonic-gate 
19370Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_open enter\n"));
19380Sstevel@tonic-gate 	/*
19390Sstevel@tonic-gate 	 * Char only
19400Sstevel@tonic-gate 	 */
19410Sstevel@tonic-gate 	if (otyp != OTYP_CHR) {
19420Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_ERR, "rsm_open: bad otyp\n"));
19430Sstevel@tonic-gate 		return (EINVAL);
19440Sstevel@tonic-gate 	}
19450Sstevel@tonic-gate 
19460Sstevel@tonic-gate 	/*
19470Sstevel@tonic-gate 	 * Only zero can be opened, clones are used for resources.
19480Sstevel@tonic-gate 	 */
19490Sstevel@tonic-gate 	if (getminor(*devp) != RSM_DRIVER_MINOR) {
19500Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_ERR,
19510Sstevel@tonic-gate 		    "rsm_open: bad minor %d\n", getminor(*devp)));
19520Sstevel@tonic-gate 		return (ENODEV);
19530Sstevel@tonic-gate 	}
19540Sstevel@tonic-gate 
19550Sstevel@tonic-gate 	if ((flag & FEXCL) != 0 && secpolicy_excl_open(cred) != 0) {
19560Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_ERR, "rsm_open: bad perm\n"));
19570Sstevel@tonic-gate 		return (EPERM);
19580Sstevel@tonic-gate 	}
19590Sstevel@tonic-gate 
19600Sstevel@tonic-gate 	if (!(flag & FWRITE)) {
19610Sstevel@tonic-gate 		/*
19620Sstevel@tonic-gate 		 * The library function _rsm_librsm_init calls open for
19630Sstevel@tonic-gate 		 * /dev/rsm with flag set to O_RDONLY.  We want a valid
19640Sstevel@tonic-gate 		 * file descriptor to be returned for minor device zero.
19650Sstevel@tonic-gate 		 */
19660Sstevel@tonic-gate 
19670Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
19680Sstevel@tonic-gate 		    "rsm_open RDONLY done\n"));
19690Sstevel@tonic-gate 		return (DDI_SUCCESS);
19700Sstevel@tonic-gate 	}
19710Sstevel@tonic-gate 
19720Sstevel@tonic-gate 	/*
19730Sstevel@tonic-gate 	 * - allocate new minor number and segment.
19740Sstevel@tonic-gate 	 * - add segment to list of all segments.
19750Sstevel@tonic-gate 	 * - set minordev data to segment
19760Sstevel@tonic-gate 	 * - update devp argument to new device
19770Sstevel@tonic-gate 	 * - update s_cred to cred; make sure you do crhold(cred);
19780Sstevel@tonic-gate 	 */
19790Sstevel@tonic-gate 
19800Sstevel@tonic-gate 	/* allocate a new resource number */
19810Sstevel@tonic-gate 	if (rsmresource_alloc(&rnum) == RSM_SUCCESS) {
19820Sstevel@tonic-gate 		/*
19830Sstevel@tonic-gate 		 * We will bind this minor to a specific resource in first
19840Sstevel@tonic-gate 		 * ioctl
19850Sstevel@tonic-gate 		 */
19860Sstevel@tonic-gate 		*devp = makedevice(getmajor(*devp), rnum);
19870Sstevel@tonic-gate 	} else {
19880Sstevel@tonic-gate 		return (EAGAIN);
19890Sstevel@tonic-gate 	}
19900Sstevel@tonic-gate 
19910Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_open done\n"));
19920Sstevel@tonic-gate 	return (DDI_SUCCESS);
19930Sstevel@tonic-gate }
19940Sstevel@tonic-gate 
19950Sstevel@tonic-gate static void
rsmseg_close(rsmseg_t * seg,int force_flag)19960Sstevel@tonic-gate rsmseg_close(rsmseg_t *seg, int force_flag)
19970Sstevel@tonic-gate {
19980Sstevel@tonic-gate 	int e = RSM_SUCCESS;
19990Sstevel@tonic-gate 
20000Sstevel@tonic-gate 	DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_FUNC_ALL| RSM_DDI);
20010Sstevel@tonic-gate 
20020Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmseg_close enter\n"));
20030Sstevel@tonic-gate 
20040Sstevel@tonic-gate 	rsmseglock_acquire(seg);
20050Sstevel@tonic-gate 	if (!force_flag && (seg->s_hdr.rsmrc_type ==
20060Sstevel@tonic-gate 	    RSM_RESOURCE_EXPORT_SEGMENT)) {
20070Sstevel@tonic-gate 		/*
20080Sstevel@tonic-gate 		 * If we are processing rsm_close wait for force_destroy
20090Sstevel@tonic-gate 		 * processing to complete since force_destroy processing
20100Sstevel@tonic-gate 		 * needs to finish first before we can free the segment.
20110Sstevel@tonic-gate 		 * force_destroy is only for export segments
20120Sstevel@tonic-gate 		 */
20130Sstevel@tonic-gate 		while (seg->s_flags & RSM_FORCE_DESTROY_WAIT) {
20140Sstevel@tonic-gate 			cv_wait(&seg->s_cv, &seg->s_lock);
20150Sstevel@tonic-gate 		}
20160Sstevel@tonic-gate 	}
20170Sstevel@tonic-gate 	rsmseglock_release(seg);
20180Sstevel@tonic-gate 
20190Sstevel@tonic-gate 	/* It's ok to read the state without a lock */
20200Sstevel@tonic-gate 	switch (seg->s_state) {
20210Sstevel@tonic-gate 	case RSM_STATE_EXPORT:
20220Sstevel@tonic-gate 	case RSM_STATE_EXPORT_QUIESCING:
20230Sstevel@tonic-gate 	case RSM_STATE_EXPORT_QUIESCED:
20240Sstevel@tonic-gate 		e = rsm_unpublish(seg, 1);
20250Sstevel@tonic-gate 		/* FALLTHRU */
20260Sstevel@tonic-gate 	case RSM_STATE_BIND_QUIESCED:
20270Sstevel@tonic-gate 		/* FALLTHRU */
20280Sstevel@tonic-gate 	case RSM_STATE_BIND:
20290Sstevel@tonic-gate 		e = rsm_unbind(seg);
20300Sstevel@tonic-gate 		if (e != RSM_SUCCESS && force_flag == 1)
20310Sstevel@tonic-gate 			return;
20320Sstevel@tonic-gate 		ASSERT(seg->s_hdr.rsmrc_type == RSM_RESOURCE_EXPORT_SEGMENT);
20330Sstevel@tonic-gate 		/* FALLTHRU */
20340Sstevel@tonic-gate 	case RSM_STATE_NEW_QUIESCED:
20350Sstevel@tonic-gate 		rsmseglock_acquire(seg);
20360Sstevel@tonic-gate 		seg->s_state = RSM_STATE_NEW;
20370Sstevel@tonic-gate 		cv_broadcast(&seg->s_cv);
20380Sstevel@tonic-gate 		rsmseglock_release(seg);
20390Sstevel@tonic-gate 		break;
20400Sstevel@tonic-gate 	case RSM_STATE_NEW:
20410Sstevel@tonic-gate 		break;
20420Sstevel@tonic-gate 	case RSM_STATE_ZOMBIE:
20430Sstevel@tonic-gate 		/*
20440Sstevel@tonic-gate 		 * Segments in this state have been removed off the
20450Sstevel@tonic-gate 		 * exported segments list and have been unpublished
20460Sstevel@tonic-gate 		 * and unbind. These segments have been removed during
20470Sstevel@tonic-gate 		 * a callback to the rsm_export_force_destroy, which
20480Sstevel@tonic-gate 		 * is called for the purpose of unlocking these
20490Sstevel@tonic-gate 		 * exported memory segments when a process exits but
20500Sstevel@tonic-gate 		 * leaves the segments locked down since rsm_close is
20510Sstevel@tonic-gate 		 * is not called for the segments. This can happen
20520Sstevel@tonic-gate 		 * when a process calls fork or exec and then exits.
20530Sstevel@tonic-gate 		 * Once the segments are in the ZOMBIE state, all that
20540Sstevel@tonic-gate 		 * remains is to destroy them when rsm_close is called.
20550Sstevel@tonic-gate 		 * This is done here. Thus, for such segments the
20560Sstevel@tonic-gate 		 * the state is changed to new so that later in this
20570Sstevel@tonic-gate 		 * function rsmseg_free is called.
20580Sstevel@tonic-gate 		 */
20590Sstevel@tonic-gate 		rsmseglock_acquire(seg);
20600Sstevel@tonic-gate 		seg->s_state = RSM_STATE_NEW;
20610Sstevel@tonic-gate 		rsmseglock_release(seg);
20620Sstevel@tonic-gate 		break;
20630Sstevel@tonic-gate 	case RSM_STATE_MAP_QUIESCE:
20640Sstevel@tonic-gate 	case RSM_STATE_ACTIVE:
20650Sstevel@tonic-gate 		/* Disconnect will handle the unmap */
20660Sstevel@tonic-gate 	case RSM_STATE_CONN_QUIESCE:
20670Sstevel@tonic-gate 	case RSM_STATE_CONNECT:
20680Sstevel@tonic-gate 	case RSM_STATE_DISCONNECT:
20690Sstevel@tonic-gate 		ASSERT(seg->s_hdr.rsmrc_type == RSM_RESOURCE_IMPORT_SEGMENT);
20700Sstevel@tonic-gate 		(void) rsm_disconnect(seg);
20710Sstevel@tonic-gate 		break;
20720Sstevel@tonic-gate 	case RSM_STATE_MAPPING:
20730Sstevel@tonic-gate 		/*FALLTHRU*/
20740Sstevel@tonic-gate 	case RSM_STATE_END:
20750Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_ERR,
20760Sstevel@tonic-gate 		    "Invalid segment state %d in rsm_close\n", seg->s_state));
20770Sstevel@tonic-gate 		break;
20780Sstevel@tonic-gate 	default:
20790Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_ERR,
20800Sstevel@tonic-gate 		    "Invalid segment state %d in rsm_close\n", seg->s_state));
20810Sstevel@tonic-gate 		break;
20820Sstevel@tonic-gate 	}
20830Sstevel@tonic-gate 
20840Sstevel@tonic-gate 	/*
20850Sstevel@tonic-gate 	 * check state.
20860Sstevel@tonic-gate 	 * - make sure you do crfree(s_cred);
20870Sstevel@tonic-gate 	 * release segment and minor number
20880Sstevel@tonic-gate 	 */
20890Sstevel@tonic-gate 	ASSERT(seg->s_state == RSM_STATE_NEW);
20900Sstevel@tonic-gate 
20910Sstevel@tonic-gate 	/*
20920Sstevel@tonic-gate 	 * The export_force_destroy callback is created to unlock
20930Sstevel@tonic-gate 	 * the exported segments of a process
20940Sstevel@tonic-gate 	 * when the process does a fork or exec and then exits calls this
20950Sstevel@tonic-gate 	 * function with the force flag set to 1 which indicates that the
20960Sstevel@tonic-gate 	 * segment state must be converted to ZOMBIE. This state means that the
20970Sstevel@tonic-gate 	 * segments still exist and have been unlocked and most importantly the
20980Sstevel@tonic-gate 	 * only operation allowed is to destroy them on an rsm_close.
20990Sstevel@tonic-gate 	 */
21000Sstevel@tonic-gate 	if (force_flag) {
21010Sstevel@tonic-gate 		rsmseglock_acquire(seg);
21020Sstevel@tonic-gate 		seg->s_state = RSM_STATE_ZOMBIE;
21030Sstevel@tonic-gate 		rsmseglock_release(seg);
21040Sstevel@tonic-gate 	} else {
21050Sstevel@tonic-gate 		rsmseg_free(seg);
21060Sstevel@tonic-gate 	}
21070Sstevel@tonic-gate 
21080Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmseg_close done\n"));
21090Sstevel@tonic-gate }
21100Sstevel@tonic-gate 
21110Sstevel@tonic-gate static int
rsm_close(dev_t dev,int flag,int otyp,cred_t * cred)21120Sstevel@tonic-gate rsm_close(dev_t dev, int flag, int otyp, cred_t *cred)
21130Sstevel@tonic-gate {
21140Sstevel@tonic-gate 	minor_t	rnum = getminor(dev);
21150Sstevel@tonic-gate 	rsmresource_t *res;
21160Sstevel@tonic-gate 	DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_FUNC_ALL| RSM_DDI);
21170Sstevel@tonic-gate 
21180Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_close enter\n"));
21190Sstevel@tonic-gate 
21200Sstevel@tonic-gate 	flag = flag; cred = cred;
21210Sstevel@tonic-gate 
21220Sstevel@tonic-gate 	if (otyp != OTYP_CHR)
21230Sstevel@tonic-gate 		return (EINVAL);
21240Sstevel@tonic-gate 
21250Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rnum = %d\n", rnum));
21260Sstevel@tonic-gate 
21270Sstevel@tonic-gate 	/*
21280Sstevel@tonic-gate 	 * At this point we are the last reference to the resource.
21290Sstevel@tonic-gate 	 * Free resource number from resource table.
21300Sstevel@tonic-gate 	 * It's ok to remove number before we free the segment.
21310Sstevel@tonic-gate 	 * We need to lock the resource to protect against remote calls.
21320Sstevel@tonic-gate 	 */
21330Sstevel@tonic-gate 	if (rnum == RSM_DRIVER_MINOR ||
21340Sstevel@tonic-gate 	    (res = rsmresource_free(rnum)) == NULL) {
21350Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_close done\n"));
21360Sstevel@tonic-gate 		return (DDI_SUCCESS);
21370Sstevel@tonic-gate 	}
21380Sstevel@tonic-gate 
21390Sstevel@tonic-gate 	switch (res->rsmrc_type) {
21400Sstevel@tonic-gate 	case RSM_RESOURCE_EXPORT_SEGMENT:
21410Sstevel@tonic-gate 	case RSM_RESOURCE_IMPORT_SEGMENT:
21420Sstevel@tonic-gate 		rsmseg_close((rsmseg_t *)res, 0);
21430Sstevel@tonic-gate 		break;
21440Sstevel@tonic-gate 	case RSM_RESOURCE_BAR:
21450Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_ERR, "bad resource in rsm_close\n"));
21460Sstevel@tonic-gate 		break;
21470Sstevel@tonic-gate 	default:
21480Sstevel@tonic-gate 		break;
21490Sstevel@tonic-gate 	}
21500Sstevel@tonic-gate 
21510Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_close done\n"));
21520Sstevel@tonic-gate 
21530Sstevel@tonic-gate 	return (DDI_SUCCESS);
21540Sstevel@tonic-gate }
21550Sstevel@tonic-gate 
21560Sstevel@tonic-gate /*
21570Sstevel@tonic-gate  * rsm_inc_pgcnt
21580Sstevel@tonic-gate  *
21590Sstevel@tonic-gate  * Description: increment rsm page counter.
21600Sstevel@tonic-gate  *
21610Sstevel@tonic-gate  * Parameters:	pgcnt_t	pnum;	number of pages to be used
21620Sstevel@tonic-gate  *
21630Sstevel@tonic-gate  * Returns:	RSM_SUCCESS	if memory limit not exceeded
21640Sstevel@tonic-gate  *		ENOSPC		if memory limit exceeded. In this case, the
21650Sstevel@tonic-gate  *				page counter remains unchanged.
21660Sstevel@tonic-gate  *
21670Sstevel@tonic-gate  */
21680Sstevel@tonic-gate static int
rsm_inc_pgcnt(pgcnt_t pnum)21690Sstevel@tonic-gate rsm_inc_pgcnt(pgcnt_t pnum)
21700Sstevel@tonic-gate {
21710Sstevel@tonic-gate 	DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_EXPORT);
21720Sstevel@tonic-gate 	if (rsm_pgcnt_max == 0) { /* no upper limit has been set */
21730Sstevel@tonic-gate 		return (RSM_SUCCESS);
21740Sstevel@tonic-gate 	}
21750Sstevel@tonic-gate 
21760Sstevel@tonic-gate 	mutex_enter(&rsm_pgcnt_lock);
21770Sstevel@tonic-gate 
21780Sstevel@tonic-gate 	if (rsm_pgcnt + pnum > rsm_pgcnt_max) {
21790Sstevel@tonic-gate 		/* ensure that limits have not been exceeded */
21800Sstevel@tonic-gate 		mutex_exit(&rsm_pgcnt_lock);
21810Sstevel@tonic-gate 		return (RSMERR_INSUFFICIENT_MEM);
21820Sstevel@tonic-gate 	}
21830Sstevel@tonic-gate 
21840Sstevel@tonic-gate 	rsm_pgcnt += pnum;
21850Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG, "rsm_pgcnt incr to %d.\n",
21860Sstevel@tonic-gate 	    rsm_pgcnt));
21870Sstevel@tonic-gate 	mutex_exit(&rsm_pgcnt_lock);
21880Sstevel@tonic-gate 
21890Sstevel@tonic-gate 	return (RSM_SUCCESS);
21900Sstevel@tonic-gate }
21910Sstevel@tonic-gate 
21920Sstevel@tonic-gate /*
21930Sstevel@tonic-gate  * rsm_dec_pgcnt
21940Sstevel@tonic-gate  *
21950Sstevel@tonic-gate  * Description:	decrement rsm page counter.
21960Sstevel@tonic-gate  *
21970Sstevel@tonic-gate  * Parameters:	pgcnt_t	pnum;	number of pages freed
21980Sstevel@tonic-gate  *
21990Sstevel@tonic-gate  */
22000Sstevel@tonic-gate static void
rsm_dec_pgcnt(pgcnt_t pnum)22010Sstevel@tonic-gate rsm_dec_pgcnt(pgcnt_t pnum)
22020Sstevel@tonic-gate {
22030Sstevel@tonic-gate 	DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_EXPORT);
22040Sstevel@tonic-gate 
22050Sstevel@tonic-gate 	if (rsm_pgcnt_max == 0) { /* no upper limit has been set */
22060Sstevel@tonic-gate 		return;
22070Sstevel@tonic-gate 	}
22080Sstevel@tonic-gate 
22090Sstevel@tonic-gate 	mutex_enter(&rsm_pgcnt_lock);
22100Sstevel@tonic-gate 	ASSERT(rsm_pgcnt >= pnum);
22110Sstevel@tonic-gate 	rsm_pgcnt -= pnum;
22120Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG, "rsm_pgcnt decr to %d.\n",
22130Sstevel@tonic-gate 	    rsm_pgcnt));
22140Sstevel@tonic-gate 	mutex_exit(&rsm_pgcnt_lock);
22150Sstevel@tonic-gate }
22160Sstevel@tonic-gate 
22170Sstevel@tonic-gate static struct umem_callback_ops rsm_as_ops = {
22180Sstevel@tonic-gate 	UMEM_CALLBACK_VERSION, /* version number */
22190Sstevel@tonic-gate 	rsm_export_force_destroy,
22200Sstevel@tonic-gate };
22210Sstevel@tonic-gate 
22220Sstevel@tonic-gate static int
rsm_bind_pages(ddi_umem_cookie_t * cookie,caddr_t vaddr,size_t len,proc_t * procp)22230Sstevel@tonic-gate rsm_bind_pages(ddi_umem_cookie_t *cookie, caddr_t vaddr, size_t len,
22240Sstevel@tonic-gate     proc_t *procp)
22250Sstevel@tonic-gate {
22260Sstevel@tonic-gate 	int error = RSM_SUCCESS;
22270Sstevel@tonic-gate 	ulong_t pnum;
22280Sstevel@tonic-gate 	struct umem_callback_ops *callbackops = &rsm_as_ops;
22290Sstevel@tonic-gate 
22300Sstevel@tonic-gate 	DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_EXPORT);
22310Sstevel@tonic-gate 
22320Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_bind_pages enter\n"));
22330Sstevel@tonic-gate 
22340Sstevel@tonic-gate 	/*
22350Sstevel@tonic-gate 	 * Make sure vaddr and len are aligned on a page boundary
22360Sstevel@tonic-gate 	 */
22370Sstevel@tonic-gate 	if ((uintptr_t)vaddr & (PAGESIZE - 1)) {
22380Sstevel@tonic-gate 		return (RSMERR_BAD_ADDR);
22390Sstevel@tonic-gate 	}
22400Sstevel@tonic-gate 
22410Sstevel@tonic-gate 	if (len & (PAGESIZE - 1)) {
22420Sstevel@tonic-gate 		return (RSMERR_BAD_LENGTH);
22430Sstevel@tonic-gate 	}
22440Sstevel@tonic-gate 
22450Sstevel@tonic-gate 	/*
22460Sstevel@tonic-gate 	 * Find number of pages
22470Sstevel@tonic-gate 	 */
22480Sstevel@tonic-gate 	pnum = btopr(len);
22490Sstevel@tonic-gate 	error = rsm_inc_pgcnt(pnum);
22500Sstevel@tonic-gate 	if (error != RSM_SUCCESS) {
22510Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_ERR,
22520Sstevel@tonic-gate 		    "rsm_bind_pages:mem limit exceeded\n"));
22530Sstevel@tonic-gate 		return (RSMERR_INSUFFICIENT_MEM);
22540Sstevel@tonic-gate 	}
22550Sstevel@tonic-gate 
22560Sstevel@tonic-gate 	error = umem_lockmemory(vaddr, len,
22570Sstevel@tonic-gate 	    DDI_UMEMLOCK_WRITE|DDI_UMEMLOCK_READ|DDI_UMEMLOCK_LONGTERM,
22580Sstevel@tonic-gate 	    cookie,
22590Sstevel@tonic-gate 	    callbackops, procp);
22600Sstevel@tonic-gate 
22610Sstevel@tonic-gate 	if (error) {
22620Sstevel@tonic-gate 		rsm_dec_pgcnt(pnum);
22630Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_ERR,
22640Sstevel@tonic-gate 		    "rsm_bind_pages:ddi_umem_lock failed\n"));
22650Sstevel@tonic-gate 		/*
22660Sstevel@tonic-gate 		 * ddi_umem_lock, in the case of failure, returns one of
22670Sstevel@tonic-gate 		 * the following three errors. These are translated into
22680Sstevel@tonic-gate 		 * the RSMERR namespace and returned.
22690Sstevel@tonic-gate 		 */
22700Sstevel@tonic-gate 		if (error == EFAULT)
22710Sstevel@tonic-gate 			return (RSMERR_BAD_ADDR);
22720Sstevel@tonic-gate 		else if (error == EACCES)
22730Sstevel@tonic-gate 			return (RSMERR_PERM_DENIED);
22740Sstevel@tonic-gate 		else
22750Sstevel@tonic-gate 			return (RSMERR_INSUFFICIENT_MEM);
22760Sstevel@tonic-gate 	}
22770Sstevel@tonic-gate 
22780Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_bind_pages done\n"));
22790Sstevel@tonic-gate 
22800Sstevel@tonic-gate 	return (error);
22810Sstevel@tonic-gate 
22820Sstevel@tonic-gate }
22830Sstevel@tonic-gate 
22840Sstevel@tonic-gate static int
rsm_unbind_pages(rsmseg_t * seg)22850Sstevel@tonic-gate rsm_unbind_pages(rsmseg_t *seg)
22860Sstevel@tonic-gate {
22870Sstevel@tonic-gate 	DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_EXPORT);
22880Sstevel@tonic-gate 
22890Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_unbind_pages enter\n"));
22900Sstevel@tonic-gate 
22910Sstevel@tonic-gate 	ASSERT(rsmseglock_held(seg));
22920Sstevel@tonic-gate 
22930Sstevel@tonic-gate 	if (seg->s_cookie != NULL) {
22940Sstevel@tonic-gate 		/* unlock address range */
22950Sstevel@tonic-gate 		ddi_umem_unlock(seg->s_cookie);
22960Sstevel@tonic-gate 		rsm_dec_pgcnt(btopr(seg->s_len));
22970Sstevel@tonic-gate 		seg->s_cookie = NULL;
22980Sstevel@tonic-gate 	}
22990Sstevel@tonic-gate 
23000Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_unbind_pages done\n"));
23010Sstevel@tonic-gate 
23020Sstevel@tonic-gate 	return (RSM_SUCCESS);
23030Sstevel@tonic-gate }
23040Sstevel@tonic-gate 
23050Sstevel@tonic-gate 
23060Sstevel@tonic-gate static int
rsm_bind(rsmseg_t * seg,rsm_ioctlmsg_t * msg,intptr_t dataptr,int mode)23070Sstevel@tonic-gate rsm_bind(rsmseg_t *seg, rsm_ioctlmsg_t *msg, intptr_t dataptr, int mode)
23080Sstevel@tonic-gate {
23090Sstevel@tonic-gate 	int e;
23100Sstevel@tonic-gate 	adapter_t *adapter;
23110Sstevel@tonic-gate 	DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_EXPORT);
23120Sstevel@tonic-gate 
23130Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_bind enter\n"));
23140Sstevel@tonic-gate 
23150Sstevel@tonic-gate 	adapter = rsm_getadapter(msg, mode);
23160Sstevel@tonic-gate 	if (adapter == NULL) {
23170Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
23180Sstevel@tonic-gate 		    "rsm_bind done:no adapter\n"));
23190Sstevel@tonic-gate 		return (RSMERR_CTLR_NOT_PRESENT);
23200Sstevel@tonic-gate 	}
23210Sstevel@tonic-gate 
23220Sstevel@tonic-gate 	/* lock address range */
23230Sstevel@tonic-gate 	if (msg->vaddr == NULL) {
23240Sstevel@tonic-gate 		rsmka_release_adapter(adapter);
23250Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_ERR,
23260Sstevel@tonic-gate 		    "rsm: rsm_bind done: invalid vaddr\n"));
23270Sstevel@tonic-gate 		return (RSMERR_BAD_ADDR);
23280Sstevel@tonic-gate 	}
23290Sstevel@tonic-gate 	if (msg->len <= 0) {
23300Sstevel@tonic-gate 		rsmka_release_adapter(adapter);
23310Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_ERR,
23320Sstevel@tonic-gate 		    "rsm_bind: invalid length\n"));
23330Sstevel@tonic-gate 		return (RSMERR_BAD_LENGTH);
23340Sstevel@tonic-gate 	}
23350Sstevel@tonic-gate 
23360Sstevel@tonic-gate 	/* Lock segment */
23370Sstevel@tonic-gate 	rsmseglock_acquire(seg);
23380Sstevel@tonic-gate 
23390Sstevel@tonic-gate 	while (seg->s_state == RSM_STATE_NEW_QUIESCED) {
23400Sstevel@tonic-gate 		if (cv_wait_sig(&seg->s_cv, &seg->s_lock) == 0) {
23410Sstevel@tonic-gate 			DBG_PRINTF((category, RSM_DEBUG,
23420Sstevel@tonic-gate 			    "rsm_bind done: cv_wait INTERRUPTED"));
23430Sstevel@tonic-gate 			rsmka_release_adapter(adapter);
23440Sstevel@tonic-gate 			rsmseglock_release(seg);
23450Sstevel@tonic-gate 			return (RSMERR_INTERRUPTED);
23460Sstevel@tonic-gate 		}
23470Sstevel@tonic-gate 	}
23480Sstevel@tonic-gate 
23490Sstevel@tonic-gate 	ASSERT(seg->s_state == RSM_STATE_NEW);
23500Sstevel@tonic-gate 
23510Sstevel@tonic-gate 	ASSERT(seg->s_cookie == NULL);
23520Sstevel@tonic-gate 
23530Sstevel@tonic-gate 	e = rsm_bind_pages(&seg->s_cookie, msg->vaddr, msg->len, curproc);
23540Sstevel@tonic-gate 	if (e == RSM_SUCCESS) {
23550Sstevel@tonic-gate 		seg->s_flags |= RSM_USER_MEMORY;
23560Sstevel@tonic-gate 		if (msg->perm & RSM_ALLOW_REBIND) {
23570Sstevel@tonic-gate 			seg->s_flags |= RSMKA_ALLOW_UNBIND_REBIND;
23580Sstevel@tonic-gate 		}
23590Sstevel@tonic-gate 		if (msg->perm & RSM_CREATE_SEG_DONTWAIT) {
23600Sstevel@tonic-gate 			seg->s_flags |= RSMKA_SET_RESOURCE_DONTWAIT;
23610Sstevel@tonic-gate 		}
23620Sstevel@tonic-gate 		seg->s_region.r_vaddr = msg->vaddr;
23630Sstevel@tonic-gate 		/*
23640Sstevel@tonic-gate 		 * Set the s_pid value in the segment structure. This is used
23650Sstevel@tonic-gate 		 * to identify exported segments belonging to a particular
23660Sstevel@tonic-gate 		 * process so that when the process exits, these segments can
23670Sstevel@tonic-gate 		 * be unlocked forcefully even if rsm_close is not called on
23680Sstevel@tonic-gate 		 * process exit since there maybe other processes referencing
23690Sstevel@tonic-gate 		 * them (for example on a fork or exec).
23700Sstevel@tonic-gate 		 * The s_pid value is also used to authenticate the process
23710Sstevel@tonic-gate 		 * doing a publish or unpublish on the export segment. Only
23720Sstevel@tonic-gate 		 * the creator of the export segment has a right to do a
23730Sstevel@tonic-gate 		 * publish or unpublish and unbind on the segment.
23740Sstevel@tonic-gate 		 */
23750Sstevel@tonic-gate 		seg->s_pid = ddi_get_pid();
23760Sstevel@tonic-gate 		seg->s_len = msg->len;
23770Sstevel@tonic-gate 		seg->s_state = RSM_STATE_BIND;
23780Sstevel@tonic-gate 		seg->s_adapter = adapter;
23790Sstevel@tonic-gate 		seg->s_proc = curproc;
23800Sstevel@tonic-gate 	} else {
23810Sstevel@tonic-gate 		rsmka_release_adapter(adapter);
23820Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_WARNING,
23830Sstevel@tonic-gate 		    "unable to lock down pages\n"));
23840Sstevel@tonic-gate 	}
23850Sstevel@tonic-gate 
23860Sstevel@tonic-gate 	msg->rnum = seg->s_minor;
23870Sstevel@tonic-gate 	/* Unlock segment */
23880Sstevel@tonic-gate 	rsmseglock_release(seg);
23890Sstevel@tonic-gate 
23900Sstevel@tonic-gate 	if (e == RSM_SUCCESS) {
23910Sstevel@tonic-gate 		/* copyout the resource number */
23920Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL
23930Sstevel@tonic-gate 		if ((mode & DATAMODEL_MASK) == DATAMODEL_ILP32) {
23940Sstevel@tonic-gate 			rsm_ioctlmsg32_t msg32;
23950Sstevel@tonic-gate 
23960Sstevel@tonic-gate 			msg32.rnum = msg->rnum;
23970Sstevel@tonic-gate 			if (ddi_copyout((caddr_t)&msg32.rnum,
23980Sstevel@tonic-gate 			    (caddr_t)&((rsm_ioctlmsg32_t *)dataptr)->rnum,
23990Sstevel@tonic-gate 			    sizeof (minor_t), mode)) {
24000Sstevel@tonic-gate 				rsmka_release_adapter(adapter);
24010Sstevel@tonic-gate 				e = RSMERR_BAD_ADDR;
24020Sstevel@tonic-gate 			}
24030Sstevel@tonic-gate 		}
24040Sstevel@tonic-gate #endif
24050Sstevel@tonic-gate 		if (ddi_copyout((caddr_t)&msg->rnum,
24060Sstevel@tonic-gate 		    (caddr_t)&((rsm_ioctlmsg_t *)dataptr)->rnum,
24070Sstevel@tonic-gate 		    sizeof (minor_t), mode)) {
24080Sstevel@tonic-gate 			rsmka_release_adapter(adapter);
24090Sstevel@tonic-gate 			e = RSMERR_BAD_ADDR;
24100Sstevel@tonic-gate 		}
24110Sstevel@tonic-gate 	}
24120Sstevel@tonic-gate 
24130Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_bind done\n"));
24140Sstevel@tonic-gate 
24150Sstevel@tonic-gate 	return (e);
24160Sstevel@tonic-gate }
24170Sstevel@tonic-gate 
24180Sstevel@tonic-gate static void
rsm_remap_local_importers(rsm_node_id_t src_nodeid,rsm_memseg_id_t ex_segid,ddi_umem_cookie_t cookie)24190Sstevel@tonic-gate rsm_remap_local_importers(rsm_node_id_t src_nodeid,
24200Sstevel@tonic-gate     rsm_memseg_id_t ex_segid,
24210Sstevel@tonic-gate     ddi_umem_cookie_t cookie)
24220Sstevel@tonic-gate 
24230Sstevel@tonic-gate {
24240Sstevel@tonic-gate 	rsmresource_t	*p = NULL;
24250Sstevel@tonic-gate 	rsmhash_table_t *rhash = &rsm_import_segs;
24260Sstevel@tonic-gate 	uint_t		index;
24270Sstevel@tonic-gate 
24280Sstevel@tonic-gate 	DBG_PRINTF((RSM_KERNEL_AGENT | RSM_FUNC_ALL, RSM_DEBUG_VERBOSE,
24290Sstevel@tonic-gate 	    "rsm_remap_local_importers enter\n"));
24300Sstevel@tonic-gate 
24310Sstevel@tonic-gate 	index = rsmhash(ex_segid);
24320Sstevel@tonic-gate 
24330Sstevel@tonic-gate 	rw_enter(&rhash->rsmhash_rw, RW_READER);
24340Sstevel@tonic-gate 
24350Sstevel@tonic-gate 	p = rsmhash_getbkt(rhash, index);
24360Sstevel@tonic-gate 
24370Sstevel@tonic-gate 	for (; p; p = p->rsmrc_next) {
24380Sstevel@tonic-gate 		rsmseg_t *seg = (rsmseg_t *)p;
24390Sstevel@tonic-gate 		rsmseglock_acquire(seg);
24400Sstevel@tonic-gate 		/*
24410Sstevel@tonic-gate 		 * Change the s_cookie value of only the local importers
24420Sstevel@tonic-gate 		 * which have been mapped (in state RSM_STATE_ACTIVE).
24430Sstevel@tonic-gate 		 * Note that there is no need to change the s_cookie value
24440Sstevel@tonic-gate 		 * if the imported segment is in RSM_STATE_MAPPING since
24450Sstevel@tonic-gate 		 * eventually the s_cookie will be updated via the mapping
24460Sstevel@tonic-gate 		 * functionality.
24470Sstevel@tonic-gate 		 */
24480Sstevel@tonic-gate 		if ((seg->s_segid == ex_segid) && (seg->s_node == src_nodeid) &&
24490Sstevel@tonic-gate 		    (seg->s_state == RSM_STATE_ACTIVE)) {
24500Sstevel@tonic-gate 			seg->s_cookie = cookie;
24510Sstevel@tonic-gate 		}
24520Sstevel@tonic-gate 		rsmseglock_release(seg);
24530Sstevel@tonic-gate 	}
24540Sstevel@tonic-gate 	rw_exit(&rhash->rsmhash_rw);
24550Sstevel@tonic-gate 
24560Sstevel@tonic-gate 	DBG_PRINTF((RSM_KERNEL_AGENT | RSM_FUNC_ALL, RSM_DEBUG_VERBOSE,
24570Sstevel@tonic-gate 	    "rsm_remap_local_importers done\n"));
24580Sstevel@tonic-gate }
24590Sstevel@tonic-gate 
24600Sstevel@tonic-gate static int
rsm_rebind(rsmseg_t * seg,rsm_ioctlmsg_t * msg)24610Sstevel@tonic-gate rsm_rebind(rsmseg_t *seg, rsm_ioctlmsg_t *msg)
24620Sstevel@tonic-gate {
24630Sstevel@tonic-gate 	int e;
24640Sstevel@tonic-gate 	adapter_t *adapter;
24650Sstevel@tonic-gate 	ddi_umem_cookie_t cookie;
24660Sstevel@tonic-gate 	DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_EXPORT);
24670Sstevel@tonic-gate 
24680Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_rebind enter\n"));
24690Sstevel@tonic-gate 
24700Sstevel@tonic-gate 	/* Check for permissions to rebind */
24710Sstevel@tonic-gate 	if (!(seg->s_flags & RSMKA_ALLOW_UNBIND_REBIND)) {
24720Sstevel@tonic-gate 		return (RSMERR_REBIND_NOT_ALLOWED);
24730Sstevel@tonic-gate 	}
24740Sstevel@tonic-gate 
24750Sstevel@tonic-gate 	if (seg->s_pid != ddi_get_pid() &&
24760Sstevel@tonic-gate 	    ddi_get_pid() != 0) {
24770Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_ERR, "rsm_rebind: Not owner\n"));
24780Sstevel@tonic-gate 		return (RSMERR_NOT_CREATOR);
24790Sstevel@tonic-gate 	}
24800Sstevel@tonic-gate 
24810Sstevel@tonic-gate 	/*
24820Sstevel@tonic-gate 	 * We will not be allowing partial rebind and hence length passed
24830Sstevel@tonic-gate 	 * in must be same as segment length
24840Sstevel@tonic-gate 	 */
24850Sstevel@tonic-gate 	if (msg->vaddr == NULL) {
24860Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_ERR,
24870Sstevel@tonic-gate 		    "rsm_rebind done: null msg->vaddr\n"));
24880Sstevel@tonic-gate 		return (RSMERR_BAD_ADDR);
24890Sstevel@tonic-gate 	}
24900Sstevel@tonic-gate 	if (msg->len != seg->s_len) {
24910Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_ERR,
24920Sstevel@tonic-gate 		    "rsm_rebind: invalid length\n"));
24930Sstevel@tonic-gate 		return (RSMERR_BAD_LENGTH);
24940Sstevel@tonic-gate 	}
24950Sstevel@tonic-gate 
24960Sstevel@tonic-gate 	/* Lock segment */
24970Sstevel@tonic-gate 	rsmseglock_acquire(seg);
24980Sstevel@tonic-gate 
24990Sstevel@tonic-gate 	while ((seg->s_state == RSM_STATE_BIND_QUIESCED) ||
25000Sstevel@tonic-gate 	    (seg->s_state == RSM_STATE_EXPORT_QUIESCING) ||
25010Sstevel@tonic-gate 	    (seg->s_state == RSM_STATE_EXPORT_QUIESCED)) {
25020Sstevel@tonic-gate 		if (cv_wait_sig(&seg->s_cv, &seg->s_lock) == 0) {
25030Sstevel@tonic-gate 			rsmseglock_release(seg);
25040Sstevel@tonic-gate 			DBG_PRINTF((category, RSM_DEBUG,
25050Sstevel@tonic-gate 			    "rsm_rebind done: cv_wait INTERRUPTED"));
25060Sstevel@tonic-gate 			return (RSMERR_INTERRUPTED);
25070Sstevel@tonic-gate 		}
25080Sstevel@tonic-gate 	}
25090Sstevel@tonic-gate 
25100Sstevel@tonic-gate 	/* verify segment state */
25110Sstevel@tonic-gate 	if ((seg->s_state != RSM_STATE_BIND) &&
25120Sstevel@tonic-gate 	    (seg->s_state != RSM_STATE_EXPORT)) {
25130Sstevel@tonic-gate 		/* Unlock segment */
25140Sstevel@tonic-gate 		rsmseglock_release(seg);
25150Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
25160Sstevel@tonic-gate 		    "rsm_rebind done: invalid state\n"));
25170Sstevel@tonic-gate 		return (RSMERR_BAD_SEG_HNDL);
25180Sstevel@tonic-gate 	}
25190Sstevel@tonic-gate 
25200Sstevel@tonic-gate 	ASSERT(seg->s_cookie != NULL);
25210Sstevel@tonic-gate 
25220Sstevel@tonic-gate 	if (msg->vaddr == seg->s_region.r_vaddr) {
25230Sstevel@tonic-gate 		rsmseglock_release(seg);
25240Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_rebind done\n"));
25250Sstevel@tonic-gate 		return (RSM_SUCCESS);
25260Sstevel@tonic-gate 	}
25270Sstevel@tonic-gate 
25280Sstevel@tonic-gate 	e = rsm_bind_pages(&cookie, msg->vaddr, msg->len, curproc);
25290Sstevel@tonic-gate 	if (e == RSM_SUCCESS) {
25300Sstevel@tonic-gate 		struct buf *xbuf;
25310Sstevel@tonic-gate 		dev_t sdev = 0;
25320Sstevel@tonic-gate 		rsm_memory_local_t mem;
25330Sstevel@tonic-gate 
25340Sstevel@tonic-gate 		xbuf = ddi_umem_iosetup(cookie, 0, msg->len, B_WRITE,
25350Sstevel@tonic-gate 		    sdev, 0, NULL, DDI_UMEM_SLEEP);
25360Sstevel@tonic-gate 		ASSERT(xbuf != NULL);
25370Sstevel@tonic-gate 
25380Sstevel@tonic-gate 		mem.ms_type = RSM_MEM_BUF;
25390Sstevel@tonic-gate 		mem.ms_bp = xbuf;
25400Sstevel@tonic-gate 
25410Sstevel@tonic-gate 		adapter = seg->s_adapter;
25420Sstevel@tonic-gate 		e = adapter->rsmpi_ops->rsm_rebind(
25430Sstevel@tonic-gate 		    seg->s_handle.out, 0, &mem,
25440Sstevel@tonic-gate 		    RSM_RESOURCE_DONTWAIT, NULL);
25450Sstevel@tonic-gate 
25460Sstevel@tonic-gate 		if (e == RSM_SUCCESS) {
25470Sstevel@tonic-gate 			/*
25480Sstevel@tonic-gate 			 * unbind the older pages, and unload local importers;
25490Sstevel@tonic-gate 			 * but don't disconnect importers
25500Sstevel@tonic-gate 			 */
25510Sstevel@tonic-gate 			(void) rsm_unbind_pages(seg);
25520Sstevel@tonic-gate 			seg->s_cookie = cookie;
25530Sstevel@tonic-gate 			seg->s_region.r_vaddr = msg->vaddr;
25540Sstevel@tonic-gate 			rsm_remap_local_importers(my_nodeid, seg->s_segid,
25550Sstevel@tonic-gate 			    cookie);
25560Sstevel@tonic-gate 		} else {
25570Sstevel@tonic-gate 			/*
25580Sstevel@tonic-gate 			 * Unbind the pages associated with "cookie" by the
25590Sstevel@tonic-gate 			 * rsm_bind_pages calls prior to this. This is
25600Sstevel@tonic-gate 			 * similar to what is done in the rsm_unbind_pages
25610Sstevel@tonic-gate 			 * routine for the seg->s_cookie.
25620Sstevel@tonic-gate 			 */
25630Sstevel@tonic-gate 			ddi_umem_unlock(cookie);
25640Sstevel@tonic-gate 			rsm_dec_pgcnt(btopr(msg->len));
25650Sstevel@tonic-gate 			DBG_PRINTF((category, RSM_ERR,
25660Sstevel@tonic-gate 			    "rsm_rebind failed with %d\n", e));
25670Sstevel@tonic-gate 		}
25680Sstevel@tonic-gate 		/*
25690Sstevel@tonic-gate 		 * At present there is no dependency on the existence of xbuf.
25700Sstevel@tonic-gate 		 * So we can free it here. If in the future this changes, it can
25710Sstevel@tonic-gate 		 * be freed sometime during the segment destroy.
25720Sstevel@tonic-gate 		 */
25730Sstevel@tonic-gate 		freerbuf(xbuf);
25740Sstevel@tonic-gate 	}
25750Sstevel@tonic-gate 
25760Sstevel@tonic-gate 	/* Unlock segment */
25770Sstevel@tonic-gate 	rsmseglock_release(seg);
25780Sstevel@tonic-gate 
25790Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_rebind done\n"));
25800Sstevel@tonic-gate 
25810Sstevel@tonic-gate 	return (e);
25820Sstevel@tonic-gate }
25830Sstevel@tonic-gate 
25840Sstevel@tonic-gate static int
rsm_unbind(rsmseg_t * seg)25850Sstevel@tonic-gate rsm_unbind(rsmseg_t *seg)
25860Sstevel@tonic-gate {
25870Sstevel@tonic-gate 	DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_EXPORT);
25880Sstevel@tonic-gate 
25890Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_unbind enter\n"));
25900Sstevel@tonic-gate 
25910Sstevel@tonic-gate 	rsmseglock_acquire(seg);
25920Sstevel@tonic-gate 
25930Sstevel@tonic-gate 	/* verify segment state */
25940Sstevel@tonic-gate 	if ((seg->s_state != RSM_STATE_BIND) &&
25950Sstevel@tonic-gate 	    (seg->s_state != RSM_STATE_BIND_QUIESCED)) {
25960Sstevel@tonic-gate 		rsmseglock_release(seg);
25970Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
25980Sstevel@tonic-gate 		    "rsm_unbind: invalid state\n"));
25990Sstevel@tonic-gate 		return (RSMERR_BAD_SEG_HNDL);
26000Sstevel@tonic-gate 	}
26010Sstevel@tonic-gate 
26020Sstevel@tonic-gate 	/* unlock current range */
26030Sstevel@tonic-gate 	(void) rsm_unbind_pages(seg);
26040Sstevel@tonic-gate 
26050Sstevel@tonic-gate 	if (seg->s_state == RSM_STATE_BIND) {
26060Sstevel@tonic-gate 		seg->s_state = RSM_STATE_NEW;
26070Sstevel@tonic-gate 	} else if (seg->s_state == RSM_STATE_BIND_QUIESCED) {
26080Sstevel@tonic-gate 		seg->s_state = RSM_STATE_NEW_QUIESCED;
26090Sstevel@tonic-gate 	}
26100Sstevel@tonic-gate 
26110Sstevel@tonic-gate 	rsmseglock_release(seg);
26120Sstevel@tonic-gate 
26130Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_unbind done\n"));
26140Sstevel@tonic-gate 
26150Sstevel@tonic-gate 	return (RSM_SUCCESS);
26160Sstevel@tonic-gate }
26170Sstevel@tonic-gate 
26180Sstevel@tonic-gate /* **************************** Exporter Access List Management ******* */
26190Sstevel@tonic-gate static void
rsmacl_free(rsmapi_access_entry_t * acl,int acl_len)26200Sstevel@tonic-gate rsmacl_free(rsmapi_access_entry_t *acl, int acl_len)
26210Sstevel@tonic-gate {
26220Sstevel@tonic-gate 	int	acl_sz;
26230Sstevel@tonic-gate 	DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_EXPORT);
26240Sstevel@tonic-gate 
26250Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmacl_free enter\n"));
26260Sstevel@tonic-gate 
26270Sstevel@tonic-gate 	/* acl could be NULL */
26280Sstevel@tonic-gate 
26290Sstevel@tonic-gate 	if (acl != NULL && acl_len > 0) {
26300Sstevel@tonic-gate 		acl_sz = acl_len * sizeof (rsmapi_access_entry_t);
26310Sstevel@tonic-gate 		kmem_free((void *)acl, acl_sz);
26320Sstevel@tonic-gate 	}
26330Sstevel@tonic-gate 
26340Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmacl_free done\n"));
26350Sstevel@tonic-gate }
26360Sstevel@tonic-gate 
26370Sstevel@tonic-gate static void
rsmpiacl_free(rsm_access_entry_t * acl,int acl_len)26380Sstevel@tonic-gate rsmpiacl_free(rsm_access_entry_t *acl, int acl_len)
26390Sstevel@tonic-gate {
26400Sstevel@tonic-gate 	int	acl_sz;
26410Sstevel@tonic-gate 	DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_EXPORT);
26420Sstevel@tonic-gate 
26430Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmpiacl_free enter\n"));
26440Sstevel@tonic-gate 
26450Sstevel@tonic-gate 	if (acl != NULL && acl_len > 0) {
26460Sstevel@tonic-gate 		acl_sz = acl_len * sizeof (rsm_access_entry_t);
26470Sstevel@tonic-gate 		kmem_free((void *)acl, acl_sz);
26480Sstevel@tonic-gate 	}
26490Sstevel@tonic-gate 
26500Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmpiacl_free done\n"));
26510Sstevel@tonic-gate 
26520Sstevel@tonic-gate }
26530Sstevel@tonic-gate 
26540Sstevel@tonic-gate static int
rsmacl_build(rsm_ioctlmsg_t * msg,int mode,rsmapi_access_entry_t ** list,int * len,int loopback)26550Sstevel@tonic-gate rsmacl_build(rsm_ioctlmsg_t *msg, int mode,
26560Sstevel@tonic-gate     rsmapi_access_entry_t **list, int *len, int loopback)
26570Sstevel@tonic-gate {
26580Sstevel@tonic-gate 	rsmapi_access_entry_t *acl;
26590Sstevel@tonic-gate 	int	acl_len;
26600Sstevel@tonic-gate 	int i;
26610Sstevel@tonic-gate 	DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_EXPORT);
26620Sstevel@tonic-gate 
26630Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmacl_build enter\n"));
26640Sstevel@tonic-gate 
26650Sstevel@tonic-gate 	*len = 0;
26660Sstevel@tonic-gate 	*list = NULL;
26670Sstevel@tonic-gate 
26680Sstevel@tonic-gate 	acl_len = msg->acl_len;
26690Sstevel@tonic-gate 	if ((loopback && acl_len > 1) || (acl_len < 0) ||
26700Sstevel@tonic-gate 	    (acl_len > MAX_NODES)) {
26710Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
26720Sstevel@tonic-gate 		    "rsmacl_build done: acl invalid\n"));
26730Sstevel@tonic-gate 		return (RSMERR_BAD_ACL);
26740Sstevel@tonic-gate 	}
26750Sstevel@tonic-gate 
26760Sstevel@tonic-gate 	if (acl_len > 0 && acl_len <= MAX_NODES) {
26770Sstevel@tonic-gate 		size_t acl_size = acl_len * sizeof (rsmapi_access_entry_t);
26780Sstevel@tonic-gate 
26790Sstevel@tonic-gate 		acl = kmem_alloc(acl_size, KM_SLEEP);
26800Sstevel@tonic-gate 
26810Sstevel@tonic-gate 		if (ddi_copyin((caddr_t)msg->acl, (caddr_t)acl,
26820Sstevel@tonic-gate 		    acl_size, mode)) {
26830Sstevel@tonic-gate 			kmem_free((void *) acl, acl_size);
26840Sstevel@tonic-gate 			DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
26850Sstevel@tonic-gate 			    "rsmacl_build done: BAD_ADDR\n"));
26860Sstevel@tonic-gate 			return (RSMERR_BAD_ADDR);
26870Sstevel@tonic-gate 		}
26880Sstevel@tonic-gate 
26890Sstevel@tonic-gate 		/*
26900Sstevel@tonic-gate 		 * Verify access list
26910Sstevel@tonic-gate 		 */
26920Sstevel@tonic-gate 		for (i = 0; i < acl_len; i++) {
26930Sstevel@tonic-gate 			if (acl[i].ae_node > MAX_NODES ||
26940Sstevel@tonic-gate 			    (loopback && (acl[i].ae_node != my_nodeid)) ||
26950Sstevel@tonic-gate 			    acl[i].ae_permission > RSM_ACCESS_TRUSTED) {
26960Sstevel@tonic-gate 				/* invalid entry */
26970Sstevel@tonic-gate 				kmem_free((void *) acl, acl_size);
26980Sstevel@tonic-gate 				DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
26990Sstevel@tonic-gate 				    "rsmacl_build done: EINVAL\n"));
27000Sstevel@tonic-gate 				return (RSMERR_BAD_ACL);
27010Sstevel@tonic-gate 			}
27020Sstevel@tonic-gate 		}
27030Sstevel@tonic-gate 
27040Sstevel@tonic-gate 		*len = acl_len;
27050Sstevel@tonic-gate 		*list = acl;
27060Sstevel@tonic-gate 	}
27070Sstevel@tonic-gate 
27080Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmacl_build done\n"));
27090Sstevel@tonic-gate 
27100Sstevel@tonic-gate 	return (DDI_SUCCESS);
27110Sstevel@tonic-gate }
27120Sstevel@tonic-gate 
27130Sstevel@tonic-gate static int
rsmpiacl_create(rsmapi_access_entry_t * src,rsm_access_entry_t ** dest,int acl_len,adapter_t * adapter)27140Sstevel@tonic-gate rsmpiacl_create(rsmapi_access_entry_t *src, rsm_access_entry_t **dest,
27150Sstevel@tonic-gate     int acl_len, adapter_t *adapter)
27160Sstevel@tonic-gate {
27170Sstevel@tonic-gate 	rsm_access_entry_t *acl;
27180Sstevel@tonic-gate 	rsm_addr_t hwaddr;
27190Sstevel@tonic-gate 	int i;
27200Sstevel@tonic-gate 	DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_EXPORT);
27210Sstevel@tonic-gate 
27220Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmpiacl_create enter\n"));
27230Sstevel@tonic-gate 
27240Sstevel@tonic-gate 	if (src != NULL) {
27250Sstevel@tonic-gate 		size_t acl_size = acl_len * sizeof (rsm_access_entry_t);
27260Sstevel@tonic-gate 		acl = kmem_alloc(acl_size, KM_SLEEP);
27270Sstevel@tonic-gate 
27280Sstevel@tonic-gate 		/*
27290Sstevel@tonic-gate 		 * translate access list
27300Sstevel@tonic-gate 		 */
27310Sstevel@tonic-gate 		for (i = 0; i < acl_len; i++) {
27320Sstevel@tonic-gate 			if (src[i].ae_node == my_nodeid) {
27330Sstevel@tonic-gate 				acl[i].ae_addr = adapter->hwaddr;
27340Sstevel@tonic-gate 			} else {
27350Sstevel@tonic-gate 				hwaddr = get_remote_hwaddr(adapter,
27360Sstevel@tonic-gate 				    src[i].ae_node);
27370Sstevel@tonic-gate 				if ((int64_t)hwaddr < 0) {
27380Sstevel@tonic-gate 					/* invalid hwaddr */
27390Sstevel@tonic-gate 					kmem_free((void *) acl, acl_size);
27400Sstevel@tonic-gate 					DBG_PRINTF((category,
27410Sstevel@tonic-gate 					    RSM_DEBUG_VERBOSE,
27420Sstevel@tonic-gate 					    "rsmpiacl_create done:"
27430Sstevel@tonic-gate 					    "EINVAL hwaddr\n"));
27440Sstevel@tonic-gate 					return (RSMERR_INTERNAL_ERROR);
27450Sstevel@tonic-gate 				}
27460Sstevel@tonic-gate 				acl[i].ae_addr = hwaddr;
27470Sstevel@tonic-gate 			}
27480Sstevel@tonic-gate 			/* rsmpi understands only RSM_PERM_XXXX */
27490Sstevel@tonic-gate 			acl[i].ae_permission =
27500Sstevel@tonic-gate 			    src[i].ae_permission & RSM_PERM_RDWR;
27510Sstevel@tonic-gate 		}
27520Sstevel@tonic-gate 		*dest = acl;
27530Sstevel@tonic-gate 	} else {
27540Sstevel@tonic-gate 		*dest = NULL;
27550Sstevel@tonic-gate 	}
27560Sstevel@tonic-gate 
27570Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmpiacl_create done\n"));
27580Sstevel@tonic-gate 
27590Sstevel@tonic-gate 	return (RSM_SUCCESS);
27600Sstevel@tonic-gate }
27610Sstevel@tonic-gate 
27620Sstevel@tonic-gate static int
rsmsegacl_validate(rsmipc_request_t * req,rsm_node_id_t rnode,rsmipc_reply_t * reply)27630Sstevel@tonic-gate rsmsegacl_validate(rsmipc_request_t *req, rsm_node_id_t rnode,
27640Sstevel@tonic-gate     rsmipc_reply_t *reply)
27650Sstevel@tonic-gate {
27660Sstevel@tonic-gate 
27670Sstevel@tonic-gate 	int		i;
27680Sstevel@tonic-gate 	rsmseg_t	*seg;
27690Sstevel@tonic-gate 	rsm_memseg_id_t key = req->rsmipc_key;
27700Sstevel@tonic-gate 	rsm_permission_t perm = req->rsmipc_perm;
27710Sstevel@tonic-gate 	DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_EXPORT);
27720Sstevel@tonic-gate 
27730Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
27740Sstevel@tonic-gate 	    "rsmsegacl_validate enter\n"));
27750Sstevel@tonic-gate 
27760Sstevel@tonic-gate 	/*
27770Sstevel@tonic-gate 	 * Find segment and grab its lock. The reason why we grab the segment
27780Sstevel@tonic-gate 	 * lock in side the search is to avoid the race when the segment is
27790Sstevel@tonic-gate 	 * being deleted and we already have a pointer to it.
27800Sstevel@tonic-gate 	 */
27810Sstevel@tonic-gate 	seg = rsmexport_lookup(key);
27820Sstevel@tonic-gate 	if (!seg) {
27830Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
27840Sstevel@tonic-gate 		    "rsmsegacl_validate done: %u ENXIO\n", key));
27850Sstevel@tonic-gate 		return (RSMERR_SEG_NOT_PUBLISHED);
27860Sstevel@tonic-gate 	}
27870Sstevel@tonic-gate 
27880Sstevel@tonic-gate 	ASSERT(rsmseglock_held(seg));
27890Sstevel@tonic-gate 	ASSERT(seg->s_state == RSM_STATE_EXPORT);
27900Sstevel@tonic-gate 
27910Sstevel@tonic-gate 	/*
27920Sstevel@tonic-gate 	 * We implement a 2-level protection scheme.
27930Sstevel@tonic-gate 	 * First, we check if local/remote host has access rights.
27940Sstevel@tonic-gate 	 * Second, we check if the user has access rights.
27950Sstevel@tonic-gate 	 *
27960Sstevel@tonic-gate 	 * This routine only validates the rnode access_list
27970Sstevel@tonic-gate 	 */
27980Sstevel@tonic-gate 	if (seg->s_acl_len > 0) {
27990Sstevel@tonic-gate 		/*
28000Sstevel@tonic-gate 		 * Check host access list
28010Sstevel@tonic-gate 		 */
28020Sstevel@tonic-gate 		ASSERT(seg->s_acl != NULL);
28030Sstevel@tonic-gate 		for (i = 0; i < seg->s_acl_len; i++) {
28040Sstevel@tonic-gate 			if (seg->s_acl[i].ae_node == rnode) {
28057656SSherry.Moore@Sun.COM 				perm &= seg->s_acl[i].ae_permission;
28067656SSherry.Moore@Sun.COM 				goto found;
28070Sstevel@tonic-gate 			}
28080Sstevel@tonic-gate 		}
28090Sstevel@tonic-gate 		/* rnode is not found in the list */
28100Sstevel@tonic-gate 		rsmseglock_release(seg);
28110Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
28120Sstevel@tonic-gate 		    "rsmsegacl_validate done: EPERM\n"));
28130Sstevel@tonic-gate 		return (RSMERR_SEG_NOT_PUBLISHED_TO_NODE);
28140Sstevel@tonic-gate 	} else {
28150Sstevel@tonic-gate 		/* use default owner creation umask */
28160Sstevel@tonic-gate 		perm &= seg->s_mode;
28170Sstevel@tonic-gate 	}
28180Sstevel@tonic-gate 
28190Sstevel@tonic-gate found:
28200Sstevel@tonic-gate 	/* update perm for this node */
28210Sstevel@tonic-gate 	reply->rsmipc_mode = perm;
28220Sstevel@tonic-gate 	reply->rsmipc_uid = seg->s_uid;
28230Sstevel@tonic-gate 	reply->rsmipc_gid = seg->s_gid;
28240Sstevel@tonic-gate 	reply->rsmipc_segid = seg->s_segid;
28250Sstevel@tonic-gate 	reply->rsmipc_seglen = seg->s_len;
28260Sstevel@tonic-gate 
28270Sstevel@tonic-gate 	/*
28280Sstevel@tonic-gate 	 * Perm of requesting node is valid; source will validate user
28290Sstevel@tonic-gate 	 */
28300Sstevel@tonic-gate 	rsmseglock_release(seg);
28310Sstevel@tonic-gate 
28320Sstevel@tonic-gate 	/*
28330Sstevel@tonic-gate 	 * Add the importer to the list right away, if connect fails
28340Sstevel@tonic-gate 	 * the importer will ask the exporter to remove it.
28350Sstevel@tonic-gate 	 */
28360Sstevel@tonic-gate 	importer_list_add(rnode, key, req->rsmipc_adapter_hwaddr,
28370Sstevel@tonic-gate 	    req->rsmipc_segment_cookie);
28380Sstevel@tonic-gate 
28390Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmsegacl_validate done\n"));
28400Sstevel@tonic-gate 
28410Sstevel@tonic-gate 	return (RSM_SUCCESS);
28420Sstevel@tonic-gate }
28430Sstevel@tonic-gate 
28440Sstevel@tonic-gate 
28450Sstevel@tonic-gate /* ************************** Exporter Calls ************************* */
28460Sstevel@tonic-gate 
28470Sstevel@tonic-gate static int
rsm_publish(rsmseg_t * seg,rsm_ioctlmsg_t * msg,intptr_t dataptr,int mode)28480Sstevel@tonic-gate rsm_publish(rsmseg_t *seg, rsm_ioctlmsg_t *msg, intptr_t dataptr, int mode)
28490Sstevel@tonic-gate {
28500Sstevel@tonic-gate 	int			e;
28510Sstevel@tonic-gate 	int			acl_len;
28520Sstevel@tonic-gate 	rsmapi_access_entry_t	*acl;
28530Sstevel@tonic-gate 	rsm_access_entry_t	*rsmpi_acl;
28540Sstevel@tonic-gate 	rsm_memory_local_t	mem;
28550Sstevel@tonic-gate 	struct buf		*xbuf;
28560Sstevel@tonic-gate 	dev_t 			sdev = 0;
28570Sstevel@tonic-gate 	adapter_t		*adapter;
28580Sstevel@tonic-gate 	rsm_memseg_id_t		segment_id = 0;
28590Sstevel@tonic-gate 	int			loopback_flag = 0;
28600Sstevel@tonic-gate 	int			create_flags = 0;
28610Sstevel@tonic-gate 	rsm_resource_callback_t	callback_flag;
28620Sstevel@tonic-gate 	DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_EXPORT);
28630Sstevel@tonic-gate 
28640Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_publish enter\n"));
28650Sstevel@tonic-gate 
28660Sstevel@tonic-gate 	if (seg->s_adapter == &loopback_adapter)
28670Sstevel@tonic-gate 		loopback_flag = 1;
28680Sstevel@tonic-gate 
28690Sstevel@tonic-gate 	if (seg->s_pid != ddi_get_pid() &&
28700Sstevel@tonic-gate 	    ddi_get_pid() != 0) {
28710Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_ERR,
28720Sstevel@tonic-gate 		    "rsm_publish: Not creator\n"));
28730Sstevel@tonic-gate 		return (RSMERR_NOT_CREATOR);
28740Sstevel@tonic-gate 	}
28750Sstevel@tonic-gate 
28760Sstevel@tonic-gate 	/*
28770Sstevel@tonic-gate 	 * Get per node access list
28780Sstevel@tonic-gate 	 */
28790Sstevel@tonic-gate 	e = rsmacl_build(msg, mode, &acl, &acl_len, loopback_flag);
28800Sstevel@tonic-gate 	if (e != DDI_SUCCESS) {
28810Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_ERR,
28820Sstevel@tonic-gate 		    "rsm_publish done: rsmacl_build failed\n"));
28830Sstevel@tonic-gate 		return (e);
28840Sstevel@tonic-gate 	}
28850Sstevel@tonic-gate 
28860Sstevel@tonic-gate 	/*
28870Sstevel@tonic-gate 	 * The application provided msg->key is used for resolving a
28880Sstevel@tonic-gate 	 * segment id according to the following:
28890Sstevel@tonic-gate 	 *    key = 0   		Kernel Agent selects the segment id
28900Sstevel@tonic-gate 	 *    key <= RSM_DLPI_ID_END	Reserved for system usage except
28910Sstevel@tonic-gate 	 *				RSMLIB range
28920Sstevel@tonic-gate 	 *    key < RSM_USER_APP_ID_BASE segment id = key
28930Sstevel@tonic-gate 	 *    key >= RSM_USER_APP_ID_BASE Reserved for KA selections
28940Sstevel@tonic-gate 	 *
28950Sstevel@tonic-gate 	 * rsm_nextavail_segmentid is initialized to 0x80000000 and
28960Sstevel@tonic-gate 	 * overflows to zero after 0x80000000 allocations.
28970Sstevel@tonic-gate 	 * An algorithm is needed which allows reinitialization and provides
28980Sstevel@tonic-gate 	 * for reallocation after overflow.  For now, ENOMEM is returned
28990Sstevel@tonic-gate 	 * once the overflow condition has occurred.
29000Sstevel@tonic-gate 	 */
29010Sstevel@tonic-gate 	if (msg->key == 0) {
29020Sstevel@tonic-gate 		mutex_enter(&rsm_lock);
29030Sstevel@tonic-gate 		segment_id = rsm_nextavail_segmentid;
29040Sstevel@tonic-gate 		if (segment_id != 0) {
29050Sstevel@tonic-gate 			rsm_nextavail_segmentid++;
29060Sstevel@tonic-gate 			mutex_exit(&rsm_lock);
29070Sstevel@tonic-gate 		} else {
29080Sstevel@tonic-gate 			mutex_exit(&rsm_lock);
29090Sstevel@tonic-gate 			DBG_PRINTF((category, RSM_ERR,
29100Sstevel@tonic-gate 			    "rsm_publish done: no more keys avlbl\n"));
29110Sstevel@tonic-gate 			return (RSMERR_INSUFFICIENT_RESOURCES);
29120Sstevel@tonic-gate 		}
29130Sstevel@tonic-gate 	} else	if BETWEEN(msg->key, RSM_RSMLIB_ID_BASE, RSM_RSMLIB_ID_END)
29140Sstevel@tonic-gate 		/* range reserved for internal use by base/ndi libraries */
29150Sstevel@tonic-gate 		segment_id = msg->key;
29160Sstevel@tonic-gate 	else	if (msg->key <= RSM_DLPI_ID_END)
29170Sstevel@tonic-gate 		return (RSMERR_RESERVED_SEGID);
29180Sstevel@tonic-gate 	else if (msg->key <= (uint_t)RSM_USER_APP_ID_BASE -1)
29190Sstevel@tonic-gate 		segment_id = msg->key;
29200Sstevel@tonic-gate 	else {
29210Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_ERR,
29220Sstevel@tonic-gate 		    "rsm_publish done: invalid key %u\n", msg->key));
29230Sstevel@tonic-gate 		return (RSMERR_RESERVED_SEGID);
29240Sstevel@tonic-gate 	}
29250Sstevel@tonic-gate 
29260Sstevel@tonic-gate 	/* Add key to exportlist; The segment lock is held on success */
29270Sstevel@tonic-gate 	e = rsmexport_add(seg, segment_id);
29280Sstevel@tonic-gate 	if (e) {
29290Sstevel@tonic-gate 		rsmacl_free(acl, acl_len);
29300Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_ERR,
29310Sstevel@tonic-gate 		    "rsm_publish done: export_add failed: %d\n", e));
29320Sstevel@tonic-gate 		return (e);
29330Sstevel@tonic-gate 	}
29340Sstevel@tonic-gate 
29350Sstevel@tonic-gate 	seg->s_segid = segment_id;
29360Sstevel@tonic-gate 
29370Sstevel@tonic-gate 	if ((seg->s_state != RSM_STATE_BIND) &&
29380Sstevel@tonic-gate 	    (seg->s_state != RSM_STATE_BIND_QUIESCED)) {
29390Sstevel@tonic-gate 		/* state changed since then, free acl and return */
29400Sstevel@tonic-gate 		rsmseglock_release(seg);
29410Sstevel@tonic-gate 		rsmexport_rm(seg);
29420Sstevel@tonic-gate 		rsmacl_free(acl, acl_len);
29430Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_ERR,
29440Sstevel@tonic-gate 		    "rsm_publish done: segment in wrong state: %d\n",
29450Sstevel@tonic-gate 		    seg->s_state));
29460Sstevel@tonic-gate 		return (RSMERR_BAD_SEG_HNDL);
29470Sstevel@tonic-gate 	}
29480Sstevel@tonic-gate 
29490Sstevel@tonic-gate 	/*
29500Sstevel@tonic-gate 	 * If this is for a local memory handle and permissions are zero,
29510Sstevel@tonic-gate 	 * then the surrogate segment is very large and we want to skip
29520Sstevel@tonic-gate 	 * allocation of DVMA space.
29530Sstevel@tonic-gate 	 *
29540Sstevel@tonic-gate 	 * Careful!  If the user didn't use an ACL list, acl will be a NULL
29550Sstevel@tonic-gate 	 * pointer.  Check that before dereferencing it.
29560Sstevel@tonic-gate 	 */
29570Sstevel@tonic-gate 	if (acl != (rsmapi_access_entry_t *)NULL) {
29580Sstevel@tonic-gate 		if (acl[0].ae_node == my_nodeid && acl[0].ae_permission == 0)
29590Sstevel@tonic-gate 			goto skipdriver;
29600Sstevel@tonic-gate 	}
29610Sstevel@tonic-gate 
29620Sstevel@tonic-gate 	/* create segment  */
29630Sstevel@tonic-gate 	xbuf = ddi_umem_iosetup(seg->s_cookie, 0, seg->s_len, B_WRITE,
29640Sstevel@tonic-gate 	    sdev, 0, NULL, DDI_UMEM_SLEEP);
29650Sstevel@tonic-gate 	ASSERT(xbuf != NULL);
29660Sstevel@tonic-gate 
29670Sstevel@tonic-gate 	mem.ms_type = RSM_MEM_BUF;
29680Sstevel@tonic-gate 	mem.ms_bp = xbuf;
29690Sstevel@tonic-gate 
29700Sstevel@tonic-gate 	/* This call includes a bind operations */
29710Sstevel@tonic-gate 
29720Sstevel@tonic-gate 	adapter = seg->s_adapter;
29730Sstevel@tonic-gate 	/*
29740Sstevel@tonic-gate 	 * create a acl list with hwaddr for RSMPI publish
29750Sstevel@tonic-gate 	 */
29760Sstevel@tonic-gate 	e = rsmpiacl_create(acl, &rsmpi_acl, acl_len, adapter);
29770Sstevel@tonic-gate 
29780Sstevel@tonic-gate 	if (e != RSM_SUCCESS) {
29790Sstevel@tonic-gate 		rsmseglock_release(seg);
29800Sstevel@tonic-gate 		rsmexport_rm(seg);
29810Sstevel@tonic-gate 		rsmacl_free(acl, acl_len);
29820Sstevel@tonic-gate 		freerbuf(xbuf);
29830Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_ERR,
29840Sstevel@tonic-gate 		    "rsm_publish done: rsmpiacl_create failed: %d\n", e));
29850Sstevel@tonic-gate 		return (e);
29860Sstevel@tonic-gate 	}
29870Sstevel@tonic-gate 
29880Sstevel@tonic-gate 	if (seg->s_state == RSM_STATE_BIND) {
29890Sstevel@tonic-gate 		/* create segment  */
29900Sstevel@tonic-gate 
29910Sstevel@tonic-gate 		/* This call includes a bind operations */
29920Sstevel@tonic-gate 
29930Sstevel@tonic-gate 		if (seg->s_flags & RSMKA_ALLOW_UNBIND_REBIND) {
29940Sstevel@tonic-gate 			create_flags = RSM_ALLOW_UNBIND_REBIND;
29950Sstevel@tonic-gate 		}
29960Sstevel@tonic-gate 
29970Sstevel@tonic-gate 		if (seg->s_flags & RSMKA_SET_RESOURCE_DONTWAIT) {
29980Sstevel@tonic-gate 			callback_flag  = RSM_RESOURCE_DONTWAIT;
29990Sstevel@tonic-gate 		} else {
30000Sstevel@tonic-gate 			callback_flag  = RSM_RESOURCE_SLEEP;
30010Sstevel@tonic-gate 		}
30020Sstevel@tonic-gate 
30030Sstevel@tonic-gate 		e = adapter->rsmpi_ops->rsm_seg_create(
30040Sstevel@tonic-gate 		    adapter->rsmpi_handle,
30050Sstevel@tonic-gate 		    &seg->s_handle.out, seg->s_len,
30060Sstevel@tonic-gate 		    create_flags, &mem,
30070Sstevel@tonic-gate 		    callback_flag, NULL);
30080Sstevel@tonic-gate 		/*
30090Sstevel@tonic-gate 		 * At present there is no dependency on the existence of xbuf.
30100Sstevel@tonic-gate 		 * So we can free it here. If in the future this changes, it can
30110Sstevel@tonic-gate 		 * be freed sometime during the segment destroy.
30120Sstevel@tonic-gate 		 */
30130Sstevel@tonic-gate 		freerbuf(xbuf);
30140Sstevel@tonic-gate 
30150Sstevel@tonic-gate 		if (e != RSM_SUCCESS) {
30160Sstevel@tonic-gate 			rsmseglock_release(seg);
30170Sstevel@tonic-gate 			rsmexport_rm(seg);
30180Sstevel@tonic-gate 			rsmacl_free(acl, acl_len);
30190Sstevel@tonic-gate 			rsmpiacl_free(rsmpi_acl, acl_len);
30200Sstevel@tonic-gate 			DBG_PRINTF((category, RSM_ERR,
30210Sstevel@tonic-gate 			    "rsm_publish done: export_create failed: %d\n", e));
30220Sstevel@tonic-gate 			/*
30230Sstevel@tonic-gate 			 * The following assertion ensures that the two errors
30240Sstevel@tonic-gate 			 * related to the length and its alignment do not occur
30250Sstevel@tonic-gate 			 * since they have been checked during export_create
30260Sstevel@tonic-gate 			 */
30270Sstevel@tonic-gate 			ASSERT(e != RSMERR_BAD_MEM_ALIGNMENT &&
30280Sstevel@tonic-gate 			    e != RSMERR_BAD_LENGTH);
30290Sstevel@tonic-gate 			if (e == RSMERR_NOT_MEM)
30300Sstevel@tonic-gate 				e = RSMERR_INSUFFICIENT_MEM;
30310Sstevel@tonic-gate 
30320Sstevel@tonic-gate 			return (e);
30330Sstevel@tonic-gate 		}
30340Sstevel@tonic-gate 		/* export segment, this should create an IMMU mapping */
30350Sstevel@tonic-gate 		e = adapter->rsmpi_ops->rsm_publish(
30360Sstevel@tonic-gate 		    seg->s_handle.out,
30370Sstevel@tonic-gate 		    rsmpi_acl, acl_len,
30380Sstevel@tonic-gate 		    seg->s_segid,
30390Sstevel@tonic-gate 		    RSM_RESOURCE_DONTWAIT, NULL);
30400Sstevel@tonic-gate 
30410Sstevel@tonic-gate 		if (e != RSM_SUCCESS) {
30420Sstevel@tonic-gate 			adapter->rsmpi_ops->rsm_seg_destroy(seg->s_handle.out);
30430Sstevel@tonic-gate 			rsmseglock_release(seg);
30440Sstevel@tonic-gate 			rsmexport_rm(seg);
30450Sstevel@tonic-gate 			rsmacl_free(acl, acl_len);
30460Sstevel@tonic-gate 			rsmpiacl_free(rsmpi_acl, acl_len);
30470Sstevel@tonic-gate 			DBG_PRINTF((category, RSM_ERR,
30480Sstevel@tonic-gate 			    "rsm_publish done: export_publish failed: %d\n",
30490Sstevel@tonic-gate 			    e));
30500Sstevel@tonic-gate 			return (e);
30510Sstevel@tonic-gate 		}
30520Sstevel@tonic-gate 	}
30530Sstevel@tonic-gate 
30540Sstevel@tonic-gate 	seg->s_acl_in = rsmpi_acl;
30550Sstevel@tonic-gate 
30560Sstevel@tonic-gate skipdriver:
30570Sstevel@tonic-gate 	/* defer s_acl/s_acl_len -> avoid crash in rsmseg_free */
30580Sstevel@tonic-gate 	seg->s_acl_len	= acl_len;
30590Sstevel@tonic-gate 	seg->s_acl	= acl;
30600Sstevel@tonic-gate 
30610Sstevel@tonic-gate 	if (seg->s_state == RSM_STATE_BIND) {
30620Sstevel@tonic-gate 		seg->s_state = RSM_STATE_EXPORT;
30630Sstevel@tonic-gate 	} else if (seg->s_state == RSM_STATE_BIND_QUIESCED) {
30640Sstevel@tonic-gate 		seg->s_state = RSM_STATE_EXPORT_QUIESCED;
30650Sstevel@tonic-gate 		cv_broadcast(&seg->s_cv);
30660Sstevel@tonic-gate 	}
30670Sstevel@tonic-gate 
30680Sstevel@tonic-gate 	rsmseglock_release(seg);
30690Sstevel@tonic-gate 
30700Sstevel@tonic-gate 	/*
30710Sstevel@tonic-gate 	 * If the segment id was solicited, then return it in
30720Sstevel@tonic-gate 	 * the original incoming message.
30730Sstevel@tonic-gate 	 */
30740Sstevel@tonic-gate 	if (msg->key == 0) {
30750Sstevel@tonic-gate 		msg->key = segment_id;
30760Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL
30770Sstevel@tonic-gate 		if ((mode & DATAMODEL_MASK) == DATAMODEL_ILP32) {
30780Sstevel@tonic-gate 			rsm_ioctlmsg32_t msg32;
30790Sstevel@tonic-gate 
30800Sstevel@tonic-gate 			msg32.key = msg->key;
30810Sstevel@tonic-gate 			DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
30820Sstevel@tonic-gate 			    "rsm_publish done\n"));
30830Sstevel@tonic-gate 			return (ddi_copyout((caddr_t)&msg32,
30840Sstevel@tonic-gate 			    (caddr_t)dataptr, sizeof (msg32), mode));
30850Sstevel@tonic-gate 		}
30860Sstevel@tonic-gate #endif
30870Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
30880Sstevel@tonic-gate 		    "rsm_publish done\n"));
30890Sstevel@tonic-gate 		return (ddi_copyout((caddr_t)msg,
30900Sstevel@tonic-gate 		    (caddr_t)dataptr, sizeof (*msg), mode));
30910Sstevel@tonic-gate 	}
30920Sstevel@tonic-gate 
30930Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_publish done\n"));
30940Sstevel@tonic-gate 	return (DDI_SUCCESS);
30950Sstevel@tonic-gate }
30960Sstevel@tonic-gate 
30970Sstevel@tonic-gate /*
30980Sstevel@tonic-gate  * This function modifies the access control list of an already published
30990Sstevel@tonic-gate  * segment.  There is no effect on import segments which are already
31000Sstevel@tonic-gate  * connected.
31010Sstevel@tonic-gate  */
31020Sstevel@tonic-gate static int
rsm_republish(rsmseg_t * seg,rsm_ioctlmsg_t * msg,int mode)31030Sstevel@tonic-gate rsm_republish(rsmseg_t *seg, rsm_ioctlmsg_t *msg, int mode)
31040Sstevel@tonic-gate {
31050Sstevel@tonic-gate 	rsmapi_access_entry_t	*new_acl, *old_acl, *tmp_acl;
31060Sstevel@tonic-gate 	rsm_access_entry_t	*rsmpi_new_acl, *rsmpi_old_acl;
31070Sstevel@tonic-gate 	int			new_acl_len, old_acl_len, tmp_acl_len;
31080Sstevel@tonic-gate 	int			e, i;
31090Sstevel@tonic-gate 	adapter_t		*adapter;
31100Sstevel@tonic-gate 	int			loopback_flag = 0;
31110Sstevel@tonic-gate 	rsm_memseg_id_t		key;
31120Sstevel@tonic-gate 	rsm_permission_t	permission;
31130Sstevel@tonic-gate 	DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_EXPORT);
31140Sstevel@tonic-gate 
31150Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_republish enter\n"));
31160Sstevel@tonic-gate 
31170Sstevel@tonic-gate 	if ((seg->s_state != RSM_STATE_EXPORT) &&
31180Sstevel@tonic-gate 	    (seg->s_state != RSM_STATE_EXPORT_QUIESCED) &&
31190Sstevel@tonic-gate 	    (seg->s_state != RSM_STATE_EXPORT_QUIESCING))
31200Sstevel@tonic-gate 		return (RSMERR_SEG_NOT_PUBLISHED);
31210Sstevel@tonic-gate 
31220Sstevel@tonic-gate 	if (seg->s_pid != ddi_get_pid() &&
31230Sstevel@tonic-gate 	    ddi_get_pid() != 0) {
31240Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_ERR,
31250Sstevel@tonic-gate 		    "rsm_republish: Not owner\n"));
31260Sstevel@tonic-gate 		return (RSMERR_NOT_CREATOR);
31270Sstevel@tonic-gate 	}
31280Sstevel@tonic-gate 
31290Sstevel@tonic-gate 	if (seg->s_adapter == &loopback_adapter)
31300Sstevel@tonic-gate 		loopback_flag = 1;
31310Sstevel@tonic-gate 
31320Sstevel@tonic-gate 	/*
31330Sstevel@tonic-gate 	 * Build new list first
31340Sstevel@tonic-gate 	 */
31350Sstevel@tonic-gate 	e = rsmacl_build(msg, mode, &new_acl, &new_acl_len, loopback_flag);
31360Sstevel@tonic-gate 	if (e) {
31370Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
31380Sstevel@tonic-gate 		    "rsm_republish done: rsmacl_build failed %d", e));
31390Sstevel@tonic-gate 		return (e);
31400Sstevel@tonic-gate 	}
31410Sstevel@tonic-gate 
31420Sstevel@tonic-gate 	/* Lock segment */
31430Sstevel@tonic-gate 	rsmseglock_acquire(seg);
31440Sstevel@tonic-gate 	/*
31450Sstevel@tonic-gate 	 * a republish is in progress - REPUBLISH message is being
31460Sstevel@tonic-gate 	 * sent to the importers so wait for it to complete OR
31470Sstevel@tonic-gate 	 * wait till DR completes
31480Sstevel@tonic-gate 	 */
31490Sstevel@tonic-gate 	while (((seg->s_state == RSM_STATE_EXPORT) &&
31500Sstevel@tonic-gate 	    (seg->s_flags & RSM_REPUBLISH_WAIT)) ||
31510Sstevel@tonic-gate 	    (seg->s_state == RSM_STATE_EXPORT_QUIESCED) ||
31520Sstevel@tonic-gate 	    (seg->s_state == RSM_STATE_EXPORT_QUIESCING)) {
31530Sstevel@tonic-gate 		if (cv_wait_sig(&seg->s_cv, &seg->s_lock) == 0) {
31540Sstevel@tonic-gate 			DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
31550Sstevel@tonic-gate 			    "rsm_republish done: cv_wait  INTERRUPTED"));
31560Sstevel@tonic-gate 			rsmseglock_release(seg);
31570Sstevel@tonic-gate 			rsmacl_free(new_acl, new_acl_len);
31580Sstevel@tonic-gate 			return (RSMERR_INTERRUPTED);
31590Sstevel@tonic-gate 		}
31600Sstevel@tonic-gate 	}
31610Sstevel@tonic-gate 
31620Sstevel@tonic-gate 	/* recheck if state is valid */
31630Sstevel@tonic-gate 	if (seg->s_state != RSM_STATE_EXPORT) {
31640Sstevel@tonic-gate 		rsmseglock_release(seg);
31650Sstevel@tonic-gate 		rsmacl_free(new_acl, new_acl_len);
31660Sstevel@tonic-gate 		return (RSMERR_SEG_NOT_PUBLISHED);
31670Sstevel@tonic-gate 	}
31680Sstevel@tonic-gate 
31690Sstevel@tonic-gate 	key = seg->s_key;
31700Sstevel@tonic-gate 	old_acl = seg->s_acl;
31710Sstevel@tonic-gate 	old_acl_len = seg->s_acl_len;
31720Sstevel@tonic-gate 
31730Sstevel@tonic-gate 	seg->s_acl = new_acl;
31740Sstevel@tonic-gate 	seg->s_acl_len = new_acl_len;
31750Sstevel@tonic-gate 
31760Sstevel@tonic-gate 	/*
31770Sstevel@tonic-gate 	 * This call will only be meaningful if and when the interconnect
31780Sstevel@tonic-gate 	 * layer makes use of the access list
31790Sstevel@tonic-gate 	 */
31800Sstevel@tonic-gate 	adapter = seg->s_adapter;
31810Sstevel@tonic-gate 	/*
31820Sstevel@tonic-gate 	 * create a acl list with hwaddr for RSMPI publish
31830Sstevel@tonic-gate 	 */
31840Sstevel@tonic-gate 	e = rsmpiacl_create(new_acl, &rsmpi_new_acl, new_acl_len, adapter);
31850Sstevel@tonic-gate 
31860Sstevel@tonic-gate 	if (e != RSM_SUCCESS) {
31870Sstevel@tonic-gate 		seg->s_acl = old_acl;
31880Sstevel@tonic-gate 		seg->s_acl_len = old_acl_len;
31890Sstevel@tonic-gate 		rsmseglock_release(seg);
31900Sstevel@tonic-gate 		rsmacl_free(new_acl, new_acl_len);
31910Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
31920Sstevel@tonic-gate 		    "rsm_republish done: rsmpiacl_create failed %d", e));
31930Sstevel@tonic-gate 		return (e);
31940Sstevel@tonic-gate 	}
31950Sstevel@tonic-gate 	rsmpi_old_acl = seg->s_acl_in;
31960Sstevel@tonic-gate 	seg->s_acl_in = rsmpi_new_acl;
31970Sstevel@tonic-gate 
31980Sstevel@tonic-gate 	e = adapter->rsmpi_ops->rsm_republish(seg->s_handle.out,
31990Sstevel@tonic-gate 	    seg->s_acl_in, seg->s_acl_len,
32000Sstevel@tonic-gate 	    RSM_RESOURCE_DONTWAIT, NULL);
32010Sstevel@tonic-gate 
32020Sstevel@tonic-gate 	if (e != RSM_SUCCESS) {
32030Sstevel@tonic-gate 		seg->s_acl = old_acl;
32040Sstevel@tonic-gate 		seg->s_acl_in = rsmpi_old_acl;
32050Sstevel@tonic-gate 		seg->s_acl_len = old_acl_len;
32060Sstevel@tonic-gate 		rsmseglock_release(seg);
32070Sstevel@tonic-gate 		rsmacl_free(new_acl, new_acl_len);
32080Sstevel@tonic-gate 		rsmpiacl_free(rsmpi_new_acl, new_acl_len);
32090Sstevel@tonic-gate 
32100Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
32110Sstevel@tonic-gate 		    "rsm_republish done: rsmpi republish failed %d\n", e));
32120Sstevel@tonic-gate 		return (e);
32130Sstevel@tonic-gate 	}
32140Sstevel@tonic-gate 
32150Sstevel@tonic-gate 	/* create a tmp copy of the new acl */
32160Sstevel@tonic-gate 	tmp_acl_len = new_acl_len;
32170Sstevel@tonic-gate 	if (tmp_acl_len > 0) {
32180Sstevel@tonic-gate 		tmp_acl = kmem_zalloc(new_acl_len*sizeof (*tmp_acl), KM_SLEEP);
32190Sstevel@tonic-gate 		for (i = 0; i < tmp_acl_len; i++) {
32200Sstevel@tonic-gate 			tmp_acl[i].ae_node = new_acl[i].ae_node;
32210Sstevel@tonic-gate 			tmp_acl[i].ae_permission = new_acl[i].ae_permission;
32220Sstevel@tonic-gate 		}
32230Sstevel@tonic-gate 		/*
32240Sstevel@tonic-gate 		 * The default permission of a node which was in the old
32250Sstevel@tonic-gate 		 * ACL but not in the new ACL is 0 ie no access.
32260Sstevel@tonic-gate 		 */
32270Sstevel@tonic-gate 		permission = 0;
32280Sstevel@tonic-gate 	} else {
32290Sstevel@tonic-gate 		/*
32300Sstevel@tonic-gate 		 * NULL acl means all importers can connect and
32310Sstevel@tonic-gate 		 * default permission will be owner creation umask
32320Sstevel@tonic-gate 		 */
32330Sstevel@tonic-gate 		tmp_acl = NULL;
32340Sstevel@tonic-gate 		permission = seg->s_mode;
32350Sstevel@tonic-gate 	}
32360Sstevel@tonic-gate 
32370Sstevel@tonic-gate 	/* make other republishers to wait for republish to complete */
32380Sstevel@tonic-gate 	seg->s_flags |= RSM_REPUBLISH_WAIT;
32390Sstevel@tonic-gate 
32400Sstevel@tonic-gate 	rsmseglock_release(seg);
32410Sstevel@tonic-gate 
32420Sstevel@tonic-gate 	/* send the new perms to the importing nodes */
32430Sstevel@tonic-gate 	rsm_send_republish(key, tmp_acl, tmp_acl_len, permission);
32440Sstevel@tonic-gate 
32450Sstevel@tonic-gate 	rsmseglock_acquire(seg);
32460Sstevel@tonic-gate 	seg->s_flags &= ~RSM_REPUBLISH_WAIT;
32470Sstevel@tonic-gate 	/* wake up any one waiting for republish to complete */
32480Sstevel@tonic-gate 	cv_broadcast(&seg->s_cv);
32490Sstevel@tonic-gate 	rsmseglock_release(seg);
32500Sstevel@tonic-gate 
32510Sstevel@tonic-gate 	rsmacl_free(tmp_acl, tmp_acl_len);
32520Sstevel@tonic-gate 	rsmacl_free(old_acl, old_acl_len);
32530Sstevel@tonic-gate 	rsmpiacl_free(rsmpi_old_acl, old_acl_len);
32540Sstevel@tonic-gate 
32550Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_republish done\n"));
32560Sstevel@tonic-gate 	return (DDI_SUCCESS);
32570Sstevel@tonic-gate }
32580Sstevel@tonic-gate 
32590Sstevel@tonic-gate static int
rsm_unpublish(rsmseg_t * seg,int mode)32600Sstevel@tonic-gate rsm_unpublish(rsmseg_t *seg, int mode)
32610Sstevel@tonic-gate {
32620Sstevel@tonic-gate 	rsmapi_access_entry_t	*acl;
32630Sstevel@tonic-gate 	rsm_access_entry_t	*rsmpi_acl;
32640Sstevel@tonic-gate 	int			acl_len;
32650Sstevel@tonic-gate 	int			e;
32660Sstevel@tonic-gate 	adapter_t *adapter;
32670Sstevel@tonic-gate 	DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_EXPORT);
32680Sstevel@tonic-gate 
32690Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_unpublish enter\n"));
32700Sstevel@tonic-gate 
32710Sstevel@tonic-gate 	if (seg->s_pid != ddi_get_pid() &&
32720Sstevel@tonic-gate 	    ddi_get_pid() != 0) {
32730Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_ERR,
32740Sstevel@tonic-gate 		    "rsm_unpublish: Not creator\n"));
32750Sstevel@tonic-gate 		return (RSMERR_NOT_CREATOR);
32760Sstevel@tonic-gate 	}
32770Sstevel@tonic-gate 
32780Sstevel@tonic-gate 	rsmseglock_acquire(seg);
32790Sstevel@tonic-gate 	/*
32800Sstevel@tonic-gate 	 * wait for QUIESCING to complete here before rsmexport_rm
32810Sstevel@tonic-gate 	 * is called because the SUSPEND_COMPLETE mesg which changes
32820Sstevel@tonic-gate 	 * the seg state from EXPORT_QUIESCING to EXPORT_QUIESCED and
32830Sstevel@tonic-gate 	 * signals the cv_wait needs to find it in the hashtable.
32840Sstevel@tonic-gate 	 */
32850Sstevel@tonic-gate 	while ((seg->s_state == RSM_STATE_EXPORT_QUIESCING) ||
32860Sstevel@tonic-gate 	    ((seg->s_state == RSM_STATE_EXPORT) && (seg->s_rdmacnt > 0))) {
32870Sstevel@tonic-gate 		if (cv_wait_sig(&seg->s_cv, &seg->s_lock) == 0) {
32880Sstevel@tonic-gate 			rsmseglock_release(seg);
32890Sstevel@tonic-gate 			DBG_PRINTF((category, RSM_ERR,
32900Sstevel@tonic-gate 			    "rsm_unpublish done: cv_wait INTR qscing"
32910Sstevel@tonic-gate 			    "getv/putv in progress"));
32920Sstevel@tonic-gate 			return (RSMERR_INTERRUPTED);
32930Sstevel@tonic-gate 		}
32940Sstevel@tonic-gate 	}
32950Sstevel@tonic-gate 
32960Sstevel@tonic-gate 	/* verify segment state */
32970Sstevel@tonic-gate 	if ((seg->s_state != RSM_STATE_EXPORT) &&
32980Sstevel@tonic-gate 	    (seg->s_state != RSM_STATE_EXPORT_QUIESCED)) {
32990Sstevel@tonic-gate 		rsmseglock_release(seg);
33000Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_ERR,
33010Sstevel@tonic-gate 		    "rsm_unpublish done: bad state %x\n", seg->s_state));
33020Sstevel@tonic-gate 		return (RSMERR_SEG_NOT_PUBLISHED);
33030Sstevel@tonic-gate 	}
33040Sstevel@tonic-gate 
33050Sstevel@tonic-gate 	rsmseglock_release(seg);
33060Sstevel@tonic-gate 
33070Sstevel@tonic-gate 	rsmexport_rm(seg);
33080Sstevel@tonic-gate 
33090Sstevel@tonic-gate 	rsm_send_importer_disconnects(seg->s_segid, my_nodeid);
33100Sstevel@tonic-gate 
33110Sstevel@tonic-gate 	rsmseglock_acquire(seg);
33120Sstevel@tonic-gate 	/*
33130Sstevel@tonic-gate 	 * wait for republish to complete
33140Sstevel@tonic-gate 	 */
33150Sstevel@tonic-gate 	while ((seg->s_state == RSM_STATE_EXPORT) &&
33160Sstevel@tonic-gate 	    (seg->s_flags & RSM_REPUBLISH_WAIT)) {
33170Sstevel@tonic-gate 		if (cv_wait_sig(&seg->s_cv, &seg->s_lock) == 0) {
33180Sstevel@tonic-gate 			DBG_PRINTF((category, RSM_ERR,
33190Sstevel@tonic-gate 			    "rsm_unpublish done: cv_wait INTR repubing"));
33200Sstevel@tonic-gate 			rsmseglock_release(seg);
33210Sstevel@tonic-gate 			return (RSMERR_INTERRUPTED);
33220Sstevel@tonic-gate 		}
33230Sstevel@tonic-gate 	}
33240Sstevel@tonic-gate 
33250Sstevel@tonic-gate 	if ((seg->s_state != RSM_STATE_EXPORT) &&
33260Sstevel@tonic-gate 	    (seg->s_state != RSM_STATE_EXPORT_QUIESCED)) {
33270Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_ERR,
33280Sstevel@tonic-gate 		    "rsm_unpublish done: invalid state"));
33290Sstevel@tonic-gate 		rsmseglock_release(seg);
33300Sstevel@tonic-gate 		return (RSMERR_SEG_NOT_PUBLISHED);
33310Sstevel@tonic-gate 	}
33320Sstevel@tonic-gate 
33330Sstevel@tonic-gate 	/*
33340Sstevel@tonic-gate 	 * check for putv/get surrogate segment which was not published
33350Sstevel@tonic-gate 	 * to the driver.
33360Sstevel@tonic-gate 	 *
33370Sstevel@tonic-gate 	 * Be certain to see if there is an ACL first!  If this segment was
33380Sstevel@tonic-gate 	 * not published with an ACL, acl will be a null pointer.  Check
33390Sstevel@tonic-gate 	 * that before dereferencing it.
33400Sstevel@tonic-gate 	 */
33410Sstevel@tonic-gate 	acl = seg->s_acl;
33420Sstevel@tonic-gate 	if (acl != (rsmapi_access_entry_t *)NULL) {
33430Sstevel@tonic-gate 		if (acl[0].ae_node == my_nodeid && acl[0].ae_permission == 0)
33440Sstevel@tonic-gate 			goto bypass;
33450Sstevel@tonic-gate 	}
33460Sstevel@tonic-gate 
33470Sstevel@tonic-gate 	/* The RSMPI unpublish/destroy has been done if seg is QUIESCED */
33480Sstevel@tonic-gate 	if (seg->s_state == RSM_STATE_EXPORT_QUIESCED)
33490Sstevel@tonic-gate 		goto bypass;
33500Sstevel@tonic-gate 
33510Sstevel@tonic-gate 	adapter = seg->s_adapter;
33520Sstevel@tonic-gate 	for (;;) {
33530Sstevel@tonic-gate 		if (seg->s_state != RSM_STATE_EXPORT) {
33540Sstevel@tonic-gate 			rsmseglock_release(seg);
33550Sstevel@tonic-gate 			DBG_PRINTF((category, RSM_ERR,
33560Sstevel@tonic-gate 			    "rsm_unpublish done: bad state %x\n",
33570Sstevel@tonic-gate 			    seg->s_state));
33580Sstevel@tonic-gate 			return (RSMERR_SEG_NOT_PUBLISHED);
33590Sstevel@tonic-gate 		}
33600Sstevel@tonic-gate 
33610Sstevel@tonic-gate 		/* unpublish from adapter */
33620Sstevel@tonic-gate 		e = adapter->rsmpi_ops->rsm_unpublish(seg->s_handle.out);
33630Sstevel@tonic-gate 
33640Sstevel@tonic-gate 		if (e == RSM_SUCCESS) {
33650Sstevel@tonic-gate 			break;
33660Sstevel@tonic-gate 		}
33670Sstevel@tonic-gate 
33680Sstevel@tonic-gate 		if (e == RSMERR_SEG_IN_USE && mode == 1) {
33690Sstevel@tonic-gate 			/*
33700Sstevel@tonic-gate 			 * wait for unpublish to succeed, it's busy.
33710Sstevel@tonic-gate 			 */
33720Sstevel@tonic-gate 			seg->s_flags |= RSM_EXPORT_WAIT;
33730Sstevel@tonic-gate 
33740Sstevel@tonic-gate 			/* wait for a max of 1 ms - this is an empirical */
33750Sstevel@tonic-gate 			/* value that was found by some minimal testing  */
33760Sstevel@tonic-gate 			/* can be fine tuned when we have better numbers */
33770Sstevel@tonic-gate 			/* A long term fix would be to send cv_signal	 */
33780Sstevel@tonic-gate 			/* from the intr callback routine		 */
3379*11066Srafael.vanoni@sun.com 			/* currently nobody signals this wait		 */
3380*11066Srafael.vanoni@sun.com 			(void) cv_reltimedwait(&seg->s_cv, &seg->s_lock,
3381*11066Srafael.vanoni@sun.com 			    drv_usectohz(1000), TR_CLOCK_TICK);
33820Sstevel@tonic-gate 
33830Sstevel@tonic-gate 			DBG_PRINTF((category, RSM_ERR,
33840Sstevel@tonic-gate 			    "rsm_unpublish: SEG_IN_USE\n"));
33850Sstevel@tonic-gate 
33860Sstevel@tonic-gate 			seg->s_flags &= ~RSM_EXPORT_WAIT;
33870Sstevel@tonic-gate 		} else {
33880Sstevel@tonic-gate 			if (mode == 1) {
33890Sstevel@tonic-gate 				DBG_PRINTF((category, RSM_ERR,
33900Sstevel@tonic-gate 				    "rsm:rsmpi unpublish err %x\n", e));
33910Sstevel@tonic-gate 				seg->s_state = RSM_STATE_BIND;
33920Sstevel@tonic-gate 			}
33930Sstevel@tonic-gate 			rsmseglock_release(seg);
33940Sstevel@tonic-gate 			return (e);
33950Sstevel@tonic-gate 		}
33960Sstevel@tonic-gate 	}
33970Sstevel@tonic-gate 
33980Sstevel@tonic-gate 	/* Free segment */
33990Sstevel@tonic-gate 	e = adapter->rsmpi_ops->rsm_seg_destroy(seg->s_handle.out);
34000Sstevel@tonic-gate 
34010Sstevel@tonic-gate 	if (e != RSM_SUCCESS) {
34020Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_ERR,
34030Sstevel@tonic-gate 		    "rsm_unpublish: rsmpi destroy key=%x failed %x\n",
34040Sstevel@tonic-gate 		    seg->s_key, e));
34050Sstevel@tonic-gate 	}
34060Sstevel@tonic-gate 
34070Sstevel@tonic-gate bypass:
34080Sstevel@tonic-gate 	acl = seg->s_acl;
34090Sstevel@tonic-gate 	rsmpi_acl = seg->s_acl_in;
34100Sstevel@tonic-gate 	acl_len = seg->s_acl_len;
34110Sstevel@tonic-gate 
34120Sstevel@tonic-gate 	seg->s_acl = NULL;
34130Sstevel@tonic-gate 	seg->s_acl_in = NULL;
34140Sstevel@tonic-gate 	seg->s_acl_len = 0;
34150Sstevel@tonic-gate 
34160Sstevel@tonic-gate 	if (seg->s_state == RSM_STATE_EXPORT) {
34170Sstevel@tonic-gate 		seg->s_state = RSM_STATE_BIND;
34180Sstevel@tonic-gate 	} else if (seg->s_state == RSM_STATE_EXPORT_QUIESCED) {
34190Sstevel@tonic-gate 		seg->s_state = RSM_STATE_BIND_QUIESCED;
34200Sstevel@tonic-gate 		cv_broadcast(&seg->s_cv);
34210Sstevel@tonic-gate 	}
34220Sstevel@tonic-gate 
34230Sstevel@tonic-gate 	rsmseglock_release(seg);
34240Sstevel@tonic-gate 
34250Sstevel@tonic-gate 	rsmacl_free(acl, acl_len);
34260Sstevel@tonic-gate 	rsmpiacl_free(rsmpi_acl, acl_len);
34270Sstevel@tonic-gate 
34280Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_unpublish done\n"));
34290Sstevel@tonic-gate 
34300Sstevel@tonic-gate 	return (DDI_SUCCESS);
34310Sstevel@tonic-gate }
34320Sstevel@tonic-gate 
34330Sstevel@tonic-gate /*
34340Sstevel@tonic-gate  * Called from rsm_unpublish to force an unload and disconnection of all
34350Sstevel@tonic-gate  * importers of the unpublished segment.
34360Sstevel@tonic-gate  *
34370Sstevel@tonic-gate  * First build the list of segments requiring a force disconnect, then
34380Sstevel@tonic-gate  * send a request for each.
34390Sstevel@tonic-gate  */
34400Sstevel@tonic-gate static void
rsm_send_importer_disconnects(rsm_memseg_id_t ex_segid,rsm_node_id_t ex_nodeid)34410Sstevel@tonic-gate rsm_send_importer_disconnects(rsm_memseg_id_t ex_segid,
34420Sstevel@tonic-gate     rsm_node_id_t ex_nodeid)
34430Sstevel@tonic-gate {
34440Sstevel@tonic-gate 	rsmipc_request_t 	request;
34450Sstevel@tonic-gate 	importing_token_t	*prev_token, *token, *tmp_token, *tokp;
34460Sstevel@tonic-gate 	importing_token_t	*force_disconnect_list = NULL;
34470Sstevel@tonic-gate 	int			index;
34480Sstevel@tonic-gate 
34490Sstevel@tonic-gate 	DBG_PRINTF((RSM_KERNEL_AGENT | RSM_EXPORT, RSM_DEBUG_VERBOSE,
34500Sstevel@tonic-gate 	    "rsm_send_importer_disconnects enter\n"));
34510Sstevel@tonic-gate 
34520Sstevel@tonic-gate 	index = rsmhash(ex_segid);
34530Sstevel@tonic-gate 
34540Sstevel@tonic-gate 	mutex_enter(&importer_list.lock);
34550Sstevel@tonic-gate 
34560Sstevel@tonic-gate 	prev_token = NULL;
34570Sstevel@tonic-gate 	token = importer_list.bucket[index];
34580Sstevel@tonic-gate 
34590Sstevel@tonic-gate 	while (token != NULL) {
34600Sstevel@tonic-gate 		if (token->key == ex_segid) {
34610Sstevel@tonic-gate 			/*
34620Sstevel@tonic-gate 			 * take it off the importer list and add it
34630Sstevel@tonic-gate 			 * to the force disconnect list.
34640Sstevel@tonic-gate 			 */
34650Sstevel@tonic-gate 			if (prev_token == NULL)
34660Sstevel@tonic-gate 				importer_list.bucket[index] = token->next;
34670Sstevel@tonic-gate 			else
34680Sstevel@tonic-gate 				prev_token->next = token->next;
34690Sstevel@tonic-gate 			tmp_token = token;
34700Sstevel@tonic-gate 			token = token->next;
34710Sstevel@tonic-gate 			if (force_disconnect_list == NULL) {
34720Sstevel@tonic-gate 				force_disconnect_list = tmp_token;
34730Sstevel@tonic-gate 				tmp_token->next = NULL;
34740Sstevel@tonic-gate 			} else {
34750Sstevel@tonic-gate 				tokp = force_disconnect_list;
34760Sstevel@tonic-gate 				/*
34770Sstevel@tonic-gate 				 * make sure that the tmp_token's node
34780Sstevel@tonic-gate 				 * is not already on the force disconnect
34790Sstevel@tonic-gate 				 * list.
34800Sstevel@tonic-gate 				 */
34810Sstevel@tonic-gate 				while (tokp != NULL) {
34820Sstevel@tonic-gate 					if (tokp->importing_node ==
34830Sstevel@tonic-gate 					    tmp_token->importing_node) {
34840Sstevel@tonic-gate 						break;
34850Sstevel@tonic-gate 					}
34860Sstevel@tonic-gate 					tokp = tokp->next;
34870Sstevel@tonic-gate 				}
34880Sstevel@tonic-gate 				if (tokp == NULL) {
34890Sstevel@tonic-gate 					tmp_token->next =
34900Sstevel@tonic-gate 					    force_disconnect_list;
34910Sstevel@tonic-gate 					force_disconnect_list = tmp_token;
34920Sstevel@tonic-gate 				} else {
34930Sstevel@tonic-gate 					kmem_free((void *)tmp_token,
34940Sstevel@tonic-gate 					    sizeof (*token));
34950Sstevel@tonic-gate 				}
34960Sstevel@tonic-gate 			}
34970Sstevel@tonic-gate 
34980Sstevel@tonic-gate 		} else {
34990Sstevel@tonic-gate 			prev_token = token;
35000Sstevel@tonic-gate 			token = token->next;
35010Sstevel@tonic-gate 		}
35020Sstevel@tonic-gate 	}
35030Sstevel@tonic-gate 	mutex_exit(&importer_list.lock);
35040Sstevel@tonic-gate 
35050Sstevel@tonic-gate 	token = force_disconnect_list;
35060Sstevel@tonic-gate 	while (token != NULL) {
35070Sstevel@tonic-gate 		if (token->importing_node == my_nodeid) {
35080Sstevel@tonic-gate 			rsm_force_unload(ex_nodeid, ex_segid,
35090Sstevel@tonic-gate 			    DISCONNECT);
35100Sstevel@tonic-gate 		} else {
35110Sstevel@tonic-gate 			request.rsmipc_hdr.rsmipc_type =
35120Sstevel@tonic-gate 			    RSMIPC_MSG_DISCONNECT;
35130Sstevel@tonic-gate 			request.rsmipc_key = token->key;
35145116Sjg97986 			for (;;) {
35155116Sjg97986 				if (rsmipc_send(token->importing_node,
35160Sstevel@tonic-gate 				    &request,
35175116Sjg97986 				    RSM_NO_REPLY) == RSM_SUCCESS) {
35185116Sjg97986 					break;
35195116Sjg97986 				} else {
35205116Sjg97986 					delay(drv_usectohz(10000));
35215116Sjg97986 				}
35225116Sjg97986 			}
35230Sstevel@tonic-gate 		}
35240Sstevel@tonic-gate 		tmp_token = token;
35250Sstevel@tonic-gate 		token = token->next;
35260Sstevel@tonic-gate 		kmem_free((void *)tmp_token, sizeof (*token));
35270Sstevel@tonic-gate 	}
35280Sstevel@tonic-gate 
35290Sstevel@tonic-gate 	DBG_PRINTF((RSM_KERNEL_AGENT | RSM_EXPORT, RSM_DEBUG_VERBOSE,
35307656SSherry.Moore@Sun.COM 	    "rsm_send_importer_disconnects done\n"));
35310Sstevel@tonic-gate }
35320Sstevel@tonic-gate 
35330Sstevel@tonic-gate /*
35340Sstevel@tonic-gate  * This function is used as a callback for unlocking the pages locked
35350Sstevel@tonic-gate  * down by a process which then does a fork or an exec.
35360Sstevel@tonic-gate  * It marks the export segments corresponding to umem cookie given by
35370Sstevel@tonic-gate  * the *arg to be in a ZOMBIE state(by calling rsmseg_close to be
35380Sstevel@tonic-gate  * destroyed later when an rsm_close occurs).
35390Sstevel@tonic-gate  */
35400Sstevel@tonic-gate static void
rsm_export_force_destroy(ddi_umem_cookie_t * ck)35410Sstevel@tonic-gate rsm_export_force_destroy(ddi_umem_cookie_t *ck)
35420Sstevel@tonic-gate {
35430Sstevel@tonic-gate 	rsmresource_blk_t *blk;
35440Sstevel@tonic-gate 	rsmresource_t *p;
35450Sstevel@tonic-gate 	rsmseg_t *eseg = NULL;
35460Sstevel@tonic-gate 	int i, j;
35470Sstevel@tonic-gate 	int found = 0;
35480Sstevel@tonic-gate 
35490Sstevel@tonic-gate 	DBG_PRINTF((RSM_KERNEL_AGENT | RSM_EXPORT, RSM_DEBUG_VERBOSE,
35500Sstevel@tonic-gate 	    "rsm_export_force_destroy enter\n"));
35510Sstevel@tonic-gate 
35520Sstevel@tonic-gate 	/*
35530Sstevel@tonic-gate 	 * Walk the resource list and locate the export segment (either
35540Sstevel@tonic-gate 	 * in the BIND or the EXPORT state) which corresponds to the
35550Sstevel@tonic-gate 	 * ddi_umem_cookie_t being freed up, and call rsmseg_close.
35560Sstevel@tonic-gate 	 * Change the state to ZOMBIE by calling rsmseg_close with the
35570Sstevel@tonic-gate 	 * force_flag argument (the second argument) set to 1. Also,
35580Sstevel@tonic-gate 	 * unpublish and unbind the segment, but don't free it. Free it
35590Sstevel@tonic-gate 	 * only on a rsm_close call for the segment.
35600Sstevel@tonic-gate 	 */
35610Sstevel@tonic-gate 	rw_enter(&rsm_resource.rsmrc_lock, RW_READER);
35620Sstevel@tonic-gate 
35630Sstevel@tonic-gate 	for (i = 0; i < rsm_resource.rsmrc_len; i++) {
35640Sstevel@tonic-gate 		blk = rsm_resource.rsmrc_root[i];
35650Sstevel@tonic-gate 		if (blk == NULL) {
35660Sstevel@tonic-gate 			continue;
35670Sstevel@tonic-gate 		}
35680Sstevel@tonic-gate 
35690Sstevel@tonic-gate 		for (j = 0; j < RSMRC_BLKSZ; j++) {
35700Sstevel@tonic-gate 			p = blk->rsmrcblk_blks[j];
35710Sstevel@tonic-gate 			if ((p != NULL) && (p != RSMRC_RESERVED) &&
35720Sstevel@tonic-gate 			    (p->rsmrc_type == RSM_RESOURCE_EXPORT_SEGMENT)) {
35730Sstevel@tonic-gate 				eseg = (rsmseg_t *)p;
35740Sstevel@tonic-gate 				if (eseg->s_cookie != ck)
35750Sstevel@tonic-gate 					continue; /* continue searching */
35760Sstevel@tonic-gate 				/*
35770Sstevel@tonic-gate 				 * Found the segment, set flag to indicate
35780Sstevel@tonic-gate 				 * force destroy processing is in progress
35790Sstevel@tonic-gate 				 */
35800Sstevel@tonic-gate 				rsmseglock_acquire(eseg);
35810Sstevel@tonic-gate 				eseg->s_flags |= RSM_FORCE_DESTROY_WAIT;
35820Sstevel@tonic-gate 				rsmseglock_release(eseg);
35830Sstevel@tonic-gate 				found = 1;
35840Sstevel@tonic-gate 				break;
35850Sstevel@tonic-gate 			}
35860Sstevel@tonic-gate 		}
35870Sstevel@tonic-gate 
35880Sstevel@tonic-gate 		if (found)
35890Sstevel@tonic-gate 			break;
35900Sstevel@tonic-gate 	}
35910Sstevel@tonic-gate 
35920Sstevel@tonic-gate 	rw_exit(&rsm_resource.rsmrc_lock);
35930Sstevel@tonic-gate 
35940Sstevel@tonic-gate 	if (found) {
35950Sstevel@tonic-gate 		ASSERT(eseg != NULL);
35960Sstevel@tonic-gate 		/* call rsmseg_close with force flag set to 1 */
35970Sstevel@tonic-gate 		rsmseg_close(eseg, 1);
35980Sstevel@tonic-gate 		/*
35990Sstevel@tonic-gate 		 * force destroy processing done, clear flag and signal any
36000Sstevel@tonic-gate 		 * thread waiting in rsmseg_close.
36010Sstevel@tonic-gate 		 */
36020Sstevel@tonic-gate 		rsmseglock_acquire(eseg);
36030Sstevel@tonic-gate 		eseg->s_flags &= ~RSM_FORCE_DESTROY_WAIT;
36040Sstevel@tonic-gate 		cv_broadcast(&eseg->s_cv);
36050Sstevel@tonic-gate 		rsmseglock_release(eseg);
36060Sstevel@tonic-gate 	}
36070Sstevel@tonic-gate 
36080Sstevel@tonic-gate 	DBG_PRINTF((RSM_KERNEL_AGENT | RSM_EXPORT, RSM_DEBUG_VERBOSE,
36090Sstevel@tonic-gate 	    "rsm_export_force_destroy done\n"));
36100Sstevel@tonic-gate }
36110Sstevel@tonic-gate 
36120Sstevel@tonic-gate /* ******************************* Remote Calls *********************** */
36130Sstevel@tonic-gate static void
rsm_intr_segconnect(rsm_node_id_t src,rsmipc_request_t * req)36140Sstevel@tonic-gate rsm_intr_segconnect(rsm_node_id_t src, rsmipc_request_t *req)
36150Sstevel@tonic-gate {
36160Sstevel@tonic-gate 	rsmipc_reply_t reply;
36170Sstevel@tonic-gate 	DBG_DEFINE(category,
36180Sstevel@tonic-gate 	    RSM_KERNEL_AGENT | RSM_FUNC_ALL | RSM_INTR_CALLBACK);
36190Sstevel@tonic-gate 
36200Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
36210Sstevel@tonic-gate 	    "rsm_intr_segconnect enter\n"));
36220Sstevel@tonic-gate 
36230Sstevel@tonic-gate 	reply.rsmipc_status = (short)rsmsegacl_validate(req, src, &reply);
36240Sstevel@tonic-gate 
36250Sstevel@tonic-gate 	reply.rsmipc_hdr.rsmipc_type = RSMIPC_MSG_REPLY;
36260Sstevel@tonic-gate 	reply.rsmipc_hdr.rsmipc_cookie = req->rsmipc_hdr.rsmipc_cookie;
36270Sstevel@tonic-gate 
36280Sstevel@tonic-gate 	(void) rsmipc_send(src, NULL, &reply);
36290Sstevel@tonic-gate 
36300Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
36310Sstevel@tonic-gate 	    "rsm_intr_segconnect done\n"));
36320Sstevel@tonic-gate }
36330Sstevel@tonic-gate 
36340Sstevel@tonic-gate 
36350Sstevel@tonic-gate /*
36360Sstevel@tonic-gate  * When an exported segment is unpublished the exporter sends an ipc
36370Sstevel@tonic-gate  * message (RSMIPC_MSG_DISCONNECT) to all importers.  The recv ipc dispatcher
36380Sstevel@tonic-gate  * calls this function.  The import list is scanned; segments which match the
36390Sstevel@tonic-gate  * exported segment id are unloaded and disconnected.
36400Sstevel@tonic-gate  *
36410Sstevel@tonic-gate  * Will also be called from rsm_rebind with disconnect_flag FALSE.
36420Sstevel@tonic-gate  *
36430Sstevel@tonic-gate  */
36440Sstevel@tonic-gate static void
rsm_force_unload(rsm_node_id_t src_nodeid,rsm_memseg_id_t ex_segid,boolean_t disconnect_flag)36450Sstevel@tonic-gate rsm_force_unload(rsm_node_id_t src_nodeid,
36460Sstevel@tonic-gate     rsm_memseg_id_t ex_segid,
36470Sstevel@tonic-gate     boolean_t disconnect_flag)
36480Sstevel@tonic-gate 
36490Sstevel@tonic-gate {
36500Sstevel@tonic-gate 	rsmresource_t	*p = NULL;
36510Sstevel@tonic-gate 	rsmhash_table_t *rhash = &rsm_import_segs;
36520Sstevel@tonic-gate 	uint_t		index;
36530Sstevel@tonic-gate 	DBG_DEFINE(category,
36540Sstevel@tonic-gate 	    RSM_KERNEL_AGENT | RSM_FUNC_ALL | RSM_INTR_CALLBACK);
36550Sstevel@tonic-gate 
36560Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_force_unload enter\n"));
36570Sstevel@tonic-gate 
36580Sstevel@tonic-gate 	index = rsmhash(ex_segid);
36590Sstevel@tonic-gate 
36600Sstevel@tonic-gate 	rw_enter(&rhash->rsmhash_rw, RW_READER);
36610Sstevel@tonic-gate 
36620Sstevel@tonic-gate 	p = rsmhash_getbkt(rhash, index);
36630Sstevel@tonic-gate 
36640Sstevel@tonic-gate 	for (; p; p = p->rsmrc_next) {
36650Sstevel@tonic-gate 		rsmseg_t *seg = (rsmseg_t *)p;
36660Sstevel@tonic-gate 		if ((seg->s_segid == ex_segid) && (seg->s_node == src_nodeid)) {
36670Sstevel@tonic-gate 			/*
36680Sstevel@tonic-gate 			 * In order to make rsmseg_unload and rsm_force_unload
36690Sstevel@tonic-gate 			 * thread safe, acquire the segment lock here.
36700Sstevel@tonic-gate 			 * rsmseg_unload is responsible for releasing the lock.
36710Sstevel@tonic-gate 			 * rsmseg_unload releases the lock just before a call
36720Sstevel@tonic-gate 			 * to rsmipc_send or in case of an early exit which
36730Sstevel@tonic-gate 			 * occurs if the segment was in the state
36740Sstevel@tonic-gate 			 * RSM_STATE_CONNECTING or RSM_STATE_NEW.
36750Sstevel@tonic-gate 			 */
36760Sstevel@tonic-gate 			rsmseglock_acquire(seg);
36770Sstevel@tonic-gate 			if (disconnect_flag)
36780Sstevel@tonic-gate 				seg->s_flags |= RSM_FORCE_DISCONNECT;
36790Sstevel@tonic-gate 			rsmseg_unload(seg);
36800Sstevel@tonic-gate 		}
36810Sstevel@tonic-gate 	}
36820Sstevel@tonic-gate 	rw_exit(&rhash->rsmhash_rw);
36830Sstevel@tonic-gate 
36840Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_force_unload done\n"));
36850Sstevel@tonic-gate }
36860Sstevel@tonic-gate 
36870Sstevel@tonic-gate static void
rsm_intr_reply(rsmipc_msghdr_t * msg)36880Sstevel@tonic-gate rsm_intr_reply(rsmipc_msghdr_t *msg)
36890Sstevel@tonic-gate {
36900Sstevel@tonic-gate 	/*
36910Sstevel@tonic-gate 	 * Find slot for cookie in reply.
36920Sstevel@tonic-gate 	 * Match sequence with sequence in cookie
36930Sstevel@tonic-gate 	 * If no match; return
36940Sstevel@tonic-gate 	 * Try to grap lock of slot, if locked return
36950Sstevel@tonic-gate 	 * copy data into reply slot area
36960Sstevel@tonic-gate 	 * signal waiter
36970Sstevel@tonic-gate 	 */
36980Sstevel@tonic-gate 	rsmipc_slot_t 	*slot;
36990Sstevel@tonic-gate 	rsmipc_cookie_t	*cookie;
37000Sstevel@tonic-gate 	void *data = (void *) msg;
37010Sstevel@tonic-gate 	size_t size = sizeof (rsmipc_reply_t);
37020Sstevel@tonic-gate 	DBG_DEFINE(category,
37030Sstevel@tonic-gate 	    RSM_KERNEL_AGENT | RSM_FUNC_ALL | RSM_INTR_CALLBACK);
37040Sstevel@tonic-gate 
37050Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_intr_reply enter\n"));
37060Sstevel@tonic-gate 
37070Sstevel@tonic-gate 	cookie = &msg->rsmipc_cookie;
37080Sstevel@tonic-gate 	if (cookie->ic.index >= RSMIPC_SZ) {
37090Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_ERR,
37100Sstevel@tonic-gate 		    "rsm: rsm_intr_reply bad cookie %d\n", cookie->ic.index));
37110Sstevel@tonic-gate 		return;
37120Sstevel@tonic-gate 	}
37130Sstevel@tonic-gate 
37140Sstevel@tonic-gate 	ASSERT(cookie->ic.index < RSMIPC_SZ);
37150Sstevel@tonic-gate 	slot = &rsm_ipc.slots[cookie->ic.index];
37160Sstevel@tonic-gate 	mutex_enter(&slot->rsmipc_lock);
37170Sstevel@tonic-gate 	if (slot->rsmipc_cookie.value == cookie->value) {
37180Sstevel@tonic-gate 		/* found a match */
37190Sstevel@tonic-gate 		if (RSMIPC_GET(slot, RSMIPC_PENDING)) {
37200Sstevel@tonic-gate 			bcopy(data, slot->rsmipc_data, size);
37210Sstevel@tonic-gate 			RSMIPC_CLEAR(slot, RSMIPC_PENDING);
37220Sstevel@tonic-gate 			cv_signal(&slot->rsmipc_cv);
37230Sstevel@tonic-gate 		}
37240Sstevel@tonic-gate 	} else {
37250Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_DEBUG,
37260Sstevel@tonic-gate 		    "rsm: rsm_intr_reply mismatched reply %d\n",
37270Sstevel@tonic-gate 		    cookie->ic.index));
37280Sstevel@tonic-gate 	}
37290Sstevel@tonic-gate 	mutex_exit(&slot->rsmipc_lock);
37300Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_intr_reply done\n"));
37310Sstevel@tonic-gate }
37320Sstevel@tonic-gate 
37330Sstevel@tonic-gate /*
37340Sstevel@tonic-gate  * This function gets dispatched on the worker thread when we receive
37350Sstevel@tonic-gate  * the SQREADY message. This function sends the SQREADY_ACK message.
37360Sstevel@tonic-gate  */
37370Sstevel@tonic-gate static void
rsm_sqready_ack_deferred(void * arg)37380Sstevel@tonic-gate rsm_sqready_ack_deferred(void *arg)
37390Sstevel@tonic-gate {
37400Sstevel@tonic-gate 	path_t	*path = (path_t *)arg;
37410Sstevel@tonic-gate 	DBG_DEFINE(category,
37420Sstevel@tonic-gate 	    RSM_KERNEL_AGENT | RSM_FUNC_ALL | RSM_INTR_CALLBACK);
37430Sstevel@tonic-gate 
37440Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
37450Sstevel@tonic-gate 	    "rsm_sqready_ack_deferred enter\n"));
37460Sstevel@tonic-gate 
37470Sstevel@tonic-gate 	mutex_enter(&path->mutex);
37480Sstevel@tonic-gate 
37490Sstevel@tonic-gate 	/*
37500Sstevel@tonic-gate 	 * If path is not active no point in sending the ACK
37510Sstevel@tonic-gate 	 * because the whole SQREADY protocol will again start
37520Sstevel@tonic-gate 	 * when the path becomes active.
37530Sstevel@tonic-gate 	 */
37540Sstevel@tonic-gate 	if (path->state != RSMKA_PATH_ACTIVE) {
37550Sstevel@tonic-gate 		/*
37560Sstevel@tonic-gate 		 * decrement the path refcnt incremented in rsm_proc_sqready
37570Sstevel@tonic-gate 		 */
37580Sstevel@tonic-gate 		PATH_RELE_NOLOCK(path);
37590Sstevel@tonic-gate 		mutex_exit(&path->mutex);
37600Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
37610Sstevel@tonic-gate 		    "rsm_sqready_ack_deferred done:!ACTIVE\n"));
37620Sstevel@tonic-gate 		return;
37630Sstevel@tonic-gate 	}
37640Sstevel@tonic-gate 
37650Sstevel@tonic-gate 	/* send an SQREADY_ACK message */
37660Sstevel@tonic-gate 	(void) rsmipc_send_controlmsg(path, RSMIPC_MSG_SQREADY_ACK);
37670Sstevel@tonic-gate 
37680Sstevel@tonic-gate 	/* initialize credits to the max level */
37690Sstevel@tonic-gate 	path->sendq_token.msgbuf_avail = RSMIPC_MAX_MESSAGES;
37700Sstevel@tonic-gate 
37710Sstevel@tonic-gate 	/* wake up any send that is waiting for credits */
37720Sstevel@tonic-gate 	cv_broadcast(&path->sendq_token.sendq_cv);
37730Sstevel@tonic-gate 
37740Sstevel@tonic-gate 	/*
37750Sstevel@tonic-gate 	 * decrement the path refcnt since we incremented it in
37760Sstevel@tonic-gate 	 * rsm_proc_sqready
37770Sstevel@tonic-gate 	 */
37780Sstevel@tonic-gate 	PATH_RELE_NOLOCK(path);
37790Sstevel@tonic-gate 
37800Sstevel@tonic-gate 	mutex_exit(&path->mutex);
37810Sstevel@tonic-gate 
37820Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
37830Sstevel@tonic-gate 	    "rsm_sqready_ack_deferred done\n"));
37840Sstevel@tonic-gate }
37850Sstevel@tonic-gate 
37860Sstevel@tonic-gate /*
37870Sstevel@tonic-gate  * Process the SQREADY message
37880Sstevel@tonic-gate  */
37890Sstevel@tonic-gate static void
rsm_proc_sqready(rsmipc_controlmsg_t * msg,rsm_addr_t src_hwaddr,rsm_intr_hand_arg_t arg)37900Sstevel@tonic-gate rsm_proc_sqready(rsmipc_controlmsg_t *msg, rsm_addr_t src_hwaddr,
37910Sstevel@tonic-gate     rsm_intr_hand_arg_t arg)
37920Sstevel@tonic-gate {
37930Sstevel@tonic-gate 	rsmipc_msghdr_t		*msghdr = (rsmipc_msghdr_t *)msg;
37940Sstevel@tonic-gate 	srv_handler_arg_t	*hdlr_argp = (srv_handler_arg_t *)arg;
37950Sstevel@tonic-gate 	path_t			*path;
37960Sstevel@tonic-gate 	DBG_DEFINE(category,
37970Sstevel@tonic-gate 	    RSM_KERNEL_AGENT | RSM_FUNC_ALL | RSM_INTR_CALLBACK);
37980Sstevel@tonic-gate 
37990Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_proc_sqready enter\n"));
38000Sstevel@tonic-gate 
38010Sstevel@tonic-gate 	/* look up the path - incr the path refcnt */
38020Sstevel@tonic-gate 	path = rsm_find_path(hdlr_argp->adapter_name,
38030Sstevel@tonic-gate 	    hdlr_argp->adapter_instance, src_hwaddr);
38040Sstevel@tonic-gate 
38050Sstevel@tonic-gate 	/*
38060Sstevel@tonic-gate 	 * No path exists or path is not active - drop the message
38070Sstevel@tonic-gate 	 */
38080Sstevel@tonic-gate 	if (path == NULL) {
38090Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_DEBUG,
38100Sstevel@tonic-gate 		    "rsm_proc_sqready done: msg dropped no path\n"));
38110Sstevel@tonic-gate 		return;
38120Sstevel@tonic-gate 	}
38130Sstevel@tonic-gate 
38140Sstevel@tonic-gate 	mutex_exit(&path->mutex);
38150Sstevel@tonic-gate 
38160Sstevel@tonic-gate 	/* drain any tasks from the previous incarnation */
38170Sstevel@tonic-gate 	taskq_wait(path->recv_taskq);
38180Sstevel@tonic-gate 
38190Sstevel@tonic-gate 	mutex_enter(&path->mutex);
38200Sstevel@tonic-gate 	/*
38210Sstevel@tonic-gate 	 * If we'd sent an SQREADY message and were waiting for SQREADY_ACK
38220Sstevel@tonic-gate 	 * in the meanwhile we received an SQREADY message, blindly reset
38230Sstevel@tonic-gate 	 * the WAIT_FOR_SQACK flag because we'll just send SQREADY_ACK
38240Sstevel@tonic-gate 	 * and forget about the SQREADY that we sent.
38250Sstevel@tonic-gate 	 */
38260Sstevel@tonic-gate 	path->flags &= ~RSMKA_WAIT_FOR_SQACK;
38270Sstevel@tonic-gate 
38280Sstevel@tonic-gate 	if (path->state != RSMKA_PATH_ACTIVE) {
38290Sstevel@tonic-gate 		/* decr refcnt and drop the mutex */
38300Sstevel@tonic-gate 		PATH_RELE_NOLOCK(path);
38310Sstevel@tonic-gate 		mutex_exit(&path->mutex);
38320Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_DEBUG,
38330Sstevel@tonic-gate 		    "rsm_proc_sqready done: msg dropped path !ACTIVE\n"));
38340Sstevel@tonic-gate 		return;
38350Sstevel@tonic-gate 	}
38360Sstevel@tonic-gate 
38370Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG, "rsm_proc_sqready:path=%lx "
38380Sstevel@tonic-gate 	    " src=%lx:%llx\n", path, msghdr->rsmipc_src, src_hwaddr));
38390Sstevel@tonic-gate 
38400Sstevel@tonic-gate 	/*
38410Sstevel@tonic-gate 	 * The sender's local incarnation number is our remote incarnation
38420Sstevel@tonic-gate 	 * number save it in the path data structure
38430Sstevel@tonic-gate 	 */
38440Sstevel@tonic-gate 	path->remote_incn = msg->rsmipc_local_incn;
38450Sstevel@tonic-gate 	path->sendq_token.msgbuf_avail = 0;
38460Sstevel@tonic-gate 	path->procmsg_cnt = 0;
38470Sstevel@tonic-gate 
38480Sstevel@tonic-gate 	/*
38490Sstevel@tonic-gate 	 * path is active - dispatch task to send SQREADY_ACK - remember
38500Sstevel@tonic-gate 	 * RSMPI calls can't be done in interrupt context
38510Sstevel@tonic-gate 	 *
38520Sstevel@tonic-gate 	 * We can use the recv_taskq to send because the remote endpoint
38530Sstevel@tonic-gate 	 * cannot start sending messages till it receives SQREADY_ACK hence
38540Sstevel@tonic-gate 	 * at this point there are no tasks on recv_taskq.
38550Sstevel@tonic-gate 	 *
38560Sstevel@tonic-gate 	 * The path refcnt will be decremented in rsm_sqready_ack_deferred.
38570Sstevel@tonic-gate 	 */
38580Sstevel@tonic-gate 	(void) taskq_dispatch(path->recv_taskq,
38590Sstevel@tonic-gate 	    rsm_sqready_ack_deferred, path, KM_NOSLEEP);
38600Sstevel@tonic-gate 
38610Sstevel@tonic-gate 	mutex_exit(&path->mutex);
38620Sstevel@tonic-gate 
38630Sstevel@tonic-gate 
38640Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_proc_sqready done\n"));
38650Sstevel@tonic-gate }
38660Sstevel@tonic-gate 
38670Sstevel@tonic-gate /*
38680Sstevel@tonic-gate  * Process the SQREADY_ACK message
38690Sstevel@tonic-gate  */
38700Sstevel@tonic-gate static void
rsm_proc_sqready_ack(rsmipc_controlmsg_t * msg,rsm_addr_t src_hwaddr,rsm_intr_hand_arg_t arg)38710Sstevel@tonic-gate rsm_proc_sqready_ack(rsmipc_controlmsg_t *msg, rsm_addr_t src_hwaddr,
38720Sstevel@tonic-gate     rsm_intr_hand_arg_t arg)
38730Sstevel@tonic-gate {
38740Sstevel@tonic-gate 	rsmipc_msghdr_t		*msghdr = (rsmipc_msghdr_t *)msg;
38750Sstevel@tonic-gate 	srv_handler_arg_t	*hdlr_argp = (srv_handler_arg_t *)arg;
38760Sstevel@tonic-gate 	path_t			*path;
38770Sstevel@tonic-gate 	DBG_DEFINE(category,
38780Sstevel@tonic-gate 	    RSM_KERNEL_AGENT | RSM_FUNC_ALL | RSM_INTR_CALLBACK);
38790Sstevel@tonic-gate 
38800Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
38810Sstevel@tonic-gate 	    "rsm_proc_sqready_ack enter\n"));
38820Sstevel@tonic-gate 
38830Sstevel@tonic-gate 	/* look up the path - incr the path refcnt */
38840Sstevel@tonic-gate 	path = rsm_find_path(hdlr_argp->adapter_name,
38850Sstevel@tonic-gate 	    hdlr_argp->adapter_instance, src_hwaddr);
38860Sstevel@tonic-gate 
38870Sstevel@tonic-gate 	/*
38880Sstevel@tonic-gate 	 * drop the message if - no path exists or path is not active
38890Sstevel@tonic-gate 	 * or if its not waiting for SQREADY_ACK message
38900Sstevel@tonic-gate 	 */
38910Sstevel@tonic-gate 	if (path == NULL) {
38920Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_DEBUG,
38930Sstevel@tonic-gate 		    "rsm_proc_sqready_ack done: msg dropped no path\n"));
38940Sstevel@tonic-gate 		return;
38950Sstevel@tonic-gate 	}
38960Sstevel@tonic-gate 
38970Sstevel@tonic-gate 	if ((path->state != RSMKA_PATH_ACTIVE) ||
38980Sstevel@tonic-gate 	    !(path->flags & RSMKA_WAIT_FOR_SQACK)) {
38990Sstevel@tonic-gate 		/* decrement the refcnt */
39000Sstevel@tonic-gate 		PATH_RELE_NOLOCK(path);
39010Sstevel@tonic-gate 		mutex_exit(&path->mutex);
39020Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_DEBUG,
39030Sstevel@tonic-gate 		    "rsm_proc_sqready_ack done: msg dropped\n"));
39040Sstevel@tonic-gate 		return;
39050Sstevel@tonic-gate 	}
39060Sstevel@tonic-gate 
39070Sstevel@tonic-gate 	/*
39080Sstevel@tonic-gate 	 * Check if this message is in response to the last RSMIPC_MSG_SQREADY
39090Sstevel@tonic-gate 	 * sent, if not drop it.
39100Sstevel@tonic-gate 	 */
39110Sstevel@tonic-gate 	if (path->local_incn != msghdr->rsmipc_incn) {
39120Sstevel@tonic-gate 		/* decrement the refcnt */
39130Sstevel@tonic-gate 		PATH_RELE_NOLOCK(path);
39140Sstevel@tonic-gate 		mutex_exit(&path->mutex);
39150Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_DEBUG,
39160Sstevel@tonic-gate 		    "rsm_proc_sqready_ack done: msg old incn %lld\n",
39170Sstevel@tonic-gate 		    msghdr->rsmipc_incn));
39180Sstevel@tonic-gate 		return;
39190Sstevel@tonic-gate 	}
39200Sstevel@tonic-gate 
39210Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG, "rsm_proc_sqready_ack:path=%lx "
39227656SSherry.Moore@Sun.COM 	    " src=%lx:%llx\n", path, msghdr->rsmipc_src, src_hwaddr));
39230Sstevel@tonic-gate 
39240Sstevel@tonic-gate 	/*
39250Sstevel@tonic-gate 	 * clear the WAIT_FOR_SQACK flag since we have recvd the ack
39260Sstevel@tonic-gate 	 */
39270Sstevel@tonic-gate 	path->flags &= ~RSMKA_WAIT_FOR_SQACK;
39280Sstevel@tonic-gate 
39290Sstevel@tonic-gate 	/* save the remote sendq incn number */
39300Sstevel@tonic-gate 	path->remote_incn = msg->rsmipc_local_incn;
39310Sstevel@tonic-gate 
39320Sstevel@tonic-gate 	/* initialize credits to the max level */
39330Sstevel@tonic-gate 	path->sendq_token.msgbuf_avail = RSMIPC_MAX_MESSAGES;
39340Sstevel@tonic-gate 
39350Sstevel@tonic-gate 	/* wake up any send that is waiting for credits */
39360Sstevel@tonic-gate 	cv_broadcast(&path->sendq_token.sendq_cv);
39370Sstevel@tonic-gate 
39380Sstevel@tonic-gate 	/* decrement the refcnt */
39390Sstevel@tonic-gate 	PATH_RELE_NOLOCK(path);
39400Sstevel@tonic-gate 
39410Sstevel@tonic-gate 	mutex_exit(&path->mutex);
39420Sstevel@tonic-gate 
39430Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
39440Sstevel@tonic-gate 	    "rsm_proc_sqready_ack done\n"));
39450Sstevel@tonic-gate }
39460Sstevel@tonic-gate 
39470Sstevel@tonic-gate /*
39480Sstevel@tonic-gate  * process the RSMIPC_MSG_CREDIT message
39490Sstevel@tonic-gate  */
39500Sstevel@tonic-gate static void
rsm_add_credits(rsmipc_controlmsg_t * msg,rsm_addr_t src_hwaddr,rsm_intr_hand_arg_t arg)39510Sstevel@tonic-gate rsm_add_credits(rsmipc_controlmsg_t *msg, rsm_addr_t src_hwaddr,
39520Sstevel@tonic-gate     rsm_intr_hand_arg_t arg)
39530Sstevel@tonic-gate {
39540Sstevel@tonic-gate 	rsmipc_msghdr_t		*msghdr = (rsmipc_msghdr_t *)msg;
39550Sstevel@tonic-gate 	srv_handler_arg_t	*hdlr_argp = (srv_handler_arg_t *)arg;
39560Sstevel@tonic-gate 	path_t			*path;
39570Sstevel@tonic-gate 	DBG_DEFINE(category,
39587656SSherry.Moore@Sun.COM 	    RSM_KERNEL_AGENT | RSM_FUNC_ALL |
39597656SSherry.Moore@Sun.COM 	    RSM_INTR_CALLBACK | RSM_FLOWCONTROL);
39600Sstevel@tonic-gate 
39610Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_add_credits enter\n"));
39620Sstevel@tonic-gate 
39630Sstevel@tonic-gate 	/* look up the path - incr the path refcnt */
39640Sstevel@tonic-gate 	path = rsm_find_path(hdlr_argp->adapter_name,
39650Sstevel@tonic-gate 	    hdlr_argp->adapter_instance, src_hwaddr);
39660Sstevel@tonic-gate 
39670Sstevel@tonic-gate 	if (path == NULL) {
39680Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_DEBUG,
39690Sstevel@tonic-gate 		    "rsm_add_credits enter: path not found\n"));
39700Sstevel@tonic-gate 		return;
39710Sstevel@tonic-gate 	}
39720Sstevel@tonic-gate 
39730Sstevel@tonic-gate 	/* the path is not active - discard credits */
39740Sstevel@tonic-gate 	if (path->state != RSMKA_PATH_ACTIVE) {
39750Sstevel@tonic-gate 		PATH_RELE_NOLOCK(path);
39760Sstevel@tonic-gate 		mutex_exit(&path->mutex);
39770Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_DEBUG,
39780Sstevel@tonic-gate 		    "rsm_add_credits enter:path=%lx !ACTIVE\n", path));
39790Sstevel@tonic-gate 		return;
39800Sstevel@tonic-gate 	}
39810Sstevel@tonic-gate 
39820Sstevel@tonic-gate 	/*
39830Sstevel@tonic-gate 	 * Check if these credits are for current incarnation of the path.
39840Sstevel@tonic-gate 	 */
39850Sstevel@tonic-gate 	if (path->local_incn != msghdr->rsmipc_incn) {
39860Sstevel@tonic-gate 		/* decrement the refcnt */
39870Sstevel@tonic-gate 		PATH_RELE_NOLOCK(path);
39880Sstevel@tonic-gate 		mutex_exit(&path->mutex);
39890Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_DEBUG,
39900Sstevel@tonic-gate 		    "rsm_add_credits enter: old incn %lld\n",
39910Sstevel@tonic-gate 		    msghdr->rsmipc_incn));
39920Sstevel@tonic-gate 		return;
39930Sstevel@tonic-gate 	}
39940Sstevel@tonic-gate 
39950Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG,
39960Sstevel@tonic-gate 	    "rsm_add_credits:path=%lx new-creds=%d "
39970Sstevel@tonic-gate 	    "curr credits=%d src=%lx:%llx\n", path, msg->rsmipc_credits,
39980Sstevel@tonic-gate 	    path->sendq_token.msgbuf_avail, msghdr->rsmipc_src,
39990Sstevel@tonic-gate 	    src_hwaddr));
40000Sstevel@tonic-gate 
40010Sstevel@tonic-gate 
40020Sstevel@tonic-gate 	/* add credits to the path's sendq */
40030Sstevel@tonic-gate 	path->sendq_token.msgbuf_avail += msg->rsmipc_credits;
40040Sstevel@tonic-gate 
40050Sstevel@tonic-gate 	ASSERT(path->sendq_token.msgbuf_avail <= RSMIPC_MAX_MESSAGES);
40060Sstevel@tonic-gate 
40070Sstevel@tonic-gate 	/* wake up any send that is waiting for credits */
40080Sstevel@tonic-gate 	cv_broadcast(&path->sendq_token.sendq_cv);
40090Sstevel@tonic-gate 
40100Sstevel@tonic-gate 	/* decrement the refcnt */
40110Sstevel@tonic-gate 	PATH_RELE_NOLOCK(path);
40120Sstevel@tonic-gate 
40130Sstevel@tonic-gate 	mutex_exit(&path->mutex);
40140Sstevel@tonic-gate 
40150Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_add_credits done\n"));
40160Sstevel@tonic-gate }
40170Sstevel@tonic-gate 
40180Sstevel@tonic-gate static void
rsm_intr_event(rsmipc_request_t * msg)40190Sstevel@tonic-gate rsm_intr_event(rsmipc_request_t *msg)
40200Sstevel@tonic-gate {
40210Sstevel@tonic-gate 	rsmseg_t	*seg;
40220Sstevel@tonic-gate 	rsmresource_t	*p;
40230Sstevel@tonic-gate 	rsm_node_id_t	src_node;
40240Sstevel@tonic-gate 	DBG_DEFINE(category,
40250Sstevel@tonic-gate 	    RSM_KERNEL_AGENT | RSM_FUNC_ALL | RSM_INTR_CALLBACK);
40260Sstevel@tonic-gate 
40270Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_intr_event enter\n"));
40280Sstevel@tonic-gate 
40290Sstevel@tonic-gate 	src_node = msg->rsmipc_hdr.rsmipc_src;
40300Sstevel@tonic-gate 
40310Sstevel@tonic-gate 	if ((seg = msg->rsmipc_segment_cookie) != NULL) {
40320Sstevel@tonic-gate 		/* This is for an import segment */
40330Sstevel@tonic-gate 		uint_t hashval = rsmhash(msg->rsmipc_key);
40340Sstevel@tonic-gate 
40350Sstevel@tonic-gate 		rw_enter(&rsm_import_segs.rsmhash_rw, RW_READER);
40360Sstevel@tonic-gate 
40370Sstevel@tonic-gate 		p = (rsmresource_t *)rsmhash_getbkt(&rsm_import_segs, hashval);
40380Sstevel@tonic-gate 
40390Sstevel@tonic-gate 		for (; p; p = p->rsmrc_next) {
40400Sstevel@tonic-gate 			if ((p->rsmrc_key == msg->rsmipc_key) &&
40410Sstevel@tonic-gate 			    (p->rsmrc_node == src_node)) {
40420Sstevel@tonic-gate 				seg = (rsmseg_t *)p;
40430Sstevel@tonic-gate 				rsmseglock_acquire(seg);
40440Sstevel@tonic-gate 
40450Sstevel@tonic-gate 				atomic_add_32(&seg->s_pollevent, 1);
40460Sstevel@tonic-gate 
40470Sstevel@tonic-gate 				if (seg->s_pollflag & RSM_SEGMENT_POLL)
40480Sstevel@tonic-gate 					pollwakeup(&seg->s_poll, POLLRDNORM);
40490Sstevel@tonic-gate 
40500Sstevel@tonic-gate 				rsmseglock_release(seg);
40510Sstevel@tonic-gate 			}
40520Sstevel@tonic-gate 		}
40530Sstevel@tonic-gate 
40540Sstevel@tonic-gate 		rw_exit(&rsm_import_segs.rsmhash_rw);
40550Sstevel@tonic-gate 	} else {
40560Sstevel@tonic-gate 		/* This is for an export segment */
40570Sstevel@tonic-gate 		seg = rsmexport_lookup(msg->rsmipc_key);
40580Sstevel@tonic-gate 		if (!seg) {
40590Sstevel@tonic-gate 			DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
40600Sstevel@tonic-gate 			    "rsm_intr_event done: exp seg not found\n"));
40610Sstevel@tonic-gate 			return;
40620Sstevel@tonic-gate 		}
40630Sstevel@tonic-gate 
40640Sstevel@tonic-gate 		ASSERT(rsmseglock_held(seg));
40650Sstevel@tonic-gate 
40660Sstevel@tonic-gate 		atomic_add_32(&seg->s_pollevent, 1);
40670Sstevel@tonic-gate 
40680Sstevel@tonic-gate 		/*
40690Sstevel@tonic-gate 		 * We must hold the segment lock here, or else the segment
40700Sstevel@tonic-gate 		 * can be freed while pollwakeup is using it. This implies
40710Sstevel@tonic-gate 		 * that we MUST NOT grab the segment lock during rsm_chpoll,
40720Sstevel@tonic-gate 		 * as outlined in the chpoll(2) man page.
40730Sstevel@tonic-gate 		 */
40740Sstevel@tonic-gate 		if (seg->s_pollflag & RSM_SEGMENT_POLL)
40750Sstevel@tonic-gate 			pollwakeup(&seg->s_poll, POLLRDNORM);
40760Sstevel@tonic-gate 
40770Sstevel@tonic-gate 		rsmseglock_release(seg);
40780Sstevel@tonic-gate 	}
40790Sstevel@tonic-gate 
40800Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_intr_event done\n"));
40810Sstevel@tonic-gate }
40820Sstevel@tonic-gate 
40830Sstevel@tonic-gate /*
40840Sstevel@tonic-gate  * The exporter did a republish and changed the ACL - this change is only
40850Sstevel@tonic-gate  * visible to new importers.
40860Sstevel@tonic-gate  */
40870Sstevel@tonic-gate static void
importer_update(rsm_node_id_t src_node,rsm_memseg_id_t key,rsm_permission_t perm)40880Sstevel@tonic-gate importer_update(rsm_node_id_t src_node, rsm_memseg_id_t key,
40890Sstevel@tonic-gate     rsm_permission_t perm)
40900Sstevel@tonic-gate {
40910Sstevel@tonic-gate 
40920Sstevel@tonic-gate 	rsmresource_t	*p;
40930Sstevel@tonic-gate 	rsmseg_t	*seg;
40940Sstevel@tonic-gate 	uint_t		hashval = rsmhash(key);
40950Sstevel@tonic-gate 	DBG_DEFINE(category,
40960Sstevel@tonic-gate 	    RSM_KERNEL_AGENT | RSM_FUNC_ALL | RSM_INTR_CALLBACK);
40970Sstevel@tonic-gate 
40980Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "importer_update enter\n"));
40990Sstevel@tonic-gate 
41000Sstevel@tonic-gate 	rw_enter(&rsm_import_segs.rsmhash_rw, RW_READER);
41010Sstevel@tonic-gate 
41020Sstevel@tonic-gate 	p = (rsmresource_t *)rsmhash_getbkt(&rsm_import_segs, hashval);
41030Sstevel@tonic-gate 
41040Sstevel@tonic-gate 	for (; p; p = p->rsmrc_next) {
41050Sstevel@tonic-gate 		/*
41060Sstevel@tonic-gate 		 * find the importer and update the permission in the shared
41070Sstevel@tonic-gate 		 * data structure. Any new importers will use the new perms
41080Sstevel@tonic-gate 		 */
41090Sstevel@tonic-gate 		if ((p->rsmrc_key == key) && (p->rsmrc_node == src_node)) {
41100Sstevel@tonic-gate 			seg = (rsmseg_t *)p;
41110Sstevel@tonic-gate 
41120Sstevel@tonic-gate 			rsmseglock_acquire(seg);
41130Sstevel@tonic-gate 			rsmsharelock_acquire(seg);
41140Sstevel@tonic-gate 			seg->s_share->rsmsi_mode = perm;
41150Sstevel@tonic-gate 			rsmsharelock_release(seg);
41160Sstevel@tonic-gate 			rsmseglock_release(seg);
41170Sstevel@tonic-gate 
41180Sstevel@tonic-gate 			break;
41190Sstevel@tonic-gate 		}
41200Sstevel@tonic-gate 	}
41210Sstevel@tonic-gate 
41220Sstevel@tonic-gate 	rw_exit(&rsm_import_segs.rsmhash_rw);
41230Sstevel@tonic-gate 
41240Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "importer_update done\n"));
41250Sstevel@tonic-gate }
41260Sstevel@tonic-gate 
41270Sstevel@tonic-gate void
rsm_suspend_complete(rsm_node_id_t src_node,int flag)41280Sstevel@tonic-gate rsm_suspend_complete(rsm_node_id_t src_node, int flag)
41290Sstevel@tonic-gate {
41300Sstevel@tonic-gate 	int		done = 1; /* indicate all SUSPENDS have been acked */
41310Sstevel@tonic-gate 	list_element_t	*elem;
41320Sstevel@tonic-gate 	DBG_DEFINE(category,
41330Sstevel@tonic-gate 	    RSM_KERNEL_AGENT | RSM_FUNC_ALL | RSM_INTR_CALLBACK);
41340Sstevel@tonic-gate 
41350Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
41360Sstevel@tonic-gate 	    "rsm_suspend_complete enter\n"));
41370Sstevel@tonic-gate 
41380Sstevel@tonic-gate 	mutex_enter(&rsm_suspend_list.list_lock);
41390Sstevel@tonic-gate 
41400Sstevel@tonic-gate 	if (rsm_suspend_list.list_head == NULL) {
41410Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
41420Sstevel@tonic-gate 		    "rsm_suspend_complete done: suspend_list is empty\n"));
41430Sstevel@tonic-gate 		mutex_exit(&rsm_suspend_list.list_lock);
41440Sstevel@tonic-gate 		return;
41450Sstevel@tonic-gate 	}
41460Sstevel@tonic-gate 
41470Sstevel@tonic-gate 	elem = rsm_suspend_list.list_head;
41480Sstevel@tonic-gate 	while (elem != NULL) {
41490Sstevel@tonic-gate 		if (elem->nodeid == src_node) {
41500Sstevel@tonic-gate 			/* clear the pending flag for the node */
41510Sstevel@tonic-gate 			elem->flags &= ~RSM_SUSPEND_ACKPENDING;
41520Sstevel@tonic-gate 			elem->flags |= flag;
41530Sstevel@tonic-gate 		}
41540Sstevel@tonic-gate 
41550Sstevel@tonic-gate 		if (done && (elem->flags & RSM_SUSPEND_ACKPENDING))
41560Sstevel@tonic-gate 			done = 0; /* still some nodes have not yet ACKED */
41570Sstevel@tonic-gate 
41580Sstevel@tonic-gate 		elem = elem->next;
41590Sstevel@tonic-gate 	}
41600Sstevel@tonic-gate 
41610Sstevel@tonic-gate 	mutex_exit(&rsm_suspend_list.list_lock);
41620Sstevel@tonic-gate 
41630Sstevel@tonic-gate 	if (!done) {
41640Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
41650Sstevel@tonic-gate 		    "rsm_suspend_complete done: acks pending\n"));
41660Sstevel@tonic-gate 		return;
41670Sstevel@tonic-gate 	}
41680Sstevel@tonic-gate 	/*
41690Sstevel@tonic-gate 	 * Now that we are done with suspending all the remote importers
41700Sstevel@tonic-gate 	 * time to quiesce the local exporters
41710Sstevel@tonic-gate 	 */
41720Sstevel@tonic-gate 	exporter_quiesce();
41730Sstevel@tonic-gate 
41740Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
41750Sstevel@tonic-gate 	    "rsm_suspend_complete done\n"));
41760Sstevel@tonic-gate }
41770Sstevel@tonic-gate 
41780Sstevel@tonic-gate static void
exporter_quiesce()41790Sstevel@tonic-gate exporter_quiesce()
41800Sstevel@tonic-gate {
41810Sstevel@tonic-gate 	int		i, e;
41820Sstevel@tonic-gate 	rsmresource_t	*current;
41830Sstevel@tonic-gate 	rsmseg_t	*seg;
41840Sstevel@tonic-gate 	adapter_t	*adapter;
41850Sstevel@tonic-gate 	DBG_DEFINE(category,
41860Sstevel@tonic-gate 	    RSM_KERNEL_AGENT | RSM_FUNC_ALL | RSM_INTR_CALLBACK);
41870Sstevel@tonic-gate 
41880Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "exporter_quiesce enter\n"));
41890Sstevel@tonic-gate 	/*
41900Sstevel@tonic-gate 	 * The importers send a SUSPEND_COMPLETE to the exporter node
41910Sstevel@tonic-gate 	 *	Unpublish, unbind the export segment and
41920Sstevel@tonic-gate 	 *	move the segments to the EXPORT_QUIESCED state
41930Sstevel@tonic-gate 	 */
41940Sstevel@tonic-gate 
41950Sstevel@tonic-gate 	rw_enter(&rsm_export_segs.rsmhash_rw, RW_READER);
41960Sstevel@tonic-gate 
41970Sstevel@tonic-gate 	for (i = 0; i < rsm_hash_size; i++) {
41980Sstevel@tonic-gate 		current = rsm_export_segs.bucket[i];
41990Sstevel@tonic-gate 		while (current != NULL) {
42000Sstevel@tonic-gate 			seg = (rsmseg_t *)current;
42010Sstevel@tonic-gate 			rsmseglock_acquire(seg);
42020Sstevel@tonic-gate 			if (current->rsmrc_state ==
42030Sstevel@tonic-gate 			    RSM_STATE_EXPORT_QUIESCING) {
42040Sstevel@tonic-gate 				adapter = seg->s_adapter;
42050Sstevel@tonic-gate 				/*
42060Sstevel@tonic-gate 				 * some local memory handles are not published
42070Sstevel@tonic-gate 				 * check if it was published
42080Sstevel@tonic-gate 				 */
42090Sstevel@tonic-gate 				if ((seg->s_acl == NULL) ||
42100Sstevel@tonic-gate 				    (seg->s_acl[0].ae_node != my_nodeid) ||
42110Sstevel@tonic-gate 				    (seg->s_acl[0].ae_permission != 0)) {
42120Sstevel@tonic-gate 
42130Sstevel@tonic-gate 					e = adapter->rsmpi_ops->rsm_unpublish(
42140Sstevel@tonic-gate 					    seg->s_handle.out);
42150Sstevel@tonic-gate 					DBG_PRINTF((category, RSM_DEBUG,
42160Sstevel@tonic-gate 					    "exporter_quiesce:unpub %d\n", e));
42170Sstevel@tonic-gate 
42180Sstevel@tonic-gate 					e = adapter->rsmpi_ops->rsm_seg_destroy(
42190Sstevel@tonic-gate 					    seg->s_handle.out);
42200Sstevel@tonic-gate 
42210Sstevel@tonic-gate 					DBG_PRINTF((category, RSM_DEBUG,
42220Sstevel@tonic-gate 					    "exporter_quiesce:destroy %d\n",
42230Sstevel@tonic-gate 					    e));
42240Sstevel@tonic-gate 				}
42250Sstevel@tonic-gate 
42260Sstevel@tonic-gate 				(void) rsm_unbind_pages(seg);
42270Sstevel@tonic-gate 				seg->s_state = RSM_STATE_EXPORT_QUIESCED;
42280Sstevel@tonic-gate 				cv_broadcast(&seg->s_cv);
42290Sstevel@tonic-gate 			}
42300Sstevel@tonic-gate 			rsmseglock_release(seg);
42310Sstevel@tonic-gate 			current = current->rsmrc_next;
42320Sstevel@tonic-gate 		}
42330Sstevel@tonic-gate 	}
42340Sstevel@tonic-gate 	rw_exit(&rsm_export_segs.rsmhash_rw);
42350Sstevel@tonic-gate 
42360Sstevel@tonic-gate 	/*
42370Sstevel@tonic-gate 	 * All the local segments we are done with the pre-del processing
42380Sstevel@tonic-gate 	 * - time to move to PREDEL_COMPLETED.
42390Sstevel@tonic-gate 	 */
42400Sstevel@tonic-gate 
42410Sstevel@tonic-gate 	mutex_enter(&rsm_drv_data.drv_lock);
42420Sstevel@tonic-gate 
42430Sstevel@tonic-gate 	ASSERT(rsm_drv_data.drv_state == RSM_DRV_PREDEL_STARTED);
42440Sstevel@tonic-gate 
42450Sstevel@tonic-gate 	rsm_drv_data.drv_state = RSM_DRV_PREDEL_COMPLETED;
42460Sstevel@tonic-gate 
42470Sstevel@tonic-gate 	cv_broadcast(&rsm_drv_data.drv_cv);
42480Sstevel@tonic-gate 
42490Sstevel@tonic-gate 	mutex_exit(&rsm_drv_data.drv_lock);
42500Sstevel@tonic-gate 
42510Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "exporter_quiesce done\n"));
42520Sstevel@tonic-gate }
42530Sstevel@tonic-gate 
42540Sstevel@tonic-gate static void
importer_suspend(rsm_node_id_t src_node)42550Sstevel@tonic-gate importer_suspend(rsm_node_id_t src_node)
42560Sstevel@tonic-gate {
42570Sstevel@tonic-gate 	int		i;
42580Sstevel@tonic-gate 	int		susp_flg; /* true means already suspended */
42590Sstevel@tonic-gate 	int		num_importers;
42600Sstevel@tonic-gate 	rsmresource_t	*p = NULL, *curp;
42610Sstevel@tonic-gate 	rsmhash_table_t *rhash = &rsm_import_segs;
42620Sstevel@tonic-gate 	rsmseg_t	*seg;
42630Sstevel@tonic-gate 	rsmipc_request_t request;
42640Sstevel@tonic-gate 	DBG_DEFINE(category,
42650Sstevel@tonic-gate 	    RSM_KERNEL_AGENT | RSM_FUNC_ALL | RSM_INTR_CALLBACK);
42660Sstevel@tonic-gate 
42670Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "importer_suspend enter\n"));
42680Sstevel@tonic-gate 
42690Sstevel@tonic-gate 	rw_enter(&rhash->rsmhash_rw, RW_READER);
42700Sstevel@tonic-gate 	for (i = 0; i < rsm_hash_size; i++) {
42710Sstevel@tonic-gate 		p = rhash->bucket[i];
42720Sstevel@tonic-gate 
42730Sstevel@tonic-gate 		/*
42740Sstevel@tonic-gate 		 * Suspend all importers with same <node, key> pair.
42750Sstevel@tonic-gate 		 * After the last one of the shared importers has been
42760Sstevel@tonic-gate 		 * suspended - suspend the shared mappings/connection.
42770Sstevel@tonic-gate 		 */
42780Sstevel@tonic-gate 		for (; p; p = p->rsmrc_next) {
42790Sstevel@tonic-gate 			rsmseg_t *first = (rsmseg_t *)p;
42800Sstevel@tonic-gate 			if ((first->s_node != src_node) ||
42810Sstevel@tonic-gate 			    (first->s_state == RSM_STATE_DISCONNECT))
42820Sstevel@tonic-gate 				continue; /* go to next entry */
42830Sstevel@tonic-gate 			/*
42840Sstevel@tonic-gate 			 * search the rest of the bucket for
42850Sstevel@tonic-gate 			 * other siblings (imprtrs with the same key)
42860Sstevel@tonic-gate 			 * of "first" and suspend them.
42870Sstevel@tonic-gate 			 * All importers with same key fall in
42880Sstevel@tonic-gate 			 * the same bucket.
42890Sstevel@tonic-gate 			 */
42900Sstevel@tonic-gate 			num_importers = 0;
42910Sstevel@tonic-gate 			for (curp = p; curp; curp = curp->rsmrc_next) {
42920Sstevel@tonic-gate 				seg = (rsmseg_t *)curp;
42930Sstevel@tonic-gate 
42940Sstevel@tonic-gate 				rsmseglock_acquire(seg);
42950Sstevel@tonic-gate 
42960Sstevel@tonic-gate 				if ((seg->s_node != first->s_node) ||
42970Sstevel@tonic-gate 				    (seg->s_key != first->s_key) ||
42980Sstevel@tonic-gate 				    (seg->s_state == RSM_STATE_DISCONNECT)) {
42990Sstevel@tonic-gate 					/*
43000Sstevel@tonic-gate 					 * either not a peer segment or its a
43010Sstevel@tonic-gate 					 * disconnected segment - skip it
43020Sstevel@tonic-gate 					 */
43030Sstevel@tonic-gate 					rsmseglock_release(seg);
43040Sstevel@tonic-gate 					continue;
43050Sstevel@tonic-gate 				}
43060Sstevel@tonic-gate 
43070Sstevel@tonic-gate 				rsmseg_suspend(seg, &susp_flg);
43080Sstevel@tonic-gate 
43090Sstevel@tonic-gate 				if (susp_flg) { /* seg already suspended */
43100Sstevel@tonic-gate 					rsmseglock_release(seg);
43110Sstevel@tonic-gate 					break; /* the inner for loop */
43120Sstevel@tonic-gate 				}
43130Sstevel@tonic-gate 
43140Sstevel@tonic-gate 				num_importers++;
43150Sstevel@tonic-gate 				rsmsharelock_acquire(seg);
43160Sstevel@tonic-gate 				/*
43170Sstevel@tonic-gate 				 * we've processed all importers that are
43180Sstevel@tonic-gate 				 * siblings of "first"
43190Sstevel@tonic-gate 				 */
43200Sstevel@tonic-gate 				if (num_importers ==
43210Sstevel@tonic-gate 				    seg->s_share->rsmsi_refcnt) {
43220Sstevel@tonic-gate 					rsmsharelock_release(seg);
43230Sstevel@tonic-gate 					rsmseglock_release(seg);
43240Sstevel@tonic-gate 					break;
43250Sstevel@tonic-gate 				}
43260Sstevel@tonic-gate 				rsmsharelock_release(seg);
43270Sstevel@tonic-gate 				rsmseglock_release(seg);
43280Sstevel@tonic-gate 			}
43290Sstevel@tonic-gate 
43300Sstevel@tonic-gate 			/*
43310Sstevel@tonic-gate 			 * All the importers with the same key and
43320Sstevel@tonic-gate 			 * nodeid as "first" have been suspended.
43330Sstevel@tonic-gate 			 * Now suspend the shared connect/mapping.
43340Sstevel@tonic-gate 			 * This is done only once.
43350Sstevel@tonic-gate 			 */
43360Sstevel@tonic-gate 			if (!susp_flg) {
43370Sstevel@tonic-gate 				rsmsegshare_suspend(seg);
43380Sstevel@tonic-gate 			}
43390Sstevel@tonic-gate 		}
43400Sstevel@tonic-gate 	}
43410Sstevel@tonic-gate 
43420Sstevel@tonic-gate 	rw_exit(&rhash->rsmhash_rw);
43430Sstevel@tonic-gate 
43440Sstevel@tonic-gate 	/* send an ACK for SUSPEND message */
43450Sstevel@tonic-gate 	request.rsmipc_hdr.rsmipc_type = RSMIPC_MSG_SUSPEND_DONE;
43460Sstevel@tonic-gate 	(void) rsmipc_send(src_node, &request, RSM_NO_REPLY);
43470Sstevel@tonic-gate 
43480Sstevel@tonic-gate 
43490Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "importer_suspend done\n"));
43500Sstevel@tonic-gate 
43510Sstevel@tonic-gate }
43520Sstevel@tonic-gate 
43530Sstevel@tonic-gate static void
rsmseg_suspend(rsmseg_t * seg,int * susp_flg)43540Sstevel@tonic-gate rsmseg_suspend(rsmseg_t *seg, int *susp_flg)
43550Sstevel@tonic-gate {
43560Sstevel@tonic-gate 	int		recheck_state;
43570Sstevel@tonic-gate 	rsmcookie_t	*hdl;
43580Sstevel@tonic-gate 	DBG_DEFINE(category,
43590Sstevel@tonic-gate 	    RSM_KERNEL_AGENT | RSM_FUNC_ALL | RSM_INTR_CALLBACK);
43600Sstevel@tonic-gate 
43610Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
43620Sstevel@tonic-gate 	    "rsmseg_suspend enter: key=%u\n", seg->s_key));
43630Sstevel@tonic-gate 
43640Sstevel@tonic-gate 	*susp_flg = 0;
43650Sstevel@tonic-gate 
43660Sstevel@tonic-gate 	ASSERT(rsmseglock_held(seg));
43670Sstevel@tonic-gate 	/* wait if putv/getv is in progress */
43680Sstevel@tonic-gate 	while (seg->s_rdmacnt > 0)
43690Sstevel@tonic-gate 		cv_wait(&seg->s_cv, &seg->s_lock);
43700Sstevel@tonic-gate 
43710Sstevel@tonic-gate 	do {
43720Sstevel@tonic-gate 		recheck_state = 0;
43730Sstevel@tonic-gate 
43740Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
43750Sstevel@tonic-gate 		    "rsmseg_suspend:segment %x state=%d\n",
43760Sstevel@tonic-gate 		    seg->s_key, seg->s_state));
43770Sstevel@tonic-gate 
43780Sstevel@tonic-gate 		switch (seg->s_state) {
43790Sstevel@tonic-gate 		case RSM_STATE_NEW:
43800Sstevel@tonic-gate 			/* not a valid state */
43810Sstevel@tonic-gate 			break;
43820Sstevel@tonic-gate 		case RSM_STATE_CONNECTING:
43830Sstevel@tonic-gate 			seg->s_state = RSM_STATE_ABORT_CONNECT;
43840Sstevel@tonic-gate 			break;
43850Sstevel@tonic-gate 		case RSM_STATE_ABORT_CONNECT:
43860Sstevel@tonic-gate 			break;
43870Sstevel@tonic-gate 		case RSM_STATE_CONNECT:
43880Sstevel@tonic-gate 			seg->s_handle.in = NULL;
43890Sstevel@tonic-gate 			seg->s_state = RSM_STATE_CONN_QUIESCE;
43900Sstevel@tonic-gate 			break;
43910Sstevel@tonic-gate 		case RSM_STATE_MAPPING:
43920Sstevel@tonic-gate 			/* wait until segment leaves the mapping state */
43930Sstevel@tonic-gate 			while (seg->s_state == RSM_STATE_MAPPING)
43940Sstevel@tonic-gate 				cv_wait(&seg->s_cv, &seg->s_lock);
43950Sstevel@tonic-gate 			recheck_state = 1;
43960Sstevel@tonic-gate 			break;
43970Sstevel@tonic-gate 		case RSM_STATE_ACTIVE:
43980Sstevel@tonic-gate 			/* unload the mappings */
43990Sstevel@tonic-gate 			if (seg->s_ckl != NULL) {
44000Sstevel@tonic-gate 				hdl = seg->s_ckl;
44010Sstevel@tonic-gate 				for (; hdl != NULL; hdl = hdl->c_next) {
44020Sstevel@tonic-gate 					(void) devmap_unload(hdl->c_dhp,
44037656SSherry.Moore@Sun.COM 					    hdl->c_off, hdl->c_len);
44040Sstevel@tonic-gate 				}
44050Sstevel@tonic-gate 			}
44060Sstevel@tonic-gate 			seg->s_mapinfo = NULL;
44070Sstevel@tonic-gate 			seg->s_state = RSM_STATE_MAP_QUIESCE;
44080Sstevel@tonic-gate 			break;
44090Sstevel@tonic-gate 		case RSM_STATE_CONN_QUIESCE:
44100Sstevel@tonic-gate 			/* FALLTHRU */
44110Sstevel@tonic-gate 		case RSM_STATE_MAP_QUIESCE:
44120Sstevel@tonic-gate 			/* rsmseg_suspend already done for seg */
44130Sstevel@tonic-gate 			*susp_flg = 1;
44140Sstevel@tonic-gate 			break;
44150Sstevel@tonic-gate 		case RSM_STATE_DISCONNECT:
44160Sstevel@tonic-gate 			break;
44170Sstevel@tonic-gate 		default:
44180Sstevel@tonic-gate 			ASSERT(0); /* invalid state */
44190Sstevel@tonic-gate 		}
44200Sstevel@tonic-gate 	} while (recheck_state);
44210Sstevel@tonic-gate 
44220Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmseg_suspend done\n"));
44230Sstevel@tonic-gate }
44240Sstevel@tonic-gate 
44250Sstevel@tonic-gate static void
rsmsegshare_suspend(rsmseg_t * seg)44260Sstevel@tonic-gate rsmsegshare_suspend(rsmseg_t *seg)
44270Sstevel@tonic-gate {
44280Sstevel@tonic-gate 	int			e;
44290Sstevel@tonic-gate 	adapter_t		*adapter;
44300Sstevel@tonic-gate 	rsm_import_share_t	*sharedp;
44310Sstevel@tonic-gate 	DBG_DEFINE(category,
44320Sstevel@tonic-gate 	    RSM_KERNEL_AGENT | RSM_FUNC_ALL | RSM_INTR_CALLBACK);
44330Sstevel@tonic-gate 
44340Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
44350Sstevel@tonic-gate 	    "rsmsegshare_suspend enter\n"));
44360Sstevel@tonic-gate 
44370Sstevel@tonic-gate 	rsmseglock_acquire(seg);
44380Sstevel@tonic-gate 	rsmsharelock_acquire(seg);
44390Sstevel@tonic-gate 
44400Sstevel@tonic-gate 	sharedp = seg->s_share;
44410Sstevel@tonic-gate 	adapter = seg->s_adapter;
44420Sstevel@tonic-gate 	switch (sharedp->rsmsi_state) {
44430Sstevel@tonic-gate 	case RSMSI_STATE_NEW:
44440Sstevel@tonic-gate 		break;
44450Sstevel@tonic-gate 	case RSMSI_STATE_CONNECTING:
44460Sstevel@tonic-gate 		sharedp->rsmsi_state = RSMSI_STATE_ABORT_CONNECT;
44470Sstevel@tonic-gate 		break;
44480Sstevel@tonic-gate 	case RSMSI_STATE_ABORT_CONNECT:
44490Sstevel@tonic-gate 		break;
44500Sstevel@tonic-gate 	case RSMSI_STATE_CONNECTED:
44510Sstevel@tonic-gate 		/* do the rsmpi disconnect */
44520Sstevel@tonic-gate 		if (sharedp->rsmsi_node != my_nodeid) {
44530Sstevel@tonic-gate 			e = adapter->rsmpi_ops->
44540Sstevel@tonic-gate 			    rsm_disconnect(sharedp->rsmsi_handle);
44550Sstevel@tonic-gate 
44560Sstevel@tonic-gate 			DBG_PRINTF((category, RSM_DEBUG,
44570Sstevel@tonic-gate 			    "rsm:rsmpi disconnect seg=%x:err=%d\n",
44580Sstevel@tonic-gate 			    sharedp->rsmsi_segid, e));
44590Sstevel@tonic-gate 		}
44600Sstevel@tonic-gate 
44610Sstevel@tonic-gate 		sharedp->rsmsi_handle = NULL;
44620Sstevel@tonic-gate 
44630Sstevel@tonic-gate 		sharedp->rsmsi_state = RSMSI_STATE_CONN_QUIESCE;
44640Sstevel@tonic-gate 		break;
44650Sstevel@tonic-gate 	case RSMSI_STATE_CONN_QUIESCE:
44660Sstevel@tonic-gate 		break;
44670Sstevel@tonic-gate 	case RSMSI_STATE_MAPPED:
44680Sstevel@tonic-gate 		/* do the rsmpi unmap and disconnect */
44690Sstevel@tonic-gate 		if (sharedp->rsmsi_node != my_nodeid) {
44700Sstevel@tonic-gate 			e = adapter->rsmpi_ops->rsm_unmap(seg->s_handle.in);
44710Sstevel@tonic-gate 
44720Sstevel@tonic-gate 			DBG_PRINTF((category, RSM_DEBUG,
44730Sstevel@tonic-gate 			    "rsmshare_suspend: rsmpi unmap %d\n", e));
44740Sstevel@tonic-gate 
44750Sstevel@tonic-gate 			e = adapter->rsmpi_ops->
44760Sstevel@tonic-gate 			    rsm_disconnect(sharedp->rsmsi_handle);
44770Sstevel@tonic-gate 			DBG_PRINTF((category, RSM_DEBUG,
44780Sstevel@tonic-gate 			    "rsm:rsmpi disconnect seg=%x:err=%d\n",
44790Sstevel@tonic-gate 			    sharedp->rsmsi_segid, e));
44800Sstevel@tonic-gate 		}
44810Sstevel@tonic-gate 
44820Sstevel@tonic-gate 		sharedp->rsmsi_handle = NULL;
44830Sstevel@tonic-gate 
44840Sstevel@tonic-gate 		sharedp->rsmsi_state = RSMSI_STATE_MAP_QUIESCE;
44850Sstevel@tonic-gate 		break;
44860Sstevel@tonic-gate 	case RSMSI_STATE_MAP_QUIESCE:
44870Sstevel@tonic-gate 		break;
44880Sstevel@tonic-gate 	case RSMSI_STATE_DISCONNECTED:
44890Sstevel@tonic-gate 		break;
44900Sstevel@tonic-gate 	default:
44910Sstevel@tonic-gate 		ASSERT(0); /* invalid state */
44920Sstevel@tonic-gate 	}
44930Sstevel@tonic-gate 
44940Sstevel@tonic-gate 	rsmsharelock_release(seg);
44950Sstevel@tonic-gate 	rsmseglock_release(seg);
44960Sstevel@tonic-gate 
44970Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
44980Sstevel@tonic-gate 	    "rsmsegshare_suspend done\n"));
44990Sstevel@tonic-gate }
45000Sstevel@tonic-gate 
45010Sstevel@tonic-gate /*
45020Sstevel@tonic-gate  * This should get called on receiving a RESUME message or from
45030Sstevel@tonic-gate  * the pathmanger if the node undergoing DR dies.
45040Sstevel@tonic-gate  */
45050Sstevel@tonic-gate static void
importer_resume(rsm_node_id_t src_node)45060Sstevel@tonic-gate importer_resume(rsm_node_id_t src_node)
45070Sstevel@tonic-gate {
45080Sstevel@tonic-gate 	int		i;
45090Sstevel@tonic-gate 	rsmresource_t	*p = NULL;
45100Sstevel@tonic-gate 	rsmhash_table_t *rhash = &rsm_import_segs;
45110Sstevel@tonic-gate 	void		*cookie;
45120Sstevel@tonic-gate 	DBG_DEFINE(category,
45130Sstevel@tonic-gate 	    RSM_KERNEL_AGENT | RSM_FUNC_ALL | RSM_INTR_CALLBACK);
45140Sstevel@tonic-gate 
45150Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "importer_resume enter\n"));
45160Sstevel@tonic-gate 
45170Sstevel@tonic-gate 	rw_enter(&rhash->rsmhash_rw, RW_READER);
45180Sstevel@tonic-gate 
45190Sstevel@tonic-gate 	for (i = 0; i < rsm_hash_size; i++) {
45200Sstevel@tonic-gate 		p = rhash->bucket[i];
45210Sstevel@tonic-gate 
45220Sstevel@tonic-gate 		for (; p; p = p->rsmrc_next) {
45230Sstevel@tonic-gate 			rsmseg_t *seg = (rsmseg_t *)p;
45240Sstevel@tonic-gate 
45250Sstevel@tonic-gate 			rsmseglock_acquire(seg);
45260Sstevel@tonic-gate 
45270Sstevel@tonic-gate 			/* process only importers of node undergoing DR */
45280Sstevel@tonic-gate 			if (seg->s_node != src_node) {
45290Sstevel@tonic-gate 				rsmseglock_release(seg);
45300Sstevel@tonic-gate 				continue;
45310Sstevel@tonic-gate 			}
45320Sstevel@tonic-gate 
45330Sstevel@tonic-gate 			if (rsmseg_resume(seg, &cookie) != RSM_SUCCESS) {
45340Sstevel@tonic-gate 				rsmipc_request_t	request;
45350Sstevel@tonic-gate 				/*
45360Sstevel@tonic-gate 				 * rsmpi map/connect failed
45370Sstevel@tonic-gate 				 * inform the exporter so that it can
45380Sstevel@tonic-gate 				 * remove the importer.
45390Sstevel@tonic-gate 				 */
45400Sstevel@tonic-gate 				request.rsmipc_hdr.rsmipc_type =
45410Sstevel@tonic-gate 				    RSMIPC_MSG_NOTIMPORTING;
45420Sstevel@tonic-gate 				request.rsmipc_key = seg->s_segid;
45430Sstevel@tonic-gate 				request.rsmipc_segment_cookie = cookie;
45440Sstevel@tonic-gate 				rsmseglock_release(seg);
45450Sstevel@tonic-gate 				(void) rsmipc_send(seg->s_node, &request,
45467656SSherry.Moore@Sun.COM 				    RSM_NO_REPLY);
45470Sstevel@tonic-gate 			} else {
45480Sstevel@tonic-gate 				rsmseglock_release(seg);
45490Sstevel@tonic-gate 			}
45500Sstevel@tonic-gate 		}
45510Sstevel@tonic-gate 	}
45520Sstevel@tonic-gate 
45530Sstevel@tonic-gate 	rw_exit(&rhash->rsmhash_rw);
45540Sstevel@tonic-gate 
45550Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "importer_resume done\n"));
45560Sstevel@tonic-gate }
45570Sstevel@tonic-gate 
45580Sstevel@tonic-gate static int
rsmseg_resume(rsmseg_t * seg,void ** cookie)45590Sstevel@tonic-gate rsmseg_resume(rsmseg_t *seg, void **cookie)
45600Sstevel@tonic-gate {
45610Sstevel@tonic-gate 	int			e;
45620Sstevel@tonic-gate 	int			retc;
45630Sstevel@tonic-gate 	off_t			dev_offset;
45640Sstevel@tonic-gate 	size_t			maplen;
45650Sstevel@tonic-gate 	uint_t			maxprot;
45660Sstevel@tonic-gate 	rsm_mapinfo_t		*p;
45670Sstevel@tonic-gate 	rsmcookie_t		*hdl;
45680Sstevel@tonic-gate 	rsm_import_share_t	*sharedp;
45690Sstevel@tonic-gate 	DBG_DEFINE(category,
45700Sstevel@tonic-gate 	    RSM_KERNEL_AGENT | RSM_FUNC_ALL | RSM_INTR_CALLBACK);
45710Sstevel@tonic-gate 
45720Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
45730Sstevel@tonic-gate 	    "rsmseg_resume enter: key=%u\n", seg->s_key));
45740Sstevel@tonic-gate 
45750Sstevel@tonic-gate 	*cookie = NULL;
45760Sstevel@tonic-gate 
45770Sstevel@tonic-gate 	ASSERT(rsmseglock_held(seg));
45780Sstevel@tonic-gate 
45790Sstevel@tonic-gate 	if ((seg->s_state != RSM_STATE_CONN_QUIESCE) &&
45800Sstevel@tonic-gate 	    (seg->s_state != RSM_STATE_MAP_QUIESCE)) {
45810Sstevel@tonic-gate 		return (RSM_SUCCESS);
45820Sstevel@tonic-gate 	}
45830Sstevel@tonic-gate 
45840Sstevel@tonic-gate 	sharedp = seg->s_share;
45850Sstevel@tonic-gate 
45860Sstevel@tonic-gate 	rsmsharelock_acquire(seg);
45870Sstevel@tonic-gate 
45880Sstevel@tonic-gate 	/* resume the shared connection and/or mapping */
45890Sstevel@tonic-gate 	retc = rsmsegshare_resume(seg);
45900Sstevel@tonic-gate 
45910Sstevel@tonic-gate 	if (seg->s_state == RSM_STATE_CONN_QUIESCE) {
45920Sstevel@tonic-gate 		/* shared state can either be connected or mapped */
45930Sstevel@tonic-gate 		if ((sharedp->rsmsi_state == RSMSI_STATE_CONNECTED) ||
45940Sstevel@tonic-gate 		    (sharedp->rsmsi_state == RSMSI_STATE_MAPPED)) {
45950Sstevel@tonic-gate 			ASSERT(retc == RSM_SUCCESS);
45960Sstevel@tonic-gate 			seg->s_handle.in = sharedp->rsmsi_handle;
45970Sstevel@tonic-gate 			rsmsharelock_release(seg);
45980Sstevel@tonic-gate 			seg->s_state = RSM_STATE_CONNECT;
45990Sstevel@tonic-gate 
46000Sstevel@tonic-gate 		} else { /* error in rsmpi connect during resume */
46010Sstevel@tonic-gate 			seg->s_handle.in = NULL;
46020Sstevel@tonic-gate 			seg->s_state = RSM_STATE_DISCONNECT;
46030Sstevel@tonic-gate 
46040Sstevel@tonic-gate 			sharedp->rsmsi_refcnt--;
46050Sstevel@tonic-gate 			cookie = (void *)sharedp->rsmsi_cookie;
46060Sstevel@tonic-gate 
46070Sstevel@tonic-gate 			if (sharedp->rsmsi_refcnt == 0) {
46080Sstevel@tonic-gate 				ASSERT(sharedp->rsmsi_mapcnt == 0);
46090Sstevel@tonic-gate 				rsmsharelock_release(seg);
46100Sstevel@tonic-gate 
46110Sstevel@tonic-gate 				/* clean up the shared data structure */
46120Sstevel@tonic-gate 				mutex_destroy(&sharedp->rsmsi_lock);
46130Sstevel@tonic-gate 				cv_destroy(&sharedp->rsmsi_cv);
46140Sstevel@tonic-gate 				kmem_free((void *)(sharedp),
46150Sstevel@tonic-gate 				    sizeof (rsm_import_share_t));
46160Sstevel@tonic-gate 
46170Sstevel@tonic-gate 			} else {
46180Sstevel@tonic-gate 				rsmsharelock_release(seg);
46190Sstevel@tonic-gate 			}
46200Sstevel@tonic-gate 			/*
46210Sstevel@tonic-gate 			 * The following needs to be done after any
46220Sstevel@tonic-gate 			 * rsmsharelock calls which use seg->s_share.
46230Sstevel@tonic-gate 			 */
46240Sstevel@tonic-gate 			seg->s_share = NULL;
46250Sstevel@tonic-gate 		}
46260Sstevel@tonic-gate 
46270Sstevel@tonic-gate 		/* signal any waiting segment */
46280Sstevel@tonic-gate 		cv_broadcast(&seg->s_cv);
46290Sstevel@tonic-gate 
46300Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
46310Sstevel@tonic-gate 		    "rsmseg_resume done:state=%d\n", seg->s_state));
46320Sstevel@tonic-gate 		return (retc);
46330Sstevel@tonic-gate 	}
46340Sstevel@tonic-gate 
46350Sstevel@tonic-gate 	ASSERT(seg->s_state == RSM_STATE_MAP_QUIESCE);
46360Sstevel@tonic-gate 
46370Sstevel@tonic-gate 	/* Setup protections for remap */
46380Sstevel@tonic-gate 	maxprot = PROT_USER;
46390Sstevel@tonic-gate 	if (seg->s_mode & RSM_PERM_READ) {
46400Sstevel@tonic-gate 		maxprot |= PROT_READ;
46410Sstevel@tonic-gate 	}
46420Sstevel@tonic-gate 	if (seg->s_mode & RSM_PERM_WRITE) {
46430Sstevel@tonic-gate 		maxprot |= PROT_WRITE;
46440Sstevel@tonic-gate 	}
46450Sstevel@tonic-gate 
46460Sstevel@tonic-gate 	if (sharedp->rsmsi_state != RSMSI_STATE_MAPPED) {
46470Sstevel@tonic-gate 		/* error in rsmpi connect or map during resume */
46480Sstevel@tonic-gate 
46490Sstevel@tonic-gate 		/* remap to trash page */
46500Sstevel@tonic-gate 		ASSERT(seg->s_ckl != NULL);
46510Sstevel@tonic-gate 
46520Sstevel@tonic-gate 		for (hdl = seg->s_ckl; hdl != NULL; hdl = hdl->c_next) {
46530Sstevel@tonic-gate 			e = devmap_umem_remap(hdl->c_dhp, rsm_dip,
46540Sstevel@tonic-gate 			    remap_cookie, hdl->c_off, hdl->c_len,
46550Sstevel@tonic-gate 			    maxprot, 0, NULL);
46560Sstevel@tonic-gate 
46570Sstevel@tonic-gate 			DBG_PRINTF((category, RSM_ERR,
46580Sstevel@tonic-gate 			    "rsmseg_resume:remap=%d\n", e));
46590Sstevel@tonic-gate 		}
46600Sstevel@tonic-gate 
46610Sstevel@tonic-gate 		seg->s_handle.in = NULL;
46620Sstevel@tonic-gate 		seg->s_state = RSM_STATE_DISCONNECT;
46630Sstevel@tonic-gate 
46640Sstevel@tonic-gate 		sharedp->rsmsi_refcnt--;
46650Sstevel@tonic-gate 
46660Sstevel@tonic-gate 		sharedp->rsmsi_mapcnt--;
46670Sstevel@tonic-gate 		seg->s_mapinfo = NULL;
46680Sstevel@tonic-gate 
46690Sstevel@tonic-gate 		if (sharedp->rsmsi_refcnt == 0) {
46700Sstevel@tonic-gate 			ASSERT(sharedp->rsmsi_mapcnt == 0);
46710Sstevel@tonic-gate 			rsmsharelock_release(seg);
46720Sstevel@tonic-gate 
46730Sstevel@tonic-gate 			/* clean up the shared data structure */
46740Sstevel@tonic-gate 			mutex_destroy(&sharedp->rsmsi_lock);
46750Sstevel@tonic-gate 			cv_destroy(&sharedp->rsmsi_cv);
46760Sstevel@tonic-gate 			kmem_free((void *)(sharedp),
46770Sstevel@tonic-gate 			    sizeof (rsm_import_share_t));
46780Sstevel@tonic-gate 
46790Sstevel@tonic-gate 		} else {
46800Sstevel@tonic-gate 			rsmsharelock_release(seg);
46810Sstevel@tonic-gate 		}
46820Sstevel@tonic-gate 		/*
46830Sstevel@tonic-gate 		 * The following needs to be done after any
46840Sstevel@tonic-gate 		 * rsmsharelock calls which use seg->s_share.
46850Sstevel@tonic-gate 		 */
46860Sstevel@tonic-gate 		seg->s_share = NULL;
46870Sstevel@tonic-gate 
46880Sstevel@tonic-gate 		/* signal any waiting segment */
46890Sstevel@tonic-gate 		cv_broadcast(&seg->s_cv);
46900Sstevel@tonic-gate 
46910Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
46920Sstevel@tonic-gate 		    "rsmseg_resume done:seg=%x,err=%d\n",
46930Sstevel@tonic-gate 		    seg->s_key, retc));
46940Sstevel@tonic-gate 		return (retc);
46950Sstevel@tonic-gate 
46960Sstevel@tonic-gate 	}
46970Sstevel@tonic-gate 
46980Sstevel@tonic-gate 	seg->s_handle.in = sharedp->rsmsi_handle;
46990Sstevel@tonic-gate 
47000Sstevel@tonic-gate 	if (seg->s_node == my_nodeid) { /* loopback */
47010Sstevel@tonic-gate 		ASSERT(seg->s_mapinfo == NULL);
47020Sstevel@tonic-gate 
47030Sstevel@tonic-gate 		for (hdl = seg->s_ckl; hdl != NULL; hdl = hdl->c_next) {
47040Sstevel@tonic-gate 			e = devmap_umem_remap(hdl->c_dhp,
47050Sstevel@tonic-gate 			    rsm_dip, seg->s_cookie,
47060Sstevel@tonic-gate 			    hdl->c_off, hdl->c_len,
47070Sstevel@tonic-gate 			    maxprot, 0, NULL);
47080Sstevel@tonic-gate 
47090Sstevel@tonic-gate 			DBG_PRINTF((category, RSM_ERR,
47100Sstevel@tonic-gate 			    "rsmseg_resume:remap=%d\n", e));
47110Sstevel@tonic-gate 		}
47120Sstevel@tonic-gate 	} else { /* remote exporter */
47130Sstevel@tonic-gate 		/* remap to the new rsmpi maps */
47140Sstevel@tonic-gate 		seg->s_mapinfo = sharedp->rsmsi_mapinfo;
47150Sstevel@tonic-gate 
47160Sstevel@tonic-gate 		for (hdl = seg->s_ckl; hdl != NULL; hdl = hdl->c_next) {
47170Sstevel@tonic-gate 			p = rsm_get_mapinfo(seg, hdl->c_off, hdl->c_len,
47180Sstevel@tonic-gate 			    &dev_offset, &maplen);
47190Sstevel@tonic-gate 			e = devmap_devmem_remap(hdl->c_dhp,
47200Sstevel@tonic-gate 			    p->dip, p->dev_register, dev_offset,
47210Sstevel@tonic-gate 			    maplen, maxprot, 0, NULL);
47220Sstevel@tonic-gate 
47230Sstevel@tonic-gate 			DBG_PRINTF((category, RSM_ERR,
47240Sstevel@tonic-gate 			    "rsmseg_resume:remap=%d\n", e));
47250Sstevel@tonic-gate 		}
47260Sstevel@tonic-gate 	}
47270Sstevel@tonic-gate 
47280Sstevel@tonic-gate 	rsmsharelock_release(seg);
47290Sstevel@tonic-gate 
47300Sstevel@tonic-gate 	seg->s_state = RSM_STATE_ACTIVE;
47310Sstevel@tonic-gate 	cv_broadcast(&seg->s_cv);
47320Sstevel@tonic-gate 
47330Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmseg_resume done\n"));
47340Sstevel@tonic-gate 
47350Sstevel@tonic-gate 	return (retc);
47360Sstevel@tonic-gate }
47370Sstevel@tonic-gate 
47380Sstevel@tonic-gate static int
rsmsegshare_resume(rsmseg_t * seg)47390Sstevel@tonic-gate rsmsegshare_resume(rsmseg_t *seg)
47400Sstevel@tonic-gate {
47410Sstevel@tonic-gate 	int			e = RSM_SUCCESS;
47420Sstevel@tonic-gate 	adapter_t		*adapter;
47430Sstevel@tonic-gate 	rsm_import_share_t	*sharedp;
47440Sstevel@tonic-gate 	DBG_DEFINE(category,
47450Sstevel@tonic-gate 	    RSM_KERNEL_AGENT | RSM_FUNC_ALL | RSM_INTR_CALLBACK);
47460Sstevel@tonic-gate 
47470Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmsegshare_resume enter\n"));
47480Sstevel@tonic-gate 
47490Sstevel@tonic-gate 	ASSERT(rsmseglock_held(seg));
47500Sstevel@tonic-gate 	ASSERT(rsmsharelock_held(seg));
47510Sstevel@tonic-gate 
47520Sstevel@tonic-gate 	sharedp = seg->s_share;
47530Sstevel@tonic-gate 
47540Sstevel@tonic-gate 	/*
47550Sstevel@tonic-gate 	 * If we are not in a xxxx_QUIESCE state that means shared
47560Sstevel@tonic-gate 	 * connect/mapping processing has been already been done
47570Sstevel@tonic-gate 	 * so return success.
47580Sstevel@tonic-gate 	 */
47590Sstevel@tonic-gate 	if ((sharedp->rsmsi_state != RSMSI_STATE_CONN_QUIESCE) &&
47600Sstevel@tonic-gate 	    (sharedp->rsmsi_state != RSMSI_STATE_MAP_QUIESCE)) {
47610Sstevel@tonic-gate 		return (RSM_SUCCESS);
47620Sstevel@tonic-gate 	}
47630Sstevel@tonic-gate 
47640Sstevel@tonic-gate 	adapter = seg->s_adapter;
47650Sstevel@tonic-gate 
47660Sstevel@tonic-gate 	if (sharedp->rsmsi_node != my_nodeid) {
47670Sstevel@tonic-gate 		rsm_addr_t	hwaddr;
47680Sstevel@tonic-gate 		hwaddr = get_remote_hwaddr(adapter, sharedp->rsmsi_node);
47690Sstevel@tonic-gate 
47700Sstevel@tonic-gate 		e = adapter->rsmpi_ops->rsm_connect(
47710Sstevel@tonic-gate 		    adapter->rsmpi_handle, hwaddr,
47720Sstevel@tonic-gate 		    sharedp->rsmsi_segid, &sharedp->rsmsi_handle);
47730Sstevel@tonic-gate 
47740Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_DEBUG,
47750Sstevel@tonic-gate 		    "rsmsegshare_resume:rsmpi connect seg=%x:err=%d\n",
47760Sstevel@tonic-gate 		    sharedp->rsmsi_segid, e));
47770Sstevel@tonic-gate 
47780Sstevel@tonic-gate 		if (e != RSM_SUCCESS) {
47790Sstevel@tonic-gate 			/* when do we send the NOT_IMPORTING message */
47800Sstevel@tonic-gate 			sharedp->rsmsi_handle = NULL;
47810Sstevel@tonic-gate 			sharedp->rsmsi_state = RSMSI_STATE_DISCONNECTED;
47820Sstevel@tonic-gate 			/* signal any waiting segment */
47830Sstevel@tonic-gate 			cv_broadcast(&sharedp->rsmsi_cv);
47840Sstevel@tonic-gate 			return (e);
47850Sstevel@tonic-gate 		}
47860Sstevel@tonic-gate 	}
47870Sstevel@tonic-gate 
47880Sstevel@tonic-gate 	if (sharedp->rsmsi_state == RSMSI_STATE_CONN_QUIESCE) {
47890Sstevel@tonic-gate 		sharedp->rsmsi_state = RSMSI_STATE_CONNECTED;
47900Sstevel@tonic-gate 		/* signal any waiting segment */
47910Sstevel@tonic-gate 		cv_broadcast(&sharedp->rsmsi_cv);
47920Sstevel@tonic-gate 		return (e);
47930Sstevel@tonic-gate 	}
47940Sstevel@tonic-gate 
47950Sstevel@tonic-gate 	ASSERT(sharedp->rsmsi_state == RSMSI_STATE_MAP_QUIESCE);
47960Sstevel@tonic-gate 
47970Sstevel@tonic-gate 	/* do the rsmpi map of the whole segment here */
47980Sstevel@tonic-gate 	if (sharedp->rsmsi_node != my_nodeid) {
47990Sstevel@tonic-gate 		size_t mapped_len;
48000Sstevel@tonic-gate 		rsm_mapinfo_t *p;
48010Sstevel@tonic-gate 
48020Sstevel@tonic-gate 		/*
48030Sstevel@tonic-gate 		 * We need to do rsmpi maps with <off, lens> identical to
48040Sstevel@tonic-gate 		 * the old mapinfo list because the segment mapping handles
48050Sstevel@tonic-gate 		 * dhp and such need the fragmentation of rsmpi maps to be
48060Sstevel@tonic-gate 		 * identical to what it was during the mmap of the segment
48070Sstevel@tonic-gate 		 */
48080Sstevel@tonic-gate 		p = sharedp->rsmsi_mapinfo;
48090Sstevel@tonic-gate 
48100Sstevel@tonic-gate 		while (p != NULL) {
48110Sstevel@tonic-gate 			mapped_len = 0;
48120Sstevel@tonic-gate 
48130Sstevel@tonic-gate 			e = adapter->rsmpi_ops->rsm_map(
48140Sstevel@tonic-gate 			    sharedp->rsmsi_handle, p->start_offset,
48150Sstevel@tonic-gate 			    p->individual_len, &mapped_len,
48160Sstevel@tonic-gate 			    &p->dip, &p->dev_register, &p->dev_offset,
48170Sstevel@tonic-gate 			    NULL, NULL);
48180Sstevel@tonic-gate 
48190Sstevel@tonic-gate 			if (e != 0) {
48200Sstevel@tonic-gate 				DBG_PRINTF((category, RSM_ERR,
48210Sstevel@tonic-gate 				    "rsmsegshare_resume: rsmpi map err=%d\n",
48220Sstevel@tonic-gate 				    e));
48230Sstevel@tonic-gate 				break;
48240Sstevel@tonic-gate 			}
48250Sstevel@tonic-gate 
48260Sstevel@tonic-gate 			if (mapped_len != p->individual_len) {
48270Sstevel@tonic-gate 				DBG_PRINTF((category, RSM_ERR,
48280Sstevel@tonic-gate 				    "rsmsegshare_resume: rsmpi maplen"
48290Sstevel@tonic-gate 				    "< reqlen=%lx\n", mapped_len));
48300Sstevel@tonic-gate 				e = RSMERR_BAD_LENGTH;
48310Sstevel@tonic-gate 				break;
48320Sstevel@tonic-gate 			}
48330Sstevel@tonic-gate 
48340Sstevel@tonic-gate 			p = p->next;
48350Sstevel@tonic-gate 
48360Sstevel@tonic-gate 		}
48370Sstevel@tonic-gate 
48380Sstevel@tonic-gate 
48390Sstevel@tonic-gate 		if (e != RSM_SUCCESS) { /* rsmpi map failed */
48400Sstevel@tonic-gate 			int	err;
48410Sstevel@tonic-gate 			/* Check if this is the first rsm_map */
48420Sstevel@tonic-gate 			if (p != sharedp->rsmsi_mapinfo) {
48430Sstevel@tonic-gate 				/*
48440Sstevel@tonic-gate 				 * A single rsm_unmap undoes multiple rsm_maps.
48450Sstevel@tonic-gate 				 */
48460Sstevel@tonic-gate 				(void) seg->s_adapter->rsmpi_ops->
48470Sstevel@tonic-gate 				    rsm_unmap(sharedp->rsmsi_handle);
48480Sstevel@tonic-gate 			}
48490Sstevel@tonic-gate 
48500Sstevel@tonic-gate 			rsm_free_mapinfo(sharedp->rsmsi_mapinfo);
48510Sstevel@tonic-gate 			sharedp->rsmsi_mapinfo = NULL;
48520Sstevel@tonic-gate 
48530Sstevel@tonic-gate 			err = adapter->rsmpi_ops->
48547656SSherry.Moore@Sun.COM 			    rsm_disconnect(sharedp->rsmsi_handle);
48550Sstevel@tonic-gate 
48560Sstevel@tonic-gate 			DBG_PRINTF((category, RSM_DEBUG,
48570Sstevel@tonic-gate 			    "rsmsegshare_resume:disconn seg=%x:err=%d\n",
48580Sstevel@tonic-gate 			    sharedp->rsmsi_segid, err));
48590Sstevel@tonic-gate 
48600Sstevel@tonic-gate 			sharedp->rsmsi_handle = NULL;
48610Sstevel@tonic-gate 			sharedp->rsmsi_state = RSMSI_STATE_DISCONNECTED;
48620Sstevel@tonic-gate 
48630Sstevel@tonic-gate 			/* signal the waiting segments */
48640Sstevel@tonic-gate 			cv_broadcast(&sharedp->rsmsi_cv);
48650Sstevel@tonic-gate 			DBG_PRINTF((category, RSM_DEBUG,
48660Sstevel@tonic-gate 			    "rsmsegshare_resume done: rsmpi map err\n"));
48670Sstevel@tonic-gate 			return (e);
48680Sstevel@tonic-gate 		}
48690Sstevel@tonic-gate 	}
48700Sstevel@tonic-gate 
48710Sstevel@tonic-gate 	sharedp->rsmsi_state = RSMSI_STATE_MAPPED;
48720Sstevel@tonic-gate 
48730Sstevel@tonic-gate 	/* signal any waiting segment */
48740Sstevel@tonic-gate 	cv_broadcast(&sharedp->rsmsi_cv);
48750Sstevel@tonic-gate 
48760Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmsegshare_resume done\n"));
48770Sstevel@tonic-gate 
48780Sstevel@tonic-gate 	return (e);
48790Sstevel@tonic-gate }
48800Sstevel@tonic-gate 
48810Sstevel@tonic-gate /*
48820Sstevel@tonic-gate  * this is the routine that gets called by recv_taskq which is the
48830Sstevel@tonic-gate  * thread that processes messages that are flow-controlled.
48840Sstevel@tonic-gate  */
48850Sstevel@tonic-gate static void
rsm_intr_proc_deferred(void * arg)48860Sstevel@tonic-gate rsm_intr_proc_deferred(void *arg)
48870Sstevel@tonic-gate {
48880Sstevel@tonic-gate 	path_t			*path = (path_t *)arg;
48890Sstevel@tonic-gate 	rsmipc_request_t	*msg;
48900Sstevel@tonic-gate 	rsmipc_msghdr_t		*msghdr;
48910Sstevel@tonic-gate 	rsm_node_id_t		src_node;
48920Sstevel@tonic-gate 	msgbuf_elem_t		*head;
48930Sstevel@tonic-gate 	int			e;
48940Sstevel@tonic-gate 	DBG_DEFINE(category,
48950Sstevel@tonic-gate 	    RSM_KERNEL_AGENT | RSM_FUNC_ALL | RSM_INTR_CALLBACK);
48960Sstevel@tonic-gate 
48970Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
48980Sstevel@tonic-gate 	    "rsm_intr_proc_deferred enter\n"));
48990Sstevel@tonic-gate 
49000Sstevel@tonic-gate 	mutex_enter(&path->mutex);
49010Sstevel@tonic-gate 
49020Sstevel@tonic-gate 	/* use the head of the msgbuf_queue */
49030Sstevel@tonic-gate 	head = rsmka_gethead_msgbuf(path);
49040Sstevel@tonic-gate 
49050Sstevel@tonic-gate 	mutex_exit(&path->mutex);
49060Sstevel@tonic-gate 
49070Sstevel@tonic-gate 	msg = (rsmipc_request_t *)&(head->msg);
49080Sstevel@tonic-gate 	msghdr = (rsmipc_msghdr_t *)msg;
49090Sstevel@tonic-gate 
49100Sstevel@tonic-gate 	src_node = msghdr->rsmipc_src;
49110Sstevel@tonic-gate 
49120Sstevel@tonic-gate 	/*
49130Sstevel@tonic-gate 	 * messages that need to send a reply should check the message version
49140Sstevel@tonic-gate 	 * before processing the message. And all messages that need to
49150Sstevel@tonic-gate 	 * send a reply should be processed here by the worker thread.
49160Sstevel@tonic-gate 	 */
49170Sstevel@tonic-gate 	switch (msghdr->rsmipc_type) {
49180Sstevel@tonic-gate 	case RSMIPC_MSG_SEGCONNECT:
49190Sstevel@tonic-gate 		if (msghdr->rsmipc_version != RSM_VERSION) {
49200Sstevel@tonic-gate 			rsmipc_reply_t reply;
49210Sstevel@tonic-gate 			reply.rsmipc_status = RSMERR_BAD_DRIVER_VERSION;
49220Sstevel@tonic-gate 			reply.rsmipc_hdr.rsmipc_type = RSMIPC_MSG_REPLY;
49230Sstevel@tonic-gate 			reply.rsmipc_hdr.rsmipc_cookie = msghdr->rsmipc_cookie;
49240Sstevel@tonic-gate 			(void) rsmipc_send(msghdr->rsmipc_src, NULL, &reply);
49250Sstevel@tonic-gate 		} else {
49260Sstevel@tonic-gate 			rsm_intr_segconnect(src_node, msg);
49270Sstevel@tonic-gate 		}
49280Sstevel@tonic-gate 		break;
49290Sstevel@tonic-gate 	case RSMIPC_MSG_DISCONNECT:
49300Sstevel@tonic-gate 		rsm_force_unload(src_node, msg->rsmipc_key, DISCONNECT);
49310Sstevel@tonic-gate 		break;
49320Sstevel@tonic-gate 	case RSMIPC_MSG_SUSPEND:
49330Sstevel@tonic-gate 		importer_suspend(src_node);
49340Sstevel@tonic-gate 		break;
49350Sstevel@tonic-gate 	case RSMIPC_MSG_SUSPEND_DONE:
49360Sstevel@tonic-gate 		rsm_suspend_complete(src_node, 0);
49370Sstevel@tonic-gate 		break;
49380Sstevel@tonic-gate 	case RSMIPC_MSG_RESUME:
49390Sstevel@tonic-gate 		importer_resume(src_node);
49400Sstevel@tonic-gate 		break;
49410Sstevel@tonic-gate 	default:
49420Sstevel@tonic-gate 		ASSERT(0);
49430Sstevel@tonic-gate 	}
49440Sstevel@tonic-gate 
49450Sstevel@tonic-gate 	mutex_enter(&path->mutex);
49460Sstevel@tonic-gate 
49470Sstevel@tonic-gate 	rsmka_dequeue_msgbuf(path);
49480Sstevel@tonic-gate 
49490Sstevel@tonic-gate 	/* incr procmsg_cnt can be at most RSMIPC_MAX_MESSAGES */
49500Sstevel@tonic-gate 	if (path->procmsg_cnt < RSMIPC_MAX_MESSAGES)
49510Sstevel@tonic-gate 		path->procmsg_cnt++;
49520Sstevel@tonic-gate 
49530Sstevel@tonic-gate 	ASSERT(path->procmsg_cnt <= RSMIPC_MAX_MESSAGES);
49540Sstevel@tonic-gate 
49550Sstevel@tonic-gate 	/* No need to send credits if path is going down */
49560Sstevel@tonic-gate 	if ((path->state == RSMKA_PATH_ACTIVE) &&
49570Sstevel@tonic-gate 	    (path->procmsg_cnt >= RSMIPC_LOTSFREE_MSGBUFS)) {
49580Sstevel@tonic-gate 		/*
49590Sstevel@tonic-gate 		 * send credits and reset procmsg_cnt if success otherwise
49600Sstevel@tonic-gate 		 * credits will be sent after processing the next message
49610Sstevel@tonic-gate 		 */
49620Sstevel@tonic-gate 		e = rsmipc_send_controlmsg(path, RSMIPC_MSG_CREDIT);
49630Sstevel@tonic-gate 		if (e == 0)
49640Sstevel@tonic-gate 			path->procmsg_cnt = 0;
49650Sstevel@tonic-gate 		else
49660Sstevel@tonic-gate 			DBG_PRINTF((category, RSM_ERR,
49670Sstevel@tonic-gate 			    "rsm_intr_proc_deferred:send credits err=%d\n", e));
49680Sstevel@tonic-gate 	}
49690Sstevel@tonic-gate 
49700Sstevel@tonic-gate 	/*
49710Sstevel@tonic-gate 	 * decrement the path refcnt since we incremented it in
49720Sstevel@tonic-gate 	 * rsm_intr_callback_dispatch
49730Sstevel@tonic-gate 	 */
49740Sstevel@tonic-gate 	PATH_RELE_NOLOCK(path);
49750Sstevel@tonic-gate 
49760Sstevel@tonic-gate 	mutex_exit(&path->mutex);
49770Sstevel@tonic-gate 
49780Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
49790Sstevel@tonic-gate 	    "rsm_intr_proc_deferred done\n"));
49800Sstevel@tonic-gate }
49810Sstevel@tonic-gate 
49820Sstevel@tonic-gate /*
49830Sstevel@tonic-gate  * Flow-controlled messages are enqueued and dispatched onto a taskq here
49840Sstevel@tonic-gate  */
49850Sstevel@tonic-gate static void
rsm_intr_callback_dispatch(void * data,rsm_addr_t src_hwaddr,rsm_intr_hand_arg_t arg)49860Sstevel@tonic-gate rsm_intr_callback_dispatch(void *data, rsm_addr_t src_hwaddr,
49870Sstevel@tonic-gate     rsm_intr_hand_arg_t arg)
49880Sstevel@tonic-gate {
49890Sstevel@tonic-gate 	srv_handler_arg_t	*hdlr_argp = (srv_handler_arg_t *)arg;
49900Sstevel@tonic-gate 	path_t			*path;
49910Sstevel@tonic-gate 	rsmipc_msghdr_t *msghdr = (rsmipc_msghdr_t *)data;
49920Sstevel@tonic-gate 	DBG_DEFINE(category,
49930Sstevel@tonic-gate 	    RSM_KERNEL_AGENT | RSM_FUNC_ALL | RSM_INTR_CALLBACK);
49940Sstevel@tonic-gate 
49950Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
49960Sstevel@tonic-gate 	    "rsm_intr_callback_dispatch enter\n"));
49970Sstevel@tonic-gate 	ASSERT(data && hdlr_argp);
49980Sstevel@tonic-gate 
49990Sstevel@tonic-gate 	/* look up the path - incr the path refcnt */
50000Sstevel@tonic-gate 	path = rsm_find_path(hdlr_argp->adapter_name,
50010Sstevel@tonic-gate 	    hdlr_argp->adapter_instance, src_hwaddr);
50020Sstevel@tonic-gate 
50030Sstevel@tonic-gate 	/* the path has been removed - drop this message */
50040Sstevel@tonic-gate 	if (path == NULL) {
50050Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_DEBUG,
50060Sstevel@tonic-gate 		    "rsm_intr_callback_dispatch done: msg dropped\n"));
50070Sstevel@tonic-gate 		return;
50080Sstevel@tonic-gate 	}
50090Sstevel@tonic-gate 	/* the path is not active - don't accept new messages */
50100Sstevel@tonic-gate 	if (path->state != RSMKA_PATH_ACTIVE) {
50110Sstevel@tonic-gate 		PATH_RELE_NOLOCK(path);
50120Sstevel@tonic-gate 		mutex_exit(&path->mutex);
50130Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_DEBUG,
50140Sstevel@tonic-gate 		    "rsm_intr_callback_dispatch done: msg dropped"
50150Sstevel@tonic-gate 		    " path=%lx !ACTIVE\n", path));
50160Sstevel@tonic-gate 		return;
50170Sstevel@tonic-gate 	}
50180Sstevel@tonic-gate 
50190Sstevel@tonic-gate 	/*
50200Sstevel@tonic-gate 	 * Check if this message was sent to an older incarnation
50210Sstevel@tonic-gate 	 * of the path/sendq.
50220Sstevel@tonic-gate 	 */
50230Sstevel@tonic-gate 	if (path->local_incn != msghdr->rsmipc_incn) {
50240Sstevel@tonic-gate 		/* decrement the refcnt */
50250Sstevel@tonic-gate 		PATH_RELE_NOLOCK(path);
50260Sstevel@tonic-gate 		mutex_exit(&path->mutex);
50270Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_DEBUG,
50280Sstevel@tonic-gate 		    "rsm_intr_callback_dispatch done: old incn %lld\n",
50290Sstevel@tonic-gate 		    msghdr->rsmipc_incn));
50300Sstevel@tonic-gate 		return;
50310Sstevel@tonic-gate 	}
50320Sstevel@tonic-gate 
50330Sstevel@tonic-gate 	/* copy and enqueue msg on the path's msgbuf queue */
50340Sstevel@tonic-gate 	rsmka_enqueue_msgbuf(path, data);
50350Sstevel@tonic-gate 
50360Sstevel@tonic-gate 	/*
50370Sstevel@tonic-gate 	 * schedule task to process messages - ignore retval from
50380Sstevel@tonic-gate 	 * task_dispatch because we sender cannot send more than
50390Sstevel@tonic-gate 	 * what receiver can handle.
50400Sstevel@tonic-gate 	 */
50410Sstevel@tonic-gate 	(void) taskq_dispatch(path->recv_taskq,
50420Sstevel@tonic-gate 	    rsm_intr_proc_deferred, path, KM_NOSLEEP);
50430Sstevel@tonic-gate 
50440Sstevel@tonic-gate 	mutex_exit(&path->mutex);
50450Sstevel@tonic-gate 
50460Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
50470Sstevel@tonic-gate 	    "rsm_intr_callback_dispatch done\n"));
50480Sstevel@tonic-gate }
50490Sstevel@tonic-gate 
50500Sstevel@tonic-gate /*
50510Sstevel@tonic-gate  * This procedure is called from rsm_srv_func when a remote node creates a
50520Sstevel@tonic-gate  * a send queue.  This event is used as a hint that an  earlier failed
50530Sstevel@tonic-gate  * attempt to create a send queue to that remote node may now succeed and
50540Sstevel@tonic-gate  * should be retried.  Indication of an earlier failed attempt is provided
50550Sstevel@tonic-gate  * by the RSMKA_SQCREATE_PENDING flag.
50560Sstevel@tonic-gate  */
50570Sstevel@tonic-gate static void
rsm_sqcreateop_callback(rsm_addr_t src_hwaddr,rsm_intr_hand_arg_t arg)50580Sstevel@tonic-gate rsm_sqcreateop_callback(rsm_addr_t src_hwaddr, rsm_intr_hand_arg_t arg)
50590Sstevel@tonic-gate {
50600Sstevel@tonic-gate 	srv_handler_arg_t	*hdlr_argp = (srv_handler_arg_t *)arg;
50610Sstevel@tonic-gate 	path_t			*path;
50620Sstevel@tonic-gate 	DBG_DEFINE(category,
50630Sstevel@tonic-gate 	    RSM_KERNEL_AGENT | RSM_FUNC_ALL | RSM_INTR_CALLBACK);
50640Sstevel@tonic-gate 
50650Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
50660Sstevel@tonic-gate 	    "rsm_sqcreateop_callback enter\n"));
50670Sstevel@tonic-gate 
50680Sstevel@tonic-gate 	/* look up the path - incr the path refcnt */
50690Sstevel@tonic-gate 	path = rsm_find_path(hdlr_argp->adapter_name,
50700Sstevel@tonic-gate 	    hdlr_argp->adapter_instance, src_hwaddr);
50710Sstevel@tonic-gate 
50720Sstevel@tonic-gate 	if (path == NULL) {
50730Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_DEBUG,
50740Sstevel@tonic-gate 		    "rsm_sqcreateop_callback done: no path\n"));
50750Sstevel@tonic-gate 		return;
50760Sstevel@tonic-gate 	}
50770Sstevel@tonic-gate 
50780Sstevel@tonic-gate 	if ((path->state == RSMKA_PATH_UP) &&
50790Sstevel@tonic-gate 	    (path->flags & RSMKA_SQCREATE_PENDING)) {
50800Sstevel@tonic-gate 		/*
50810Sstevel@tonic-gate 		 * previous attempt to create sendq had failed, retry
50820Sstevel@tonic-gate 		 * it and move to RSMKA_PATH_ACTIVE state if successful.
50830Sstevel@tonic-gate 		 * the refcnt will be decremented in the do_deferred_work
50840Sstevel@tonic-gate 		 */
50850Sstevel@tonic-gate 		(void) rsmka_do_path_active(path, RSMKA_NO_SLEEP);
50860Sstevel@tonic-gate 	} else {
50870Sstevel@tonic-gate 		/* decrement the refcnt */
50880Sstevel@tonic-gate 		PATH_RELE_NOLOCK(path);
50890Sstevel@tonic-gate 	}
50900Sstevel@tonic-gate 	mutex_exit(&path->mutex);
50910Sstevel@tonic-gate 
50920Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
50930Sstevel@tonic-gate 	    "rsm_sqcreateop_callback done\n"));
50940Sstevel@tonic-gate }
50950Sstevel@tonic-gate 
50960Sstevel@tonic-gate static void
rsm_intr_callback(void * data,rsm_addr_t src_hwaddr,rsm_intr_hand_arg_t arg)50970Sstevel@tonic-gate rsm_intr_callback(void *data, rsm_addr_t src_hwaddr, rsm_intr_hand_arg_t arg)
50980Sstevel@tonic-gate {
50990Sstevel@tonic-gate 	rsmipc_msghdr_t *msghdr = (rsmipc_msghdr_t *)data;
51000Sstevel@tonic-gate 	rsmipc_request_t *msg = (rsmipc_request_t *)data;
51010Sstevel@tonic-gate 	rsmipc_controlmsg_t *ctrlmsg = (rsmipc_controlmsg_t *)data;
51020Sstevel@tonic-gate 	rsm_node_id_t src_node;
51030Sstevel@tonic-gate 	DBG_DEFINE(category,
51040Sstevel@tonic-gate 	    RSM_KERNEL_AGENT | RSM_FUNC_ALL | RSM_INTR_CALLBACK);
51050Sstevel@tonic-gate 
51060Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_intr_callback enter:"
51070Sstevel@tonic-gate 	    "src=%d, type=%d\n", msghdr->rsmipc_src,
51080Sstevel@tonic-gate 	    msghdr->rsmipc_type));
51090Sstevel@tonic-gate 
51100Sstevel@tonic-gate 	/*
51110Sstevel@tonic-gate 	 * Check for the version number in the msg header. If it is not
51120Sstevel@tonic-gate 	 * RSM_VERSION, drop the message. In the future, we need to manage
51130Sstevel@tonic-gate 	 * incompatible version numbers in some way
51140Sstevel@tonic-gate 	 */
51150Sstevel@tonic-gate 	if (msghdr->rsmipc_version != RSM_VERSION) {
51160Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_ERR, "wrong KA version\n"));
51170Sstevel@tonic-gate 		/*
51180Sstevel@tonic-gate 		 * Drop requests that don't have a reply right here
51190Sstevel@tonic-gate 		 * Request with reply will send a BAD_VERSION reply
51200Sstevel@tonic-gate 		 * when they get processed by the worker thread.
51210Sstevel@tonic-gate 		 */
51220Sstevel@tonic-gate 		if (msghdr->rsmipc_type != RSMIPC_MSG_SEGCONNECT) {
51230Sstevel@tonic-gate 			return;
51240Sstevel@tonic-gate 		}
51250Sstevel@tonic-gate 
51260Sstevel@tonic-gate 	}
51270Sstevel@tonic-gate 
51280Sstevel@tonic-gate 	src_node = msghdr->rsmipc_src;
51290Sstevel@tonic-gate 
51300Sstevel@tonic-gate 	switch (msghdr->rsmipc_type) {
51310Sstevel@tonic-gate 	case RSMIPC_MSG_SEGCONNECT:
51320Sstevel@tonic-gate 	case RSMIPC_MSG_DISCONNECT:
51330Sstevel@tonic-gate 	case RSMIPC_MSG_SUSPEND:
51340Sstevel@tonic-gate 	case RSMIPC_MSG_SUSPEND_DONE:
51350Sstevel@tonic-gate 	case RSMIPC_MSG_RESUME:
51360Sstevel@tonic-gate 		/*
51370Sstevel@tonic-gate 		 * These message types are handled by a worker thread using
51380Sstevel@tonic-gate 		 * the flow-control algorithm.
51390Sstevel@tonic-gate 		 * Any message processing that does one or more of the
51400Sstevel@tonic-gate 		 * following should be handled in a worker thread.
51410Sstevel@tonic-gate 		 *	- allocates resources and might sleep
51420Sstevel@tonic-gate 		 *	- makes RSMPI calls down to the interconnect driver
51430Sstevel@tonic-gate 		 *	this by defn include requests with reply.
51440Sstevel@tonic-gate 		 *	- takes a long duration of time
51450Sstevel@tonic-gate 		 */
51460Sstevel@tonic-gate 		rsm_intr_callback_dispatch(data, src_hwaddr, arg);
51470Sstevel@tonic-gate 		break;
51480Sstevel@tonic-gate 	case RSMIPC_MSG_NOTIMPORTING:
51490Sstevel@tonic-gate 		importer_list_rm(src_node, msg->rsmipc_key,
51500Sstevel@tonic-gate 		    msg->rsmipc_segment_cookie);
51510Sstevel@tonic-gate 		break;
51520Sstevel@tonic-gate 	case RSMIPC_MSG_SQREADY:
51530Sstevel@tonic-gate 		rsm_proc_sqready(data, src_hwaddr, arg);
51540Sstevel@tonic-gate 		break;
51550Sstevel@tonic-gate 	case RSMIPC_MSG_SQREADY_ACK:
51560Sstevel@tonic-gate 		rsm_proc_sqready_ack(data, src_hwaddr, arg);
51570Sstevel@tonic-gate 		break;
51580Sstevel@tonic-gate 	case RSMIPC_MSG_CREDIT:
51590Sstevel@tonic-gate 		rsm_add_credits(ctrlmsg, src_hwaddr, arg);
51600Sstevel@tonic-gate 		break;
51610Sstevel@tonic-gate 	case RSMIPC_MSG_REPLY:
51620Sstevel@tonic-gate 		rsm_intr_reply(msghdr);
51630Sstevel@tonic-gate 		break;
51640Sstevel@tonic-gate 	case RSMIPC_MSG_BELL:
51650Sstevel@tonic-gate 		rsm_intr_event(msg);
51660Sstevel@tonic-gate 		break;
51670Sstevel@tonic-gate 	case RSMIPC_MSG_IMPORTING:
51680Sstevel@tonic-gate 		importer_list_add(src_node, msg->rsmipc_key,
51690Sstevel@tonic-gate 		    msg->rsmipc_adapter_hwaddr,
51700Sstevel@tonic-gate 		    msg->rsmipc_segment_cookie);
51710Sstevel@tonic-gate 		break;
51720Sstevel@tonic-gate 	case RSMIPC_MSG_REPUBLISH:
51730Sstevel@tonic-gate 		importer_update(src_node, msg->rsmipc_key, msg->rsmipc_perm);
51740Sstevel@tonic-gate 		break;
51750Sstevel@tonic-gate 	default:
51760Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_DEBUG,
51770Sstevel@tonic-gate 		    "rsm_intr_callback: bad msg %lx type %d data %lx\n",
51780Sstevel@tonic-gate 		    (size_t)msg, (int)(msghdr->rsmipc_type), (size_t)data));
51790Sstevel@tonic-gate 	}
51800Sstevel@tonic-gate 
51810Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_intr_callback done\n"));
51820Sstevel@tonic-gate 
51830Sstevel@tonic-gate }
51840Sstevel@tonic-gate 
rsm_srv_func(rsm_controller_object_t * chd,rsm_intr_q_op_t opcode,rsm_addr_t src,void * data,size_t size,rsm_intr_hand_arg_t arg)51850Sstevel@tonic-gate rsm_intr_hand_ret_t rsm_srv_func(rsm_controller_object_t *chd,
51860Sstevel@tonic-gate     rsm_intr_q_op_t opcode, rsm_addr_t src,
51870Sstevel@tonic-gate     void *data, size_t size, rsm_intr_hand_arg_t arg)
51880Sstevel@tonic-gate {
51890Sstevel@tonic-gate 	DBG_DEFINE(category,
51900Sstevel@tonic-gate 	    RSM_KERNEL_AGENT | RSM_FUNC_ALL | RSM_INTR_CALLBACK);
51910Sstevel@tonic-gate 
51920Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_srv_func enter\n"));
51930Sstevel@tonic-gate 
51940Sstevel@tonic-gate 	switch (opcode) {
51950Sstevel@tonic-gate 	case RSM_INTR_Q_OP_CREATE:
51960Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_DEBUG, "rsm_srv_func:OP_CREATE\n"));
51970Sstevel@tonic-gate 		rsm_sqcreateop_callback(src, arg);
51980Sstevel@tonic-gate 		break;
51990Sstevel@tonic-gate 	case RSM_INTR_Q_OP_DESTROY:
52000Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_DEBUG, "rsm_srv_func:OP_DESTROY\n"));
52010Sstevel@tonic-gate 		break;
52020Sstevel@tonic-gate 	case RSM_INTR_Q_OP_RECEIVE:
52030Sstevel@tonic-gate 		rsm_intr_callback(data, src, arg);
52040Sstevel@tonic-gate 		break;
52050Sstevel@tonic-gate 	default:
52060Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
52070Sstevel@tonic-gate 		    "rsm_srv_func: unknown opcode = %x\n", opcode));
52080Sstevel@tonic-gate 	}
52090Sstevel@tonic-gate 
52100Sstevel@tonic-gate 	chd = chd;
52110Sstevel@tonic-gate 	size = size;
52120Sstevel@tonic-gate 
52130Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_srv_func done\n"));
52140Sstevel@tonic-gate 
52150Sstevel@tonic-gate 	return (RSM_INTR_HAND_CLAIMED);
52160Sstevel@tonic-gate }
52170Sstevel@tonic-gate 
52180Sstevel@tonic-gate /* *************************** IPC slots ************************* */
52190Sstevel@tonic-gate static rsmipc_slot_t *
rsmipc_alloc()52200Sstevel@tonic-gate rsmipc_alloc()
52210Sstevel@tonic-gate {
52220Sstevel@tonic-gate 	int i;
52230Sstevel@tonic-gate 	rsmipc_slot_t *slot;
52240Sstevel@tonic-gate 	DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_FUNC_ALL);
52250Sstevel@tonic-gate 
52260Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmipc_alloc enter\n"));
52270Sstevel@tonic-gate 
52280Sstevel@tonic-gate 	/* try to find a free slot, if not wait */
52290Sstevel@tonic-gate 	mutex_enter(&rsm_ipc.lock);
52300Sstevel@tonic-gate 
52310Sstevel@tonic-gate 	while (rsm_ipc.count == 0) {
52320Sstevel@tonic-gate 		rsm_ipc.wanted = 1;
52330Sstevel@tonic-gate 		cv_wait(&rsm_ipc.cv, &rsm_ipc.lock);
52340Sstevel@tonic-gate 	}
52350Sstevel@tonic-gate 
52360Sstevel@tonic-gate 	/* An empty slot is available, find it */
52370Sstevel@tonic-gate 	slot = &rsm_ipc.slots[0];
52380Sstevel@tonic-gate 	for (i = 0; i < RSMIPC_SZ; i++, slot++) {
52390Sstevel@tonic-gate 		if (RSMIPC_GET(slot, RSMIPC_FREE)) {
52400Sstevel@tonic-gate 			RSMIPC_CLEAR(slot, RSMIPC_FREE);
52410Sstevel@tonic-gate 			break;
52420Sstevel@tonic-gate 		}
52430Sstevel@tonic-gate 	}
52440Sstevel@tonic-gate 
52450Sstevel@tonic-gate 	ASSERT(i < RSMIPC_SZ);
52460Sstevel@tonic-gate 	rsm_ipc.count--;	/* one less is available */
52470Sstevel@tonic-gate 	rsm_ipc.sequence++; /* new sequence */
52480Sstevel@tonic-gate 
52490Sstevel@tonic-gate 	slot->rsmipc_cookie.ic.sequence = (uint_t)rsm_ipc.sequence;
52500Sstevel@tonic-gate 	slot->rsmipc_cookie.ic.index = (uint_t)i;
52510Sstevel@tonic-gate 
52520Sstevel@tonic-gate 	mutex_exit(&rsm_ipc.lock);
52530Sstevel@tonic-gate 
52540Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmipc_alloc done\n"));
52550Sstevel@tonic-gate 
52560Sstevel@tonic-gate 	return (slot);
52570Sstevel@tonic-gate }
52580Sstevel@tonic-gate 
52590Sstevel@tonic-gate static void
rsmipc_free(rsmipc_slot_t * slot)52600Sstevel@tonic-gate rsmipc_free(rsmipc_slot_t *slot)
52610Sstevel@tonic-gate {
52620Sstevel@tonic-gate 	DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_FUNC_ALL);
52630Sstevel@tonic-gate 
52640Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmipc_free enter\n"));
52650Sstevel@tonic-gate 
52660Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&slot->rsmipc_lock));
52670Sstevel@tonic-gate 	ASSERT(&rsm_ipc.slots[slot->rsmipc_cookie.ic.index] == slot);
52680Sstevel@tonic-gate 
52690Sstevel@tonic-gate 	mutex_enter(&rsm_ipc.lock);
52700Sstevel@tonic-gate 
52710Sstevel@tonic-gate 	RSMIPC_SET(slot, RSMIPC_FREE);
52720Sstevel@tonic-gate 
52730Sstevel@tonic-gate 	slot->rsmipc_cookie.ic.sequence = 0;
52740Sstevel@tonic-gate 
52750Sstevel@tonic-gate 	mutex_exit(&slot->rsmipc_lock);
52760Sstevel@tonic-gate 	rsm_ipc.count++;
52770Sstevel@tonic-gate 	ASSERT(rsm_ipc.count <= RSMIPC_SZ);
52780Sstevel@tonic-gate 	if (rsm_ipc.wanted) {
52790Sstevel@tonic-gate 		rsm_ipc.wanted = 0;
52800Sstevel@tonic-gate 		cv_broadcast(&rsm_ipc.cv);
52810Sstevel@tonic-gate 	}
52820Sstevel@tonic-gate 
52830Sstevel@tonic-gate 	mutex_exit(&rsm_ipc.lock);
52840Sstevel@tonic-gate 
52850Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmipc_free done\n"));
52860Sstevel@tonic-gate }
52870Sstevel@tonic-gate 
52880Sstevel@tonic-gate static int
rsmipc_send(rsm_node_id_t dest,rsmipc_request_t * req,rsmipc_reply_t * reply)52890Sstevel@tonic-gate rsmipc_send(rsm_node_id_t dest, rsmipc_request_t *req, rsmipc_reply_t *reply)
52900Sstevel@tonic-gate {
52910Sstevel@tonic-gate 	int		e = 0;
52920Sstevel@tonic-gate 	int		credit_check = 0;
52930Sstevel@tonic-gate 	int		retry_cnt = 0;
52940Sstevel@tonic-gate 	int		min_retry_cnt = 10;
52950Sstevel@tonic-gate 	rsm_send_t	is;
52960Sstevel@tonic-gate 	rsmipc_slot_t	*rslot;
52970Sstevel@tonic-gate 	adapter_t	*adapter;
52980Sstevel@tonic-gate 	path_t		*path;
52990Sstevel@tonic-gate 	sendq_token_t	*sendq_token;
53000Sstevel@tonic-gate 	sendq_token_t	*used_sendq_token = NULL;
53010Sstevel@tonic-gate 	rsm_send_q_handle_t	ipc_handle;
53020Sstevel@tonic-gate 	DBG_DEFINE(category,
53030Sstevel@tonic-gate 	    RSM_KERNEL_AGENT | RSM_FUNC_ALL | RSM_INTR_CALLBACK);
53040Sstevel@tonic-gate 
53050Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmipc_send enter:dest=%d",
53060Sstevel@tonic-gate 	    dest));
53070Sstevel@tonic-gate 
53080Sstevel@tonic-gate 	/*
53090Sstevel@tonic-gate 	 * Check if this is a local case
53100Sstevel@tonic-gate 	 */
53110Sstevel@tonic-gate 	if (dest == my_nodeid) {
53120Sstevel@tonic-gate 		switch (req->rsmipc_hdr.rsmipc_type) {
53130Sstevel@tonic-gate 		case RSMIPC_MSG_SEGCONNECT:
53140Sstevel@tonic-gate 			reply->rsmipc_status = (short)rsmsegacl_validate(
53157656SSherry.Moore@Sun.COM 			    req, dest, reply);
53160Sstevel@tonic-gate 			break;
53170Sstevel@tonic-gate 		case RSMIPC_MSG_BELL:
53180Sstevel@tonic-gate 			req->rsmipc_hdr.rsmipc_src = dest;
53190Sstevel@tonic-gate 			rsm_intr_event(req);
53200Sstevel@tonic-gate 			break;
53210Sstevel@tonic-gate 		case RSMIPC_MSG_IMPORTING:
53220Sstevel@tonic-gate 			importer_list_add(dest, req->rsmipc_key,
53230Sstevel@tonic-gate 			    req->rsmipc_adapter_hwaddr,
53240Sstevel@tonic-gate 			    req->rsmipc_segment_cookie);
53250Sstevel@tonic-gate 			break;
53260Sstevel@tonic-gate 		case RSMIPC_MSG_NOTIMPORTING:
53270Sstevel@tonic-gate 			importer_list_rm(dest, req->rsmipc_key,
53280Sstevel@tonic-gate 			    req->rsmipc_segment_cookie);
53290Sstevel@tonic-gate 			break;
53300Sstevel@tonic-gate 		case RSMIPC_MSG_REPUBLISH:
53310Sstevel@tonic-gate 			importer_update(dest, req->rsmipc_key,
53320Sstevel@tonic-gate 			    req->rsmipc_perm);
53330Sstevel@tonic-gate 			break;
53340Sstevel@tonic-gate 		case RSMIPC_MSG_SUSPEND:
53350Sstevel@tonic-gate 			importer_suspend(dest);
53360Sstevel@tonic-gate 			break;
53370Sstevel@tonic-gate 		case RSMIPC_MSG_SUSPEND_DONE:
53380Sstevel@tonic-gate 			rsm_suspend_complete(dest, 0);
53390Sstevel@tonic-gate 			break;
53400Sstevel@tonic-gate 		case RSMIPC_MSG_RESUME:
53410Sstevel@tonic-gate 			importer_resume(dest);
53420Sstevel@tonic-gate 			break;
53430Sstevel@tonic-gate 		default:
53440Sstevel@tonic-gate 			ASSERT(0);
53450Sstevel@tonic-gate 		}
53460Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
53470Sstevel@tonic-gate 		    "rsmipc_send done\n"));
53480Sstevel@tonic-gate 		return (0);
53490Sstevel@tonic-gate 	}
53500Sstevel@tonic-gate 
53510Sstevel@tonic-gate 	if (dest >= MAX_NODES) {
53520Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_ERR,
53530Sstevel@tonic-gate 		    "rsm: rsmipc_send bad node number %x\n", dest));
53540Sstevel@tonic-gate 		return (RSMERR_REMOTE_NODE_UNREACHABLE);
53550Sstevel@tonic-gate 	}
53560Sstevel@tonic-gate 
53570Sstevel@tonic-gate 	/*
53580Sstevel@tonic-gate 	 * Oh boy! we are going remote.
53590Sstevel@tonic-gate 	 */
53600Sstevel@tonic-gate 
53610Sstevel@tonic-gate 	/*
53620Sstevel@tonic-gate 	 * identify if we need to have credits to send this message
53630Sstevel@tonic-gate 	 * - only selected requests are flow controlled
53640Sstevel@tonic-gate 	 */
53650Sstevel@tonic-gate 	if (req != NULL) {
53660Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
53670Sstevel@tonic-gate 		    "rsmipc_send:request type=%d\n",
53680Sstevel@tonic-gate 		    req->rsmipc_hdr.rsmipc_type));
53690Sstevel@tonic-gate 
53700Sstevel@tonic-gate 		switch (req->rsmipc_hdr.rsmipc_type) {
53710Sstevel@tonic-gate 		case RSMIPC_MSG_SEGCONNECT:
53720Sstevel@tonic-gate 		case RSMIPC_MSG_DISCONNECT:
53730Sstevel@tonic-gate 		case RSMIPC_MSG_IMPORTING:
53740Sstevel@tonic-gate 		case RSMIPC_MSG_SUSPEND:
53750Sstevel@tonic-gate 		case RSMIPC_MSG_SUSPEND_DONE:
53760Sstevel@tonic-gate 		case RSMIPC_MSG_RESUME:
53770Sstevel@tonic-gate 			credit_check = 1;
53780Sstevel@tonic-gate 			break;
53790Sstevel@tonic-gate 		default:
53800Sstevel@tonic-gate 			credit_check = 0;
53810Sstevel@tonic-gate 		}
53820Sstevel@tonic-gate 	}
53830Sstevel@tonic-gate 
53840Sstevel@tonic-gate again:
53850Sstevel@tonic-gate 	if (retry_cnt++ == min_retry_cnt) {
53860Sstevel@tonic-gate 		/* backoff before further retries for 10ms */
53870Sstevel@tonic-gate 		delay(drv_usectohz(10000));
53880Sstevel@tonic-gate 		retry_cnt = 0; /* reset retry_cnt */
53890Sstevel@tonic-gate 	}
53900Sstevel@tonic-gate 	sendq_token = rsmka_get_sendq_token(dest, used_sendq_token);
53910Sstevel@tonic-gate 	if (sendq_token == NULL) {
53920Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_ERR,
53930Sstevel@tonic-gate 		    "rsm: rsmipc_send no device to reach node %d\n", dest));
53940Sstevel@tonic-gate 		return (RSMERR_REMOTE_NODE_UNREACHABLE);
53950Sstevel@tonic-gate 	}
53960Sstevel@tonic-gate 
53970Sstevel@tonic-gate 	if ((sendq_token == used_sendq_token) &&
53980Sstevel@tonic-gate 	    ((e == RSMERR_CONN_ABORTED) || (e == RSMERR_TIMEOUT) ||
53997656SSherry.Moore@Sun.COM 	    (e == RSMERR_COMM_ERR_MAYBE_DELIVERED))) {
54000Sstevel@tonic-gate 		rele_sendq_token(sendq_token);
54010Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_DEBUG, "rsmipc_send done=%d\n", e));
54020Sstevel@tonic-gate 		return (RSMERR_CONN_ABORTED);
54030Sstevel@tonic-gate 	} else
54040Sstevel@tonic-gate 		used_sendq_token = sendq_token;
54050Sstevel@tonic-gate 
54060Sstevel@tonic-gate /* lint -save -e413 */
54070Sstevel@tonic-gate 	path = SQ_TOKEN_TO_PATH(sendq_token);
54080Sstevel@tonic-gate 	adapter = path->local_adapter;
54090Sstevel@tonic-gate /* lint -restore */
54100Sstevel@tonic-gate 	ipc_handle = sendq_token->rsmpi_sendq_handle;
54110Sstevel@tonic-gate 
54120Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
54130Sstevel@tonic-gate 	    "rsmipc_send: path=%lx sendq_hdl=%lx\n", path, ipc_handle));
54140Sstevel@tonic-gate 
54150Sstevel@tonic-gate 	if (reply == NULL) {
54160Sstevel@tonic-gate 		/* Send request without ack */
54170Sstevel@tonic-gate 		/*
54180Sstevel@tonic-gate 		 * Set the rsmipc_version number in the msghdr for KA
54190Sstevel@tonic-gate 		 * communication versioning
54200Sstevel@tonic-gate 		 */
54210Sstevel@tonic-gate 		req->rsmipc_hdr.rsmipc_version = RSM_VERSION;
54220Sstevel@tonic-gate 		req->rsmipc_hdr.rsmipc_src = my_nodeid;
54230Sstevel@tonic-gate 		/*
54240Sstevel@tonic-gate 		 * remote endpoints incn should match the value in our
54250Sstevel@tonic-gate 		 * path's remote_incn field. No need to grab any lock
54260Sstevel@tonic-gate 		 * since we have refcnted the path in rsmka_get_sendq_token
54270Sstevel@tonic-gate 		 */
54280Sstevel@tonic-gate 		req->rsmipc_hdr.rsmipc_incn = path->remote_incn;
54290Sstevel@tonic-gate 
54300Sstevel@tonic-gate 		is.is_data = (void *)req;
54310Sstevel@tonic-gate 		is.is_size = sizeof (*req);
54320Sstevel@tonic-gate 		is.is_flags = RSM_INTR_SEND_DELIVER | RSM_INTR_SEND_SLEEP;
54330Sstevel@tonic-gate 		is.is_wait = 0;
54340Sstevel@tonic-gate 
54350Sstevel@tonic-gate 		if (credit_check) {
54360Sstevel@tonic-gate 			mutex_enter(&path->mutex);
54370Sstevel@tonic-gate 			/*
54380Sstevel@tonic-gate 			 * wait till we recv credits or path goes down. If path
54390Sstevel@tonic-gate 			 * goes down rsm_send will fail and we handle the error
54400Sstevel@tonic-gate 			 * then
54410Sstevel@tonic-gate 			 */
54420Sstevel@tonic-gate 			while ((sendq_token->msgbuf_avail == 0) &&
54430Sstevel@tonic-gate 			    (path->state == RSMKA_PATH_ACTIVE)) {
54440Sstevel@tonic-gate 				e = cv_wait_sig(&sendq_token->sendq_cv,
54450Sstevel@tonic-gate 				    &path->mutex);
54460Sstevel@tonic-gate 				if (e == 0) {
54470Sstevel@tonic-gate 					mutex_exit(&path->mutex);
54480Sstevel@tonic-gate 					no_reply_cnt++;
54490Sstevel@tonic-gate 					rele_sendq_token(sendq_token);
54500Sstevel@tonic-gate 					DBG_PRINTF((category, RSM_DEBUG,
54510Sstevel@tonic-gate 					    "rsmipc_send done: "
54520Sstevel@tonic-gate 					    "cv_wait INTERRUPTED"));
54530Sstevel@tonic-gate 					return (RSMERR_INTERRUPTED);
54540Sstevel@tonic-gate 				}
54550Sstevel@tonic-gate 			}
54560Sstevel@tonic-gate 
54570Sstevel@tonic-gate 			/*
54580Sstevel@tonic-gate 			 * path is not active retry on another path.
54590Sstevel@tonic-gate 			 */
54600Sstevel@tonic-gate 			if (path->state != RSMKA_PATH_ACTIVE) {
54610Sstevel@tonic-gate 				mutex_exit(&path->mutex);
54620Sstevel@tonic-gate 				rele_sendq_token(sendq_token);
54630Sstevel@tonic-gate 				e = RSMERR_CONN_ABORTED;
54640Sstevel@tonic-gate 				DBG_PRINTF((category, RSM_ERR,
54650Sstevel@tonic-gate 				    "rsm: rsmipc_send: path !ACTIVE"));
54660Sstevel@tonic-gate 				goto again;
54670Sstevel@tonic-gate 			}
54680Sstevel@tonic-gate 
54690Sstevel@tonic-gate 			ASSERT(sendq_token->msgbuf_avail > 0);
54700Sstevel@tonic-gate 
54710Sstevel@tonic-gate 			/*
54720Sstevel@tonic-gate 			 * reserve a msgbuf
54730Sstevel@tonic-gate 			 */
54740Sstevel@tonic-gate 			sendq_token->msgbuf_avail--;
54750Sstevel@tonic-gate 
54760Sstevel@tonic-gate 			mutex_exit(&path->mutex);
54770Sstevel@tonic-gate 
54780Sstevel@tonic-gate 			e = adapter->rsmpi_ops->rsm_send(ipc_handle, &is,
54790Sstevel@tonic-gate 			    NULL);
54800Sstevel@tonic-gate 
54810Sstevel@tonic-gate 			if (e != RSM_SUCCESS) {
54820Sstevel@tonic-gate 				mutex_enter(&path->mutex);
54830Sstevel@tonic-gate 				/*
54840Sstevel@tonic-gate 				 * release the reserved msgbuf since
54850Sstevel@tonic-gate 				 * the send failed
54860Sstevel@tonic-gate 				 */
54870Sstevel@tonic-gate 				sendq_token->msgbuf_avail++;
54880Sstevel@tonic-gate 				cv_broadcast(&sendq_token->sendq_cv);
54890Sstevel@tonic-gate 				mutex_exit(&path->mutex);
54900Sstevel@tonic-gate 			}
54910Sstevel@tonic-gate 		} else
54920Sstevel@tonic-gate 			e = adapter->rsmpi_ops->rsm_send(ipc_handle, &is,
54930Sstevel@tonic-gate 			    NULL);
54940Sstevel@tonic-gate 
54950Sstevel@tonic-gate 		no_reply_cnt++;
54960Sstevel@tonic-gate 		rele_sendq_token(sendq_token);
54970Sstevel@tonic-gate 		if (e != RSM_SUCCESS) {
54980Sstevel@tonic-gate 			DBG_PRINTF((category, RSM_ERR,
54990Sstevel@tonic-gate 			    "rsm: rsmipc_send no reply send"
55000Sstevel@tonic-gate 			    " err = %d no reply count = %d\n",
55010Sstevel@tonic-gate 			    e, no_reply_cnt));
55020Sstevel@tonic-gate 			ASSERT(e != RSMERR_QUEUE_FENCE_UP &&
55030Sstevel@tonic-gate 			    e != RSMERR_BAD_BARRIER_HNDL);
55040Sstevel@tonic-gate 			atomic_add_64(&rsm_ipcsend_errcnt, 1);
55050Sstevel@tonic-gate 			goto again;
55060Sstevel@tonic-gate 		} else {
55070Sstevel@tonic-gate 			DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
55080Sstevel@tonic-gate 			    "rsmipc_send done\n"));
55090Sstevel@tonic-gate 			return (e);
55100Sstevel@tonic-gate 		}
55110Sstevel@tonic-gate 
55120Sstevel@tonic-gate 	}
55130Sstevel@tonic-gate 
55140Sstevel@tonic-gate 	if (req == NULL) {
55150Sstevel@tonic-gate 		/* Send reply - No flow control is done for reply */
55160Sstevel@tonic-gate 		/*
55170Sstevel@tonic-gate 		 * Set the version in the msg header for KA communication
55180Sstevel@tonic-gate 		 * versioning
55190Sstevel@tonic-gate 		 */
55200Sstevel@tonic-gate 		reply->rsmipc_hdr.rsmipc_version = RSM_VERSION;
55210Sstevel@tonic-gate 		reply->rsmipc_hdr.rsmipc_src = my_nodeid;
55220Sstevel@tonic-gate 		/* incn number is not used for reply msgs currently */
55230Sstevel@tonic-gate 		reply->rsmipc_hdr.rsmipc_incn = path->remote_incn;
55240Sstevel@tonic-gate 
55250Sstevel@tonic-gate 		is.is_data = (void *)reply;
55260Sstevel@tonic-gate 		is.is_size = sizeof (*reply);
55270Sstevel@tonic-gate 		is.is_flags = RSM_INTR_SEND_DELIVER | RSM_INTR_SEND_SLEEP;
55280Sstevel@tonic-gate 		is.is_wait = 0;
55290Sstevel@tonic-gate 		e = adapter->rsmpi_ops->rsm_send(ipc_handle, &is, NULL);
55300Sstevel@tonic-gate 		rele_sendq_token(sendq_token);
55310Sstevel@tonic-gate 		if (e != RSM_SUCCESS) {
55320Sstevel@tonic-gate 			DBG_PRINTF((category, RSM_ERR,
55330Sstevel@tonic-gate 			    "rsm: rsmipc_send reply send"
55340Sstevel@tonic-gate 			    " err = %d\n", e));
55350Sstevel@tonic-gate 			atomic_add_64(&rsm_ipcsend_errcnt, 1);
55360Sstevel@tonic-gate 			goto again;
55370Sstevel@tonic-gate 		} else {
55380Sstevel@tonic-gate 			DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
55390Sstevel@tonic-gate 			    "rsmipc_send done\n"));
55400Sstevel@tonic-gate 			return (e);
55410Sstevel@tonic-gate 		}
55420Sstevel@tonic-gate 	}
55430Sstevel@tonic-gate 
55440Sstevel@tonic-gate 	/* Reply needed */
55450Sstevel@tonic-gate 	rslot = rsmipc_alloc(); /* allocate a new ipc slot */
55460Sstevel@tonic-gate 
55470Sstevel@tonic-gate 	mutex_enter(&rslot->rsmipc_lock);
55480Sstevel@tonic-gate 
55490Sstevel@tonic-gate 	rslot->rsmipc_data = (void *)reply;
55500Sstevel@tonic-gate 	RSMIPC_SET(rslot, RSMIPC_PENDING);
55510Sstevel@tonic-gate 
55520Sstevel@tonic-gate 	while (RSMIPC_GET(rslot, RSMIPC_PENDING)) {
55530Sstevel@tonic-gate 		/*
55540Sstevel@tonic-gate 		 * Set the rsmipc_version number in the msghdr for KA
55550Sstevel@tonic-gate 		 * communication versioning
55560Sstevel@tonic-gate 		 */
55570Sstevel@tonic-gate 		req->rsmipc_hdr.rsmipc_version = RSM_VERSION;
55580Sstevel@tonic-gate 		req->rsmipc_hdr.rsmipc_src = my_nodeid;
55590Sstevel@tonic-gate 		req->rsmipc_hdr.rsmipc_cookie = rslot->rsmipc_cookie;
55600Sstevel@tonic-gate 		/*
55610Sstevel@tonic-gate 		 * remote endpoints incn should match the value in our
55620Sstevel@tonic-gate 		 * path's remote_incn field. No need to grab any lock
55630Sstevel@tonic-gate 		 * since we have refcnted the path in rsmka_get_sendq_token
55640Sstevel@tonic-gate 		 */
55650Sstevel@tonic-gate 		req->rsmipc_hdr.rsmipc_incn = path->remote_incn;
55660Sstevel@tonic-gate 
55670Sstevel@tonic-gate 		is.is_data = (void *)req;
55680Sstevel@tonic-gate 		is.is_size = sizeof (*req);
55690Sstevel@tonic-gate 		is.is_flags = RSM_INTR_SEND_DELIVER | RSM_INTR_SEND_SLEEP;
55700Sstevel@tonic-gate 		is.is_wait = 0;
55710Sstevel@tonic-gate 		if (credit_check) {
55720Sstevel@tonic-gate 
55730Sstevel@tonic-gate 			mutex_enter(&path->mutex);
55740Sstevel@tonic-gate 			/*
55750Sstevel@tonic-gate 			 * wait till we recv credits or path goes down. If path
55760Sstevel@tonic-gate 			 * goes down rsm_send will fail and we handle the error
55770Sstevel@tonic-gate 			 * then.
55780Sstevel@tonic-gate 			 */
55790Sstevel@tonic-gate 			while ((sendq_token->msgbuf_avail == 0) &&
55800Sstevel@tonic-gate 			    (path->state == RSMKA_PATH_ACTIVE)) {
55810Sstevel@tonic-gate 				e = cv_wait_sig(&sendq_token->sendq_cv,
55820Sstevel@tonic-gate 				    &path->mutex);
55830Sstevel@tonic-gate 				if (e == 0) {
55840Sstevel@tonic-gate 					mutex_exit(&path->mutex);
55850Sstevel@tonic-gate 					RSMIPC_CLEAR(rslot, RSMIPC_PENDING);
55860Sstevel@tonic-gate 					rsmipc_free(rslot);
55870Sstevel@tonic-gate 					rele_sendq_token(sendq_token);
55880Sstevel@tonic-gate 					DBG_PRINTF((category, RSM_DEBUG,
55890Sstevel@tonic-gate 					    "rsmipc_send done: "
55900Sstevel@tonic-gate 					    "cv_wait INTERRUPTED"));
55910Sstevel@tonic-gate 					return (RSMERR_INTERRUPTED);
55920Sstevel@tonic-gate 				}
55930Sstevel@tonic-gate 			}
55940Sstevel@tonic-gate 
55950Sstevel@tonic-gate 			/*
55960Sstevel@tonic-gate 			 * path is not active retry on another path.
55970Sstevel@tonic-gate 			 */
55980Sstevel@tonic-gate 			if (path->state != RSMKA_PATH_ACTIVE) {
55990Sstevel@tonic-gate 				mutex_exit(&path->mutex);
56000Sstevel@tonic-gate 				RSMIPC_CLEAR(rslot, RSMIPC_PENDING);
56010Sstevel@tonic-gate 				rsmipc_free(rslot);
56020Sstevel@tonic-gate 				rele_sendq_token(sendq_token);
56030Sstevel@tonic-gate 				e = RSMERR_CONN_ABORTED;
56040Sstevel@tonic-gate 				DBG_PRINTF((category, RSM_ERR,
56050Sstevel@tonic-gate 				    "rsm: rsmipc_send: path !ACTIVE"));
56060Sstevel@tonic-gate 				goto again;
56070Sstevel@tonic-gate 			}
56080Sstevel@tonic-gate 
56090Sstevel@tonic-gate 			ASSERT(sendq_token->msgbuf_avail > 0);
56100Sstevel@tonic-gate 
56110Sstevel@tonic-gate 			/*
56120Sstevel@tonic-gate 			 * reserve a msgbuf
56130Sstevel@tonic-gate 			 */
56140Sstevel@tonic-gate 			sendq_token->msgbuf_avail--;
56150Sstevel@tonic-gate 
56160Sstevel@tonic-gate 			mutex_exit(&path->mutex);
56170Sstevel@tonic-gate 
56180Sstevel@tonic-gate 			e = adapter->rsmpi_ops->rsm_send(ipc_handle, &is,
56190Sstevel@tonic-gate 			    NULL);
56200Sstevel@tonic-gate 
56210Sstevel@tonic-gate 			if (e != RSM_SUCCESS) {
56220Sstevel@tonic-gate 				mutex_enter(&path->mutex);
56230Sstevel@tonic-gate 				/*
56240Sstevel@tonic-gate 				 * release the reserved msgbuf since
56250Sstevel@tonic-gate 				 * the send failed
56260Sstevel@tonic-gate 				 */
56270Sstevel@tonic-gate 				sendq_token->msgbuf_avail++;
56280Sstevel@tonic-gate 				cv_broadcast(&sendq_token->sendq_cv);
56290Sstevel@tonic-gate 				mutex_exit(&path->mutex);
56300Sstevel@tonic-gate 			}
56310Sstevel@tonic-gate 		} else
56320Sstevel@tonic-gate 			e = adapter->rsmpi_ops->rsm_send(ipc_handle, &is,
56330Sstevel@tonic-gate 			    NULL);
56340Sstevel@tonic-gate 
56350Sstevel@tonic-gate 		if (e != RSM_SUCCESS) {
56360Sstevel@tonic-gate 			DBG_PRINTF((category, RSM_ERR,
56370Sstevel@tonic-gate 			    "rsm: rsmipc_send rsmpi send err = %d\n", e));
56380Sstevel@tonic-gate 			RSMIPC_CLEAR(rslot, RSMIPC_PENDING);
56390Sstevel@tonic-gate 			rsmipc_free(rslot);
56400Sstevel@tonic-gate 			rele_sendq_token(sendq_token);
56410Sstevel@tonic-gate 			atomic_add_64(&rsm_ipcsend_errcnt, 1);
56420Sstevel@tonic-gate 			goto again;
56430Sstevel@tonic-gate 		}
56440Sstevel@tonic-gate 
56450Sstevel@tonic-gate 		/* wait for a reply signal, a SIGINT, or 5 sec. timeout */
5646*11066Srafael.vanoni@sun.com 		e = cv_reltimedwait_sig(&rslot->rsmipc_cv, &rslot->rsmipc_lock,
5647*11066Srafael.vanoni@sun.com 		    drv_usectohz(5000000), TR_CLOCK_TICK);
56480Sstevel@tonic-gate 		if (e < 0) {
56490Sstevel@tonic-gate 			/* timed out - retry */
56500Sstevel@tonic-gate 			e = RSMERR_TIMEOUT;
56510Sstevel@tonic-gate 		} else if (e == 0) {
56520Sstevel@tonic-gate 			/* signalled - return error */
56530Sstevel@tonic-gate 			e = RSMERR_INTERRUPTED;
56540Sstevel@tonic-gate 			break;
56550Sstevel@tonic-gate 		} else {
56560Sstevel@tonic-gate 			e = RSM_SUCCESS;
56570Sstevel@tonic-gate 		}
56580Sstevel@tonic-gate 	}
56590Sstevel@tonic-gate 
56600Sstevel@tonic-gate 	RSMIPC_CLEAR(rslot, RSMIPC_PENDING);
56610Sstevel@tonic-gate 	rsmipc_free(rslot);
56620Sstevel@tonic-gate 	rele_sendq_token(sendq_token);
56630Sstevel@tonic-gate 
56640Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmipc_send done=%d\n", e));
56650Sstevel@tonic-gate 	return (e);
56660Sstevel@tonic-gate }
56670Sstevel@tonic-gate 
56680Sstevel@tonic-gate static int
rsm_send_notimporting(rsm_node_id_t dest,rsm_memseg_id_t segid,void * cookie)56690Sstevel@tonic-gate rsm_send_notimporting(rsm_node_id_t dest, rsm_memseg_id_t segid,  void *cookie)
56700Sstevel@tonic-gate {
56710Sstevel@tonic-gate 	rsmipc_request_t request;
56720Sstevel@tonic-gate 
56730Sstevel@tonic-gate 	/*
56740Sstevel@tonic-gate 	 *  inform the exporter to delete this importer
56750Sstevel@tonic-gate 	 */
56760Sstevel@tonic-gate 	request.rsmipc_hdr.rsmipc_type = RSMIPC_MSG_NOTIMPORTING;
56770Sstevel@tonic-gate 	request.rsmipc_key = segid;
56780Sstevel@tonic-gate 	request.rsmipc_segment_cookie = cookie;
56790Sstevel@tonic-gate 	return (rsmipc_send(dest, &request, RSM_NO_REPLY));
56800Sstevel@tonic-gate }
56810Sstevel@tonic-gate 
56820Sstevel@tonic-gate static void
rsm_send_republish(rsm_memseg_id_t segid,rsmapi_access_entry_t * acl,int acl_len,rsm_permission_t default_permission)56830Sstevel@tonic-gate rsm_send_republish(rsm_memseg_id_t segid, rsmapi_access_entry_t	*acl,
56840Sstevel@tonic-gate     int acl_len, rsm_permission_t default_permission)
56850Sstevel@tonic-gate {
56860Sstevel@tonic-gate 	int			i;
56870Sstevel@tonic-gate 	importing_token_t	*token;
56880Sstevel@tonic-gate 	rsmipc_request_t	request;
56890Sstevel@tonic-gate 	republish_token_t	*republish_list = NULL;
56900Sstevel@tonic-gate 	republish_token_t	*rp;
56910Sstevel@tonic-gate 	rsm_permission_t	permission;
56920Sstevel@tonic-gate 	int			index;
56930Sstevel@tonic-gate 
56940Sstevel@tonic-gate 	/*
56950Sstevel@tonic-gate 	 * send the new access mode to all the nodes that have imported
56960Sstevel@tonic-gate 	 * this segment.
56970Sstevel@tonic-gate 	 * If the new acl does not have a node that was present in
56980Sstevel@tonic-gate 	 * the old acl a access permission of 0 is sent.
56990Sstevel@tonic-gate 	 */
57000Sstevel@tonic-gate 
57010Sstevel@tonic-gate 	index = rsmhash(segid);
57020Sstevel@tonic-gate 
57030Sstevel@tonic-gate 	/*
57040Sstevel@tonic-gate 	 * create a list of node/permissions to send the republish message
57050Sstevel@tonic-gate 	 */
57060Sstevel@tonic-gate 	mutex_enter(&importer_list.lock);
57070Sstevel@tonic-gate 
57080Sstevel@tonic-gate 	token = importer_list.bucket[index];
57090Sstevel@tonic-gate 	while (token != NULL) {
57100Sstevel@tonic-gate 		if (segid == token->key) {
57110Sstevel@tonic-gate 			permission = default_permission;
57120Sstevel@tonic-gate 
57130Sstevel@tonic-gate 			for (i = 0; i < acl_len; i++) {
57140Sstevel@tonic-gate 				if (token->importing_node == acl[i].ae_node) {
57150Sstevel@tonic-gate 					permission = acl[i].ae_permission;
57160Sstevel@tonic-gate 					break;
57170Sstevel@tonic-gate 				}
57180Sstevel@tonic-gate 			}
57190Sstevel@tonic-gate 			rp = kmem_zalloc(sizeof (republish_token_t), KM_SLEEP);
57200Sstevel@tonic-gate 
57210Sstevel@tonic-gate 			rp->key = segid;
57220Sstevel@tonic-gate 			rp->importing_node = token->importing_node;
57230Sstevel@tonic-gate 			rp->permission = permission;
57240Sstevel@tonic-gate 			rp->next = republish_list;
57250Sstevel@tonic-gate 			republish_list = rp;
57260Sstevel@tonic-gate 		}
57270Sstevel@tonic-gate 		token = token->next;
57280Sstevel@tonic-gate 	}
57290Sstevel@tonic-gate 
57300Sstevel@tonic-gate 	mutex_exit(&importer_list.lock);
57310Sstevel@tonic-gate 
57320Sstevel@tonic-gate 	request.rsmipc_hdr.rsmipc_type = RSMIPC_MSG_REPUBLISH;
57330Sstevel@tonic-gate 	request.rsmipc_key = segid;
57340Sstevel@tonic-gate 
57350Sstevel@tonic-gate 	while (republish_list != NULL) {
57360Sstevel@tonic-gate 		request.rsmipc_perm = republish_list->permission;
57370Sstevel@tonic-gate 		(void) rsmipc_send(republish_list->importing_node,
57380Sstevel@tonic-gate 		    &request, RSM_NO_REPLY);
57390Sstevel@tonic-gate 		rp = republish_list;
57400Sstevel@tonic-gate 		republish_list = republish_list->next;
57410Sstevel@tonic-gate 		kmem_free(rp, sizeof (republish_token_t));
57420Sstevel@tonic-gate 	}
57430Sstevel@tonic-gate }
57440Sstevel@tonic-gate 
57450Sstevel@tonic-gate static void
rsm_send_suspend()57460Sstevel@tonic-gate rsm_send_suspend()
57470Sstevel@tonic-gate {
57480Sstevel@tonic-gate 	int			i, e;
57490Sstevel@tonic-gate 	rsmipc_request_t 	request;
57500Sstevel@tonic-gate 	list_element_t		*tokp;
57510Sstevel@tonic-gate 	list_element_t		*head = NULL;
57520Sstevel@tonic-gate 	importing_token_t	*token;
57530Sstevel@tonic-gate 	DBG_PRINTF((RSM_KERNEL_AGENT | RSM_EXPORT, RSM_DEBUG_VERBOSE,
57540Sstevel@tonic-gate 	    "rsm_send_suspend enter\n"));
57550Sstevel@tonic-gate 
57560Sstevel@tonic-gate 	/*
57570Sstevel@tonic-gate 	 * create a list of node to send the suspend message
57580Sstevel@tonic-gate 	 *
57590Sstevel@tonic-gate 	 * Currently the whole importer list is scanned and we obtain
57600Sstevel@tonic-gate 	 * all the nodes - this basically gets all nodes that at least
57610Sstevel@tonic-gate 	 * import one segment from the local node.
57620Sstevel@tonic-gate 	 *
57630Sstevel@tonic-gate 	 * no need to grab the rsm_suspend_list lock here since we are
57640Sstevel@tonic-gate 	 * single threaded when suspend is called.
57650Sstevel@tonic-gate 	 */
57660Sstevel@tonic-gate 
57670Sstevel@tonic-gate 	mutex_enter(&importer_list.lock);
57680Sstevel@tonic-gate 	for (i = 0; i < rsm_hash_size; i++) {
57690Sstevel@tonic-gate 
57700Sstevel@tonic-gate 		token = importer_list.bucket[i];
57710Sstevel@tonic-gate 
57720Sstevel@tonic-gate 		while (token != NULL) {
57730Sstevel@tonic-gate 
57740Sstevel@tonic-gate 			tokp = head;
57750Sstevel@tonic-gate 
57760Sstevel@tonic-gate 			/*
57770Sstevel@tonic-gate 			 * make sure that the token's node
57780Sstevel@tonic-gate 			 * is not already on the suspend list
57790Sstevel@tonic-gate 			 */
57800Sstevel@tonic-gate 			while (tokp != NULL) {
57810Sstevel@tonic-gate 				if (tokp->nodeid == token->importing_node) {
57820Sstevel@tonic-gate 					break;
57830Sstevel@tonic-gate 				}
57840Sstevel@tonic-gate 				tokp = tokp->next;
57850Sstevel@tonic-gate 			}
57860Sstevel@tonic-gate 
57870Sstevel@tonic-gate 			if (tokp == NULL) { /* not in suspend list */
57880Sstevel@tonic-gate 				tokp = kmem_zalloc(sizeof (list_element_t),
57897656SSherry.Moore@Sun.COM 				    KM_SLEEP);
57900Sstevel@tonic-gate 				tokp->nodeid = token->importing_node;
57910Sstevel@tonic-gate 				tokp->next = head;
57920Sstevel@tonic-gate 				head = tokp;
57930Sstevel@tonic-gate 			}
57940Sstevel@tonic-gate 
57950Sstevel@tonic-gate 			token = token->next;
57960Sstevel@tonic-gate 		}
57970Sstevel@tonic-gate 	}
57980Sstevel@tonic-gate 	mutex_exit(&importer_list.lock);
57990Sstevel@tonic-gate 
58000Sstevel@tonic-gate 	if (head == NULL) { /* no importers so go ahead and quiesce segments */
58010Sstevel@tonic-gate 		exporter_quiesce();
58020Sstevel@tonic-gate 		return;
58030Sstevel@tonic-gate 	}
58040Sstevel@tonic-gate 
58050Sstevel@tonic-gate 	mutex_enter(&rsm_suspend_list.list_lock);
58060Sstevel@tonic-gate 	ASSERT(rsm_suspend_list.list_head == NULL);
58070Sstevel@tonic-gate 	/*
58080Sstevel@tonic-gate 	 * update the suspend list righaway so that if a node dies the
58090Sstevel@tonic-gate 	 * pathmanager can set the NODE dead flag
58100Sstevel@tonic-gate 	 */
58110Sstevel@tonic-gate 	rsm_suspend_list.list_head = head;
58120Sstevel@tonic-gate 	mutex_exit(&rsm_suspend_list.list_lock);
58130Sstevel@tonic-gate 
58140Sstevel@tonic-gate 	tokp = head;
58150Sstevel@tonic-gate 
58160Sstevel@tonic-gate 	while (tokp != NULL) {
58170Sstevel@tonic-gate 		request.rsmipc_hdr.rsmipc_type = RSMIPC_MSG_SUSPEND;
58180Sstevel@tonic-gate 		e = rsmipc_send(tokp->nodeid, &request, RSM_NO_REPLY);
58190Sstevel@tonic-gate 		/*
58200Sstevel@tonic-gate 		 * Error in rsmipc_send currently happens due to inaccessibility
58210Sstevel@tonic-gate 		 * of the remote node.
58220Sstevel@tonic-gate 		 */
58230Sstevel@tonic-gate 		if (e == RSM_SUCCESS) { /* send failed - don't wait for ack */
58240Sstevel@tonic-gate 			tokp->flags |= RSM_SUSPEND_ACKPENDING;
58250Sstevel@tonic-gate 		}
58260Sstevel@tonic-gate 
58270Sstevel@tonic-gate 		tokp = tokp->next;
58280Sstevel@tonic-gate 	}
58290Sstevel@tonic-gate 
58300Sstevel@tonic-gate 	DBG_PRINTF((RSM_KERNEL_AGENT | RSM_EXPORT, RSM_DEBUG_VERBOSE,
58310Sstevel@tonic-gate 	    "rsm_send_suspend done\n"));
58320Sstevel@tonic-gate 
58330Sstevel@tonic-gate }
58340Sstevel@tonic-gate 
58350Sstevel@tonic-gate static void
rsm_send_resume()58360Sstevel@tonic-gate rsm_send_resume()
58370Sstevel@tonic-gate {
58380Sstevel@tonic-gate 	rsmipc_request_t 	request;
58390Sstevel@tonic-gate 	list_element_t		*elem, *head;
58400Sstevel@tonic-gate 
58410Sstevel@tonic-gate 	/*
58420Sstevel@tonic-gate 	 * save the suspend list so that we know where to send
58430Sstevel@tonic-gate 	 * the resume messages and make the suspend list head
58440Sstevel@tonic-gate 	 * NULL.
58450Sstevel@tonic-gate 	 */
58460Sstevel@tonic-gate 	mutex_enter(&rsm_suspend_list.list_lock);
58470Sstevel@tonic-gate 	head = rsm_suspend_list.list_head;
58480Sstevel@tonic-gate 	rsm_suspend_list.list_head = NULL;
58490Sstevel@tonic-gate 	mutex_exit(&rsm_suspend_list.list_lock);
58500Sstevel@tonic-gate 
58510Sstevel@tonic-gate 	while (head != NULL) {
58520Sstevel@tonic-gate 		elem = head;
58530Sstevel@tonic-gate 		head = head->next;
58540Sstevel@tonic-gate 
58550Sstevel@tonic-gate 		request.rsmipc_hdr.rsmipc_type = RSMIPC_MSG_RESUME;
58560Sstevel@tonic-gate 
58570Sstevel@tonic-gate 		(void) rsmipc_send(elem->nodeid, &request, RSM_NO_REPLY);
58580Sstevel@tonic-gate 
58590Sstevel@tonic-gate 		kmem_free((void *)elem, sizeof (list_element_t));
58600Sstevel@tonic-gate 
58610Sstevel@tonic-gate 	}
58620Sstevel@tonic-gate 
58630Sstevel@tonic-gate }
58640Sstevel@tonic-gate 
58650Sstevel@tonic-gate /*
58660Sstevel@tonic-gate  * This function takes path and sends a message using the sendq
58670Sstevel@tonic-gate  * corresponding to it. The RSMIPC_MSG_SQREADY, RSMIPC_MSG_SQREADY_ACK
58680Sstevel@tonic-gate  * and RSMIPC_MSG_CREDIT are sent using this function.
58690Sstevel@tonic-gate  */
58700Sstevel@tonic-gate int
rsmipc_send_controlmsg(path_t * path,int msgtype)58710Sstevel@tonic-gate rsmipc_send_controlmsg(path_t *path, int msgtype)
58720Sstevel@tonic-gate {
58730Sstevel@tonic-gate 	int			e;
58740Sstevel@tonic-gate 	int			retry_cnt = 0;
58750Sstevel@tonic-gate 	int			min_retry_cnt = 10;
58760Sstevel@tonic-gate 	adapter_t		*adapter;
58770Sstevel@tonic-gate 	rsm_send_t		is;
58780Sstevel@tonic-gate 	rsm_send_q_handle_t	ipc_handle;
58790Sstevel@tonic-gate 	rsmipc_controlmsg_t	msg;
58800Sstevel@tonic-gate 	DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_FUNC_ALL | RSM_FLOWCONTROL);
58810Sstevel@tonic-gate 
58820Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
58830Sstevel@tonic-gate 	    "rsmipc_send_controlmsg enter\n"));
58840Sstevel@tonic-gate 
58850Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&path->mutex));
58860Sstevel@tonic-gate 
58870Sstevel@tonic-gate 	adapter = path->local_adapter;
58880Sstevel@tonic-gate 
58890Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG, "rsmipc_send_controlmsg:path=%lx "
58900Sstevel@tonic-gate 	    "msgtype=%d %lx:%llx->%lx:%llx procmsg=%d\n", path, msgtype,
58910Sstevel@tonic-gate 	    my_nodeid, adapter->hwaddr, path->remote_node,
58920Sstevel@tonic-gate 	    path->remote_hwaddr, path->procmsg_cnt));
58930Sstevel@tonic-gate 
58940Sstevel@tonic-gate 	if (path->state != RSMKA_PATH_ACTIVE) {
58950Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
58960Sstevel@tonic-gate 		    "rsmipc_send_controlmsg done: ! RSMKA_PATH_ACTIVE"));
58970Sstevel@tonic-gate 		return (1);
58980Sstevel@tonic-gate 	}
58990Sstevel@tonic-gate 
59000Sstevel@tonic-gate 	ipc_handle = path->sendq_token.rsmpi_sendq_handle;
59010Sstevel@tonic-gate 
59020Sstevel@tonic-gate 	msg.rsmipc_hdr.rsmipc_version = RSM_VERSION;
59030Sstevel@tonic-gate 	msg.rsmipc_hdr.rsmipc_src = my_nodeid;
59040Sstevel@tonic-gate 	msg.rsmipc_hdr.rsmipc_type = msgtype;
59050Sstevel@tonic-gate 	msg.rsmipc_hdr.rsmipc_incn = path->remote_incn;
59060Sstevel@tonic-gate 
59070Sstevel@tonic-gate 	if (msgtype == RSMIPC_MSG_CREDIT)
59080Sstevel@tonic-gate 		msg.rsmipc_credits = path->procmsg_cnt;
59090Sstevel@tonic-gate 
59100Sstevel@tonic-gate 	msg.rsmipc_local_incn = path->local_incn;
59110Sstevel@tonic-gate 
59120Sstevel@tonic-gate 	msg.rsmipc_adapter_hwaddr = adapter->hwaddr;
59130Sstevel@tonic-gate 	/* incr the sendq, path refcnt */
59140Sstevel@tonic-gate 	PATH_HOLD_NOLOCK(path);
59150Sstevel@tonic-gate 	SENDQ_TOKEN_HOLD(path);
59160Sstevel@tonic-gate 
59170Sstevel@tonic-gate 	do {
59180Sstevel@tonic-gate 		/* drop the path lock before doing the rsm_send */
59190Sstevel@tonic-gate 		mutex_exit(&path->mutex);
59200Sstevel@tonic-gate 
59210Sstevel@tonic-gate 		is.is_data = (void *)&msg;
59220Sstevel@tonic-gate 		is.is_size = sizeof (msg);
59230Sstevel@tonic-gate 		is.is_flags = RSM_INTR_SEND_DELIVER | RSM_INTR_SEND_SLEEP;
59240Sstevel@tonic-gate 		is.is_wait = 0;
59250Sstevel@tonic-gate 
59260Sstevel@tonic-gate 		e = adapter->rsmpi_ops->rsm_send(ipc_handle, &is, NULL);
59270Sstevel@tonic-gate 
59280Sstevel@tonic-gate 		ASSERT(e != RSMERR_QUEUE_FENCE_UP &&
59290Sstevel@tonic-gate 		    e != RSMERR_BAD_BARRIER_HNDL);
59300Sstevel@tonic-gate 
59310Sstevel@tonic-gate 		mutex_enter(&path->mutex);
59320Sstevel@tonic-gate 
59330Sstevel@tonic-gate 		if (e == RSM_SUCCESS) {
59340Sstevel@tonic-gate 			break;
59350Sstevel@tonic-gate 		}
59360Sstevel@tonic-gate 		/* error counter for statistics */
59370Sstevel@tonic-gate 		atomic_add_64(&rsm_ctrlmsg_errcnt, 1);
59380Sstevel@tonic-gate 
59390Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_ERR,
59400Sstevel@tonic-gate 		    "rsmipc_send_controlmsg:rsm_send error=%d", e));
59410Sstevel@tonic-gate 
59420Sstevel@tonic-gate 		if (++retry_cnt == min_retry_cnt) { /* backoff before retry */
5943*11066Srafael.vanoni@sun.com 			(void) cv_reltimedwait(&path->sendq_token.sendq_cv,
5944*11066Srafael.vanoni@sun.com 			    &path->mutex, drv_usectohz(10000), TR_CLOCK_TICK);
59450Sstevel@tonic-gate 			retry_cnt = 0;
59460Sstevel@tonic-gate 		}
59470Sstevel@tonic-gate 	} while (path->state == RSMKA_PATH_ACTIVE);
59480Sstevel@tonic-gate 
59490Sstevel@tonic-gate 	/* decrement the sendq,path refcnt that we incr before rsm_send */
59500Sstevel@tonic-gate 	SENDQ_TOKEN_RELE(path);
59510Sstevel@tonic-gate 	PATH_RELE_NOLOCK(path);
59520Sstevel@tonic-gate 
59530Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
59540Sstevel@tonic-gate 	    "rsmipc_send_controlmsg done=%d", e));
59550Sstevel@tonic-gate 	return (e);
59560Sstevel@tonic-gate }
59570Sstevel@tonic-gate 
59580Sstevel@tonic-gate /*
59590Sstevel@tonic-gate  * Called from rsm_force_unload and path_importer_disconnect. The memory
59600Sstevel@tonic-gate  * mapping for the imported segment is removed and the segment is
59610Sstevel@tonic-gate  * disconnected at the interconnect layer if disconnect_flag is TRUE.
59620Sstevel@tonic-gate  * rsm_force_unload will get disconnect_flag TRUE from rsm_intr_callback
59630Sstevel@tonic-gate  * and FALSE from rsm_rebind.
59640Sstevel@tonic-gate  *
59650Sstevel@tonic-gate  * When subsequent accesses cause page faulting, the dummy page is mapped
59660Sstevel@tonic-gate  * to resolve the fault, and the mapping generation number is incremented
59670Sstevel@tonic-gate  * so that the application can be notified on a close barrier operation.
59680Sstevel@tonic-gate  *
59690Sstevel@tonic-gate  * It is important to note that the caller of rsmseg_unload is responsible for
59700Sstevel@tonic-gate  * acquiring the segment lock before making a call to rsmseg_unload. This is
59710Sstevel@tonic-gate  * required to make the caller and rsmseg_unload thread safe. The segment lock
59720Sstevel@tonic-gate  * will be released by the rsmseg_unload function.
59730Sstevel@tonic-gate  */
59740Sstevel@tonic-gate void
rsmseg_unload(rsmseg_t * im_seg)59750Sstevel@tonic-gate rsmseg_unload(rsmseg_t *im_seg)
59760Sstevel@tonic-gate {
59770Sstevel@tonic-gate 	rsmcookie_t		*hdl;
59780Sstevel@tonic-gate 	void			*shared_cookie;
59790Sstevel@tonic-gate 	rsmipc_request_t	request;
59800Sstevel@tonic-gate 	uint_t			maxprot;
59810Sstevel@tonic-gate 
59820Sstevel@tonic-gate 	DBG_DEFINE(category,
59830Sstevel@tonic-gate 	    RSM_KERNEL_AGENT | RSM_FUNC_ALL | RSM_INTR_CALLBACK);
59840Sstevel@tonic-gate 
59850Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmseg_unload enter\n"));
59860Sstevel@tonic-gate 
59870Sstevel@tonic-gate 	ASSERT(im_seg->s_hdr.rsmrc_type == RSM_RESOURCE_IMPORT_SEGMENT);
59880Sstevel@tonic-gate 
59890Sstevel@tonic-gate 	/* wait until segment leaves the mapping state */
59900Sstevel@tonic-gate 	while (im_seg->s_state == RSM_STATE_MAPPING)
59910Sstevel@tonic-gate 		cv_wait(&im_seg->s_cv, &im_seg->s_lock);
59920Sstevel@tonic-gate 	/*
59930Sstevel@tonic-gate 	 * An unload is only necessary if the segment is connected. However,
59940Sstevel@tonic-gate 	 * if the segment was on the import list in state RSM_STATE_CONNECTING
59950Sstevel@tonic-gate 	 * then a connection was in progress. Change to RSM_STATE_NEW
59960Sstevel@tonic-gate 	 * here to cause an early exit from the connection process.
59970Sstevel@tonic-gate 	 */
59980Sstevel@tonic-gate 	if (im_seg->s_state == RSM_STATE_NEW) {
59990Sstevel@tonic-gate 		rsmseglock_release(im_seg);
60000Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
60010Sstevel@tonic-gate 		    "rsmseg_unload done: RSM_STATE_NEW\n"));
60020Sstevel@tonic-gate 		return;
60030Sstevel@tonic-gate 	} else if (im_seg->s_state == RSM_STATE_CONNECTING) {
60040Sstevel@tonic-gate 		im_seg->s_state = RSM_STATE_ABORT_CONNECT;
60050Sstevel@tonic-gate 		rsmsharelock_acquire(im_seg);
60060Sstevel@tonic-gate 		im_seg->s_share->rsmsi_state = RSMSI_STATE_ABORT_CONNECT;
60070Sstevel@tonic-gate 		rsmsharelock_release(im_seg);
60080Sstevel@tonic-gate 		rsmseglock_release(im_seg);
60090Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
60100Sstevel@tonic-gate 		    "rsmseg_unload done: RSM_STATE_CONNECTING\n"));
60110Sstevel@tonic-gate 		return;
60120Sstevel@tonic-gate 	}
60130Sstevel@tonic-gate 
60140Sstevel@tonic-gate 	if (im_seg->s_flags & RSM_FORCE_DISCONNECT) {
60150Sstevel@tonic-gate 		if (im_seg->s_ckl != NULL) {
60160Sstevel@tonic-gate 			int e;
60170Sstevel@tonic-gate 			/* Setup protections for remap */
60180Sstevel@tonic-gate 			maxprot = PROT_USER;
60190Sstevel@tonic-gate 			if (im_seg->s_mode & RSM_PERM_READ) {
60200Sstevel@tonic-gate 				maxprot |= PROT_READ;
60210Sstevel@tonic-gate 			}
60220Sstevel@tonic-gate 			if (im_seg->s_mode & RSM_PERM_WRITE) {
60230Sstevel@tonic-gate 				maxprot |= PROT_WRITE;
60240Sstevel@tonic-gate 			}
60250Sstevel@tonic-gate 			hdl = im_seg->s_ckl;
60260Sstevel@tonic-gate 			for (; hdl != NULL; hdl = hdl->c_next) {
60270Sstevel@tonic-gate 				e = devmap_umem_remap(hdl->c_dhp, rsm_dip,
60280Sstevel@tonic-gate 				    remap_cookie,
60290Sstevel@tonic-gate 				    hdl->c_off, hdl->c_len,
60300Sstevel@tonic-gate 				    maxprot, 0, NULL);
60310Sstevel@tonic-gate 
60320Sstevel@tonic-gate 				DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
60330Sstevel@tonic-gate 				    "remap returns %d\n", e));
60340Sstevel@tonic-gate 			}
60350Sstevel@tonic-gate 		}
60360Sstevel@tonic-gate 
60370Sstevel@tonic-gate 		(void) rsm_closeconnection(im_seg, &shared_cookie);
60380Sstevel@tonic-gate 
60390Sstevel@tonic-gate 		if (shared_cookie != NULL) {
60400Sstevel@tonic-gate 			/*
60410Sstevel@tonic-gate 			 * inform the exporting node so this import
60420Sstevel@tonic-gate 			 * can be deleted from the list of importers.
60430Sstevel@tonic-gate 			 */
60440Sstevel@tonic-gate 			request.rsmipc_hdr.rsmipc_type =
60450Sstevel@tonic-gate 			    RSMIPC_MSG_NOTIMPORTING;
60460Sstevel@tonic-gate 			request.rsmipc_key = im_seg->s_segid;
60470Sstevel@tonic-gate 			request.rsmipc_segment_cookie = shared_cookie;
60480Sstevel@tonic-gate 			rsmseglock_release(im_seg);
60490Sstevel@tonic-gate 			(void) rsmipc_send(im_seg->s_node, &request,
60500Sstevel@tonic-gate 			    RSM_NO_REPLY);
60510Sstevel@tonic-gate 		} else {
60520Sstevel@tonic-gate 			rsmseglock_release(im_seg);
60530Sstevel@tonic-gate 		}
60540Sstevel@tonic-gate 	}
60550Sstevel@tonic-gate 	else
60560Sstevel@tonic-gate 		rsmseglock_release(im_seg);
60570Sstevel@tonic-gate 
60580Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmseg_unload done\n"));
60590Sstevel@tonic-gate 
60600Sstevel@tonic-gate }
60610Sstevel@tonic-gate 
60620Sstevel@tonic-gate /* ****************************** Importer Calls ************************ */
60630Sstevel@tonic-gate 
60640Sstevel@tonic-gate static int
rsm_access(uid_t owner,gid_t group,int perm,int mode,const struct cred * cr)60650Sstevel@tonic-gate rsm_access(uid_t owner, gid_t group, int perm, int mode, const struct cred *cr)
60660Sstevel@tonic-gate {
60670Sstevel@tonic-gate 	int shifts = 0;
60680Sstevel@tonic-gate 
60690Sstevel@tonic-gate 	if (crgetuid(cr) != owner) {
60700Sstevel@tonic-gate 		shifts += 3;
60710Sstevel@tonic-gate 		if (!groupmember(group, cr))
60720Sstevel@tonic-gate 			shifts += 3;
60730Sstevel@tonic-gate 	}
60740Sstevel@tonic-gate 
60750Sstevel@tonic-gate 	mode &= ~(perm << shifts);
60760Sstevel@tonic-gate 
60770Sstevel@tonic-gate 	if (mode == 0)
60780Sstevel@tonic-gate 		return (0);
60790Sstevel@tonic-gate 
60800Sstevel@tonic-gate 	return (secpolicy_rsm_access(cr, owner, mode));
60810Sstevel@tonic-gate }
60820Sstevel@tonic-gate 
60830Sstevel@tonic-gate 
60840Sstevel@tonic-gate static int
rsm_connect(rsmseg_t * seg,rsm_ioctlmsg_t * msg,cred_t * cred,intptr_t dataptr,int mode)60850Sstevel@tonic-gate rsm_connect(rsmseg_t *seg, rsm_ioctlmsg_t *msg, cred_t *cred,
60860Sstevel@tonic-gate     intptr_t dataptr, int mode)
60870Sstevel@tonic-gate {
60880Sstevel@tonic-gate 	int e;
60890Sstevel@tonic-gate 	int			recheck_state = 0;
60900Sstevel@tonic-gate 	void			*shared_cookie;
60910Sstevel@tonic-gate 	rsmipc_request_t	request;
60920Sstevel@tonic-gate 	rsmipc_reply_t		reply;
60930Sstevel@tonic-gate 	rsm_permission_t	access;
60940Sstevel@tonic-gate 	adapter_t		*adapter;
60950Sstevel@tonic-gate 	rsm_addr_t		addr = 0;
60960Sstevel@tonic-gate 	rsm_import_share_t	*sharedp;
60970Sstevel@tonic-gate 	DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_IMPORT);
60980Sstevel@tonic-gate 
60990Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_connect enter\n"));
61000Sstevel@tonic-gate 
61010Sstevel@tonic-gate 	adapter = rsm_getadapter(msg, mode);
61020Sstevel@tonic-gate 	if (adapter == NULL) {
61030Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_ERR,
61040Sstevel@tonic-gate 		    "rsm_connect done:ENODEV adapter=NULL\n"));
61050Sstevel@tonic-gate 		return (RSMERR_CTLR_NOT_PRESENT);
61060Sstevel@tonic-gate 	}
61070Sstevel@tonic-gate 
61080Sstevel@tonic-gate 	if ((adapter == &loopback_adapter) && (msg->nodeid != my_nodeid)) {
61090Sstevel@tonic-gate 		rsmka_release_adapter(adapter);
61100Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_ERR,
61110Sstevel@tonic-gate 		    "rsm_connect done:ENODEV loopback\n"));
61120Sstevel@tonic-gate 		return (RSMERR_CTLR_NOT_PRESENT);
61130Sstevel@tonic-gate 	}
61140Sstevel@tonic-gate 
61150Sstevel@tonic-gate 
61160Sstevel@tonic-gate 	ASSERT(seg->s_hdr.rsmrc_type == RSM_RESOURCE_IMPORT_SEGMENT);
61170Sstevel@tonic-gate 	ASSERT(seg->s_state == RSM_STATE_NEW);
61180Sstevel@tonic-gate 
61190Sstevel@tonic-gate 	/*
61200Sstevel@tonic-gate 	 * Translate perm to access
61210Sstevel@tonic-gate 	 */
61220Sstevel@tonic-gate 	if (msg->perm & ~RSM_PERM_RDWR) {
61230Sstevel@tonic-gate 		rsmka_release_adapter(adapter);
61240Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_ERR,
61250Sstevel@tonic-gate 		    "rsm_connect done:EINVAL invalid perms\n"));
61260Sstevel@tonic-gate 		return (RSMERR_BAD_PERMS);
61270Sstevel@tonic-gate 	}
61280Sstevel@tonic-gate 	access = 0;
61290Sstevel@tonic-gate 	if (msg->perm & RSM_PERM_READ)
61300Sstevel@tonic-gate 		access |= RSM_ACCESS_READ;
61310Sstevel@tonic-gate 	if (msg->perm & RSM_PERM_WRITE)
61320Sstevel@tonic-gate 		access |= RSM_ACCESS_WRITE;
61330Sstevel@tonic-gate 
61340Sstevel@tonic-gate 	seg->s_node = msg->nodeid;
61350Sstevel@tonic-gate 
61360Sstevel@tonic-gate 	/*
61370Sstevel@tonic-gate 	 * Adding to the import list locks the segment; release the segment
61380Sstevel@tonic-gate 	 * lock so we can get the reply for the send.
61390Sstevel@tonic-gate 	 */
61400Sstevel@tonic-gate 	e = rsmimport_add(seg, msg->key);
61410Sstevel@tonic-gate 	if (e) {
61420Sstevel@tonic-gate 		rsmka_release_adapter(adapter);
61430Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_ERR,
61440Sstevel@tonic-gate 		    "rsm_connect done:rsmimport_add failed %d\n", e));
61450Sstevel@tonic-gate 		return (e);
61460Sstevel@tonic-gate 	}
61470Sstevel@tonic-gate 	seg->s_state = RSM_STATE_CONNECTING;
61480Sstevel@tonic-gate 
61490Sstevel@tonic-gate 	/*
61500Sstevel@tonic-gate 	 * Set the s_adapter field here so as to have a valid comparison of
61510Sstevel@tonic-gate 	 * the adapter and the s_adapter value during rsmshare_get. For
61520Sstevel@tonic-gate 	 * any error, set s_adapter to NULL before doing a release_adapter
61530Sstevel@tonic-gate 	 */
61540Sstevel@tonic-gate 	seg->s_adapter = adapter;
61550Sstevel@tonic-gate 
61560Sstevel@tonic-gate 	rsmseglock_release(seg);
61570Sstevel@tonic-gate 
61580Sstevel@tonic-gate 	/*
61590Sstevel@tonic-gate 	 * get the pointer to the shared data structure; the
61600Sstevel@tonic-gate 	 * shared data is locked and refcount has been incremented
61610Sstevel@tonic-gate 	 */
61620Sstevel@tonic-gate 	sharedp = rsmshare_get(msg->key, msg->nodeid, adapter, seg);
61630Sstevel@tonic-gate 
61640Sstevel@tonic-gate 	ASSERT(rsmsharelock_held(seg));
61650Sstevel@tonic-gate 
61660Sstevel@tonic-gate 	do {
61670Sstevel@tonic-gate 		/* flag indicates whether we need to recheck the state */
61680Sstevel@tonic-gate 		recheck_state = 0;
61690Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
61700Sstevel@tonic-gate 		    "rsm_connect:RSMSI_STATE=%d\n", sharedp->rsmsi_state));
61710Sstevel@tonic-gate 		switch (sharedp->rsmsi_state) {
61720Sstevel@tonic-gate 		case RSMSI_STATE_NEW:
61730Sstevel@tonic-gate 			sharedp->rsmsi_state = RSMSI_STATE_CONNECTING;
61740Sstevel@tonic-gate 			break;
61750Sstevel@tonic-gate 		case RSMSI_STATE_CONNECTING:
61760Sstevel@tonic-gate 			/* FALLTHRU */
61770Sstevel@tonic-gate 		case RSMSI_STATE_CONN_QUIESCE:
61780Sstevel@tonic-gate 			/* FALLTHRU */
61790Sstevel@tonic-gate 		case RSMSI_STATE_MAP_QUIESCE:
61800Sstevel@tonic-gate 			/* wait for the state to change */
61810Sstevel@tonic-gate 			while ((sharedp->rsmsi_state ==
61820Sstevel@tonic-gate 			    RSMSI_STATE_CONNECTING) ||
61830Sstevel@tonic-gate 			    (sharedp->rsmsi_state ==
61840Sstevel@tonic-gate 			    RSMSI_STATE_CONN_QUIESCE) ||
61850Sstevel@tonic-gate 			    (sharedp->rsmsi_state ==
61860Sstevel@tonic-gate 			    RSMSI_STATE_MAP_QUIESCE)) {
61870Sstevel@tonic-gate 				if (cv_wait_sig(&sharedp->rsmsi_cv,
61880Sstevel@tonic-gate 				    &sharedp->rsmsi_lock) == 0) {
61890Sstevel@tonic-gate 					/* signalled - clean up and return */
61900Sstevel@tonic-gate 					rsmsharelock_release(seg);
61910Sstevel@tonic-gate 					rsmimport_rm(seg);
61920Sstevel@tonic-gate 					seg->s_adapter = NULL;
61930Sstevel@tonic-gate 					rsmka_release_adapter(adapter);
61940Sstevel@tonic-gate 					seg->s_state = RSM_STATE_NEW;
61950Sstevel@tonic-gate 					DBG_PRINTF((category, RSM_ERR,
61960Sstevel@tonic-gate 					    "rsm_connect done: INTERRUPTED\n"));
61970Sstevel@tonic-gate 					return (RSMERR_INTERRUPTED);
61980Sstevel@tonic-gate 				}
61990Sstevel@tonic-gate 			}
62000Sstevel@tonic-gate 			/*
62010Sstevel@tonic-gate 			 * the state changed, loop back and check what it is
62020Sstevel@tonic-gate 			 */
62030Sstevel@tonic-gate 			recheck_state = 1;
62040Sstevel@tonic-gate 			break;
62050Sstevel@tonic-gate 		case RSMSI_STATE_ABORT_CONNECT:
62060Sstevel@tonic-gate 			/* exit the loop and clean up further down */
62070Sstevel@tonic-gate 			break;
62080Sstevel@tonic-gate 		case RSMSI_STATE_CONNECTED:
62090Sstevel@tonic-gate 			/* already connected, good - fall through */
62100Sstevel@tonic-gate 		case RSMSI_STATE_MAPPED:
62110Sstevel@tonic-gate 			/* already mapped, wow - fall through */
62120Sstevel@tonic-gate 			/* access validation etc is done further down */
62130Sstevel@tonic-gate 			break;
62140Sstevel@tonic-gate 		case RSMSI_STATE_DISCONNECTED:
62150Sstevel@tonic-gate 			/* disconnected - so reconnect now */
62160Sstevel@tonic-gate 			sharedp->rsmsi_state = RSMSI_STATE_CONNECTING;
62170Sstevel@tonic-gate 			break;
62180Sstevel@tonic-gate 		default:
62190Sstevel@tonic-gate 			ASSERT(0); /* Invalid State */
62200Sstevel@tonic-gate 		}
62210Sstevel@tonic-gate 	} while (recheck_state);
62220Sstevel@tonic-gate 
62230Sstevel@tonic-gate 	if (sharedp->rsmsi_state == RSMSI_STATE_CONNECTING) {
62240Sstevel@tonic-gate 		/* we are the first to connect */
62250Sstevel@tonic-gate 		rsmsharelock_release(seg);
62260Sstevel@tonic-gate 
62270Sstevel@tonic-gate 		if (msg->nodeid != my_nodeid) {
62280Sstevel@tonic-gate 			addr = get_remote_hwaddr(adapter, msg->nodeid);
62290Sstevel@tonic-gate 
62300Sstevel@tonic-gate 			if ((int64_t)addr < 0) {
62310Sstevel@tonic-gate 				rsmsharelock_acquire(seg);
62320Sstevel@tonic-gate 				rsmsharecv_signal(seg, RSMSI_STATE_CONNECTING,
62330Sstevel@tonic-gate 				    RSMSI_STATE_NEW);
62340Sstevel@tonic-gate 				rsmsharelock_release(seg);
62350Sstevel@tonic-gate 				rsmimport_rm(seg);
62360Sstevel@tonic-gate 				seg->s_adapter = NULL;
62370Sstevel@tonic-gate 				rsmka_release_adapter(adapter);
62380Sstevel@tonic-gate 				seg->s_state = RSM_STATE_NEW;
62390Sstevel@tonic-gate 				DBG_PRINTF((category, RSM_ERR,
62400Sstevel@tonic-gate 				    "rsm_connect done: hwaddr<0\n"));
62410Sstevel@tonic-gate 				return (RSMERR_INTERNAL_ERROR);
62420Sstevel@tonic-gate 			}
62430Sstevel@tonic-gate 		} else {
62440Sstevel@tonic-gate 			addr = adapter->hwaddr;
62450Sstevel@tonic-gate 		}
62460Sstevel@tonic-gate 
62470Sstevel@tonic-gate 		/*
62480Sstevel@tonic-gate 		 * send request to node [src, dest, key, msgid] and get back
62490Sstevel@tonic-gate 		 * [status, msgid, cookie]
62500Sstevel@tonic-gate 		 */
62510Sstevel@tonic-gate 		request.rsmipc_key = msg->key;
62520Sstevel@tonic-gate 		/*
62530Sstevel@tonic-gate 		 * we need the s_mode of the exporter so pass
62540Sstevel@tonic-gate 		 * RSM_ACCESS_TRUSTED
62550Sstevel@tonic-gate 		 */
62560Sstevel@tonic-gate 		request.rsmipc_perm = RSM_ACCESS_TRUSTED;
62570Sstevel@tonic-gate 		request.rsmipc_hdr.rsmipc_type = RSMIPC_MSG_SEGCONNECT;
62580Sstevel@tonic-gate 		request.rsmipc_adapter_hwaddr = addr;
62590Sstevel@tonic-gate 		request.rsmipc_segment_cookie = sharedp;
62600Sstevel@tonic-gate 
62610Sstevel@tonic-gate 		e = (int)rsmipc_send(msg->nodeid, &request, &reply);
62620Sstevel@tonic-gate 		if (e) {
62630Sstevel@tonic-gate 			rsmsharelock_acquire(seg);
62640Sstevel@tonic-gate 			rsmsharecv_signal(seg, RSMSI_STATE_CONNECTING,
62650Sstevel@tonic-gate 			    RSMSI_STATE_NEW);
62660Sstevel@tonic-gate 			rsmsharelock_release(seg);
62670Sstevel@tonic-gate 			rsmimport_rm(seg);
62680Sstevel@tonic-gate 			seg->s_adapter = NULL;
62690Sstevel@tonic-gate 			rsmka_release_adapter(adapter);
62700Sstevel@tonic-gate 			seg->s_state = RSM_STATE_NEW;
62710Sstevel@tonic-gate 			DBG_PRINTF((category, RSM_ERR,
62720Sstevel@tonic-gate 			    "rsm_connect done:rsmipc_send failed %d\n", e));
62730Sstevel@tonic-gate 			return (e);
62740Sstevel@tonic-gate 		}
62750Sstevel@tonic-gate 
62760Sstevel@tonic-gate 		if (reply.rsmipc_status != RSM_SUCCESS) {
62770Sstevel@tonic-gate 			rsmsharelock_acquire(seg);
62780Sstevel@tonic-gate 			rsmsharecv_signal(seg, RSMSI_STATE_CONNECTING,
62790Sstevel@tonic-gate 			    RSMSI_STATE_NEW);
62800Sstevel@tonic-gate 			rsmsharelock_release(seg);
62810Sstevel@tonic-gate 			rsmimport_rm(seg);
62820Sstevel@tonic-gate 			seg->s_adapter = NULL;
62830Sstevel@tonic-gate 			rsmka_release_adapter(adapter);
62840Sstevel@tonic-gate 			seg->s_state = RSM_STATE_NEW;
62850Sstevel@tonic-gate 			DBG_PRINTF((category, RSM_ERR,
62860Sstevel@tonic-gate 			    "rsm_connect done:rsmipc_send reply err %d\n",
62870Sstevel@tonic-gate 			    reply.rsmipc_status));
62880Sstevel@tonic-gate 			return (reply.rsmipc_status);
62890Sstevel@tonic-gate 		}
62900Sstevel@tonic-gate 
62910Sstevel@tonic-gate 		rsmsharelock_acquire(seg);
62920Sstevel@tonic-gate 		/* store the information recvd into the shared data struct */
62930Sstevel@tonic-gate 		sharedp->rsmsi_mode = reply.rsmipc_mode;
62940Sstevel@tonic-gate 		sharedp->rsmsi_uid = reply.rsmipc_uid;
62950Sstevel@tonic-gate 		sharedp->rsmsi_gid = reply.rsmipc_gid;
62960Sstevel@tonic-gate 		sharedp->rsmsi_seglen = reply.rsmipc_seglen;
62970Sstevel@tonic-gate 		sharedp->rsmsi_cookie = sharedp;
62980Sstevel@tonic-gate 	}
62990Sstevel@tonic-gate 
63000Sstevel@tonic-gate 	rsmsharelock_release(seg);
63010Sstevel@tonic-gate 
63020Sstevel@tonic-gate 	/*
63030Sstevel@tonic-gate 	 * Get the segment lock and check for a force disconnect
63040Sstevel@tonic-gate 	 * from the export side which would have changed the state
63050Sstevel@tonic-gate 	 * back to RSM_STATE_NEW. Once the segment lock is acquired a
63060Sstevel@tonic-gate 	 * force disconnect will be held off until the connection
63070Sstevel@tonic-gate 	 * has completed.
63080Sstevel@tonic-gate 	 */
63090Sstevel@tonic-gate 	rsmseglock_acquire(seg);
63100Sstevel@tonic-gate 	rsmsharelock_acquire(seg);
63110Sstevel@tonic-gate 	ASSERT(seg->s_state == RSM_STATE_CONNECTING ||
63120Sstevel@tonic-gate 	    seg->s_state == RSM_STATE_ABORT_CONNECT);
63130Sstevel@tonic-gate 
63140Sstevel@tonic-gate 	shared_cookie = sharedp->rsmsi_cookie;
63150Sstevel@tonic-gate 
63160Sstevel@tonic-gate 	if ((seg->s_state == RSM_STATE_ABORT_CONNECT) ||
63170Sstevel@tonic-gate 	    (sharedp->rsmsi_state == RSMSI_STATE_ABORT_CONNECT)) {
63180Sstevel@tonic-gate 		seg->s_state = RSM_STATE_NEW;
63190Sstevel@tonic-gate 		seg->s_adapter = NULL;
63200Sstevel@tonic-gate 		rsmsharelock_release(seg);
63210Sstevel@tonic-gate 		rsmseglock_release(seg);
63220Sstevel@tonic-gate 		rsmimport_rm(seg);
63230Sstevel@tonic-gate 		rsmka_release_adapter(adapter);
63240Sstevel@tonic-gate 
63250Sstevel@tonic-gate 		rsmsharelock_acquire(seg);
63260Sstevel@tonic-gate 		if (!(sharedp->rsmsi_flags & RSMSI_FLAGS_ABORTDONE)) {
63270Sstevel@tonic-gate 			/*
63280Sstevel@tonic-gate 			 * set a flag indicating abort handling has been
63290Sstevel@tonic-gate 			 * done
63300Sstevel@tonic-gate 			 */
63310Sstevel@tonic-gate 			sharedp->rsmsi_flags |= RSMSI_FLAGS_ABORTDONE;
63320Sstevel@tonic-gate 			rsmsharelock_release(seg);
63330Sstevel@tonic-gate 			/* send a message to exporter - only once */
63340Sstevel@tonic-gate 			(void) rsm_send_notimporting(msg->nodeid,
63350Sstevel@tonic-gate 			    msg->key, shared_cookie);
63360Sstevel@tonic-gate 			rsmsharelock_acquire(seg);
63370Sstevel@tonic-gate 			/*
63380Sstevel@tonic-gate 			 * wake up any waiting importers and inform that
63390Sstevel@tonic-gate 			 * connection has been aborted
63400Sstevel@tonic-gate 			 */
63410Sstevel@tonic-gate 			cv_broadcast(&sharedp->rsmsi_cv);
63420Sstevel@tonic-gate 		}
63430Sstevel@tonic-gate 		rsmsharelock_release(seg);
63440Sstevel@tonic-gate 
63450Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_ERR,
63460Sstevel@tonic-gate 		    "rsm_connect done: RSM_STATE_ABORT_CONNECT\n"));
63470Sstevel@tonic-gate 		return (RSMERR_INTERRUPTED);
63480Sstevel@tonic-gate 	}
63490Sstevel@tonic-gate 
63500Sstevel@tonic-gate 
63510Sstevel@tonic-gate 	/*
63520Sstevel@tonic-gate 	 * We need to verify that this process has access
63530Sstevel@tonic-gate 	 */
63540Sstevel@tonic-gate 	e = rsm_access(sharedp->rsmsi_uid, sharedp->rsmsi_gid,
63557656SSherry.Moore@Sun.COM 	    access & sharedp->rsmsi_mode,
63567656SSherry.Moore@Sun.COM 	    (int)(msg->perm & RSM_PERM_RDWR), cred);
63570Sstevel@tonic-gate 	if (e) {
63580Sstevel@tonic-gate 		rsmsharelock_release(seg);
63590Sstevel@tonic-gate 		seg->s_state = RSM_STATE_NEW;
63600Sstevel@tonic-gate 		seg->s_adapter = NULL;
63610Sstevel@tonic-gate 		rsmseglock_release(seg);
63620Sstevel@tonic-gate 		rsmimport_rm(seg);
63630Sstevel@tonic-gate 		rsmka_release_adapter(adapter);
63640Sstevel@tonic-gate 		/*
63650Sstevel@tonic-gate 		 * No need to lock segment it has been removed
63660Sstevel@tonic-gate 		 * from the hash table
63670Sstevel@tonic-gate 		 */
63680Sstevel@tonic-gate 		rsmsharelock_acquire(seg);
63690Sstevel@tonic-gate 		if (sharedp->rsmsi_state == RSMSI_STATE_CONNECTING) {
63700Sstevel@tonic-gate 			rsmsharelock_release(seg);
63710Sstevel@tonic-gate 			/* this is the first importer */
63720Sstevel@tonic-gate 
63730Sstevel@tonic-gate 			(void) rsm_send_notimporting(msg->nodeid, msg->key,
63740Sstevel@tonic-gate 			    shared_cookie);
63750Sstevel@tonic-gate 			rsmsharelock_acquire(seg);
63760Sstevel@tonic-gate 			sharedp->rsmsi_state = RSMSI_STATE_NEW;
63770Sstevel@tonic-gate 			cv_broadcast(&sharedp->rsmsi_cv);
63780Sstevel@tonic-gate 		}
63790Sstevel@tonic-gate 		rsmsharelock_release(seg);
63800Sstevel@tonic-gate 
63810Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_ERR,
63820Sstevel@tonic-gate 		    "rsm_connect done: ipcaccess failed\n"));
63830Sstevel@tonic-gate 		return (RSMERR_PERM_DENIED);
63840Sstevel@tonic-gate 	}
63850Sstevel@tonic-gate 
63860Sstevel@tonic-gate 	/* update state and cookie */
63870Sstevel@tonic-gate 	seg->s_segid = sharedp->rsmsi_segid;
63880Sstevel@tonic-gate 	seg->s_len = sharedp->rsmsi_seglen;
63890Sstevel@tonic-gate 	seg->s_mode = access & sharedp->rsmsi_mode;
63900Sstevel@tonic-gate 	seg->s_pid = ddi_get_pid();
63910Sstevel@tonic-gate 	seg->s_mapinfo = NULL;
63920Sstevel@tonic-gate 
63930Sstevel@tonic-gate 	if (seg->s_node != my_nodeid) {
63940Sstevel@tonic-gate 		if (sharedp->rsmsi_state == RSMSI_STATE_CONNECTING) {
63950Sstevel@tonic-gate 			e = adapter->rsmpi_ops->rsm_connect(
63960Sstevel@tonic-gate 			    adapter->rsmpi_handle,
63970Sstevel@tonic-gate 			    addr, seg->s_segid, &sharedp->rsmsi_handle);
63980Sstevel@tonic-gate 
63990Sstevel@tonic-gate 			if (e != RSM_SUCCESS) {
64000Sstevel@tonic-gate 				seg->s_state = RSM_STATE_NEW;
64010Sstevel@tonic-gate 				seg->s_adapter = NULL;
64020Sstevel@tonic-gate 				rsmsharelock_release(seg);
64030Sstevel@tonic-gate 				rsmseglock_release(seg);
64040Sstevel@tonic-gate 				rsmimport_rm(seg);
64050Sstevel@tonic-gate 				rsmka_release_adapter(adapter);
64060Sstevel@tonic-gate 				/*
64070Sstevel@tonic-gate 				 *  inform the exporter to delete this importer
64080Sstevel@tonic-gate 				 */
64090Sstevel@tonic-gate 				(void) rsm_send_notimporting(msg->nodeid,
64100Sstevel@tonic-gate 				    msg->key, shared_cookie);
64110Sstevel@tonic-gate 
64120Sstevel@tonic-gate 				/*
64130Sstevel@tonic-gate 				 * Now inform any waiting importers to
64140Sstevel@tonic-gate 				 * retry connect. This needs to be done
64150Sstevel@tonic-gate 				 * after sending notimporting so that
64160Sstevel@tonic-gate 				 * the notimporting is sent before a waiting
64170Sstevel@tonic-gate 				 * importer sends a segconnect while retrying
64180Sstevel@tonic-gate 				 *
64190Sstevel@tonic-gate 				 * No need to lock segment it has been removed
64200Sstevel@tonic-gate 				 * from the hash table
64210Sstevel@tonic-gate 				 */
64220Sstevel@tonic-gate 
64230Sstevel@tonic-gate 				rsmsharelock_acquire(seg);
64240Sstevel@tonic-gate 				sharedp->rsmsi_state = RSMSI_STATE_NEW;
64250Sstevel@tonic-gate 				cv_broadcast(&sharedp->rsmsi_cv);
64260Sstevel@tonic-gate 				rsmsharelock_release(seg);
64270Sstevel@tonic-gate 
64280Sstevel@tonic-gate 				DBG_PRINTF((category, RSM_ERR,
64290Sstevel@tonic-gate 				    "rsm_connect error %d\n", e));
64300Sstevel@tonic-gate 				if (e == RSMERR_SEG_NOT_PUBLISHED_TO_RSM_ADDR)
64310Sstevel@tonic-gate 					return (
64320Sstevel@tonic-gate 					    RSMERR_SEG_NOT_PUBLISHED_TO_NODE);
64330Sstevel@tonic-gate 				else if ((e == RSMERR_RSM_ADDR_UNREACHABLE) ||
64347656SSherry.Moore@Sun.COM 				    (e == RSMERR_UNKNOWN_RSM_ADDR))
64350Sstevel@tonic-gate 					return (RSMERR_REMOTE_NODE_UNREACHABLE);
64360Sstevel@tonic-gate 				else
64370Sstevel@tonic-gate 					return (e);
64380Sstevel@tonic-gate 			}
64390Sstevel@tonic-gate 
64400Sstevel@tonic-gate 		}
64410Sstevel@tonic-gate 		seg->s_handle.in = sharedp->rsmsi_handle;
64420Sstevel@tonic-gate 
64430Sstevel@tonic-gate 	}
64440Sstevel@tonic-gate 
64450Sstevel@tonic-gate 	seg->s_state = RSM_STATE_CONNECT;
64460Sstevel@tonic-gate 
64470Sstevel@tonic-gate 
64480Sstevel@tonic-gate 	seg->s_flags &= ~RSM_IMPORT_DUMMY;	/* clear dummy flag */
64490Sstevel@tonic-gate 	if (bar_va) {
64500Sstevel@tonic-gate 		/* increment generation number on barrier page */
64510Sstevel@tonic-gate 		atomic_add_16(bar_va + seg->s_hdr.rsmrc_num, 1);
64520Sstevel@tonic-gate 		/* return user off into barrier page where status will be */
64530Sstevel@tonic-gate 		msg->off = (int)seg->s_hdr.rsmrc_num;
64540Sstevel@tonic-gate 		msg->gnum = bar_va[msg->off]; 	/* gnum race */
64550Sstevel@tonic-gate 	} else {
64560Sstevel@tonic-gate 		msg->off = 0;
64570Sstevel@tonic-gate 		msg->gnum = 0;	/* gnum race */
64580Sstevel@tonic-gate 	}
64590Sstevel@tonic-gate 
64600Sstevel@tonic-gate 	msg->len = (int)sharedp->rsmsi_seglen;
64610Sstevel@tonic-gate 	msg->rnum = seg->s_minor;
64620Sstevel@tonic-gate 	rsmsharecv_signal(seg, RSMSI_STATE_CONNECTING, RSMSI_STATE_CONNECTED);
64630Sstevel@tonic-gate 	rsmsharelock_release(seg);
64640Sstevel@tonic-gate 	rsmseglock_release(seg);
64650Sstevel@tonic-gate 
64660Sstevel@tonic-gate 	/* Return back to user the segment size & perm in case it's needed */
64670Sstevel@tonic-gate 
64680Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL
64690Sstevel@tonic-gate 	if ((mode & DATAMODEL_MASK) == DATAMODEL_ILP32) {
64700Sstevel@tonic-gate 		rsm_ioctlmsg32_t msg32;
64710Sstevel@tonic-gate 
64720Sstevel@tonic-gate 		if (msg->len > UINT_MAX)
64730Sstevel@tonic-gate 			msg32.len = RSM_MAXSZ_PAGE_ALIGNED;
64740Sstevel@tonic-gate 		else
64750Sstevel@tonic-gate 			msg32.len = msg->len;
64760Sstevel@tonic-gate 		msg32.off = msg->off;
64770Sstevel@tonic-gate 		msg32.perm = msg->perm;
64780Sstevel@tonic-gate 		msg32.gnum = msg->gnum;
64790Sstevel@tonic-gate 		msg32.rnum = msg->rnum;
64800Sstevel@tonic-gate 
64810Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
64820Sstevel@tonic-gate 		    "rsm_connect done\n"));
64830Sstevel@tonic-gate 
64840Sstevel@tonic-gate 		if (ddi_copyout((caddr_t)&msg32, (caddr_t)dataptr,
64850Sstevel@tonic-gate 		    sizeof (msg32), mode))
64860Sstevel@tonic-gate 			return (RSMERR_BAD_ADDR);
64870Sstevel@tonic-gate 		else
64880Sstevel@tonic-gate 			return (RSM_SUCCESS);
64890Sstevel@tonic-gate 	}
64900Sstevel@tonic-gate #endif
64910Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_connect done\n"));
64920Sstevel@tonic-gate 
64930Sstevel@tonic-gate 	if (ddi_copyout((caddr_t)msg, (caddr_t)dataptr, sizeof (*msg),
64940Sstevel@tonic-gate 	    mode))
64950Sstevel@tonic-gate 		return (RSMERR_BAD_ADDR);
64960Sstevel@tonic-gate 	else
64970Sstevel@tonic-gate 		return (RSM_SUCCESS);
64980Sstevel@tonic-gate }
64990Sstevel@tonic-gate 
65000Sstevel@tonic-gate static int
rsm_unmap(rsmseg_t * seg)65010Sstevel@tonic-gate rsm_unmap(rsmseg_t *seg)
65020Sstevel@tonic-gate {
65030Sstevel@tonic-gate 	int			err;
65040Sstevel@tonic-gate 	adapter_t		*adapter;
65050Sstevel@tonic-gate 	rsm_import_share_t	*sharedp;
65060Sstevel@tonic-gate 	DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_IMPORT);
65070Sstevel@tonic-gate 
65080Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
65090Sstevel@tonic-gate 	    "rsm_unmap enter %u\n", seg->s_segid));
65100Sstevel@tonic-gate 
65110Sstevel@tonic-gate 	ASSERT(seg->s_hdr.rsmrc_type == RSM_RESOURCE_IMPORT_SEGMENT);
65120Sstevel@tonic-gate 
65130Sstevel@tonic-gate 	/* assert seg is locked */
65140Sstevel@tonic-gate 	ASSERT(rsmseglock_held(seg));
65150Sstevel@tonic-gate 	ASSERT(seg->s_state != RSM_STATE_MAPPING);
65160Sstevel@tonic-gate 
65170Sstevel@tonic-gate 	if ((seg->s_state != RSM_STATE_ACTIVE) &&
65180Sstevel@tonic-gate 	    (seg->s_state != RSM_STATE_MAP_QUIESCE)) {
65190Sstevel@tonic-gate 		/* segment unmap has already been done */
65200Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_unmap done\n"));
65210Sstevel@tonic-gate 		return (RSM_SUCCESS);
65220Sstevel@tonic-gate 	}
65230Sstevel@tonic-gate 
65240Sstevel@tonic-gate 	sharedp = seg->s_share;
65250Sstevel@tonic-gate 
65260Sstevel@tonic-gate 	rsmsharelock_acquire(seg);
65270Sstevel@tonic-gate 
65280Sstevel@tonic-gate 	/*
65290Sstevel@tonic-gate 	 *	- shared data struct is in MAPPED or MAP_QUIESCE state
65300Sstevel@tonic-gate 	 */
65310Sstevel@tonic-gate 
65320Sstevel@tonic-gate 	ASSERT(sharedp->rsmsi_state == RSMSI_STATE_MAPPED ||
65330Sstevel@tonic-gate 	    sharedp->rsmsi_state == RSMSI_STATE_MAP_QUIESCE);
65340Sstevel@tonic-gate 
65350Sstevel@tonic-gate 	/*
65360Sstevel@tonic-gate 	 * Unmap pages - previously rsm_memseg_import_unmap was called only if
65370Sstevel@tonic-gate 	 * the segment cookie list was NULL; but it is always NULL when
65380Sstevel@tonic-gate 	 * called from rsmmap_unmap and won't be NULL when called for
65390Sstevel@tonic-gate 	 * a force disconnect - so the check for NULL cookie list was removed
65400Sstevel@tonic-gate 	 */
65410Sstevel@tonic-gate 
65420Sstevel@tonic-gate 	ASSERT(sharedp->rsmsi_mapcnt > 0);
65430Sstevel@tonic-gate 
65440Sstevel@tonic-gate 	sharedp->rsmsi_mapcnt--;
65450Sstevel@tonic-gate 
65460Sstevel@tonic-gate 	if (sharedp->rsmsi_mapcnt == 0) {
65470Sstevel@tonic-gate 		if (sharedp->rsmsi_state == RSMSI_STATE_MAPPED) {
65480Sstevel@tonic-gate 			/* unmap the shared RSMPI mapping */
65490Sstevel@tonic-gate 			adapter = seg->s_adapter;
65500Sstevel@tonic-gate 			if (seg->s_node != my_nodeid) {
65510Sstevel@tonic-gate 				ASSERT(sharedp->rsmsi_handle != NULL);
65520Sstevel@tonic-gate 				err = adapter->rsmpi_ops->
65530Sstevel@tonic-gate 				    rsm_unmap(sharedp->rsmsi_handle);
65540Sstevel@tonic-gate 				DBG_PRINTF((category, RSM_DEBUG,
65550Sstevel@tonic-gate 				    "rsm_unmap: rsmpi unmap %d\n", err));
65560Sstevel@tonic-gate 				rsm_free_mapinfo(sharedp->rsmsi_mapinfo);
65570Sstevel@tonic-gate 				sharedp->rsmsi_mapinfo = NULL;
65580Sstevel@tonic-gate 			}
65590Sstevel@tonic-gate 			sharedp->rsmsi_state = RSMSI_STATE_CONNECTED;
65600Sstevel@tonic-gate 		} else { /* MAP_QUIESCE --munmap()--> CONN_QUIESCE */
65610Sstevel@tonic-gate 			sharedp->rsmsi_state = RSMSI_STATE_CONN_QUIESCE;
65620Sstevel@tonic-gate 		}
65630Sstevel@tonic-gate 	}
65640Sstevel@tonic-gate 
65650Sstevel@tonic-gate 	rsmsharelock_release(seg);
65660Sstevel@tonic-gate 
65670Sstevel@tonic-gate 	/*
65680Sstevel@tonic-gate 	 * The s_cookie field is used to store the cookie returned from the
65690Sstevel@tonic-gate 	 * ddi_umem_lock when binding the pages for an export segment. This
65700Sstevel@tonic-gate 	 * is the primary use of the s_cookie field and does not normally
65710Sstevel@tonic-gate 	 * pertain to any importing segment except in the loopback case.
65720Sstevel@tonic-gate 	 * For the loopback case, the import segment and export segment are
65730Sstevel@tonic-gate 	 * on the same node, the s_cookie field of the segment structure for
65740Sstevel@tonic-gate 	 * the importer is initialized to the s_cookie field in the exported
65750Sstevel@tonic-gate 	 * segment during the map operation and is used during the call to
65760Sstevel@tonic-gate 	 * devmap_umem_setup for the import mapping.
65770Sstevel@tonic-gate 	 * Thus, during unmap, we simply need to set s_cookie to NULL to
65780Sstevel@tonic-gate 	 * indicate that the mapping no longer exists.
65790Sstevel@tonic-gate 	 */
65800Sstevel@tonic-gate 	seg->s_cookie = NULL;
65810Sstevel@tonic-gate 
65820Sstevel@tonic-gate 	seg->s_mapinfo = NULL;
65830Sstevel@tonic-gate 
65840Sstevel@tonic-gate 	if (seg->s_state == RSM_STATE_ACTIVE)
65850Sstevel@tonic-gate 		seg->s_state = RSM_STATE_CONNECT;
65860Sstevel@tonic-gate 	else
65870Sstevel@tonic-gate 		seg->s_state = RSM_STATE_CONN_QUIESCE;
65880Sstevel@tonic-gate 
65890Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_unmap done\n"));
65900Sstevel@tonic-gate 
65910Sstevel@tonic-gate 	return (RSM_SUCCESS);
65920Sstevel@tonic-gate }
65930Sstevel@tonic-gate 
65940Sstevel@tonic-gate /*
65950Sstevel@tonic-gate  * cookie returned here if not null indicates that it is
65960Sstevel@tonic-gate  * the last importer and it can be used in the RSMIPC_NOT_IMPORTING
65970Sstevel@tonic-gate  * message.
65980Sstevel@tonic-gate  */
65990Sstevel@tonic-gate static int
rsm_closeconnection(rsmseg_t * seg,void ** cookie)66000Sstevel@tonic-gate rsm_closeconnection(rsmseg_t *seg, void **cookie)
66010Sstevel@tonic-gate {
66020Sstevel@tonic-gate 	int			e;
66030Sstevel@tonic-gate 	adapter_t		*adapter;
66040Sstevel@tonic-gate 	rsm_import_share_t	*sharedp;
66050Sstevel@tonic-gate 	DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_IMPORT);
66060Sstevel@tonic-gate 
66070Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
66087656SSherry.Moore@Sun.COM 	    "rsm_closeconnection enter\n"));
66090Sstevel@tonic-gate 
66100Sstevel@tonic-gate 	*cookie = (void *)NULL;
66110Sstevel@tonic-gate 
66120Sstevel@tonic-gate 	ASSERT(seg->s_hdr.rsmrc_type == RSM_RESOURCE_IMPORT_SEGMENT);
66130Sstevel@tonic-gate 
66140Sstevel@tonic-gate 	/* assert seg is locked */
66150Sstevel@tonic-gate 	ASSERT(rsmseglock_held(seg));
66160Sstevel@tonic-gate 
66170Sstevel@tonic-gate 	if (seg->s_state == RSM_STATE_DISCONNECT) {
66180Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
66190Sstevel@tonic-gate 		    "rsm_closeconnection done: already disconnected\n"));
66200Sstevel@tonic-gate 		return (RSM_SUCCESS);
66210Sstevel@tonic-gate 	}
66220Sstevel@tonic-gate 
66230Sstevel@tonic-gate 	/* wait for all putv/getv ops to get done */
66240Sstevel@tonic-gate 	while (seg->s_rdmacnt > 0) {
66250Sstevel@tonic-gate 		cv_wait(&seg->s_cv, &seg->s_lock);
66260Sstevel@tonic-gate 	}
66270Sstevel@tonic-gate 
66280Sstevel@tonic-gate 	(void) rsm_unmap(seg);
66290Sstevel@tonic-gate 
66300Sstevel@tonic-gate 	ASSERT(seg->s_state == RSM_STATE_CONNECT ||
66310Sstevel@tonic-gate 	    seg->s_state == RSM_STATE_CONN_QUIESCE);
66320Sstevel@tonic-gate 
66330Sstevel@tonic-gate 	adapter = seg->s_adapter;
66340Sstevel@tonic-gate 	sharedp = seg->s_share;
66350Sstevel@tonic-gate 
66360Sstevel@tonic-gate 	ASSERT(sharedp != NULL);
66370Sstevel@tonic-gate 
66380Sstevel@tonic-gate 	rsmsharelock_acquire(seg);
66390Sstevel@tonic-gate 
66400Sstevel@tonic-gate 	/*
66410Sstevel@tonic-gate 	 * Disconnect on adapter
66420Sstevel@tonic-gate 	 *
66430Sstevel@tonic-gate 	 * The current algorithm is stateless, I don't have to contact
66440Sstevel@tonic-gate 	 * server when I go away. He only gives me permissions. Of course,
66450Sstevel@tonic-gate 	 * the adapters will talk to terminate the connect.
66460Sstevel@tonic-gate 	 *
66470Sstevel@tonic-gate 	 * disconnect is needed only if we are CONNECTED not in CONN_QUIESCE
66480Sstevel@tonic-gate 	 */
66490Sstevel@tonic-gate 	if ((sharedp->rsmsi_state == RSMSI_STATE_CONNECTED) &&
66500Sstevel@tonic-gate 	    (sharedp->rsmsi_node != my_nodeid)) {
66510Sstevel@tonic-gate 
66520Sstevel@tonic-gate 		if (sharedp->rsmsi_refcnt == 1) {
66530Sstevel@tonic-gate 			/* this is the last importer */
66540Sstevel@tonic-gate 			ASSERT(sharedp->rsmsi_mapcnt == 0);
66550Sstevel@tonic-gate 
66560Sstevel@tonic-gate 			e = adapter->rsmpi_ops->
66570Sstevel@tonic-gate 			    rsm_disconnect(sharedp->rsmsi_handle);
66580Sstevel@tonic-gate 			if (e != RSM_SUCCESS) {
66590Sstevel@tonic-gate 				DBG_PRINTF((category, RSM_DEBUG,
66600Sstevel@tonic-gate 				    "rsm:disconnect failed seg=%x:err=%d\n",
66610Sstevel@tonic-gate 				    seg->s_key, e));
66620Sstevel@tonic-gate 			}
66630Sstevel@tonic-gate 		}
66640Sstevel@tonic-gate 	}
66650Sstevel@tonic-gate 
66660Sstevel@tonic-gate 	seg->s_handle.in = NULL;
66670Sstevel@tonic-gate 
66680Sstevel@tonic-gate 	sharedp->rsmsi_refcnt--;
66690Sstevel@tonic-gate 
66700Sstevel@tonic-gate 	if (sharedp->rsmsi_refcnt == 0) {
66710Sstevel@tonic-gate 		*cookie = (void *)sharedp->rsmsi_cookie;
66720Sstevel@tonic-gate 		sharedp->rsmsi_state = RSMSI_STATE_DISCONNECTED;
66730Sstevel@tonic-gate 		sharedp->rsmsi_handle = NULL;
66740Sstevel@tonic-gate 		rsmsharelock_release(seg);
66750Sstevel@tonic-gate 
66760Sstevel@tonic-gate 		/* clean up the shared data structure */
66770Sstevel@tonic-gate 		mutex_destroy(&sharedp->rsmsi_lock);
66780Sstevel@tonic-gate 		cv_destroy(&sharedp->rsmsi_cv);
66790Sstevel@tonic-gate 		kmem_free((void *)(sharedp), sizeof (rsm_import_share_t));
66800Sstevel@tonic-gate 
66810Sstevel@tonic-gate 	} else {
66820Sstevel@tonic-gate 		rsmsharelock_release(seg);
66830Sstevel@tonic-gate 	}
66840Sstevel@tonic-gate 
66850Sstevel@tonic-gate 	/* increment generation number on barrier page */
66860Sstevel@tonic-gate 	if (bar_va) {
66870Sstevel@tonic-gate 		atomic_add_16(bar_va + seg->s_hdr.rsmrc_num, 1);
66880Sstevel@tonic-gate 	}
66890Sstevel@tonic-gate 
66900Sstevel@tonic-gate 	/*
66910Sstevel@tonic-gate 	 * The following needs to be done after any
66920Sstevel@tonic-gate 	 * rsmsharelock calls which use seg->s_share.
66930Sstevel@tonic-gate 	 */
66940Sstevel@tonic-gate 	seg->s_share = NULL;
66950Sstevel@tonic-gate 
66960Sstevel@tonic-gate 	seg->s_state = RSM_STATE_DISCONNECT;
66970Sstevel@tonic-gate 	/* signal anyone waiting in the CONN_QUIESCE state */
66980Sstevel@tonic-gate 	cv_broadcast(&seg->s_cv);
66990Sstevel@tonic-gate 
67000Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
67010Sstevel@tonic-gate 	    "rsm_closeconnection done\n"));
67020Sstevel@tonic-gate 
67030Sstevel@tonic-gate 	return (RSM_SUCCESS);
67040Sstevel@tonic-gate }
67050Sstevel@tonic-gate 
67060Sstevel@tonic-gate int
rsm_disconnect(rsmseg_t * seg)67070Sstevel@tonic-gate rsm_disconnect(rsmseg_t *seg)
67080Sstevel@tonic-gate {
67090Sstevel@tonic-gate 	rsmipc_request_t	request;
67100Sstevel@tonic-gate 	void			*shared_cookie;
67110Sstevel@tonic-gate 	DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_IMPORT);
67120Sstevel@tonic-gate 
67130Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_disconnect enter\n"));
67140Sstevel@tonic-gate 
67150Sstevel@tonic-gate 	ASSERT(seg->s_hdr.rsmrc_type == RSM_RESOURCE_IMPORT_SEGMENT);
67160Sstevel@tonic-gate 
67170Sstevel@tonic-gate 	/* assert seg isn't locked */
67180Sstevel@tonic-gate 	ASSERT(!rsmseglock_held(seg));
67190Sstevel@tonic-gate 
67200Sstevel@tonic-gate 
67210Sstevel@tonic-gate 	/* Remove segment from imported list */
67220Sstevel@tonic-gate 	rsmimport_rm(seg);
67230Sstevel@tonic-gate 
67240Sstevel@tonic-gate 	/* acquire the segment */
67250Sstevel@tonic-gate 	rsmseglock_acquire(seg);
67260Sstevel@tonic-gate 
67270Sstevel@tonic-gate 	/* wait until segment leaves the mapping state */
67280Sstevel@tonic-gate 	while (seg->s_state == RSM_STATE_MAPPING)
67290Sstevel@tonic-gate 		cv_wait(&seg->s_cv, &seg->s_lock);
67300Sstevel@tonic-gate 
67310Sstevel@tonic-gate 	if (seg->s_state == RSM_STATE_DISCONNECT) {
67320Sstevel@tonic-gate 		seg->s_state = RSM_STATE_NEW;
67330Sstevel@tonic-gate 		rsmseglock_release(seg);
67340Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
67350Sstevel@tonic-gate 		    "rsm_disconnect done: already disconnected\n"));
67360Sstevel@tonic-gate 		return (RSM_SUCCESS);
67370Sstevel@tonic-gate 	}
67380Sstevel@tonic-gate 
67390Sstevel@tonic-gate 	(void) rsm_closeconnection(seg, &shared_cookie);
67400Sstevel@tonic-gate 
67410Sstevel@tonic-gate 	/* update state */
67420Sstevel@tonic-gate 	seg->s_state = RSM_STATE_NEW;
67430Sstevel@tonic-gate 
67440Sstevel@tonic-gate 	if (shared_cookie != NULL) {
67450Sstevel@tonic-gate 		/*
67460Sstevel@tonic-gate 		 *  This is the last importer so inform the exporting node
67470Sstevel@tonic-gate 		 *  so this import can be deleted from the list of importers.
67480Sstevel@tonic-gate 		 */
67490Sstevel@tonic-gate 		request.rsmipc_hdr.rsmipc_type = RSMIPC_MSG_NOTIMPORTING;
67500Sstevel@tonic-gate 		request.rsmipc_key = seg->s_segid;
67510Sstevel@tonic-gate 		request.rsmipc_segment_cookie = shared_cookie;
67520Sstevel@tonic-gate 		rsmseglock_release(seg);
67530Sstevel@tonic-gate 		(void) rsmipc_send(seg->s_node, &request, RSM_NO_REPLY);
67540Sstevel@tonic-gate 	} else {
67550Sstevel@tonic-gate 		rsmseglock_release(seg);
67560Sstevel@tonic-gate 	}
67570Sstevel@tonic-gate 
67580Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_disconnect done\n"));
67590Sstevel@tonic-gate 
67600Sstevel@tonic-gate 	return (DDI_SUCCESS);
67610Sstevel@tonic-gate }
67620Sstevel@tonic-gate 
67630Sstevel@tonic-gate /*ARGSUSED*/
67640Sstevel@tonic-gate static int
rsm_chpoll(dev_t dev,short events,int anyyet,short * reventsp,struct pollhead ** phpp)67650Sstevel@tonic-gate rsm_chpoll(dev_t dev, short events, int anyyet, short *reventsp,
67660Sstevel@tonic-gate     struct pollhead **phpp)
67670Sstevel@tonic-gate {
67680Sstevel@tonic-gate 	minor_t		rnum;
67690Sstevel@tonic-gate 	rsmresource_t	*res;
67700Sstevel@tonic-gate 	rsmseg_t 	*seg;
67710Sstevel@tonic-gate 	DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_FUNC_ALL | RSM_DDI);
67720Sstevel@tonic-gate 
67730Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_chpoll enter\n"));
67740Sstevel@tonic-gate 
67750Sstevel@tonic-gate 	/* find minor, no lock */
67760Sstevel@tonic-gate 	rnum = getminor(dev);
67770Sstevel@tonic-gate 	res = rsmresource_lookup(rnum, RSM_NOLOCK);
67780Sstevel@tonic-gate 
67790Sstevel@tonic-gate 	/* poll is supported only for export/import segments */
67800Sstevel@tonic-gate 	if ((res == NULL) || (res == RSMRC_RESERVED) ||
67810Sstevel@tonic-gate 	    (res->rsmrc_type == RSM_RESOURCE_BAR)) {
67820Sstevel@tonic-gate 		return (ENXIO);
67830Sstevel@tonic-gate 	}
67840Sstevel@tonic-gate 
67850Sstevel@tonic-gate 	*reventsp = 0;
67860Sstevel@tonic-gate 
67870Sstevel@tonic-gate 	/*
67880Sstevel@tonic-gate 	 * An exported segment must be in state RSM_STATE_EXPORT; an
67890Sstevel@tonic-gate 	 * imported segment must be in state RSM_STATE_ACTIVE.
67900Sstevel@tonic-gate 	 */
67910Sstevel@tonic-gate 	seg = (rsmseg_t *)res;
67920Sstevel@tonic-gate 
67930Sstevel@tonic-gate 	if (seg->s_pollevent) {
67940Sstevel@tonic-gate 		*reventsp = POLLRDNORM;
67950Sstevel@tonic-gate 	} else if (!anyyet) {
67960Sstevel@tonic-gate 		/* cannot take segment lock here */
67970Sstevel@tonic-gate 		*phpp = &seg->s_poll;
67980Sstevel@tonic-gate 		seg->s_pollflag |= RSM_SEGMENT_POLL;
67990Sstevel@tonic-gate 	}
68000Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_chpoll done\n"));
68010Sstevel@tonic-gate 	return (0);
68020Sstevel@tonic-gate }
68030Sstevel@tonic-gate 
68040Sstevel@tonic-gate 
68050Sstevel@tonic-gate 
68060Sstevel@tonic-gate /* ************************* IOCTL Commands ********************* */
68070Sstevel@tonic-gate 
68080Sstevel@tonic-gate static rsmseg_t *
rsmresource_seg(rsmresource_t * res,minor_t rnum,cred_t * credp,rsm_resource_type_t type)68090Sstevel@tonic-gate rsmresource_seg(rsmresource_t *res, minor_t rnum, cred_t *credp,
68100Sstevel@tonic-gate     rsm_resource_type_t type)
68110Sstevel@tonic-gate {
68120Sstevel@tonic-gate 	/* get segment from resource handle */
68130Sstevel@tonic-gate 	rsmseg_t *seg;
68140Sstevel@tonic-gate 	DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_FUNC_ALL | RSM_IOCTL);
68150Sstevel@tonic-gate 
68160Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmresource_seg enter\n"));
68170Sstevel@tonic-gate 
68180Sstevel@tonic-gate 
68190Sstevel@tonic-gate 	if (res != RSMRC_RESERVED) {
68200Sstevel@tonic-gate 		seg = (rsmseg_t *)res;
68210Sstevel@tonic-gate 	} else {
68220Sstevel@tonic-gate 		/* Allocate segment now and bind it */
68230Sstevel@tonic-gate 		seg = rsmseg_alloc(rnum, credp);
68240Sstevel@tonic-gate 
68250Sstevel@tonic-gate 		/*
68260Sstevel@tonic-gate 		 * if DR pre-processing is going on or DR is in progress
68270Sstevel@tonic-gate 		 * then the new export segments should be in the NEW_QSCD state
68280Sstevel@tonic-gate 		 */
68290Sstevel@tonic-gate 		if (type == RSM_RESOURCE_EXPORT_SEGMENT) {
68300Sstevel@tonic-gate 			mutex_enter(&rsm_drv_data.drv_lock);
68310Sstevel@tonic-gate 			if ((rsm_drv_data.drv_state ==
68320Sstevel@tonic-gate 			    RSM_DRV_PREDEL_STARTED) ||
68330Sstevel@tonic-gate 			    (rsm_drv_data.drv_state ==
68340Sstevel@tonic-gate 			    RSM_DRV_PREDEL_COMPLETED) ||
68350Sstevel@tonic-gate 			    (rsm_drv_data.drv_state ==
68360Sstevel@tonic-gate 			    RSM_DRV_DR_IN_PROGRESS)) {
68370Sstevel@tonic-gate 				seg->s_state = RSM_STATE_NEW_QUIESCED;
68380Sstevel@tonic-gate 			}
68390Sstevel@tonic-gate 			mutex_exit(&rsm_drv_data.drv_lock);
68400Sstevel@tonic-gate 		}
68410Sstevel@tonic-gate 
68420Sstevel@tonic-gate 		rsmresource_insert(rnum, (rsmresource_t *)seg, type);
68430Sstevel@tonic-gate 	}
68440Sstevel@tonic-gate 
68450Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmresource_seg done\n"));
68460Sstevel@tonic-gate 
68470Sstevel@tonic-gate 	return (seg);
68480Sstevel@tonic-gate }
68490Sstevel@tonic-gate 
68500Sstevel@tonic-gate static int
rsmexport_ioctl(rsmseg_t * seg,rsm_ioctlmsg_t * msg,int cmd,intptr_t arg,int mode,cred_t * credp)68510Sstevel@tonic-gate rsmexport_ioctl(rsmseg_t *seg, rsm_ioctlmsg_t *msg, int cmd, intptr_t arg,
68520Sstevel@tonic-gate     int mode, cred_t *credp)
68530Sstevel@tonic-gate {
68540Sstevel@tonic-gate 	int error;
68550Sstevel@tonic-gate 	DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_EXPORT | RSM_IOCTL);
68560Sstevel@tonic-gate 
68570Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmexport_ioctl enter\n"));
68580Sstevel@tonic-gate 
68590Sstevel@tonic-gate 	arg = arg;
68600Sstevel@tonic-gate 	credp = credp;
68610Sstevel@tonic-gate 
68620Sstevel@tonic-gate 	ASSERT(seg != NULL);
68630Sstevel@tonic-gate 
68640Sstevel@tonic-gate 	switch (cmd) {
68650Sstevel@tonic-gate 	case RSM_IOCTL_BIND:
68660Sstevel@tonic-gate 		error = rsm_bind(seg, msg, arg, mode);
68670Sstevel@tonic-gate 		break;
68680Sstevel@tonic-gate 	case RSM_IOCTL_REBIND:
68690Sstevel@tonic-gate 		error = rsm_rebind(seg, msg);
68700Sstevel@tonic-gate 		break;
68710Sstevel@tonic-gate 	case RSM_IOCTL_UNBIND:
68720Sstevel@tonic-gate 		error = ENOTSUP;
68730Sstevel@tonic-gate 		break;
68740Sstevel@tonic-gate 	case RSM_IOCTL_PUBLISH:
68750Sstevel@tonic-gate 		error = rsm_publish(seg, msg, arg, mode);
68760Sstevel@tonic-gate 		break;
68770Sstevel@tonic-gate 	case RSM_IOCTL_REPUBLISH:
68780Sstevel@tonic-gate 		error = rsm_republish(seg, msg, mode);
68790Sstevel@tonic-gate 		break;
68800Sstevel@tonic-gate 	case RSM_IOCTL_UNPUBLISH:
68810Sstevel@tonic-gate 		error = rsm_unpublish(seg, 1);
68820Sstevel@tonic-gate 		break;
68830Sstevel@tonic-gate 	default:
68840Sstevel@tonic-gate 		error = EINVAL;
68850Sstevel@tonic-gate 		break;
68860Sstevel@tonic-gate 	}
68870Sstevel@tonic-gate 
68880Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmexport_ioctl done: %d\n",
68890Sstevel@tonic-gate 	    error));
68900Sstevel@tonic-gate 
68910Sstevel@tonic-gate 	return (error);
68920Sstevel@tonic-gate }
68930Sstevel@tonic-gate static int
rsmimport_ioctl(rsmseg_t * seg,rsm_ioctlmsg_t * msg,int cmd,intptr_t arg,int mode,cred_t * credp)68940Sstevel@tonic-gate rsmimport_ioctl(rsmseg_t *seg, rsm_ioctlmsg_t *msg, int cmd, intptr_t arg,
68950Sstevel@tonic-gate     int mode, cred_t *credp)
68960Sstevel@tonic-gate {
68970Sstevel@tonic-gate 	int error;
68980Sstevel@tonic-gate 	DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_IMPORT | RSM_IOCTL);
68990Sstevel@tonic-gate 
69000Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmimport_ioctl enter\n"));
69010Sstevel@tonic-gate 
69020Sstevel@tonic-gate 	ASSERT(seg);
69030Sstevel@tonic-gate 
69040Sstevel@tonic-gate 	switch (cmd) {
69050Sstevel@tonic-gate 	case RSM_IOCTL_CONNECT:
69060Sstevel@tonic-gate 		error = rsm_connect(seg, msg, credp, arg, mode);
69070Sstevel@tonic-gate 		break;
69080Sstevel@tonic-gate 	default:
69090Sstevel@tonic-gate 		error = EINVAL;
69100Sstevel@tonic-gate 		break;
69110Sstevel@tonic-gate 	}
69120Sstevel@tonic-gate 
69130Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmimport_ioctl done: %d\n",
69140Sstevel@tonic-gate 	    error));
69150Sstevel@tonic-gate 	return (error);
69160Sstevel@tonic-gate }
69170Sstevel@tonic-gate 
69180Sstevel@tonic-gate static int
rsmbar_ioctl(rsmseg_t * seg,rsm_ioctlmsg_t * msg,int cmd,intptr_t arg,int mode)69190Sstevel@tonic-gate rsmbar_ioctl(rsmseg_t *seg, rsm_ioctlmsg_t *msg, int cmd, intptr_t arg,
69200Sstevel@tonic-gate     int mode)
69210Sstevel@tonic-gate {
69220Sstevel@tonic-gate 	int e;
69230Sstevel@tonic-gate 	adapter_t *adapter;
69240Sstevel@tonic-gate 	DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_IMPORT | RSM_IOCTL);
69250Sstevel@tonic-gate 
69260Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmbar_ioctl enter\n"));
69270Sstevel@tonic-gate 
69280Sstevel@tonic-gate 
69290Sstevel@tonic-gate 	if ((seg->s_flags & RSM_IMPORT_DUMMY) != 0) {
69300Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
69310Sstevel@tonic-gate 		    "rsmbar_ioctl done: RSM_IMPORT_DUMMY\n"));
69320Sstevel@tonic-gate 		return (RSMERR_CONN_ABORTED);
69330Sstevel@tonic-gate 	} else if (seg->s_node == my_nodeid) {
69340Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
69350Sstevel@tonic-gate 		    "rsmbar_ioctl done: loopback\n"));
69360Sstevel@tonic-gate 		return (RSM_SUCCESS);
69370Sstevel@tonic-gate 	}
69380Sstevel@tonic-gate 
69390Sstevel@tonic-gate 	adapter = seg->s_adapter;
69400Sstevel@tonic-gate 
69410Sstevel@tonic-gate 	switch (cmd) {
69420Sstevel@tonic-gate 	case RSM_IOCTL_BAR_CHECK:
69430Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
69440Sstevel@tonic-gate 		    "rsmbar_ioctl done: RSM_BAR_CHECK %d\n", bar_va));
69450Sstevel@tonic-gate 		return (bar_va ? RSM_SUCCESS : EINVAL);
69460Sstevel@tonic-gate 	case RSM_IOCTL_BAR_OPEN:
69470Sstevel@tonic-gate 		e = adapter->rsmpi_ops->
69480Sstevel@tonic-gate 		    rsm_open_barrier_ctrl(adapter->rsmpi_handle, &msg->bar);
69490Sstevel@tonic-gate 		break;
69500Sstevel@tonic-gate 	case RSM_IOCTL_BAR_ORDER:
69510Sstevel@tonic-gate 		e = adapter->rsmpi_ops->rsm_order_barrier(&msg->bar);
69520Sstevel@tonic-gate 		break;
69530Sstevel@tonic-gate 	case RSM_IOCTL_BAR_CLOSE:
69540Sstevel@tonic-gate 		e = adapter->rsmpi_ops->rsm_close_barrier(&msg->bar);
69550Sstevel@tonic-gate 		break;
69560Sstevel@tonic-gate 	default:
69570Sstevel@tonic-gate 		e = EINVAL;
69580Sstevel@tonic-gate 		break;
69590Sstevel@tonic-gate 	}
69600Sstevel@tonic-gate 
69610Sstevel@tonic-gate 	if (e == RSM_SUCCESS) {
69620Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL
69630Sstevel@tonic-gate 		if ((mode & DATAMODEL_MASK) == DATAMODEL_ILP32) {
69640Sstevel@tonic-gate 			rsm_ioctlmsg32_t msg32;
69650Sstevel@tonic-gate 			int i;
69660Sstevel@tonic-gate 
69670Sstevel@tonic-gate 			for (i = 0; i < 4; i++) {
69680Sstevel@tonic-gate 				msg32.bar.comp[i].u64 = msg->bar.comp[i].u64;
69690Sstevel@tonic-gate 			}
69700Sstevel@tonic-gate 
69710Sstevel@tonic-gate 			DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
69720Sstevel@tonic-gate 			    "rsmbar_ioctl done\n"));
69730Sstevel@tonic-gate 			if (ddi_copyout((caddr_t)&msg32, (caddr_t)arg,
69740Sstevel@tonic-gate 			    sizeof (msg32), mode))
69750Sstevel@tonic-gate 				return (RSMERR_BAD_ADDR);
69760Sstevel@tonic-gate 			else
69770Sstevel@tonic-gate 				return (RSM_SUCCESS);
69780Sstevel@tonic-gate 		}
69790Sstevel@tonic-gate #endif
69800Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
69810Sstevel@tonic-gate 		    "rsmbar_ioctl done\n"));
69820Sstevel@tonic-gate 		if (ddi_copyout((caddr_t)&msg->bar, (caddr_t)arg,
69830Sstevel@tonic-gate 		    sizeof (*msg), mode))
69840Sstevel@tonic-gate 			return (RSMERR_BAD_ADDR);
69850Sstevel@tonic-gate 		else
69860Sstevel@tonic-gate 			return (RSM_SUCCESS);
69870Sstevel@tonic-gate 	}
69880Sstevel@tonic-gate 
69890Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
69900Sstevel@tonic-gate 	    "rsmbar_ioctl done: error=%d\n", e));
69910Sstevel@tonic-gate 
69920Sstevel@tonic-gate 	return (e);
69930Sstevel@tonic-gate }
69940Sstevel@tonic-gate 
69950Sstevel@tonic-gate /*
69960Sstevel@tonic-gate  * Ring the doorbell of the export segment to which this segment is
69970Sstevel@tonic-gate  * connected.
69980Sstevel@tonic-gate  */
69990Sstevel@tonic-gate static int
exportbell_ioctl(rsmseg_t * seg,int cmd)70000Sstevel@tonic-gate exportbell_ioctl(rsmseg_t *seg, int cmd /*ARGSUSED*/)
70010Sstevel@tonic-gate {
70020Sstevel@tonic-gate 	int e = 0;
70030Sstevel@tonic-gate 	rsmipc_request_t request;
70040Sstevel@tonic-gate 
70050Sstevel@tonic-gate 	DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_IMPORT | RSM_IOCTL);
70060Sstevel@tonic-gate 
70070Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "exportbell_ioctl enter\n"));
70080Sstevel@tonic-gate 
70090Sstevel@tonic-gate 	request.rsmipc_key = seg->s_segid;
70100Sstevel@tonic-gate 	request.rsmipc_hdr.rsmipc_type = RSMIPC_MSG_BELL;
70110Sstevel@tonic-gate 	request.rsmipc_segment_cookie = NULL;
70120Sstevel@tonic-gate 	e = rsmipc_send(seg->s_node, &request, RSM_NO_REPLY);
70130Sstevel@tonic-gate 
70140Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
70150Sstevel@tonic-gate 	    "exportbell_ioctl done: %d\n", e));
70160Sstevel@tonic-gate 
70170Sstevel@tonic-gate 	return (e);
70180Sstevel@tonic-gate }
70190Sstevel@tonic-gate 
70200Sstevel@tonic-gate /*
70210Sstevel@tonic-gate  * Ring the doorbells of all segments importing this segment
70220Sstevel@tonic-gate  */
70230Sstevel@tonic-gate static int
importbell_ioctl(rsmseg_t * seg,int cmd)70240Sstevel@tonic-gate importbell_ioctl(rsmseg_t *seg, int cmd /*ARGSUSED*/)
70250Sstevel@tonic-gate {
70260Sstevel@tonic-gate 	importing_token_t	*token = NULL;
70270Sstevel@tonic-gate 	rsmipc_request_t	request;
70280Sstevel@tonic-gate 	int			index;
70290Sstevel@tonic-gate 
70300Sstevel@tonic-gate 	DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_EXPORT | RSM_IOCTL);
70310Sstevel@tonic-gate 
70320Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "importbell_ioctl enter\n"));
70330Sstevel@tonic-gate 
70340Sstevel@tonic-gate 	ASSERT(seg->s_state != RSM_STATE_NEW &&
70350Sstevel@tonic-gate 	    seg->s_state != RSM_STATE_NEW_QUIESCED);
70360Sstevel@tonic-gate 
70370Sstevel@tonic-gate 	request.rsmipc_key = seg->s_segid;
70380Sstevel@tonic-gate 	request.rsmipc_hdr.rsmipc_type = RSMIPC_MSG_BELL;
70390Sstevel@tonic-gate 
70400Sstevel@tonic-gate 	index = rsmhash(seg->s_segid);
70410Sstevel@tonic-gate 
70420Sstevel@tonic-gate 	token = importer_list.bucket[index];
70430Sstevel@tonic-gate 
70440Sstevel@tonic-gate 	while (token != NULL) {
70450Sstevel@tonic-gate 		if (seg->s_key == token->key) {
70460Sstevel@tonic-gate 			request.rsmipc_segment_cookie =
70470Sstevel@tonic-gate 			    token->import_segment_cookie;
70480Sstevel@tonic-gate 			(void) rsmipc_send(token->importing_node,
70497656SSherry.Moore@Sun.COM 			    &request, RSM_NO_REPLY);
70500Sstevel@tonic-gate 		}
70510Sstevel@tonic-gate 		token = token->next;
70520Sstevel@tonic-gate 	}
70530Sstevel@tonic-gate 
70540Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
70550Sstevel@tonic-gate 	    "importbell_ioctl done\n"));
70560Sstevel@tonic-gate 	return (RSM_SUCCESS);
70570Sstevel@tonic-gate }
70580Sstevel@tonic-gate 
70590Sstevel@tonic-gate static int
rsm_consumeevent_copyin(caddr_t arg,rsm_consume_event_msg_t * msgp,rsm_poll_event_t ** eventspp,int mode)70600Sstevel@tonic-gate rsm_consumeevent_copyin(caddr_t arg, rsm_consume_event_msg_t *msgp,
70610Sstevel@tonic-gate     rsm_poll_event_t **eventspp, int mode)
70620Sstevel@tonic-gate {
70630Sstevel@tonic-gate 	rsm_poll_event_t	*evlist = NULL;
70640Sstevel@tonic-gate 	size_t			evlistsz;
70650Sstevel@tonic-gate 	DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_IOCTL);
70660Sstevel@tonic-gate 
70670Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL
70680Sstevel@tonic-gate 	if ((mode & DATAMODEL_MASK) == DATAMODEL_ILP32) {
70690Sstevel@tonic-gate 		int i;
70700Sstevel@tonic-gate 		rsm_consume_event_msg32_t cemsg32 = {0};
70710Sstevel@tonic-gate 		rsm_poll_event32_t	event32[RSM_MAX_POLLFDS];
70720Sstevel@tonic-gate 		rsm_poll_event32_t	*evlist32;
70730Sstevel@tonic-gate 		size_t			evlistsz32;
70740Sstevel@tonic-gate 
70750Sstevel@tonic-gate 		/* copyin the ioctl message */
70760Sstevel@tonic-gate 		if (ddi_copyin(arg, (caddr_t)&cemsg32,
70770Sstevel@tonic-gate 		    sizeof (rsm_consume_event_msg32_t), mode)) {
70780Sstevel@tonic-gate 			DBG_PRINTF((category, RSM_ERR,
70790Sstevel@tonic-gate 			    "consumeevent_copyin msgp: RSMERR_BAD_ADDR\n"));
70800Sstevel@tonic-gate 			return (RSMERR_BAD_ADDR);
70810Sstevel@tonic-gate 		}
70820Sstevel@tonic-gate 		msgp->seglist = (caddr_t)(uintptr_t)cemsg32.seglist;
70830Sstevel@tonic-gate 		msgp->numents = (int)cemsg32.numents;
70840Sstevel@tonic-gate 
70850Sstevel@tonic-gate 		evlistsz32 = sizeof (rsm_poll_event32_t) * msgp->numents;
70860Sstevel@tonic-gate 		/*
70870Sstevel@tonic-gate 		 * If numents is large alloc events list on heap otherwise
70880Sstevel@tonic-gate 		 * use the address of array that was passed in.
70890Sstevel@tonic-gate 		 */
70900Sstevel@tonic-gate 		if (msgp->numents > RSM_MAX_POLLFDS) {
70910Sstevel@tonic-gate 			if (msgp->numents > max_segs) { /* validate numents */
70920Sstevel@tonic-gate 				DBG_PRINTF((category, RSM_ERR,
70930Sstevel@tonic-gate 				    "consumeevent_copyin: "
70940Sstevel@tonic-gate 				    "RSMERR_BAD_ARGS_ERRORS\n"));
70950Sstevel@tonic-gate 				return (RSMERR_BAD_ARGS_ERRORS);
70960Sstevel@tonic-gate 			}
70970Sstevel@tonic-gate 			evlist32 = kmem_zalloc(evlistsz32, KM_SLEEP);
70980Sstevel@tonic-gate 		} else {
70990Sstevel@tonic-gate 			evlist32 = event32;
71000Sstevel@tonic-gate 		}
71010Sstevel@tonic-gate 
71020Sstevel@tonic-gate 		/* copyin the seglist into the rsm_poll_event32_t array */
71030Sstevel@tonic-gate 		if (ddi_copyin((caddr_t)msgp->seglist, (caddr_t)evlist32,
71040Sstevel@tonic-gate 		    evlistsz32, mode)) {
71050Sstevel@tonic-gate 			if ((msgp->numents > RSM_MAX_POLLFDS) && evlist32) {
71060Sstevel@tonic-gate 				kmem_free(evlist32, evlistsz32);
71070Sstevel@tonic-gate 			}
71080Sstevel@tonic-gate 			DBG_PRINTF((category, RSM_ERR,
71090Sstevel@tonic-gate 			    "consumeevent_copyin evlist: RSMERR_BAD_ADDR\n"));
71100Sstevel@tonic-gate 			return (RSMERR_BAD_ADDR);
71110Sstevel@tonic-gate 		}
71120Sstevel@tonic-gate 
71130Sstevel@tonic-gate 		/* evlist and evlistsz are based on rsm_poll_event_t type */
71140Sstevel@tonic-gate 		evlistsz = sizeof (rsm_poll_event_t)* msgp->numents;
71150Sstevel@tonic-gate 
71160Sstevel@tonic-gate 		if (msgp->numents > RSM_MAX_POLLFDS) {
71170Sstevel@tonic-gate 			evlist = kmem_zalloc(evlistsz, KM_SLEEP);
71180Sstevel@tonic-gate 			*eventspp = evlist;
71190Sstevel@tonic-gate 		} else {
71200Sstevel@tonic-gate 			evlist = *eventspp;
71210Sstevel@tonic-gate 		}
71220Sstevel@tonic-gate 		/*
71230Sstevel@tonic-gate 		 * copy the rsm_poll_event32_t array to the rsm_poll_event_t
71240Sstevel@tonic-gate 		 * array
71250Sstevel@tonic-gate 		 */
71260Sstevel@tonic-gate 		for (i = 0; i < msgp->numents; i++) {
71270Sstevel@tonic-gate 			evlist[i].rnum = evlist32[i].rnum;
71280Sstevel@tonic-gate 			evlist[i].fdsidx = evlist32[i].fdsidx;
71290Sstevel@tonic-gate 			evlist[i].revent = evlist32[i].revent;
71300Sstevel@tonic-gate 		}
71310Sstevel@tonic-gate 		/* free the temp 32-bit event list */
71320Sstevel@tonic-gate 		if ((msgp->numents > RSM_MAX_POLLFDS) && evlist32) {
71330Sstevel@tonic-gate 			kmem_free(evlist32, evlistsz32);
71340Sstevel@tonic-gate 		}
71350Sstevel@tonic-gate 
71360Sstevel@tonic-gate 		return (RSM_SUCCESS);
71370Sstevel@tonic-gate 	}
71380Sstevel@tonic-gate #endif
71390Sstevel@tonic-gate 	/* copyin the ioctl message */
71400Sstevel@tonic-gate 	if (ddi_copyin(arg, (caddr_t)msgp, sizeof (rsm_consume_event_msg_t),
71410Sstevel@tonic-gate 	    mode)) {
71420Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_ERR,
71430Sstevel@tonic-gate 		    "consumeevent_copyin msgp: RSMERR_BAD_ADDR\n"));
71440Sstevel@tonic-gate 		return (RSMERR_BAD_ADDR);
71450Sstevel@tonic-gate 	}
71460Sstevel@tonic-gate 	/*
71470Sstevel@tonic-gate 	 * If numents is large alloc events list on heap otherwise
71480Sstevel@tonic-gate 	 * use the address of array that was passed in.
71490Sstevel@tonic-gate 	 */
71500Sstevel@tonic-gate 	if (msgp->numents > RSM_MAX_POLLFDS) {
71510Sstevel@tonic-gate 		if (msgp->numents > max_segs) { /* validate numents */
71520Sstevel@tonic-gate 			DBG_PRINTF((category, RSM_ERR,
71530Sstevel@tonic-gate 			    "consumeevent_copyin: RSMERR_BAD_ARGS_ERRORS\n"));
71540Sstevel@tonic-gate 			return (RSMERR_BAD_ARGS_ERRORS);
71550Sstevel@tonic-gate 		}
71560Sstevel@tonic-gate 		evlistsz = sizeof (rsm_poll_event_t)*msgp->numents;
71570Sstevel@tonic-gate 		evlist = kmem_zalloc(evlistsz, KM_SLEEP);
71580Sstevel@tonic-gate 		*eventspp  = evlist;
71590Sstevel@tonic-gate 	}
71600Sstevel@tonic-gate 
71610Sstevel@tonic-gate 	/* copyin the seglist */
71620Sstevel@tonic-gate 	if (ddi_copyin((caddr_t)msgp->seglist, (caddr_t)(*eventspp),
71630Sstevel@tonic-gate 	    sizeof (rsm_poll_event_t)*msgp->numents, mode)) {
71640Sstevel@tonic-gate 		if (evlist) {
71650Sstevel@tonic-gate 			kmem_free(evlist, evlistsz);
71660Sstevel@tonic-gate 			*eventspp = NULL;
71670Sstevel@tonic-gate 		}
71680Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_ERR,
71690Sstevel@tonic-gate 		    "consumeevent_copyin evlist: RSMERR_BAD_ADDR\n"));
71700Sstevel@tonic-gate 		return (RSMERR_BAD_ADDR);
71710Sstevel@tonic-gate 	}
71720Sstevel@tonic-gate 
71730Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
71740Sstevel@tonic-gate 	    "consumeevent_copyin done\n"));
71750Sstevel@tonic-gate 	return (RSM_SUCCESS);
71760Sstevel@tonic-gate }
71770Sstevel@tonic-gate 
71780Sstevel@tonic-gate static int
rsm_consumeevent_copyout(rsm_consume_event_msg_t * msgp,rsm_poll_event_t * eventsp,int mode)71790Sstevel@tonic-gate rsm_consumeevent_copyout(rsm_consume_event_msg_t *msgp,
71800Sstevel@tonic-gate     rsm_poll_event_t *eventsp, int mode)
71810Sstevel@tonic-gate {
71820Sstevel@tonic-gate 	size_t			evlistsz;
71830Sstevel@tonic-gate 	int			err = RSM_SUCCESS;
71840Sstevel@tonic-gate 	DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_IOCTL);
71850Sstevel@tonic-gate 
71860Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
71870Sstevel@tonic-gate 	    "consumeevent_copyout enter: numents(%d) eventsp(%p)\n",
71880Sstevel@tonic-gate 	    msgp->numents, eventsp));
71890Sstevel@tonic-gate 
71900Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL
71910Sstevel@tonic-gate 	if ((mode & DATAMODEL_MASK) == DATAMODEL_ILP32) {
71920Sstevel@tonic-gate 		int i;
71930Sstevel@tonic-gate 		rsm_poll_event32_t	event32[RSM_MAX_POLLFDS];
71940Sstevel@tonic-gate 		rsm_poll_event32_t	*evlist32;
71950Sstevel@tonic-gate 		size_t			evlistsz32;
71960Sstevel@tonic-gate 
71970Sstevel@tonic-gate 		evlistsz32 = sizeof (rsm_poll_event32_t)*msgp->numents;
71980Sstevel@tonic-gate 		if (msgp->numents > RSM_MAX_POLLFDS) {
71990Sstevel@tonic-gate 			evlist32 = kmem_zalloc(evlistsz32, KM_SLEEP);
72000Sstevel@tonic-gate 		} else {
72010Sstevel@tonic-gate 			evlist32 = event32;
72020Sstevel@tonic-gate 		}
72030Sstevel@tonic-gate 
72040Sstevel@tonic-gate 		/*
72050Sstevel@tonic-gate 		 * copy the rsm_poll_event_t array to the rsm_poll_event32_t
72060Sstevel@tonic-gate 		 * array
72070Sstevel@tonic-gate 		 */
72080Sstevel@tonic-gate 		for (i = 0; i < msgp->numents; i++) {
72090Sstevel@tonic-gate 			evlist32[i].rnum = eventsp[i].rnum;
72100Sstevel@tonic-gate 			evlist32[i].fdsidx = eventsp[i].fdsidx;
72110Sstevel@tonic-gate 			evlist32[i].revent = eventsp[i].revent;
72120Sstevel@tonic-gate 		}
72130Sstevel@tonic-gate 
72140Sstevel@tonic-gate 		if (ddi_copyout((caddr_t)evlist32, (caddr_t)msgp->seglist,
72150Sstevel@tonic-gate 		    evlistsz32, mode)) {
72160Sstevel@tonic-gate 			err = RSMERR_BAD_ADDR;
72170Sstevel@tonic-gate 		}
72180Sstevel@tonic-gate 
72190Sstevel@tonic-gate 		if (msgp->numents > RSM_MAX_POLLFDS) {
72200Sstevel@tonic-gate 			if (evlist32) {	/* free the temp 32-bit event list */
72210Sstevel@tonic-gate 				kmem_free(evlist32, evlistsz32);
72220Sstevel@tonic-gate 			}
72230Sstevel@tonic-gate 			/*
72240Sstevel@tonic-gate 			 * eventsp and evlistsz are based on rsm_poll_event_t
72250Sstevel@tonic-gate 			 * type
72260Sstevel@tonic-gate 			 */
72270Sstevel@tonic-gate 			evlistsz = sizeof (rsm_poll_event_t)*msgp->numents;
72280Sstevel@tonic-gate 			/* event list on the heap and needs to be freed here */
72290Sstevel@tonic-gate 			if (eventsp) {
72300Sstevel@tonic-gate 				kmem_free(eventsp, evlistsz);
72310Sstevel@tonic-gate 			}
72320Sstevel@tonic-gate 		}
72330Sstevel@tonic-gate 
72340Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
72350Sstevel@tonic-gate 		    "consumeevent_copyout done: err=%d\n", err));
72360Sstevel@tonic-gate 		return (err);
72370Sstevel@tonic-gate 	}
72380Sstevel@tonic-gate #endif
72390Sstevel@tonic-gate 	evlistsz = sizeof (rsm_poll_event_t)*msgp->numents;
72400Sstevel@tonic-gate 
72410Sstevel@tonic-gate 	if (ddi_copyout((caddr_t)eventsp, (caddr_t)msgp->seglist, evlistsz,
72420Sstevel@tonic-gate 	    mode)) {
72430Sstevel@tonic-gate 		err = RSMERR_BAD_ADDR;
72440Sstevel@tonic-gate 	}
72450Sstevel@tonic-gate 
72460Sstevel@tonic-gate 	if ((msgp->numents > RSM_MAX_POLLFDS) && eventsp) {
72470Sstevel@tonic-gate 		/* event list on the heap and needs to be freed here */
72480Sstevel@tonic-gate 		kmem_free(eventsp, evlistsz);
72490Sstevel@tonic-gate 	}
72500Sstevel@tonic-gate 
72510Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
72520Sstevel@tonic-gate 	    "consumeevent_copyout done: err=%d\n", err));
72530Sstevel@tonic-gate 	return (err);
72540Sstevel@tonic-gate }
72550Sstevel@tonic-gate 
72560Sstevel@tonic-gate static int
rsm_consumeevent_ioctl(caddr_t arg,int mode)72570Sstevel@tonic-gate rsm_consumeevent_ioctl(caddr_t arg, int mode)
72580Sstevel@tonic-gate {
72590Sstevel@tonic-gate 	int	rc;
72600Sstevel@tonic-gate 	int	i;
72610Sstevel@tonic-gate 	minor_t	rnum;
72620Sstevel@tonic-gate 	rsm_consume_event_msg_t	msg = {0};
72630Sstevel@tonic-gate 	rsmseg_t		*seg;
72640Sstevel@tonic-gate 	rsm_poll_event_t	*event_list;
72650Sstevel@tonic-gate 	rsm_poll_event_t	events[RSM_MAX_POLLFDS];
72660Sstevel@tonic-gate 	DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_IOCTL);
72670Sstevel@tonic-gate 
72680Sstevel@tonic-gate 	event_list = events;
72690Sstevel@tonic-gate 
72700Sstevel@tonic-gate 	if ((rc = rsm_consumeevent_copyin(arg, &msg, &event_list, mode)) !=
72710Sstevel@tonic-gate 	    RSM_SUCCESS) {
72720Sstevel@tonic-gate 		return (rc);
72730Sstevel@tonic-gate 	}
72740Sstevel@tonic-gate 
72750Sstevel@tonic-gate 	for (i = 0; i < msg.numents; i++) {
72760Sstevel@tonic-gate 		rnum = event_list[i].rnum;
72770Sstevel@tonic-gate 		event_list[i].revent = 0;
72780Sstevel@tonic-gate 		/* get the segment structure */
72790Sstevel@tonic-gate 		seg = (rsmseg_t *)rsmresource_lookup(rnum, RSM_LOCK);
72800Sstevel@tonic-gate 		if (seg) {
72810Sstevel@tonic-gate 			DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
72820Sstevel@tonic-gate 			    "consumeevent_ioctl: rnum(%d) seg(%p)\n", rnum,
72830Sstevel@tonic-gate 			    seg));
72840Sstevel@tonic-gate 			if (seg->s_pollevent) {
72850Sstevel@tonic-gate 				/* consume the event */
72860Sstevel@tonic-gate 				atomic_add_32(&seg->s_pollevent, -1);
72870Sstevel@tonic-gate 				event_list[i].revent = POLLRDNORM;
72880Sstevel@tonic-gate 			}
72890Sstevel@tonic-gate 			rsmseglock_release(seg);
72900Sstevel@tonic-gate 		}
72910Sstevel@tonic-gate 	}
72920Sstevel@tonic-gate 
72930Sstevel@tonic-gate 	if ((rc = rsm_consumeevent_copyout(&msg, event_list, mode)) !=
72940Sstevel@tonic-gate 	    RSM_SUCCESS) {
72950Sstevel@tonic-gate 		return (rc);
72960Sstevel@tonic-gate 	}
72970Sstevel@tonic-gate 
72980Sstevel@tonic-gate 	return (RSM_SUCCESS);
72990Sstevel@tonic-gate }
73000Sstevel@tonic-gate 
73010Sstevel@tonic-gate static int
iovec_copyin(caddr_t user_vec,rsmka_iovec_t * iovec,int count,int mode)73020Sstevel@tonic-gate iovec_copyin(caddr_t user_vec, rsmka_iovec_t *iovec, int count, int mode)
73030Sstevel@tonic-gate {
73040Sstevel@tonic-gate 	int size;
73050Sstevel@tonic-gate 	DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_IMPORT | RSM_IOCTL);
73060Sstevel@tonic-gate 
73070Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "iovec_copyin enter\n"));
73080Sstevel@tonic-gate 
73090Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL
73100Sstevel@tonic-gate 	if ((mode & DATAMODEL_MASK) == DATAMODEL_ILP32) {
73110Sstevel@tonic-gate 		rsmka_iovec32_t	*iovec32, *iovec32_base;
73120Sstevel@tonic-gate 		int i;
73130Sstevel@tonic-gate 
73140Sstevel@tonic-gate 		size = count * sizeof (rsmka_iovec32_t);
73150Sstevel@tonic-gate 		iovec32_base = iovec32 = kmem_zalloc(size, KM_SLEEP);
73160Sstevel@tonic-gate 		if (ddi_copyin((caddr_t)user_vec,
73170Sstevel@tonic-gate 		    (caddr_t)iovec32, size, mode)) {
73180Sstevel@tonic-gate 			kmem_free(iovec32, size);
73190Sstevel@tonic-gate 			DBG_PRINTF((category, RSM_DEBUG,
73200Sstevel@tonic-gate 			    "iovec_copyin: returning RSMERR_BAD_ADDR\n"));
73210Sstevel@tonic-gate 			return (RSMERR_BAD_ADDR);
73220Sstevel@tonic-gate 		}
73230Sstevel@tonic-gate 
73240Sstevel@tonic-gate 		for (i = 0; i < count; i++, iovec++, iovec32++) {
73250Sstevel@tonic-gate 			iovec->io_type = (int)iovec32->io_type;
73260Sstevel@tonic-gate 			if (iovec->io_type == RSM_HANDLE_TYPE)
73270Sstevel@tonic-gate 				iovec->local.segid = (rsm_memseg_id_t)
73287656SSherry.Moore@Sun.COM 				    iovec32->local;
73290Sstevel@tonic-gate 			else
73300Sstevel@tonic-gate 				iovec->local.vaddr =
73310Sstevel@tonic-gate 				    (caddr_t)(uintptr_t)iovec32->local;
73320Sstevel@tonic-gate 			iovec->local_offset = (size_t)iovec32->local_offset;
73330Sstevel@tonic-gate 			iovec->remote_offset = (size_t)iovec32->remote_offset;
73340Sstevel@tonic-gate 			iovec->transfer_len = (size_t)iovec32->transfer_len;
73350Sstevel@tonic-gate 
73360Sstevel@tonic-gate 		}
73370Sstevel@tonic-gate 		kmem_free(iovec32_base, size);
73380Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
73390Sstevel@tonic-gate 		    "iovec_copyin done\n"));
73400Sstevel@tonic-gate 		return (DDI_SUCCESS);
73410Sstevel@tonic-gate 	}
73420Sstevel@tonic-gate #endif
73430Sstevel@tonic-gate 
73440Sstevel@tonic-gate 	size = count * sizeof (rsmka_iovec_t);
73450Sstevel@tonic-gate 	if (ddi_copyin((caddr_t)user_vec, (caddr_t)iovec, size, mode)) {
73460Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
73470Sstevel@tonic-gate 		    "iovec_copyin done: RSMERR_BAD_ADDR\n"));
73480Sstevel@tonic-gate 		return (RSMERR_BAD_ADDR);
73490Sstevel@tonic-gate 	}
73500Sstevel@tonic-gate 
73510Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "iovec_copyin done\n"));
73520Sstevel@tonic-gate 
73530Sstevel@tonic-gate 	return (DDI_SUCCESS);
73540Sstevel@tonic-gate }
73550Sstevel@tonic-gate 
73560Sstevel@tonic-gate 
73570Sstevel@tonic-gate static int
sgio_copyin(caddr_t arg,rsmka_scat_gath_t * sg_io,int mode)73580Sstevel@tonic-gate sgio_copyin(caddr_t arg, rsmka_scat_gath_t *sg_io, int mode)
73590Sstevel@tonic-gate {
73600Sstevel@tonic-gate 	DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_IMPORT | RSM_IOCTL);
73610Sstevel@tonic-gate 
73620Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "sgio_copyin enter\n"));
73630Sstevel@tonic-gate 
73640Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL
73650Sstevel@tonic-gate 	if ((mode & DATAMODEL_MASK) == DATAMODEL_ILP32) {
73660Sstevel@tonic-gate 		rsmka_scat_gath32_t sg_io32;
73670Sstevel@tonic-gate 
73680Sstevel@tonic-gate 		if (ddi_copyin(arg, (caddr_t)&sg_io32, sizeof (sg_io32),
73690Sstevel@tonic-gate 		    mode)) {
73700Sstevel@tonic-gate 			DBG_PRINTF((category, RSM_DEBUG,
73710Sstevel@tonic-gate 			    "sgio_copyin done: returning EFAULT\n"));
73720Sstevel@tonic-gate 			return (RSMERR_BAD_ADDR);
73730Sstevel@tonic-gate 		}
73740Sstevel@tonic-gate 		sg_io->local_nodeid = (rsm_node_id_t)sg_io32.local_nodeid;
73750Sstevel@tonic-gate 		sg_io->io_request_count =  (size_t)sg_io32.io_request_count;
73760Sstevel@tonic-gate 		sg_io->io_residual_count = (size_t)sg_io32.io_residual_count;
73770Sstevel@tonic-gate 		sg_io->flags = (size_t)sg_io32.flags;
73780Sstevel@tonic-gate 		sg_io->remote_handle = (rsm_memseg_import_handle_t)
73790Sstevel@tonic-gate 		    (uintptr_t)sg_io32.remote_handle;
73800Sstevel@tonic-gate 		sg_io->iovec = (rsmka_iovec_t *)(uintptr_t)sg_io32.iovec;
73810Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
73820Sstevel@tonic-gate 		    "sgio_copyin done\n"));
73830Sstevel@tonic-gate 		return (DDI_SUCCESS);
73840Sstevel@tonic-gate 	}
73850Sstevel@tonic-gate #endif
73860Sstevel@tonic-gate 	if (ddi_copyin(arg, (caddr_t)sg_io, sizeof (rsmka_scat_gath_t),
73870Sstevel@tonic-gate 	    mode)) {
73880Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_DEBUG,
73890Sstevel@tonic-gate 		    "sgio_copyin done: returning EFAULT\n"));
73900Sstevel@tonic-gate 		return (RSMERR_BAD_ADDR);
73910Sstevel@tonic-gate 	}
73920Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "sgio_copyin done\n"));
73930Sstevel@tonic-gate 	return (DDI_SUCCESS);
73940Sstevel@tonic-gate }
73950Sstevel@tonic-gate 
73960Sstevel@tonic-gate static int
sgio_resid_copyout(caddr_t arg,rsmka_scat_gath_t * sg_io,int mode)73970Sstevel@tonic-gate sgio_resid_copyout(caddr_t arg, rsmka_scat_gath_t *sg_io, int mode)
73980Sstevel@tonic-gate {
73990Sstevel@tonic-gate 	DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_IMPORT | RSM_IOCTL);
74000Sstevel@tonic-gate 
74010Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
74020Sstevel@tonic-gate 	    "sgio_resid_copyout enter\n"));
74030Sstevel@tonic-gate 
74040Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL
74050Sstevel@tonic-gate 	if ((mode & DATAMODEL_MASK) == DATAMODEL_ILP32) {
74060Sstevel@tonic-gate 		rsmka_scat_gath32_t sg_io32;
74070Sstevel@tonic-gate 
74080Sstevel@tonic-gate 		sg_io32.io_residual_count = sg_io->io_residual_count;
74090Sstevel@tonic-gate 		sg_io32.flags = sg_io->flags;
74100Sstevel@tonic-gate 
74110Sstevel@tonic-gate 		if (ddi_copyout((caddr_t)&sg_io32.io_residual_count,
74120Sstevel@tonic-gate 		    (caddr_t)&((rsmka_scat_gath32_t *)arg)->io_residual_count,
74130Sstevel@tonic-gate 		    sizeof (uint32_t), mode)) {
74140Sstevel@tonic-gate 
74150Sstevel@tonic-gate 			DBG_PRINTF((category, RSM_ERR,
74160Sstevel@tonic-gate 			    "sgio_resid_copyout error: rescnt\n"));
74170Sstevel@tonic-gate 			return (RSMERR_BAD_ADDR);
74180Sstevel@tonic-gate 		}
74190Sstevel@tonic-gate 
74200Sstevel@tonic-gate 		if (ddi_copyout((caddr_t)&sg_io32.flags,
74210Sstevel@tonic-gate 		    (caddr_t)&((rsmka_scat_gath32_t *)arg)->flags,
74220Sstevel@tonic-gate 		    sizeof (uint32_t), mode)) {
74230Sstevel@tonic-gate 
74240Sstevel@tonic-gate 			DBG_PRINTF((category, RSM_ERR,
74250Sstevel@tonic-gate 			    "sgio_resid_copyout error: flags\n"));
74260Sstevel@tonic-gate 			return (RSMERR_BAD_ADDR);
74270Sstevel@tonic-gate 		}
74280Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
74290Sstevel@tonic-gate 		    "sgio_resid_copyout done\n"));
74300Sstevel@tonic-gate 		return (DDI_SUCCESS);
74310Sstevel@tonic-gate 	}
74320Sstevel@tonic-gate #endif
74330Sstevel@tonic-gate 	if (ddi_copyout((caddr_t)&sg_io->io_residual_count,
74340Sstevel@tonic-gate 	    (caddr_t)&((rsmka_scat_gath_t *)arg)->io_residual_count,
74350Sstevel@tonic-gate 	    sizeof (ulong_t), mode)) {
74360Sstevel@tonic-gate 
74370Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_ERR,
74380Sstevel@tonic-gate 		    "sgio_resid_copyout error:rescnt\n"));
74390Sstevel@tonic-gate 		return (RSMERR_BAD_ADDR);
74400Sstevel@tonic-gate 	}
74410Sstevel@tonic-gate 
74420Sstevel@tonic-gate 	if (ddi_copyout((caddr_t)&sg_io->flags,
74430Sstevel@tonic-gate 	    (caddr_t)&((rsmka_scat_gath_t *)arg)->flags,
74440Sstevel@tonic-gate 	    sizeof (uint_t), mode)) {
74450Sstevel@tonic-gate 
74460Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_ERR,
74470Sstevel@tonic-gate 		    "sgio_resid_copyout error:flags\n"));
74480Sstevel@tonic-gate 		return (RSMERR_BAD_ADDR);
74490Sstevel@tonic-gate 	}
74500Sstevel@tonic-gate 
74510Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "sgio_resid_copyout done\n"));
74520Sstevel@tonic-gate 	return (DDI_SUCCESS);
74530Sstevel@tonic-gate }
74540Sstevel@tonic-gate 
74550Sstevel@tonic-gate 
74560Sstevel@tonic-gate static int
rsm_iovec_ioctl(dev_t dev,caddr_t arg,int cmd,int mode,cred_t * credp)74570Sstevel@tonic-gate rsm_iovec_ioctl(dev_t dev, caddr_t arg, int cmd, int mode, cred_t *credp)
74580Sstevel@tonic-gate {
74590Sstevel@tonic-gate 	rsmka_scat_gath_t	sg_io;
74600Sstevel@tonic-gate 	rsmka_iovec_t		ka_iovec_arr[RSM_MAX_IOVLEN];
74610Sstevel@tonic-gate 	rsmka_iovec_t		*ka_iovec;
74620Sstevel@tonic-gate 	rsmka_iovec_t		*ka_iovec_start;
74630Sstevel@tonic-gate 	rsmpi_scat_gath_t	rsmpi_sg_io;
74640Sstevel@tonic-gate 	rsmpi_iovec_t		iovec_arr[RSM_MAX_IOVLEN];
74650Sstevel@tonic-gate 	rsmpi_iovec_t		*iovec;
74660Sstevel@tonic-gate 	rsmpi_iovec_t		*iovec_start = NULL;
74670Sstevel@tonic-gate 	rsmapi_access_entry_t	*acl;
74680Sstevel@tonic-gate 	rsmresource_t		*res;
74690Sstevel@tonic-gate 	minor_t			rnum;
74700Sstevel@tonic-gate 	rsmseg_t		*im_seg, *ex_seg;
74710Sstevel@tonic-gate 	int			e;
74720Sstevel@tonic-gate 	int			error = 0;
74730Sstevel@tonic-gate 	uint_t			i;
74740Sstevel@tonic-gate 	uint_t			iov_proc = 0; /* num of iovecs processed */
74750Sstevel@tonic-gate 	size_t			size = 0;
74760Sstevel@tonic-gate 	size_t			ka_size;
74770Sstevel@tonic-gate 
74780Sstevel@tonic-gate 	DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_IMPORT | RSM_IOCTL);
74790Sstevel@tonic-gate 
74800Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_iovec_ioctl enter\n"));
74810Sstevel@tonic-gate 
74820Sstevel@tonic-gate 	credp = credp;
74830Sstevel@tonic-gate 
74840Sstevel@tonic-gate 	/*
74850Sstevel@tonic-gate 	 * Copyin the scatter/gather structure  and build new structure
74860Sstevel@tonic-gate 	 * for rsmpi.
74870Sstevel@tonic-gate 	 */
74880Sstevel@tonic-gate 	e = sgio_copyin(arg, &sg_io, mode);
74890Sstevel@tonic-gate 	if (e != DDI_SUCCESS) {
74900Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
74910Sstevel@tonic-gate 		    "rsm_iovec_ioctl done: sgio_copyin %d\n", e));
74920Sstevel@tonic-gate 		return (e);
74930Sstevel@tonic-gate 	}
74940Sstevel@tonic-gate 
74950Sstevel@tonic-gate 	if (sg_io.io_request_count > RSM_MAX_SGIOREQS) {
74960Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
74970Sstevel@tonic-gate 		    "rsm_iovec_ioctl done: request_count(%d) too large\n",
74980Sstevel@tonic-gate 		    sg_io.io_request_count));
74990Sstevel@tonic-gate 		return (RSMERR_BAD_SGIO);
75000Sstevel@tonic-gate 	}
75010Sstevel@tonic-gate 
75020Sstevel@tonic-gate 	rsmpi_sg_io.io_request_count = sg_io.io_request_count;
75030Sstevel@tonic-gate 	rsmpi_sg_io.io_residual_count = sg_io.io_request_count;
75040Sstevel@tonic-gate 	rsmpi_sg_io.io_segflg = 0;
75050Sstevel@tonic-gate 
75060Sstevel@tonic-gate 	/* Allocate memory and copyin io vector array  */
75070Sstevel@tonic-gate 	if (sg_io.io_request_count > RSM_MAX_IOVLEN) {
75080Sstevel@tonic-gate 		ka_size =  sg_io.io_request_count * sizeof (rsmka_iovec_t);
75090Sstevel@tonic-gate 		ka_iovec_start = ka_iovec = kmem_zalloc(ka_size, KM_SLEEP);
75100Sstevel@tonic-gate 	} else {
75110Sstevel@tonic-gate 		ka_iovec_start = ka_iovec = ka_iovec_arr;
75120Sstevel@tonic-gate 	}
75130Sstevel@tonic-gate 	e = iovec_copyin((caddr_t)sg_io.iovec, ka_iovec,
75140Sstevel@tonic-gate 	    sg_io.io_request_count, mode);
75150Sstevel@tonic-gate 	if (e != DDI_SUCCESS) {
75160Sstevel@tonic-gate 		if (sg_io.io_request_count > RSM_MAX_IOVLEN)
75170Sstevel@tonic-gate 			kmem_free(ka_iovec, ka_size);
75180Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
75190Sstevel@tonic-gate 		    "rsm_iovec_ioctl done: iovec_copyin %d\n", e));
75200Sstevel@tonic-gate 		return (e);
75210Sstevel@tonic-gate 	}
75220Sstevel@tonic-gate 
75230Sstevel@tonic-gate 	/* get the import segment descriptor */
75240Sstevel@tonic-gate 	rnum = getminor(dev);
75250Sstevel@tonic-gate 	res = rsmresource_lookup(rnum, RSM_LOCK);
75260Sstevel@tonic-gate 
75270Sstevel@tonic-gate 	/*
75280Sstevel@tonic-gate 	 * The following sequence of locking may (or MAY NOT) cause a
75290Sstevel@tonic-gate 	 * deadlock but this is currently not addressed here since the
75300Sstevel@tonic-gate 	 * implementation will be changed to incorporate the use of
75310Sstevel@tonic-gate 	 * reference counting for both the import and the export segments.
75320Sstevel@tonic-gate 	 */
75330Sstevel@tonic-gate 
75340Sstevel@tonic-gate 	/* rsmseglock_acquire(im_seg) done in rsmresource_lookup */
75350Sstevel@tonic-gate 
75360Sstevel@tonic-gate 	im_seg = (rsmseg_t *)res;
75370Sstevel@tonic-gate 
75380Sstevel@tonic-gate 	if (im_seg == NULL) {
75390Sstevel@tonic-gate 		if (sg_io.io_request_count > RSM_MAX_IOVLEN)
75400Sstevel@tonic-gate 			kmem_free(ka_iovec, ka_size);
75410Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
75420Sstevel@tonic-gate 		    "rsm_iovec_ioctl done: rsmresource_lookup failed\n"));
75430Sstevel@tonic-gate 		return (EINVAL);
75440Sstevel@tonic-gate 	}
75450Sstevel@tonic-gate 	/* putv/getv supported is supported only on import segments */
75460Sstevel@tonic-gate 	if (im_seg->s_type != RSM_RESOURCE_IMPORT_SEGMENT) {
75470Sstevel@tonic-gate 		rsmseglock_release(im_seg);
75480Sstevel@tonic-gate 		if (sg_io.io_request_count > RSM_MAX_IOVLEN)
75490Sstevel@tonic-gate 			kmem_free(ka_iovec, ka_size);
75500Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
75510Sstevel@tonic-gate 		    "rsm_iovec_ioctl done: not an import segment\n"));
75520Sstevel@tonic-gate 		return (EINVAL);
75530Sstevel@tonic-gate 	}
75540Sstevel@tonic-gate 
75550Sstevel@tonic-gate 	/*
75560Sstevel@tonic-gate 	 * wait for a remote DR to complete ie. for segments to get UNQUIESCED
75570Sstevel@tonic-gate 	 * as well as wait for a local DR to complete.
75580Sstevel@tonic-gate 	 */
75590Sstevel@tonic-gate 	while ((im_seg->s_state == RSM_STATE_CONN_QUIESCE) ||
75600Sstevel@tonic-gate 	    (im_seg->s_state == RSM_STATE_MAP_QUIESCE) ||
75610Sstevel@tonic-gate 	    (im_seg->s_flags & RSM_DR_INPROGRESS)) {
75620Sstevel@tonic-gate 		if (cv_wait_sig(&im_seg->s_cv, &im_seg->s_lock) == 0) {
75630Sstevel@tonic-gate 			DBG_PRINTF((category, RSM_DEBUG,
75640Sstevel@tonic-gate 			    "rsm_iovec_ioctl done: cv_wait INTR"));
75650Sstevel@tonic-gate 			rsmseglock_release(im_seg);
75660Sstevel@tonic-gate 			return (RSMERR_INTERRUPTED);
75670Sstevel@tonic-gate 		}
75680Sstevel@tonic-gate 	}
75690Sstevel@tonic-gate 
75700Sstevel@tonic-gate 	if ((im_seg->s_state != RSM_STATE_CONNECT) &&
75710Sstevel@tonic-gate 	    (im_seg->s_state != RSM_STATE_ACTIVE)) {
75720Sstevel@tonic-gate 
75730Sstevel@tonic-gate 		ASSERT(im_seg->s_state == RSM_STATE_DISCONNECT ||
75740Sstevel@tonic-gate 		    im_seg->s_state == RSM_STATE_NEW);
75750Sstevel@tonic-gate 
75760Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_DEBUG,
75770Sstevel@tonic-gate 		    "rsm_iovec_ioctl done: im_seg not conn/map"));
75780Sstevel@tonic-gate 		rsmseglock_release(im_seg);
75790Sstevel@tonic-gate 		e = RSMERR_BAD_SGIO;
75800Sstevel@tonic-gate 		goto out;
75810Sstevel@tonic-gate 	}
75820Sstevel@tonic-gate 
75830Sstevel@tonic-gate 	im_seg->s_rdmacnt++;
75840Sstevel@tonic-gate 	rsmseglock_release(im_seg);
75850Sstevel@tonic-gate 
75860Sstevel@tonic-gate 	/*
75870Sstevel@tonic-gate 	 * Allocate and set up the io vector for rsmpi
75880Sstevel@tonic-gate 	 */
75890Sstevel@tonic-gate 	if (sg_io.io_request_count > RSM_MAX_IOVLEN) {
75900Sstevel@tonic-gate 		size = sg_io.io_request_count * sizeof (rsmpi_iovec_t);
75910Sstevel@tonic-gate 		iovec_start = iovec = kmem_zalloc(size, KM_SLEEP);
75920Sstevel@tonic-gate 	} else {
75930Sstevel@tonic-gate 		iovec_start = iovec = iovec_arr;
75940Sstevel@tonic-gate 	}
75950Sstevel@tonic-gate 
75960Sstevel@tonic-gate 	rsmpi_sg_io.iovec = iovec;
75970Sstevel@tonic-gate 	for (iov_proc = 0; iov_proc < sg_io.io_request_count; iov_proc++) {
75980Sstevel@tonic-gate 		if (ka_iovec->io_type == RSM_HANDLE_TYPE) {
75990Sstevel@tonic-gate 			ex_seg = rsmexport_lookup(ka_iovec->local.segid);
76000Sstevel@tonic-gate 
76010Sstevel@tonic-gate 			if (ex_seg == NULL) {
76020Sstevel@tonic-gate 				e = RSMERR_BAD_SGIO;
76030Sstevel@tonic-gate 				break;
76040Sstevel@tonic-gate 			}
76050Sstevel@tonic-gate 			ASSERT(ex_seg->s_state == RSM_STATE_EXPORT);
76060Sstevel@tonic-gate 
76070Sstevel@tonic-gate 			acl = ex_seg->s_acl;
76080Sstevel@tonic-gate 			if (acl[0].ae_permission == 0) {
76090Sstevel@tonic-gate 				struct buf *xbuf;
76100Sstevel@tonic-gate 				dev_t sdev = 0;
76110Sstevel@tonic-gate 
76120Sstevel@tonic-gate 				xbuf = ddi_umem_iosetup(ex_seg->s_cookie,
76130Sstevel@tonic-gate 				    0, ex_seg->s_len, B_WRITE,
76140Sstevel@tonic-gate 				    sdev, 0, NULL, DDI_UMEM_SLEEP);
76150Sstevel@tonic-gate 
76160Sstevel@tonic-gate 				ASSERT(xbuf != NULL);
76170Sstevel@tonic-gate 
76180Sstevel@tonic-gate 				iovec->local_mem.ms_type = RSM_MEM_BUF;
76190Sstevel@tonic-gate 				iovec->local_mem.ms_memory.bp = xbuf;
76200Sstevel@tonic-gate 			} else {
76210Sstevel@tonic-gate 				iovec->local_mem.ms_type = RSM_MEM_HANDLE;
76220Sstevel@tonic-gate 				iovec->local_mem.ms_memory.handle =
76237656SSherry.Moore@Sun.COM 				    ex_seg->s_handle.out;
76240Sstevel@tonic-gate 			}
76250Sstevel@tonic-gate 			ex_seg->s_rdmacnt++; /* refcnt the handle */
76260Sstevel@tonic-gate 			rsmseglock_release(ex_seg);
76270Sstevel@tonic-gate 		} else {
76280Sstevel@tonic-gate 			iovec->local_mem.ms_type = RSM_MEM_VADDR;
76290Sstevel@tonic-gate 			iovec->local_mem.ms_memory.vr.vaddr =
76300Sstevel@tonic-gate 			    ka_iovec->local.vaddr;
76310Sstevel@tonic-gate 		}
76320Sstevel@tonic-gate 
76330Sstevel@tonic-gate 		iovec->local_offset = ka_iovec->local_offset;
76340Sstevel@tonic-gate 		iovec->remote_handle = im_seg->s_handle.in;
76350Sstevel@tonic-gate 		iovec->remote_offset = ka_iovec->remote_offset;
76360Sstevel@tonic-gate 		iovec->transfer_length = ka_iovec->transfer_len;
76370Sstevel@tonic-gate 		iovec++;
76380Sstevel@tonic-gate 		ka_iovec++;
76390Sstevel@tonic-gate 	}
76400Sstevel@tonic-gate 
76410Sstevel@tonic-gate 	if (iov_proc <  sg_io.io_request_count) {
76420Sstevel@tonic-gate 		/* error while processing handle */
76430Sstevel@tonic-gate 		rsmseglock_acquire(im_seg);
76440Sstevel@tonic-gate 		im_seg->s_rdmacnt--;   /* decrement the refcnt for importseg */
76450Sstevel@tonic-gate 		if (im_seg->s_rdmacnt == 0) {
76460Sstevel@tonic-gate 			cv_broadcast(&im_seg->s_cv);
76470Sstevel@tonic-gate 		}
76480Sstevel@tonic-gate 		rsmseglock_release(im_seg);
76490Sstevel@tonic-gate 		goto out;
76500Sstevel@tonic-gate 	}
76510Sstevel@tonic-gate 
76520Sstevel@tonic-gate 	/* call rsmpi */
76530Sstevel@tonic-gate 	if (cmd == RSM_IOCTL_PUTV)
76540Sstevel@tonic-gate 		e = im_seg->s_adapter->rsmpi_ops->rsm_memseg_import_putv(
76550Sstevel@tonic-gate 		    im_seg->s_adapter->rsmpi_handle,
76560Sstevel@tonic-gate 		    &rsmpi_sg_io);
76570Sstevel@tonic-gate 	else if (cmd == RSM_IOCTL_GETV)
76580Sstevel@tonic-gate 		e = im_seg->s_adapter->rsmpi_ops->rsm_memseg_import_getv(
76590Sstevel@tonic-gate 		    im_seg->s_adapter->rsmpi_handle,
76600Sstevel@tonic-gate 		    &rsmpi_sg_io);
76610Sstevel@tonic-gate 	else {
76620Sstevel@tonic-gate 		e = EINVAL;
76630Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_DEBUG,
76640Sstevel@tonic-gate 		    "iovec_ioctl: bad command = %x\n", cmd));
76650Sstevel@tonic-gate 	}
76660Sstevel@tonic-gate 
76670Sstevel@tonic-gate 
76680Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
76690Sstevel@tonic-gate 	    "rsm_iovec_ioctl RSMPI oper done %d\n", e));
76700Sstevel@tonic-gate 
76710Sstevel@tonic-gate 	sg_io.io_residual_count = rsmpi_sg_io.io_residual_count;
76720Sstevel@tonic-gate 
76730Sstevel@tonic-gate 	/*
76740Sstevel@tonic-gate 	 * Check for implicit signal post flag and do the signal
76750Sstevel@tonic-gate 	 * post if needed
76760Sstevel@tonic-gate 	 */
76770Sstevel@tonic-gate 	if (sg_io.flags & RSM_IMPLICIT_SIGPOST &&
76780Sstevel@tonic-gate 	    e == RSM_SUCCESS) {
76790Sstevel@tonic-gate 		rsmipc_request_t request;
76800Sstevel@tonic-gate 
76810Sstevel@tonic-gate 		request.rsmipc_key = im_seg->s_segid;
76820Sstevel@tonic-gate 		request.rsmipc_hdr.rsmipc_type = RSMIPC_MSG_BELL;
76830Sstevel@tonic-gate 		request.rsmipc_segment_cookie = NULL;
76840Sstevel@tonic-gate 		e = rsmipc_send(im_seg->s_node, &request, RSM_NO_REPLY);
76850Sstevel@tonic-gate 		/*
76860Sstevel@tonic-gate 		 * Reset the implicit signal post flag to 0 to indicate
76870Sstevel@tonic-gate 		 * that the signal post has been done and need not be
76880Sstevel@tonic-gate 		 * done in the RSMAPI library
76890Sstevel@tonic-gate 		 */
76900Sstevel@tonic-gate 		sg_io.flags &= ~RSM_IMPLICIT_SIGPOST;
76910Sstevel@tonic-gate 	}
76920Sstevel@tonic-gate 
76930Sstevel@tonic-gate 	rsmseglock_acquire(im_seg);
76940Sstevel@tonic-gate 	im_seg->s_rdmacnt--;
76950Sstevel@tonic-gate 	if (im_seg->s_rdmacnt == 0) {
76960Sstevel@tonic-gate 		cv_broadcast(&im_seg->s_cv);
76970Sstevel@tonic-gate 	}
76980Sstevel@tonic-gate 	rsmseglock_release(im_seg);
76990Sstevel@tonic-gate 	error = sgio_resid_copyout(arg, &sg_io, mode);
77000Sstevel@tonic-gate out:
77010Sstevel@tonic-gate 	iovec = iovec_start;
77020Sstevel@tonic-gate 	ka_iovec = ka_iovec_start;
77030Sstevel@tonic-gate 	for (i = 0; i < iov_proc; i++) {
77040Sstevel@tonic-gate 		if (ka_iovec->io_type == RSM_HANDLE_TYPE) {
77050Sstevel@tonic-gate 			ex_seg = rsmexport_lookup(ka_iovec->local.segid);
77060Sstevel@tonic-gate 
77070Sstevel@tonic-gate 			ASSERT(ex_seg != NULL);
77080Sstevel@tonic-gate 			ASSERT(ex_seg->s_state == RSM_STATE_EXPORT);
77090Sstevel@tonic-gate 
77100Sstevel@tonic-gate 			ex_seg->s_rdmacnt--; /* unrefcnt the handle */
77110Sstevel@tonic-gate 			if (ex_seg->s_rdmacnt == 0) {
77120Sstevel@tonic-gate 				cv_broadcast(&ex_seg->s_cv);
77130Sstevel@tonic-gate 			}
77140Sstevel@tonic-gate 			rsmseglock_release(ex_seg);
77150Sstevel@tonic-gate 		}
77160Sstevel@tonic-gate 
77170Sstevel@tonic-gate 		ASSERT(iovec != NULL); /* true if iov_proc > 0 */
77180Sstevel@tonic-gate 
77190Sstevel@tonic-gate 		/*
77200Sstevel@tonic-gate 		 * At present there is no dependency on the existence of xbufs
77210Sstevel@tonic-gate 		 * created by ddi_umem_iosetup for each of the iovecs. So we
77220Sstevel@tonic-gate 		 * can these xbufs here.
77230Sstevel@tonic-gate 		 */
77240Sstevel@tonic-gate 		if (iovec->local_mem.ms_type == RSM_MEM_BUF) {
77250Sstevel@tonic-gate 			freerbuf(iovec->local_mem.ms_memory.bp);
77260Sstevel@tonic-gate 		}
77270Sstevel@tonic-gate 
77280Sstevel@tonic-gate 		iovec++;
77290Sstevel@tonic-gate 		ka_iovec++;
77300Sstevel@tonic-gate 	}
77310Sstevel@tonic-gate 
77320Sstevel@tonic-gate 	if (sg_io.io_request_count > RSM_MAX_IOVLEN) {
77330Sstevel@tonic-gate 		if (iovec_start)
77340Sstevel@tonic-gate 			kmem_free(iovec_start, size);
77350Sstevel@tonic-gate 		kmem_free(ka_iovec_start, ka_size);
77360Sstevel@tonic-gate 	}
77370Sstevel@tonic-gate 
77380Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
77390Sstevel@tonic-gate 	    "rsm_iovec_ioctl done %d\n", e));
77400Sstevel@tonic-gate 	/* if RSMPI call fails return that else return copyout's retval */
77410Sstevel@tonic-gate 	return ((e != RSM_SUCCESS) ? e : error);
77420Sstevel@tonic-gate 
77430Sstevel@tonic-gate }
77440Sstevel@tonic-gate 
77450Sstevel@tonic-gate 
77460Sstevel@tonic-gate static int
rsmaddr_ioctl(int cmd,rsm_ioctlmsg_t * msg,int mode)77470Sstevel@tonic-gate rsmaddr_ioctl(int cmd, rsm_ioctlmsg_t *msg, int mode)
77480Sstevel@tonic-gate {
77490Sstevel@tonic-gate 	adapter_t	*adapter;
77500Sstevel@tonic-gate 	rsm_addr_t	addr;
77510Sstevel@tonic-gate 	rsm_node_id_t	node;
77520Sstevel@tonic-gate 	int		rval = DDI_SUCCESS;
77530Sstevel@tonic-gate 	DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_FUNC_ALL | RSM_IOCTL);
77540Sstevel@tonic-gate 
77550Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmaddr_ioctl enter\n"));
77560Sstevel@tonic-gate 
77570Sstevel@tonic-gate 	adapter =  rsm_getadapter(msg, mode);
77580Sstevel@tonic-gate 	if (adapter == NULL) {
77590Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_DEBUG,
77600Sstevel@tonic-gate 		    "rsmaddr_ioctl done: adapter not found\n"));
77610Sstevel@tonic-gate 		return (RSMERR_CTLR_NOT_PRESENT);
77620Sstevel@tonic-gate 	}
77630Sstevel@tonic-gate 
77640Sstevel@tonic-gate 	switch (cmd) {
77650Sstevel@tonic-gate 	case RSM_IOCTL_MAP_TO_ADDR: /* nodeid to hwaddr mapping */
77660Sstevel@tonic-gate 		/* returns the hwaddr in msg->hwaddr */
77670Sstevel@tonic-gate 		if (msg->nodeid == my_nodeid) {
77680Sstevel@tonic-gate 			msg->hwaddr = adapter->hwaddr;
77690Sstevel@tonic-gate 		} else {
77700Sstevel@tonic-gate 			addr = get_remote_hwaddr(adapter, msg->nodeid);
77710Sstevel@tonic-gate 			if ((int64_t)addr < 0) {
77720Sstevel@tonic-gate 				rval = RSMERR_INTERNAL_ERROR;
77730Sstevel@tonic-gate 			} else {
77740Sstevel@tonic-gate 				msg->hwaddr = addr;
77750Sstevel@tonic-gate 			}
77760Sstevel@tonic-gate 		}
77770Sstevel@tonic-gate 		break;
77780Sstevel@tonic-gate 	case RSM_IOCTL_MAP_TO_NODEID: /* hwaddr to nodeid mapping */
77790Sstevel@tonic-gate 		/* returns the nodeid in msg->nodeid */
77800Sstevel@tonic-gate 		if (msg->hwaddr == adapter->hwaddr) {
77810Sstevel@tonic-gate 			msg->nodeid = my_nodeid;
77820Sstevel@tonic-gate 		} else {
77830Sstevel@tonic-gate 			node = get_remote_nodeid(adapter, msg->hwaddr);
77840Sstevel@tonic-gate 			if ((int)node < 0) {
77850Sstevel@tonic-gate 				rval = RSMERR_INTERNAL_ERROR;
77860Sstevel@tonic-gate 			} else {
77870Sstevel@tonic-gate 				msg->nodeid = (rsm_node_id_t)node;
77880Sstevel@tonic-gate 			}
77890Sstevel@tonic-gate 		}
77900Sstevel@tonic-gate 		break;
77910Sstevel@tonic-gate 	default:
77920Sstevel@tonic-gate 		rval = EINVAL;
77930Sstevel@tonic-gate 		break;
77940Sstevel@tonic-gate 	}
77950Sstevel@tonic-gate 
77960Sstevel@tonic-gate 	rsmka_release_adapter(adapter);
77970Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
77980Sstevel@tonic-gate 	    "rsmaddr_ioctl done: %d\n", rval));
77990Sstevel@tonic-gate 	return (rval);
78000Sstevel@tonic-gate }
78010Sstevel@tonic-gate 
78020Sstevel@tonic-gate static int
rsm_ddi_copyin(caddr_t arg,rsm_ioctlmsg_t * msg,int mode)78030Sstevel@tonic-gate rsm_ddi_copyin(caddr_t arg, rsm_ioctlmsg_t *msg, int mode)
78040Sstevel@tonic-gate {
78050Sstevel@tonic-gate 	DBG_DEFINE(category,
78060Sstevel@tonic-gate 	    RSM_KERNEL_AGENT | RSM_FUNC_ALL | RSM_IOCTL | RSM_DDI);
78070Sstevel@tonic-gate 
78080Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_ddi_copyin enter\n"));
78090Sstevel@tonic-gate 
78100Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL
78110Sstevel@tonic-gate 
78120Sstevel@tonic-gate 	if ((mode & DATAMODEL_MASK) == DATAMODEL_ILP32) {
78130Sstevel@tonic-gate 		rsm_ioctlmsg32_t msg32;
78140Sstevel@tonic-gate 		int i;
78150Sstevel@tonic-gate 
78160Sstevel@tonic-gate 		if (ddi_copyin(arg, (caddr_t)&msg32, sizeof (msg32), mode)) {
78170Sstevel@tonic-gate 			DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
78180Sstevel@tonic-gate 			    "rsm_ddi_copyin done: EFAULT\n"));
78190Sstevel@tonic-gate 			return (RSMERR_BAD_ADDR);
78200Sstevel@tonic-gate 		}
78210Sstevel@tonic-gate 		msg->len = msg32.len;
78220Sstevel@tonic-gate 		msg->vaddr = (caddr_t)(uintptr_t)msg32.vaddr;
78230Sstevel@tonic-gate 		msg->arg = (caddr_t)(uintptr_t)msg32.arg;
78240Sstevel@tonic-gate 		msg->key = msg32.key;
78250Sstevel@tonic-gate 		msg->acl_len = msg32.acl_len;
78260Sstevel@tonic-gate 		msg->acl = (rsmapi_access_entry_t *)(uintptr_t)msg32.acl;
78270Sstevel@tonic-gate 		msg->cnum = msg32.cnum;
78280Sstevel@tonic-gate 		msg->cname = (caddr_t)(uintptr_t)msg32.cname;
78290Sstevel@tonic-gate 		msg->cname_len = msg32.cname_len;
78300Sstevel@tonic-gate 		msg->nodeid = msg32.nodeid;
78310Sstevel@tonic-gate 		msg->hwaddr = msg32.hwaddr;
78320Sstevel@tonic-gate 		msg->perm = msg32.perm;
78330Sstevel@tonic-gate 		for (i = 0; i < 4; i++) {
78340Sstevel@tonic-gate 			msg->bar.comp[i].u64 = msg32.bar.comp[i].u64;
78350Sstevel@tonic-gate 		}
78360Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
78370Sstevel@tonic-gate 		    "rsm_ddi_copyin done\n"));
78380Sstevel@tonic-gate 		return (RSM_SUCCESS);
78390Sstevel@tonic-gate 	}
78400Sstevel@tonic-gate #endif
78410Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_ddi_copyin done\n"));
78420Sstevel@tonic-gate 	if (ddi_copyin(arg, (caddr_t)msg, sizeof (*msg), mode))
78430Sstevel@tonic-gate 		return (RSMERR_BAD_ADDR);
78440Sstevel@tonic-gate 	else
78450Sstevel@tonic-gate 		return (RSM_SUCCESS);
78460Sstevel@tonic-gate }
78470Sstevel@tonic-gate 
78480Sstevel@tonic-gate static int
rsmattr_ddi_copyout(adapter_t * adapter,caddr_t arg,int mode)78490Sstevel@tonic-gate rsmattr_ddi_copyout(adapter_t *adapter, caddr_t arg, int mode)
78500Sstevel@tonic-gate {
78510Sstevel@tonic-gate 	rsmka_int_controller_attr_t	rsm_cattr;
78520Sstevel@tonic-gate 	DBG_DEFINE(category,
78537656SSherry.Moore@Sun.COM 	    RSM_KERNEL_AGENT | RSM_FUNC_ALL | RSM_IOCTL | RSM_DDI);
78540Sstevel@tonic-gate 
78550Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
78560Sstevel@tonic-gate 	    "rsmattr_ddi_copyout enter\n"));
78570Sstevel@tonic-gate 	/*
78580Sstevel@tonic-gate 	 * need to copy appropriate data from rsm_controller_attr_t
78590Sstevel@tonic-gate 	 * to rsmka_int_controller_attr_t
78600Sstevel@tonic-gate 	 */
78610Sstevel@tonic-gate #ifdef	_MULTI_DATAMODEL
78620Sstevel@tonic-gate 	if ((mode & DATAMODEL_MASK) == DATAMODEL_ILP32) {
78630Sstevel@tonic-gate 		rsmka_int_controller_attr32_t rsm_cattr32;
78640Sstevel@tonic-gate 
78650Sstevel@tonic-gate 		rsm_cattr32.attr_direct_access_sizes =
78660Sstevel@tonic-gate 		    adapter->rsm_attr.attr_direct_access_sizes;
78670Sstevel@tonic-gate 		rsm_cattr32.attr_atomic_sizes =
78680Sstevel@tonic-gate 		    adapter->rsm_attr.attr_atomic_sizes;
78690Sstevel@tonic-gate 		rsm_cattr32.attr_page_size =
78700Sstevel@tonic-gate 		    adapter->rsm_attr.attr_page_size;
78710Sstevel@tonic-gate 		if (adapter->rsm_attr.attr_max_export_segment_size >
78720Sstevel@tonic-gate 		    UINT_MAX)
78730Sstevel@tonic-gate 			rsm_cattr32.attr_max_export_segment_size =
78740Sstevel@tonic-gate 			    RSM_MAXSZ_PAGE_ALIGNED;
78750Sstevel@tonic-gate 		else
78760Sstevel@tonic-gate 			rsm_cattr32.attr_max_export_segment_size =
78770Sstevel@tonic-gate 			    adapter->rsm_attr.attr_max_export_segment_size;
78780Sstevel@tonic-gate 		if (adapter->rsm_attr.attr_tot_export_segment_size >
78790Sstevel@tonic-gate 		    UINT_MAX)
78800Sstevel@tonic-gate 			rsm_cattr32.attr_tot_export_segment_size =
78810Sstevel@tonic-gate 			    RSM_MAXSZ_PAGE_ALIGNED;
78820Sstevel@tonic-gate 		else
78830Sstevel@tonic-gate 			rsm_cattr32.attr_tot_export_segment_size =
78840Sstevel@tonic-gate 			    adapter->rsm_attr.attr_tot_export_segment_size;
78850Sstevel@tonic-gate 		if (adapter->rsm_attr.attr_max_export_segments >
78860Sstevel@tonic-gate 		    UINT_MAX)
78870Sstevel@tonic-gate 			rsm_cattr32.attr_max_export_segments =
78880Sstevel@tonic-gate 			    UINT_MAX;
78890Sstevel@tonic-gate 		else
78900Sstevel@tonic-gate 			rsm_cattr32.attr_max_export_segments =
78910Sstevel@tonic-gate 			    adapter->rsm_attr.attr_max_export_segments;
78920Sstevel@tonic-gate 		if (adapter->rsm_attr.attr_max_import_map_size >
78930Sstevel@tonic-gate 		    UINT_MAX)
78940Sstevel@tonic-gate 			rsm_cattr32.attr_max_import_map_size =
78950Sstevel@tonic-gate 			    RSM_MAXSZ_PAGE_ALIGNED;
78960Sstevel@tonic-gate 		else
78970Sstevel@tonic-gate 			rsm_cattr32.attr_max_import_map_size =
78980Sstevel@tonic-gate 			    adapter->rsm_attr.attr_max_import_map_size;
78990Sstevel@tonic-gate 		if (adapter->rsm_attr.attr_tot_import_map_size >
79000Sstevel@tonic-gate 		    UINT_MAX)
79010Sstevel@tonic-gate 			rsm_cattr32.attr_tot_import_map_size =
79020Sstevel@tonic-gate 			    RSM_MAXSZ_PAGE_ALIGNED;
79030Sstevel@tonic-gate 		else
79040Sstevel@tonic-gate 			rsm_cattr32.attr_tot_import_map_size =
79050Sstevel@tonic-gate 			    adapter->rsm_attr.attr_tot_import_map_size;
79060Sstevel@tonic-gate 		if (adapter->rsm_attr.attr_max_import_segments >
79070Sstevel@tonic-gate 		    UINT_MAX)
79080Sstevel@tonic-gate 			rsm_cattr32.attr_max_import_segments =
79090Sstevel@tonic-gate 			    UINT_MAX;
79100Sstevel@tonic-gate 		else
79110Sstevel@tonic-gate 			rsm_cattr32.attr_max_import_segments =
79120Sstevel@tonic-gate 			    adapter->rsm_attr.attr_max_import_segments;
79130Sstevel@tonic-gate 		rsm_cattr32.attr_controller_addr =
79140Sstevel@tonic-gate 		    adapter->rsm_attr.attr_controller_addr;
79150Sstevel@tonic-gate 
79160Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
79170Sstevel@tonic-gate 		    "rsmattr_ddi_copyout done\n"));
79180Sstevel@tonic-gate 		if (ddi_copyout((caddr_t)&rsm_cattr32, arg,
79190Sstevel@tonic-gate 		    sizeof (rsmka_int_controller_attr32_t), mode)) {
79200Sstevel@tonic-gate 			return (RSMERR_BAD_ADDR);
79210Sstevel@tonic-gate 		}
79220Sstevel@tonic-gate 		else
79230Sstevel@tonic-gate 			return (RSM_SUCCESS);
79240Sstevel@tonic-gate 	}
79250Sstevel@tonic-gate #endif
79260Sstevel@tonic-gate 	rsm_cattr.attr_direct_access_sizes =
79270Sstevel@tonic-gate 	    adapter->rsm_attr.attr_direct_access_sizes;
79280Sstevel@tonic-gate 	rsm_cattr.attr_atomic_sizes =
79290Sstevel@tonic-gate 	    adapter->rsm_attr.attr_atomic_sizes;
79300Sstevel@tonic-gate 	rsm_cattr.attr_page_size =
79310Sstevel@tonic-gate 	    adapter->rsm_attr.attr_page_size;
79320Sstevel@tonic-gate 	rsm_cattr.attr_max_export_segment_size =
79330Sstevel@tonic-gate 	    adapter->rsm_attr.attr_max_export_segment_size;
79340Sstevel@tonic-gate 	rsm_cattr.attr_tot_export_segment_size =
79350Sstevel@tonic-gate 	    adapter->rsm_attr.attr_tot_export_segment_size;
79360Sstevel@tonic-gate 	rsm_cattr.attr_max_export_segments =
79370Sstevel@tonic-gate 	    adapter->rsm_attr.attr_max_export_segments;
79380Sstevel@tonic-gate 	rsm_cattr.attr_max_import_map_size =
79390Sstevel@tonic-gate 	    adapter->rsm_attr.attr_max_import_map_size;
79400Sstevel@tonic-gate 	rsm_cattr.attr_tot_import_map_size =
79410Sstevel@tonic-gate 	    adapter->rsm_attr.attr_tot_import_map_size;
79420Sstevel@tonic-gate 	rsm_cattr.attr_max_import_segments =
79430Sstevel@tonic-gate 	    adapter->rsm_attr.attr_max_import_segments;
79440Sstevel@tonic-gate 	rsm_cattr.attr_controller_addr =
79450Sstevel@tonic-gate 	    adapter->rsm_attr.attr_controller_addr;
79460Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
79470Sstevel@tonic-gate 	    "rsmattr_ddi_copyout done\n"));
79480Sstevel@tonic-gate 	if (ddi_copyout((caddr_t)&rsm_cattr, arg,
79490Sstevel@tonic-gate 	    sizeof (rsmka_int_controller_attr_t), mode)) {
79500Sstevel@tonic-gate 		return (RSMERR_BAD_ADDR);
79510Sstevel@tonic-gate 	}
79520Sstevel@tonic-gate 	else
79530Sstevel@tonic-gate 		return (RSM_SUCCESS);
79540Sstevel@tonic-gate }
79550Sstevel@tonic-gate 
79560Sstevel@tonic-gate /*ARGSUSED*/
79570Sstevel@tonic-gate static int
rsm_ioctl(dev_t dev,int cmd,intptr_t arg,int mode,cred_t * credp,int * rvalp)79580Sstevel@tonic-gate rsm_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp,
79590Sstevel@tonic-gate     int *rvalp)
79600Sstevel@tonic-gate {
79610Sstevel@tonic-gate 	rsmseg_t *seg;
79620Sstevel@tonic-gate 	rsmresource_t	*res;
79630Sstevel@tonic-gate 	minor_t		rnum;
79640Sstevel@tonic-gate 	rsm_ioctlmsg_t msg = {0};
79650Sstevel@tonic-gate 	int error;
79660Sstevel@tonic-gate 	adapter_t *adapter;
79670Sstevel@tonic-gate 	DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_FUNC_ALL | RSM_IOCTL);
79680Sstevel@tonic-gate 
79690Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_ioctl enter\n"));
79700Sstevel@tonic-gate 
79710Sstevel@tonic-gate 	if (cmd == RSM_IOCTL_CONSUMEEVENT) {
79720Sstevel@tonic-gate 		error = rsm_consumeevent_ioctl((caddr_t)arg, mode);
79730Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
79740Sstevel@tonic-gate 		    "rsm_ioctl RSM_IOCTL_CONSUMEEVENT done: %d\n", error));
79750Sstevel@tonic-gate 		return (error);
79760Sstevel@tonic-gate 	}
79770Sstevel@tonic-gate 
79780Sstevel@tonic-gate 	/* topology cmd does not use the arg common to other cmds */
79790Sstevel@tonic-gate 	if (RSM_IOCTL_CMDGRP(cmd) == RSM_IOCTL_TOPOLOGY) {
79800Sstevel@tonic-gate 		error = rsmka_topology_ioctl((caddr_t)arg, cmd, mode);
79810Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
79820Sstevel@tonic-gate 		    "rsm_ioctl done: %d\n", error));
79830Sstevel@tonic-gate 		return (error);
79840Sstevel@tonic-gate 	}
79850Sstevel@tonic-gate 
79860Sstevel@tonic-gate 	if (RSM_IOCTL_CMDGRP(cmd) == RSM_IOCTL_IOVEC) {
79870Sstevel@tonic-gate 		error = rsm_iovec_ioctl(dev, (caddr_t)arg, cmd, mode, credp);
79880Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
79890Sstevel@tonic-gate 		    "rsm_ioctl done: %d\n", error));
79900Sstevel@tonic-gate 		return (error);
79910Sstevel@tonic-gate 	}
79920Sstevel@tonic-gate 
79930Sstevel@tonic-gate 	/*
79940Sstevel@tonic-gate 	 * try to load arguments
79950Sstevel@tonic-gate 	 */
79960Sstevel@tonic-gate 	if (cmd != RSM_IOCTL_RING_BELL &&
79970Sstevel@tonic-gate 	    rsm_ddi_copyin((caddr_t)arg, &msg, mode)) {
79980Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
79990Sstevel@tonic-gate 		    "rsm_ioctl done: EFAULT\n"));
80000Sstevel@tonic-gate 		return (RSMERR_BAD_ADDR);
80010Sstevel@tonic-gate 	}
80020Sstevel@tonic-gate 
80030Sstevel@tonic-gate 	if (cmd == RSM_IOCTL_ATTR) {
80040Sstevel@tonic-gate 		adapter =  rsm_getadapter(&msg, mode);
80050Sstevel@tonic-gate 		if (adapter == NULL) {
80060Sstevel@tonic-gate 			DBG_PRINTF((category, RSM_DEBUG,
80070Sstevel@tonic-gate 			    "rsm_ioctl done: ENODEV\n"));
80080Sstevel@tonic-gate 			return (RSMERR_CTLR_NOT_PRESENT);
80090Sstevel@tonic-gate 		}
80100Sstevel@tonic-gate 		error = rsmattr_ddi_copyout(adapter, msg.arg, mode);
80110Sstevel@tonic-gate 		rsmka_release_adapter(adapter);
80120Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_DEBUG,
80130Sstevel@tonic-gate 		    "rsm_ioctl:after copyout %d\n", error));
80140Sstevel@tonic-gate 		return (error);
80150Sstevel@tonic-gate 	}
80160Sstevel@tonic-gate 
80170Sstevel@tonic-gate 	if (cmd == RSM_IOCTL_BAR_INFO) {
80180Sstevel@tonic-gate 		/* Return library off,len of barrier page */
80190Sstevel@tonic-gate 		msg.off = barrier_offset;
80200Sstevel@tonic-gate 		msg.len = (int)barrier_size;
80210Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL
80220Sstevel@tonic-gate 		if ((mode & DATAMODEL_MASK) == DATAMODEL_ILP32) {
80230Sstevel@tonic-gate 			rsm_ioctlmsg32_t msg32;
80240Sstevel@tonic-gate 
80250Sstevel@tonic-gate 			if (msg.len > UINT_MAX)
80260Sstevel@tonic-gate 				msg.len = RSM_MAXSZ_PAGE_ALIGNED;
80270Sstevel@tonic-gate 			else
80280Sstevel@tonic-gate 				msg32.len = (int32_t)msg.len;
80290Sstevel@tonic-gate 			msg32.off = (int32_t)msg.off;
80300Sstevel@tonic-gate 			DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
80310Sstevel@tonic-gate 			    "rsm_ioctl done\n"));
80320Sstevel@tonic-gate 			if (ddi_copyout((caddr_t)&msg32, (caddr_t)arg,
80330Sstevel@tonic-gate 			    sizeof (msg32), mode))
80340Sstevel@tonic-gate 				return (RSMERR_BAD_ADDR);
80350Sstevel@tonic-gate 			else
80360Sstevel@tonic-gate 				return (RSM_SUCCESS);
80370Sstevel@tonic-gate 		}
80380Sstevel@tonic-gate #endif
80390Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
80400Sstevel@tonic-gate 		    "rsm_ioctl done\n"));
80410Sstevel@tonic-gate 		if (ddi_copyout((caddr_t)&msg, (caddr_t)arg,
80420Sstevel@tonic-gate 		    sizeof (msg), mode))
80430Sstevel@tonic-gate 			return (RSMERR_BAD_ADDR);
80440Sstevel@tonic-gate 		else
80450Sstevel@tonic-gate 			return (RSM_SUCCESS);
80460Sstevel@tonic-gate 	}
80470Sstevel@tonic-gate 
80480Sstevel@tonic-gate 	if (RSM_IOCTL_CMDGRP(cmd) == RSM_IOCTL_MAP_ADDR) {
80490Sstevel@tonic-gate 		/* map the nodeid or hwaddr */
80500Sstevel@tonic-gate 		error = rsmaddr_ioctl(cmd, &msg, mode);
80510Sstevel@tonic-gate 		if (error == RSM_SUCCESS) {
80520Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL
80530Sstevel@tonic-gate 			if ((mode & DATAMODEL_MASK) == DATAMODEL_ILP32) {
80540Sstevel@tonic-gate 				rsm_ioctlmsg32_t msg32;
80550Sstevel@tonic-gate 
80560Sstevel@tonic-gate 				msg32.hwaddr = (uint64_t)msg.hwaddr;
80570Sstevel@tonic-gate 				msg32.nodeid = (uint32_t)msg.nodeid;
80580Sstevel@tonic-gate 
80590Sstevel@tonic-gate 				DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
80600Sstevel@tonic-gate 				    "rsm_ioctl done\n"));
80610Sstevel@tonic-gate 				if (ddi_copyout((caddr_t)&msg32, (caddr_t)arg,
80620Sstevel@tonic-gate 				    sizeof (msg32), mode))
80630Sstevel@tonic-gate 					return (RSMERR_BAD_ADDR);
80640Sstevel@tonic-gate 				else
80650Sstevel@tonic-gate 					return (RSM_SUCCESS);
80660Sstevel@tonic-gate 			}
80670Sstevel@tonic-gate #endif
80680Sstevel@tonic-gate 			DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
80690Sstevel@tonic-gate 			    "rsm_ioctl done\n"));
80700Sstevel@tonic-gate 			if (ddi_copyout((caddr_t)&msg, (caddr_t)arg,
80710Sstevel@tonic-gate 			    sizeof (msg), mode))
80720Sstevel@tonic-gate 				return (RSMERR_BAD_ADDR);
80730Sstevel@tonic-gate 			else
80740Sstevel@tonic-gate 				return (RSM_SUCCESS);
80750Sstevel@tonic-gate 		}
80760Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
80770Sstevel@tonic-gate 		    "rsm_ioctl done: %d\n", error));
80780Sstevel@tonic-gate 		return (error);
80790Sstevel@tonic-gate 	}
80800Sstevel@tonic-gate 
80810Sstevel@tonic-gate 	/* Find resource and look it in read mode */
80820Sstevel@tonic-gate 	rnum = getminor(dev);
80830Sstevel@tonic-gate 	res = rsmresource_lookup(rnum, RSM_NOLOCK);
80840Sstevel@tonic-gate 	ASSERT(res != NULL);
80850Sstevel@tonic-gate 
80860Sstevel@tonic-gate 	/*
80870Sstevel@tonic-gate 	 * Find command group
80880Sstevel@tonic-gate 	 */
80890Sstevel@tonic-gate 	switch (RSM_IOCTL_CMDGRP(cmd)) {
80900Sstevel@tonic-gate 	case RSM_IOCTL_EXPORT_SEG:
80910Sstevel@tonic-gate 		/*
80920Sstevel@tonic-gate 		 * Export list is searched during publish, loopback and
80930Sstevel@tonic-gate 		 * remote lookup call.
80940Sstevel@tonic-gate 		 */
80950Sstevel@tonic-gate 		seg = rsmresource_seg(res, rnum, credp,
80960Sstevel@tonic-gate 		    RSM_RESOURCE_EXPORT_SEGMENT);
80970Sstevel@tonic-gate 		if (seg->s_type == RSM_RESOURCE_EXPORT_SEGMENT) {
80980Sstevel@tonic-gate 			error = rsmexport_ioctl(seg, &msg, cmd, arg, mode,
80990Sstevel@tonic-gate 			    credp);
81000Sstevel@tonic-gate 		} else { /* export ioctl on an import/barrier resource */
81010Sstevel@tonic-gate 			error = RSMERR_BAD_SEG_HNDL;
81020Sstevel@tonic-gate 		}
81030Sstevel@tonic-gate 		break;
81040Sstevel@tonic-gate 	case RSM_IOCTL_IMPORT_SEG:
81050Sstevel@tonic-gate 		/* Import list is searched during remote unmap call. */
81060Sstevel@tonic-gate 		seg = rsmresource_seg(res, rnum, credp,
81070Sstevel@tonic-gate 		    RSM_RESOURCE_IMPORT_SEGMENT);
81080Sstevel@tonic-gate 		if (seg->s_type == RSM_RESOURCE_IMPORT_SEGMENT) {
81090Sstevel@tonic-gate 			error = rsmimport_ioctl(seg, &msg, cmd, arg, mode,
81100Sstevel@tonic-gate 			    credp);
81110Sstevel@tonic-gate 		} else  { /* import ioctl on an export/barrier resource */
81120Sstevel@tonic-gate 			error = RSMERR_BAD_SEG_HNDL;
81130Sstevel@tonic-gate 		}
81140Sstevel@tonic-gate 		break;
81150Sstevel@tonic-gate 	case RSM_IOCTL_BAR:
81160Sstevel@tonic-gate 		if (res != RSMRC_RESERVED &&
81170Sstevel@tonic-gate 		    res->rsmrc_type == RSM_RESOURCE_IMPORT_SEGMENT) {
81180Sstevel@tonic-gate 			error = rsmbar_ioctl((rsmseg_t *)res, &msg, cmd, arg,
81190Sstevel@tonic-gate 			    mode);
81200Sstevel@tonic-gate 		} else { /* invalid res value */
81210Sstevel@tonic-gate 			error = RSMERR_BAD_SEG_HNDL;
81220Sstevel@tonic-gate 		}
81230Sstevel@tonic-gate 		break;
81240Sstevel@tonic-gate 	case RSM_IOCTL_BELL:
81250Sstevel@tonic-gate 		if (res != RSMRC_RESERVED) {
81260Sstevel@tonic-gate 			if (res->rsmrc_type == RSM_RESOURCE_IMPORT_SEGMENT)
81270Sstevel@tonic-gate 				error = exportbell_ioctl((rsmseg_t *)res, cmd);
81280Sstevel@tonic-gate 			else if (res->rsmrc_type == RSM_RESOURCE_EXPORT_SEGMENT)
81290Sstevel@tonic-gate 				error = importbell_ioctl((rsmseg_t *)res, cmd);
81300Sstevel@tonic-gate 			else /* RSM_RESOURCE_BAR */
81310Sstevel@tonic-gate 				error = RSMERR_BAD_SEG_HNDL;
81320Sstevel@tonic-gate 		} else { /* invalid res value */
81330Sstevel@tonic-gate 			error = RSMERR_BAD_SEG_HNDL;
81340Sstevel@tonic-gate 		}
81350Sstevel@tonic-gate 		break;
81360Sstevel@tonic-gate 	default:
81370Sstevel@tonic-gate 		error = EINVAL;
81380Sstevel@tonic-gate 	}
81390Sstevel@tonic-gate 
81400Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_ioctl done: %d\n",
81410Sstevel@tonic-gate 	    error));
81420Sstevel@tonic-gate 	return (error);
81430Sstevel@tonic-gate }
81440Sstevel@tonic-gate 
81450Sstevel@tonic-gate 
81460Sstevel@tonic-gate /* **************************** Segment Mapping Operations ********* */
81470Sstevel@tonic-gate static rsm_mapinfo_t *
rsm_get_mapinfo(rsmseg_t * seg,off_t off,size_t len,off_t * dev_offset,size_t * map_len)81480Sstevel@tonic-gate rsm_get_mapinfo(rsmseg_t *seg, off_t off, size_t len, off_t *dev_offset,
81490Sstevel@tonic-gate     size_t *map_len)
81500Sstevel@tonic-gate {
81510Sstevel@tonic-gate 	rsm_mapinfo_t	*p;
81520Sstevel@tonic-gate 	/*
81530Sstevel@tonic-gate 	 * Find the correct mapinfo structure to use during the mapping
81540Sstevel@tonic-gate 	 * from the seg->s_mapinfo list.
81550Sstevel@tonic-gate 	 * The seg->s_mapinfo list contains in reverse order the mappings
81560Sstevel@tonic-gate 	 * as returned by the RSMPI rsm_map. In rsm_devmap, we need to
81570Sstevel@tonic-gate 	 * access the correct entry within this list for the mapping
81580Sstevel@tonic-gate 	 * requested.
81590Sstevel@tonic-gate 	 *
81600Sstevel@tonic-gate 	 * The algorithm for selecting a list entry is as follows:
81610Sstevel@tonic-gate 	 *
81620Sstevel@tonic-gate 	 * When start_offset of an entry <= off we have found the entry
81630Sstevel@tonic-gate 	 * we were looking for. Adjust the dev_offset and map_len (needs
81640Sstevel@tonic-gate 	 * to be PAGESIZE aligned).
81650Sstevel@tonic-gate 	 */
81660Sstevel@tonic-gate 	p = seg->s_mapinfo;
81670Sstevel@tonic-gate 	for (; p; p = p->next) {
81680Sstevel@tonic-gate 		if (p->start_offset <= off) {
81690Sstevel@tonic-gate 			*dev_offset = p->dev_offset + off - p->start_offset;
81700Sstevel@tonic-gate 			*map_len = (len > p->individual_len) ?
81710Sstevel@tonic-gate 			    p->individual_len : ptob(btopr(len));
81720Sstevel@tonic-gate 			return (p);
81730Sstevel@tonic-gate 		}
81740Sstevel@tonic-gate 		p = p->next;
81750Sstevel@tonic-gate 	}
81760Sstevel@tonic-gate 
81770Sstevel@tonic-gate 	return (NULL);
81780Sstevel@tonic-gate }
81790Sstevel@tonic-gate 
81800Sstevel@tonic-gate static void
rsm_free_mapinfo(rsm_mapinfo_t * mapinfo)81810Sstevel@tonic-gate rsm_free_mapinfo(rsm_mapinfo_t  *mapinfo)
81820Sstevel@tonic-gate {
81830Sstevel@tonic-gate 	rsm_mapinfo_t *p;
81840Sstevel@tonic-gate 
81850Sstevel@tonic-gate 	while (mapinfo != NULL) {
81860Sstevel@tonic-gate 		p = mapinfo;
81870Sstevel@tonic-gate 		mapinfo = mapinfo->next;
81880Sstevel@tonic-gate 		kmem_free(p, sizeof (*p));
81890Sstevel@tonic-gate 	}
81900Sstevel@tonic-gate }
81910Sstevel@tonic-gate 
81920Sstevel@tonic-gate static int
rsmmap_map(devmap_cookie_t dhp,dev_t dev,uint_t flags,offset_t off,size_t len,void ** pvtp)81930Sstevel@tonic-gate rsmmap_map(devmap_cookie_t dhp, dev_t dev, uint_t flags, offset_t off,
81940Sstevel@tonic-gate     size_t len, void **pvtp)
81950Sstevel@tonic-gate {
81960Sstevel@tonic-gate 	rsmcookie_t	*p;
81970Sstevel@tonic-gate 	rsmresource_t	*res;
81980Sstevel@tonic-gate 	rsmseg_t	*seg;
81990Sstevel@tonic-gate 	minor_t rnum;
82000Sstevel@tonic-gate 	DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_FUNC_ALL | RSM_DDI);
82010Sstevel@tonic-gate 
82020Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmmap_map enter\n"));
82030Sstevel@tonic-gate 
82040Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
82050Sstevel@tonic-gate 	    "rsmmap_map: dhp = %x\n", dhp));
82060Sstevel@tonic-gate 
82070Sstevel@tonic-gate 	flags = flags;
82080Sstevel@tonic-gate 
82090Sstevel@tonic-gate 	rnum = getminor(dev);
82100Sstevel@tonic-gate 	res = (rsmresource_t *)rsmresource_lookup(rnum, RSM_NOLOCK);
82110Sstevel@tonic-gate 	ASSERT(res != NULL);
82120Sstevel@tonic-gate 
82130Sstevel@tonic-gate 	seg = (rsmseg_t *)res;
82140Sstevel@tonic-gate 
82150Sstevel@tonic-gate 	rsmseglock_acquire(seg);
82160Sstevel@tonic-gate 
82170Sstevel@tonic-gate 	ASSERT(seg->s_hdr.rsmrc_type == RSM_RESOURCE_IMPORT_SEGMENT);
82180Sstevel@tonic-gate 
82190Sstevel@tonic-gate 	/*
82200Sstevel@tonic-gate 	 * Allocate structure and add cookie to segment list
82210Sstevel@tonic-gate 	 */
82220Sstevel@tonic-gate 	p = kmem_alloc(sizeof (*p), KM_SLEEP);
82230Sstevel@tonic-gate 
82240Sstevel@tonic-gate 	p->c_dhp = dhp;
82250Sstevel@tonic-gate 	p->c_off = off;
82260Sstevel@tonic-gate 	p->c_len = len;
82270Sstevel@tonic-gate 	p->c_next = seg->s_ckl;
82280Sstevel@tonic-gate 	seg->s_ckl = p;
82290Sstevel@tonic-gate 
82300Sstevel@tonic-gate 	*pvtp = (void *)seg;
82310Sstevel@tonic-gate 
82320Sstevel@tonic-gate 	rsmseglock_release(seg);
82330Sstevel@tonic-gate 
82340Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmmap_map done\n"));
82350Sstevel@tonic-gate 	return (DDI_SUCCESS);
82360Sstevel@tonic-gate }
82370Sstevel@tonic-gate 
82380Sstevel@tonic-gate /*
82390Sstevel@tonic-gate  * Page fault handling is done here. The prerequisite mapping setup
82400Sstevel@tonic-gate  * has been done in rsm_devmap with calls to ddi_devmem_setup or
82410Sstevel@tonic-gate  * ddi_umem_setup
82420Sstevel@tonic-gate  */
82430Sstevel@tonic-gate static int
rsmmap_access(devmap_cookie_t dhp,void * pvt,offset_t offset,size_t len,uint_t type,uint_t rw)82440Sstevel@tonic-gate rsmmap_access(devmap_cookie_t dhp, void *pvt, offset_t offset, size_t len,
82450Sstevel@tonic-gate     uint_t type, uint_t rw)
82460Sstevel@tonic-gate {
82470Sstevel@tonic-gate 	int e;
82480Sstevel@tonic-gate 	rsmseg_t *seg = (rsmseg_t *)pvt;
82490Sstevel@tonic-gate 	DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_FUNC_ALL | RSM_DDI);
82500Sstevel@tonic-gate 
82510Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmmap_access enter\n"));
82520Sstevel@tonic-gate 
82530Sstevel@tonic-gate 	rsmseglock_acquire(seg);
82540Sstevel@tonic-gate 
82550Sstevel@tonic-gate 	ASSERT(seg->s_hdr.rsmrc_type == RSM_RESOURCE_IMPORT_SEGMENT);
82560Sstevel@tonic-gate 
82570Sstevel@tonic-gate 	while (seg->s_state == RSM_STATE_MAP_QUIESCE) {
82580Sstevel@tonic-gate 		if (cv_wait_sig(&seg->s_cv, &seg->s_lock) == 0) {
82590Sstevel@tonic-gate 			DBG_PRINTF((category, RSM_DEBUG,
82600Sstevel@tonic-gate 			    "rsmmap_access done: cv_wait INTR"));
82610Sstevel@tonic-gate 			rsmseglock_release(seg);
82620Sstevel@tonic-gate 			return (RSMERR_INTERRUPTED);
82630Sstevel@tonic-gate 		}
82640Sstevel@tonic-gate 	}
82650Sstevel@tonic-gate 
82660Sstevel@tonic-gate 	ASSERT(seg->s_state == RSM_STATE_DISCONNECT ||
82670Sstevel@tonic-gate 	    seg->s_state == RSM_STATE_ACTIVE);
82680Sstevel@tonic-gate 
82690Sstevel@tonic-gate 	if (seg->s_state == RSM_STATE_DISCONNECT)
82700Sstevel@tonic-gate 		seg->s_flags |= RSM_IMPORT_DUMMY;
82710Sstevel@tonic-gate 
82720Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
82730Sstevel@tonic-gate 	    "rsmmap_access: dhp = %x\n", dhp));
82740Sstevel@tonic-gate 
82750Sstevel@tonic-gate 	rsmseglock_release(seg);
82760Sstevel@tonic-gate 
82770Sstevel@tonic-gate 	if (e = devmap_load(dhp, offset, len, type, rw)) {
82780Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_ERR, "devmap_load failed\n"));
82790Sstevel@tonic-gate 	}
82800Sstevel@tonic-gate 
82810Sstevel@tonic-gate 
82820Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmmap_access done\n"));
82830Sstevel@tonic-gate 
82840Sstevel@tonic-gate 	return (e);
82850Sstevel@tonic-gate }
82860Sstevel@tonic-gate 
82870Sstevel@tonic-gate static int
rsmmap_dup(devmap_cookie_t dhp,void * oldpvt,devmap_cookie_t new_dhp,void ** newpvt)82880Sstevel@tonic-gate rsmmap_dup(devmap_cookie_t dhp, void *oldpvt, devmap_cookie_t new_dhp,
82890Sstevel@tonic-gate 	void **newpvt)
82900Sstevel@tonic-gate {
82910Sstevel@tonic-gate 	rsmseg_t	*seg = (rsmseg_t *)oldpvt;
82920Sstevel@tonic-gate 	rsmcookie_t	*p, *old;
82930Sstevel@tonic-gate 	DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_FUNC_ALL | RSM_DDI);
82940Sstevel@tonic-gate 
82950Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmmap_dup enter\n"));
82960Sstevel@tonic-gate 
82970Sstevel@tonic-gate 	/*
82980Sstevel@tonic-gate 	 * Same as map, create an entry to hold cookie and add it to
82990Sstevel@tonic-gate 	 * connect segment list. The oldpvt is a pointer to segment.
83000Sstevel@tonic-gate 	 * Return segment pointer in newpvt.
83010Sstevel@tonic-gate 	 */
83020Sstevel@tonic-gate 	rsmseglock_acquire(seg);
83030Sstevel@tonic-gate 
83040Sstevel@tonic-gate 	ASSERT(seg->s_hdr.rsmrc_type == RSM_RESOURCE_IMPORT_SEGMENT);
83050Sstevel@tonic-gate 
83060Sstevel@tonic-gate 	/*
83070Sstevel@tonic-gate 	 * Find old cookie
83080Sstevel@tonic-gate 	 */
83090Sstevel@tonic-gate 	for (old = seg->s_ckl; old != NULL; old = old->c_next) {
83100Sstevel@tonic-gate 		if (old->c_dhp == dhp) {
83110Sstevel@tonic-gate 			break;
83120Sstevel@tonic-gate 		}
83130Sstevel@tonic-gate 	}
83140Sstevel@tonic-gate 	if (old == NULL) {
83150Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
83160Sstevel@tonic-gate 		    "rsmmap_dup done: EINVAL\n"));
83170Sstevel@tonic-gate 		rsmseglock_release(seg);
83180Sstevel@tonic-gate 		return (EINVAL);
83190Sstevel@tonic-gate 	}
83200Sstevel@tonic-gate 
83210Sstevel@tonic-gate 	p = kmem_alloc(sizeof (*p), KM_SLEEP);
83220Sstevel@tonic-gate 
83230Sstevel@tonic-gate 	p->c_dhp = new_dhp;
83240Sstevel@tonic-gate 	p->c_off = old->c_off;
83250Sstevel@tonic-gate 	p->c_len = old->c_len;
83260Sstevel@tonic-gate 	p->c_next = seg->s_ckl;
83270Sstevel@tonic-gate 	seg->s_ckl = p;
83280Sstevel@tonic-gate 
83290Sstevel@tonic-gate 	*newpvt = (void *)seg;
83300Sstevel@tonic-gate 
83310Sstevel@tonic-gate 	rsmseglock_release(seg);
83320Sstevel@tonic-gate 
83330Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmmap_dup done\n"));
83340Sstevel@tonic-gate 
83350Sstevel@tonic-gate 	return (DDI_SUCCESS);
83360Sstevel@tonic-gate }
83370Sstevel@tonic-gate 
83380Sstevel@tonic-gate static void
rsmmap_unmap(devmap_cookie_t dhp,void * pvtp,offset_t off,size_t len,devmap_cookie_t new_dhp1,void ** pvtp1,devmap_cookie_t new_dhp2,void ** pvtp2)83390Sstevel@tonic-gate rsmmap_unmap(devmap_cookie_t dhp, void *pvtp, offset_t off, size_t len,
83400Sstevel@tonic-gate 	devmap_cookie_t new_dhp1, void **pvtp1,
83410Sstevel@tonic-gate 	devmap_cookie_t new_dhp2, void **pvtp2)
83420Sstevel@tonic-gate {
83430Sstevel@tonic-gate 	/*
83440Sstevel@tonic-gate 	 * Remove pvtp structure from segment list.
83450Sstevel@tonic-gate 	 */
83460Sstevel@tonic-gate 	rsmseg_t	*seg = (rsmseg_t *)pvtp;
83470Sstevel@tonic-gate 	int freeflag;
83480Sstevel@tonic-gate 
83490Sstevel@tonic-gate 	DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_FUNC_ALL | RSM_DDI);
83500Sstevel@tonic-gate 
83510Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmmap_unmap enter\n"));
83520Sstevel@tonic-gate 
83530Sstevel@tonic-gate 	off = off; len = len;
83540Sstevel@tonic-gate 	pvtp1 = pvtp1; pvtp2 = pvtp2;
83550Sstevel@tonic-gate 
83560Sstevel@tonic-gate 	rsmseglock_acquire(seg);
83570Sstevel@tonic-gate 
83580Sstevel@tonic-gate 	ASSERT(seg->s_hdr.rsmrc_type == RSM_RESOURCE_IMPORT_SEGMENT);
83590Sstevel@tonic-gate 
83600Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
83610Sstevel@tonic-gate 	    "rsmmap_unmap: dhp = %x\n", dhp));
83620Sstevel@tonic-gate 	/*
83630Sstevel@tonic-gate 	 * We can go ahead and remove the dhps even if we are in
83640Sstevel@tonic-gate 	 * the MAPPING state because the dhps being removed here
83650Sstevel@tonic-gate 	 * belong to a different mmap and we are holding the segment
83660Sstevel@tonic-gate 	 * lock.
83670Sstevel@tonic-gate 	 */
83680Sstevel@tonic-gate 	if (new_dhp1 == NULL && new_dhp2 == NULL) {
83690Sstevel@tonic-gate 		/* find and remove dhp handle */
83700Sstevel@tonic-gate 		rsmcookie_t *tmp, **back = &seg->s_ckl;
83710Sstevel@tonic-gate 
83720Sstevel@tonic-gate 		while (*back != NULL) {
83730Sstevel@tonic-gate 			tmp = *back;
83740Sstevel@tonic-gate 			if (tmp->c_dhp == dhp) {
83750Sstevel@tonic-gate 				*back = tmp->c_next;
83760Sstevel@tonic-gate 				kmem_free(tmp, sizeof (*tmp));
83770Sstevel@tonic-gate 				break;
83780Sstevel@tonic-gate 			}
83790Sstevel@tonic-gate 			back = &tmp->c_next;
83800Sstevel@tonic-gate 		}
83810Sstevel@tonic-gate 	} else {
83820Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_DEBUG_LVL2,
83830Sstevel@tonic-gate 		    "rsmmap_unmap:parital unmap"
83840Sstevel@tonic-gate 		    "new_dhp1 %lx, new_dhp2 %lx\n",
83850Sstevel@tonic-gate 		    (size_t)new_dhp1, (size_t)new_dhp2));
83860Sstevel@tonic-gate 	}
83870Sstevel@tonic-gate 
83880Sstevel@tonic-gate 	/*
83890Sstevel@tonic-gate 	 * rsmmap_unmap is called for each mapping cookie on the list.
83900Sstevel@tonic-gate 	 * When the list becomes empty and we are not in the MAPPING
83910Sstevel@tonic-gate 	 * state then unmap in the rsmpi driver.
83920Sstevel@tonic-gate 	 */
83930Sstevel@tonic-gate 	if ((seg->s_ckl == NULL) && (seg->s_state != RSM_STATE_MAPPING))
83940Sstevel@tonic-gate 		(void) rsm_unmap(seg);
83950Sstevel@tonic-gate 
83960Sstevel@tonic-gate 	if (seg->s_state == RSM_STATE_END && seg->s_ckl == NULL) {
83970Sstevel@tonic-gate 		freeflag = 1;
83980Sstevel@tonic-gate 	} else {
83990Sstevel@tonic-gate 		freeflag = 0;
84000Sstevel@tonic-gate 	}
84010Sstevel@tonic-gate 
84020Sstevel@tonic-gate 	rsmseglock_release(seg);
84030Sstevel@tonic-gate 
84040Sstevel@tonic-gate 	if (freeflag) {
84050Sstevel@tonic-gate 		/* Free the segment structure */
84060Sstevel@tonic-gate 		rsmseg_free(seg);
84070Sstevel@tonic-gate 	}
84080Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmmap_unmap done\n"));
84090Sstevel@tonic-gate 
84100Sstevel@tonic-gate }
84110Sstevel@tonic-gate 
84120Sstevel@tonic-gate static struct devmap_callback_ctl rsmmap_ops = {
84130Sstevel@tonic-gate 	DEVMAP_OPS_REV,	/* devmap_ops version number	*/
84140Sstevel@tonic-gate 	rsmmap_map,	/* devmap_ops map routine */
84150Sstevel@tonic-gate 	rsmmap_access,	/* devmap_ops access routine */
84160Sstevel@tonic-gate 	rsmmap_dup,		/* devmap_ops dup routine		*/
84170Sstevel@tonic-gate 	rsmmap_unmap,	/* devmap_ops unmap routine */
84180Sstevel@tonic-gate };
84190Sstevel@tonic-gate 
84200Sstevel@tonic-gate static int
rsm_devmap(dev_t dev,devmap_cookie_t dhc,offset_t off,size_t len,size_t * maplen,uint_t model)84210Sstevel@tonic-gate rsm_devmap(dev_t dev, devmap_cookie_t dhc, offset_t off, size_t len,
84220Sstevel@tonic-gate     size_t *maplen, uint_t model /*ARGSUSED*/)
84230Sstevel@tonic-gate {
84240Sstevel@tonic-gate 	struct devmap_callback_ctl *callbackops = &rsmmap_ops;
84250Sstevel@tonic-gate 	int		err;
84260Sstevel@tonic-gate 	uint_t		maxprot;
84270Sstevel@tonic-gate 	minor_t		rnum;
84280Sstevel@tonic-gate 	rsmseg_t	*seg;
84290Sstevel@tonic-gate 	off_t		dev_offset;
84300Sstevel@tonic-gate 	size_t		cur_len;
84310Sstevel@tonic-gate 	DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_FUNC_ALL | RSM_DDI);
84320Sstevel@tonic-gate 
84330Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_devmap enter\n"));
84340Sstevel@tonic-gate 
84350Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
84360Sstevel@tonic-gate 	    "rsm_devmap: off = %lx, len = %lx\n", off, len));
84370Sstevel@tonic-gate 	rnum = getminor(dev);
84380Sstevel@tonic-gate 	seg = (rsmseg_t *)rsmresource_lookup(rnum, RSM_NOLOCK);
84390Sstevel@tonic-gate 	ASSERT(seg != NULL);
84400Sstevel@tonic-gate 
84410Sstevel@tonic-gate 	if (seg->s_hdr.rsmrc_type == RSM_RESOURCE_BAR) {
84420Sstevel@tonic-gate 		if ((off == barrier_offset) &&
84430Sstevel@tonic-gate 		    (len == barrier_size)) {
84440Sstevel@tonic-gate 
84450Sstevel@tonic-gate 			ASSERT(bar_va != NULL && bar_cookie != NULL);
84460Sstevel@tonic-gate 
84470Sstevel@tonic-gate 			/*
84480Sstevel@tonic-gate 			 * The offset argument in devmap_umem_setup represents
84490Sstevel@tonic-gate 			 * the offset within the kernel memory defined by the
84500Sstevel@tonic-gate 			 * cookie. We use this offset as barrier_offset.
84510Sstevel@tonic-gate 			 */
84520Sstevel@tonic-gate 			err = devmap_umem_setup(dhc, rsm_dip, NULL, bar_cookie,
84530Sstevel@tonic-gate 			    barrier_offset, len, PROT_USER|PROT_READ,
84540Sstevel@tonic-gate 			    DEVMAP_DEFAULTS, 0);
84550Sstevel@tonic-gate 
84560Sstevel@tonic-gate 			if (err != 0) {
84570Sstevel@tonic-gate 				DBG_PRINTF((category, RSM_ERR,
84580Sstevel@tonic-gate 				    "rsm_devmap done: %d\n", err));
84590Sstevel@tonic-gate 				return (RSMERR_MAP_FAILED);
84600Sstevel@tonic-gate 			}
84610Sstevel@tonic-gate 			DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
84620Sstevel@tonic-gate 			    "rsm_devmap done: %d\n", err));
84630Sstevel@tonic-gate 
84640Sstevel@tonic-gate 			*maplen = barrier_size;
84650Sstevel@tonic-gate 
84660Sstevel@tonic-gate 			return (err);
84670Sstevel@tonic-gate 		} else {
84680Sstevel@tonic-gate 			DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
84690Sstevel@tonic-gate 			    "rsm_devmap done: %d\n", err));
84700Sstevel@tonic-gate 			return (RSMERR_MAP_FAILED);
84710Sstevel@tonic-gate 		}
84720Sstevel@tonic-gate 	}
84730Sstevel@tonic-gate 
84740Sstevel@tonic-gate 	ASSERT(seg->s_hdr.rsmrc_type == RSM_RESOURCE_IMPORT_SEGMENT);
84750Sstevel@tonic-gate 	ASSERT(seg->s_state == RSM_STATE_MAPPING);
84760Sstevel@tonic-gate 
84770Sstevel@tonic-gate 	/*
84780Sstevel@tonic-gate 	 * Make sure we still have permission for the map operation.
84790Sstevel@tonic-gate 	 */
84800Sstevel@tonic-gate 	maxprot = PROT_USER;
84810Sstevel@tonic-gate 	if (seg->s_mode & RSM_PERM_READ) {
84820Sstevel@tonic-gate 		maxprot |= PROT_READ;
84830Sstevel@tonic-gate 	}
84840Sstevel@tonic-gate 
84850Sstevel@tonic-gate 	if (seg->s_mode & RSM_PERM_WRITE) {
84860Sstevel@tonic-gate 		maxprot |= PROT_WRITE;
84870Sstevel@tonic-gate 	}
84880Sstevel@tonic-gate 
84890Sstevel@tonic-gate 	/*
84900Sstevel@tonic-gate 	 * For each devmap call, rsmmap_map is called. This maintains driver
84910Sstevel@tonic-gate 	 * private information for the mapping. Thus, if there are multiple
84920Sstevel@tonic-gate 	 * devmap calls there will be multiple rsmmap_map calls and for each
84930Sstevel@tonic-gate 	 * call, the mapping information will be stored.
84940Sstevel@tonic-gate 	 * In case of an error during the processing of the devmap call, error
84950Sstevel@tonic-gate 	 * will be returned. This error return causes the caller of rsm_devmap
84960Sstevel@tonic-gate 	 * to undo all the mappings by calling rsmmap_unmap for each one.
84970Sstevel@tonic-gate 	 * rsmmap_unmap will free up the private information for the requested
84980Sstevel@tonic-gate 	 * mapping.
84990Sstevel@tonic-gate 	 */
85000Sstevel@tonic-gate 	if (seg->s_node != my_nodeid) {
85010Sstevel@tonic-gate 		rsm_mapinfo_t *p;
85020Sstevel@tonic-gate 
85030Sstevel@tonic-gate 		p = rsm_get_mapinfo(seg, off, len, &dev_offset, &cur_len);
85040Sstevel@tonic-gate 		if (p == NULL) {
85050Sstevel@tonic-gate 			DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
85060Sstevel@tonic-gate 			    "rsm_devmap: incorrect mapping info\n"));
85070Sstevel@tonic-gate 			return (RSMERR_MAP_FAILED);
85080Sstevel@tonic-gate 		}
85090Sstevel@tonic-gate 		err = devmap_devmem_setup(dhc, p->dip,
85100Sstevel@tonic-gate 		    callbackops, p->dev_register,
85110Sstevel@tonic-gate 		    dev_offset, cur_len, maxprot,
85120Sstevel@tonic-gate 		    DEVMAP_ALLOW_REMAP | DEVMAP_DEFAULTS, 0);
85130Sstevel@tonic-gate 
85140Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
85150Sstevel@tonic-gate 		    "rsm_devmap: dip=%lx,dreg=%lu,doff=%lx,"
85160Sstevel@tonic-gate 		    "off=%lx,len=%lx\n",
85170Sstevel@tonic-gate 		    p->dip, p->dev_register, dev_offset, off, cur_len));
85180Sstevel@tonic-gate 
85190Sstevel@tonic-gate 		if (err != 0) {
85200Sstevel@tonic-gate 			DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
85210Sstevel@tonic-gate 			    "rsm_devmap: devmap_devmem_setup failed %d\n",
85220Sstevel@tonic-gate 			    err));
85230Sstevel@tonic-gate 			return (RSMERR_MAP_FAILED);
85240Sstevel@tonic-gate 		}
85250Sstevel@tonic-gate 		/* cur_len is always an integral multiple pagesize */
85260Sstevel@tonic-gate 		ASSERT((cur_len & (PAGESIZE-1)) == 0);
85270Sstevel@tonic-gate 		*maplen = cur_len;
85280Sstevel@tonic-gate 		return (err);
85290Sstevel@tonic-gate 
85300Sstevel@tonic-gate 	} else {
85310Sstevel@tonic-gate 		err = devmap_umem_setup(dhc, rsm_dip, callbackops,
85320Sstevel@tonic-gate 		    seg->s_cookie, off, len, maxprot,
85330Sstevel@tonic-gate 		    DEVMAP_ALLOW_REMAP|DEVMAP_DEFAULTS, 0);
85340Sstevel@tonic-gate 		if (err != 0) {
85350Sstevel@tonic-gate 			DBG_PRINTF((category, RSM_DEBUG,
85360Sstevel@tonic-gate 			    "rsm_devmap: devmap_umem_setup failed %d\n",
85377656SSherry.Moore@Sun.COM 			    err));
85380Sstevel@tonic-gate 			return (RSMERR_MAP_FAILED);
85390Sstevel@tonic-gate 		}
85400Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
85410Sstevel@tonic-gate 		    "rsm_devmap: loopback done\n"));
85420Sstevel@tonic-gate 
85430Sstevel@tonic-gate 		*maplen = ptob(btopr(len));
85440Sstevel@tonic-gate 
85450Sstevel@tonic-gate 		return (err);
85460Sstevel@tonic-gate 	}
85470Sstevel@tonic-gate }
85480Sstevel@tonic-gate 
85490Sstevel@tonic-gate /*
85500Sstevel@tonic-gate  * We can use the devmap framework for mapping device memory to user space by
85510Sstevel@tonic-gate  * specifying this routine in the rsm_cb_ops structure. The kernel mmap
85520Sstevel@tonic-gate  * processing calls this entry point and devmap_setup is called within this
85530Sstevel@tonic-gate  * function, which eventually calls rsm_devmap
85540Sstevel@tonic-gate  */
85550Sstevel@tonic-gate static int
rsm_segmap(dev_t dev,off_t off,struct as * as,caddr_t * addrp,off_t len,uint_t prot,uint_t maxprot,uint_t flags,struct cred * cred)85560Sstevel@tonic-gate rsm_segmap(dev_t dev, off_t off, struct as *as, caddr_t *addrp, off_t len,
85570Sstevel@tonic-gate     uint_t prot, uint_t maxprot, uint_t flags, struct cred *cred)
85580Sstevel@tonic-gate {
85590Sstevel@tonic-gate 	int			error = 0;
85600Sstevel@tonic-gate 	int			old_state;
85610Sstevel@tonic-gate 	minor_t			rnum;
85620Sstevel@tonic-gate 	rsmseg_t		*seg, *eseg;
85630Sstevel@tonic-gate 	adapter_t		*adapter;
85640Sstevel@tonic-gate 	rsm_import_share_t	*sharedp;
85650Sstevel@tonic-gate 	DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_FUNC_ALL | RSM_DDI);
85660Sstevel@tonic-gate 
85670Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_segmap enter\n"));
85680Sstevel@tonic-gate 
85690Sstevel@tonic-gate 	/*
85700Sstevel@tonic-gate 	 * find segment
85710Sstevel@tonic-gate 	 */
85720Sstevel@tonic-gate 	rnum = getminor(dev);
85730Sstevel@tonic-gate 	seg = (rsmseg_t *)rsmresource_lookup(rnum, RSM_LOCK);
85740Sstevel@tonic-gate 
85750Sstevel@tonic-gate 	if (seg == NULL) {
85760Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
85770Sstevel@tonic-gate 		    "rsm_segmap done: invalid segment\n"));
85780Sstevel@tonic-gate 		return (EINVAL);
85790Sstevel@tonic-gate 	}
85800Sstevel@tonic-gate 
85810Sstevel@tonic-gate 	/*
85820Sstevel@tonic-gate 	 * the user is trying to map a resource that has not been
85830Sstevel@tonic-gate 	 * defined yet. The library uses this to map in the
85840Sstevel@tonic-gate 	 * barrier page.
85850Sstevel@tonic-gate 	 */
85860Sstevel@tonic-gate 	if (seg->s_hdr.rsmrc_type == RSM_RESOURCE_BAR) {
85870Sstevel@tonic-gate 		rsmseglock_release(seg);
85880Sstevel@tonic-gate 
85890Sstevel@tonic-gate 		/*
85900Sstevel@tonic-gate 		 * The mapping for the barrier page is identified
85910Sstevel@tonic-gate 		 * by the special offset barrier_offset
85920Sstevel@tonic-gate 		 */
85930Sstevel@tonic-gate 
85940Sstevel@tonic-gate 		if (off == (off_t)barrier_offset ||
85950Sstevel@tonic-gate 		    len == (off_t)barrier_size) {
85960Sstevel@tonic-gate 			if (bar_cookie == NULL || bar_va == NULL) {
85970Sstevel@tonic-gate 				DBG_PRINTF((category, RSM_DEBUG,
85980Sstevel@tonic-gate 				    "rsm_segmap: bar cookie/va is NULL\n"));
85990Sstevel@tonic-gate 				return (EINVAL);
86000Sstevel@tonic-gate 			}
86010Sstevel@tonic-gate 
86020Sstevel@tonic-gate 			error = devmap_setup(dev, (offset_t)off, as, addrp,
86030Sstevel@tonic-gate 			    (size_t)len, prot, maxprot, flags,  cred);
86040Sstevel@tonic-gate 
86050Sstevel@tonic-gate 			DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
86060Sstevel@tonic-gate 			    "rsm_segmap done: %d\n", error));
86070Sstevel@tonic-gate 			return (error);
86080Sstevel@tonic-gate 		} else {
86090Sstevel@tonic-gate 			DBG_PRINTF((category, RSM_DEBUG,
86100Sstevel@tonic-gate 			    "rsm_segmap: bad offset/length\n"));
86110Sstevel@tonic-gate 			return (EINVAL);
86120Sstevel@tonic-gate 		}
86130Sstevel@tonic-gate 	}
86140Sstevel@tonic-gate 
86150Sstevel@tonic-gate 	/* Make sure you can only map imported segments */
86160Sstevel@tonic-gate 	if (seg->s_hdr.rsmrc_type != RSM_RESOURCE_IMPORT_SEGMENT) {
86170Sstevel@tonic-gate 		rsmseglock_release(seg);
86180Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
86190Sstevel@tonic-gate 		    "rsm_segmap done: not an import segment\n"));
86200Sstevel@tonic-gate 		return (EINVAL);
86210Sstevel@tonic-gate 	}
86220Sstevel@tonic-gate 	/* check means library is broken */
86230Sstevel@tonic-gate 	ASSERT(seg->s_hdr.rsmrc_num == rnum);
86240Sstevel@tonic-gate 
86250Sstevel@tonic-gate 	/* wait for the segment to become unquiesced */
86260Sstevel@tonic-gate 	while (seg->s_state == RSM_STATE_CONN_QUIESCE) {
86270Sstevel@tonic-gate 		if (cv_wait_sig(&seg->s_cv, &seg->s_lock) == 0) {
86280Sstevel@tonic-gate 			rsmseglock_release(seg);
86290Sstevel@tonic-gate 			DBG_PRINTF((category, RSM_DEBUG,
86300Sstevel@tonic-gate 			    "rsm_segmap done: cv_wait INTR"));
86310Sstevel@tonic-gate 			return (ENODEV);
86320Sstevel@tonic-gate 		}
86330Sstevel@tonic-gate 	}
86340Sstevel@tonic-gate 
86350Sstevel@tonic-gate 	/* wait until segment leaves the mapping state */
86360Sstevel@tonic-gate 	while (seg->s_state == RSM_STATE_MAPPING)
86370Sstevel@tonic-gate 		cv_wait(&seg->s_cv, &seg->s_lock);
86380Sstevel@tonic-gate 
86390Sstevel@tonic-gate 	/*
86400Sstevel@tonic-gate 	 * we allow multiple maps of the same segment in the KA
86410Sstevel@tonic-gate 	 * and it works because we do an rsmpi map of the whole
86420Sstevel@tonic-gate 	 * segment during the first map and all the device mapping
86430Sstevel@tonic-gate 	 * information needed in rsm_devmap is in the mapinfo list.
86440Sstevel@tonic-gate 	 */
86450Sstevel@tonic-gate 	if ((seg->s_state != RSM_STATE_CONNECT) &&
86460Sstevel@tonic-gate 	    (seg->s_state != RSM_STATE_ACTIVE)) {
86470Sstevel@tonic-gate 		rsmseglock_release(seg);
86480Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_DEBUG,
86490Sstevel@tonic-gate 		    "rsm_segmap done: segment not connected\n"));
86500Sstevel@tonic-gate 		return (ENODEV);
86510Sstevel@tonic-gate 	}
86520Sstevel@tonic-gate 
86530Sstevel@tonic-gate 	/*
86540Sstevel@tonic-gate 	 * Make sure we are not mapping a larger segment than what's
86550Sstevel@tonic-gate 	 * exported
86560Sstevel@tonic-gate 	 */
86570Sstevel@tonic-gate 	if ((size_t)off + ptob(btopr(len)) > seg->s_len) {
86580Sstevel@tonic-gate 		rsmseglock_release(seg);
86590Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_DEBUG,
86600Sstevel@tonic-gate 		    "rsm_segmap done: off+len>seg size\n"));
86610Sstevel@tonic-gate 		return (ENXIO);
86620Sstevel@tonic-gate 	}
86630Sstevel@tonic-gate 
86640Sstevel@tonic-gate 	/*
86650Sstevel@tonic-gate 	 * Make sure we still have permission for the map operation.
86660Sstevel@tonic-gate 	 */
86670Sstevel@tonic-gate 	maxprot = PROT_USER;
86680Sstevel@tonic-gate 	if (seg->s_mode & RSM_PERM_READ) {
86690Sstevel@tonic-gate 		maxprot |= PROT_READ;
86700Sstevel@tonic-gate 	}
86710Sstevel@tonic-gate 
86720Sstevel@tonic-gate 	if (seg->s_mode & RSM_PERM_WRITE) {
86730Sstevel@tonic-gate 		maxprot |= PROT_WRITE;
86740Sstevel@tonic-gate 	}
86750Sstevel@tonic-gate 
86760Sstevel@tonic-gate 	if ((prot & maxprot) != prot) {
86770Sstevel@tonic-gate 		/* No permission */
86780Sstevel@tonic-gate 		rsmseglock_release(seg);
86790Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_DEBUG,
86800Sstevel@tonic-gate 		    "rsm_segmap done: no permission\n"));
86810Sstevel@tonic-gate 		return (EACCES);
86820Sstevel@tonic-gate 	}
86830Sstevel@tonic-gate 
86840Sstevel@tonic-gate 	old_state = seg->s_state;
86850Sstevel@tonic-gate 
86860Sstevel@tonic-gate 	ASSERT(seg->s_share != NULL);
86870Sstevel@tonic-gate 
86880Sstevel@tonic-gate 	rsmsharelock_acquire(seg);
86890Sstevel@tonic-gate 
86900Sstevel@tonic-gate 	sharedp = seg->s_share;
86910Sstevel@tonic-gate 
86920Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
86930Sstevel@tonic-gate 	    "rsm_segmap:RSMSI_STATE=%d\n", sharedp->rsmsi_state));
86940Sstevel@tonic-gate 
86950Sstevel@tonic-gate 	if ((sharedp->rsmsi_state != RSMSI_STATE_CONNECTED) &&
86960Sstevel@tonic-gate 	    (sharedp->rsmsi_state != RSMSI_STATE_MAPPED)) {
86970Sstevel@tonic-gate 		rsmsharelock_release(seg);
86980Sstevel@tonic-gate 		rsmseglock_release(seg);
86990Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_DEBUG,
87000Sstevel@tonic-gate 		    "rsm_segmap done:RSMSI_STATE %d invalid\n",
87010Sstevel@tonic-gate 		    sharedp->rsmsi_state));
87020Sstevel@tonic-gate 		return (ENODEV);
87030Sstevel@tonic-gate 	}
87040Sstevel@tonic-gate 
87050Sstevel@tonic-gate 	/*
87060Sstevel@tonic-gate 	 * Do the map - since we want importers to share mappings
87070Sstevel@tonic-gate 	 * we do the rsmpi map for the whole segment
87080Sstevel@tonic-gate 	 */
87090Sstevel@tonic-gate 	if (seg->s_node != my_nodeid) {
87100Sstevel@tonic-gate 		uint_t dev_register;
87110Sstevel@tonic-gate 		off_t dev_offset;
87120Sstevel@tonic-gate 		dev_info_t *dip;
87130Sstevel@tonic-gate 		size_t tmp_len;
87140Sstevel@tonic-gate 		size_t total_length_mapped = 0;
87150Sstevel@tonic-gate 		size_t length_to_map = seg->s_len;
87160Sstevel@tonic-gate 		off_t tmp_off = 0;
87170Sstevel@tonic-gate 		rsm_mapinfo_t *p;
87180Sstevel@tonic-gate 
87190Sstevel@tonic-gate 		/*
87200Sstevel@tonic-gate 		 * length_to_map = seg->s_len is always an integral
87210Sstevel@tonic-gate 		 * multiple of PAGESIZE. Length mapped in each entry in mapinfo
87220Sstevel@tonic-gate 		 * list is a multiple of PAGESIZE - RSMPI map ensures this
87230Sstevel@tonic-gate 		 */
87240Sstevel@tonic-gate 
87250Sstevel@tonic-gate 		adapter = seg->s_adapter;
87260Sstevel@tonic-gate 		ASSERT(sharedp->rsmsi_state == RSMSI_STATE_CONNECTED ||
87270Sstevel@tonic-gate 		    sharedp->rsmsi_state == RSMSI_STATE_MAPPED);
87280Sstevel@tonic-gate 
87290Sstevel@tonic-gate 		if (sharedp->rsmsi_state == RSMSI_STATE_CONNECTED) {
87300Sstevel@tonic-gate 			error = 0;
87310Sstevel@tonic-gate 			/* map the whole segment */
87320Sstevel@tonic-gate 			while (total_length_mapped < seg->s_len) {
87330Sstevel@tonic-gate 				tmp_len = 0;
87340Sstevel@tonic-gate 
87350Sstevel@tonic-gate 				error = adapter->rsmpi_ops->rsm_map(
87360Sstevel@tonic-gate 				    seg->s_handle.in, tmp_off,
87370Sstevel@tonic-gate 				    length_to_map, &tmp_len,
87380Sstevel@tonic-gate 				    &dip, &dev_register, &dev_offset,
87390Sstevel@tonic-gate 				    NULL, NULL);
87400Sstevel@tonic-gate 
87410Sstevel@tonic-gate 				if (error != 0)
87420Sstevel@tonic-gate 					break;
87430Sstevel@tonic-gate 
87440Sstevel@tonic-gate 				/*
87450Sstevel@tonic-gate 				 * Store the mapping info obtained from rsm_map
87460Sstevel@tonic-gate 				 */
87470Sstevel@tonic-gate 				p = kmem_alloc(sizeof (*p), KM_SLEEP);
87480Sstevel@tonic-gate 				p->dev_register = dev_register;
87490Sstevel@tonic-gate 				p->dev_offset = dev_offset;
87500Sstevel@tonic-gate 				p->dip = dip;
87510Sstevel@tonic-gate 				p->individual_len = tmp_len;
87520Sstevel@tonic-gate 				p->start_offset = tmp_off;
87530Sstevel@tonic-gate 				p->next = sharedp->rsmsi_mapinfo;
87540Sstevel@tonic-gate 				sharedp->rsmsi_mapinfo = p;
87550Sstevel@tonic-gate 
87560Sstevel@tonic-gate 				total_length_mapped += tmp_len;
87570Sstevel@tonic-gate 				length_to_map -= tmp_len;
87580Sstevel@tonic-gate 				tmp_off += tmp_len;
87590Sstevel@tonic-gate 			}
87600Sstevel@tonic-gate 			seg->s_mapinfo = sharedp->rsmsi_mapinfo;
87610Sstevel@tonic-gate 
87620Sstevel@tonic-gate 			if (error != RSM_SUCCESS) {
87630Sstevel@tonic-gate 				/* Check if this is the the first rsm_map */
87640Sstevel@tonic-gate 				if (sharedp->rsmsi_mapinfo != NULL) {
87650Sstevel@tonic-gate 					/*
87660Sstevel@tonic-gate 					 * A single rsm_unmap undoes
87670Sstevel@tonic-gate 					 * multiple rsm_maps.
87680Sstevel@tonic-gate 					 */
87690Sstevel@tonic-gate 					(void) seg->s_adapter->rsmpi_ops->
87700Sstevel@tonic-gate 					    rsm_unmap(sharedp->rsmsi_handle);
87710Sstevel@tonic-gate 					rsm_free_mapinfo(sharedp->
87720Sstevel@tonic-gate 					    rsmsi_mapinfo);
87730Sstevel@tonic-gate 				}
87740Sstevel@tonic-gate 				sharedp->rsmsi_mapinfo = NULL;
87750Sstevel@tonic-gate 				sharedp->rsmsi_state = RSMSI_STATE_CONNECTED;
87760Sstevel@tonic-gate 				rsmsharelock_release(seg);
87770Sstevel@tonic-gate 				rsmseglock_release(seg);
87780Sstevel@tonic-gate 				DBG_PRINTF((category, RSM_DEBUG,
87790Sstevel@tonic-gate 				    "rsm_segmap done: rsmpi map err %d\n",
87800Sstevel@tonic-gate 				    error));
87810Sstevel@tonic-gate 				ASSERT(error != RSMERR_BAD_LENGTH &&
87820Sstevel@tonic-gate 				    error != RSMERR_BAD_MEM_ALIGNMENT &&
87830Sstevel@tonic-gate 				    error != RSMERR_BAD_SEG_HNDL);
87840Sstevel@tonic-gate 				if (error == RSMERR_UNSUPPORTED_OPERATION)
87850Sstevel@tonic-gate 					return (ENOTSUP);
87860Sstevel@tonic-gate 				else if (error == RSMERR_INSUFFICIENT_RESOURCES)
87870Sstevel@tonic-gate 					return (EAGAIN);
87880Sstevel@tonic-gate 				else if (error == RSMERR_CONN_ABORTED)
87890Sstevel@tonic-gate 					return (ENODEV);
87900Sstevel@tonic-gate 				else
87910Sstevel@tonic-gate 					return (error);
87920Sstevel@tonic-gate 			} else {
87930Sstevel@tonic-gate 				sharedp->rsmsi_state = RSMSI_STATE_MAPPED;
87940Sstevel@tonic-gate 			}
87950Sstevel@tonic-gate 		} else {
87960Sstevel@tonic-gate 			seg->s_mapinfo = sharedp->rsmsi_mapinfo;
87970Sstevel@tonic-gate 		}
87980Sstevel@tonic-gate 
87990Sstevel@tonic-gate 		sharedp->rsmsi_mapcnt++;
88000Sstevel@tonic-gate 
88010Sstevel@tonic-gate 		rsmsharelock_release(seg);
88020Sstevel@tonic-gate 
88030Sstevel@tonic-gate 		/* move to an intermediate mapping state */
88040Sstevel@tonic-gate 		seg->s_state = RSM_STATE_MAPPING;
88050Sstevel@tonic-gate 		rsmseglock_release(seg);
88060Sstevel@tonic-gate 
88070Sstevel@tonic-gate 		error = devmap_setup(dev, (offset_t)off, as, addrp,
88080Sstevel@tonic-gate 		    len, prot, maxprot, flags, cred);
88090Sstevel@tonic-gate 
88100Sstevel@tonic-gate 		rsmseglock_acquire(seg);
88110Sstevel@tonic-gate 		ASSERT(seg->s_state == RSM_STATE_MAPPING);
88120Sstevel@tonic-gate 
88130Sstevel@tonic-gate 		if (error == DDI_SUCCESS) {
88140Sstevel@tonic-gate 			seg->s_state = RSM_STATE_ACTIVE;
88150Sstevel@tonic-gate 		} else {
88160Sstevel@tonic-gate 			rsmsharelock_acquire(seg);
88170Sstevel@tonic-gate 
88180Sstevel@tonic-gate 			ASSERT(sharedp->rsmsi_state == RSMSI_STATE_MAPPED);
88190Sstevel@tonic-gate 
88200Sstevel@tonic-gate 			sharedp->rsmsi_mapcnt--;
88210Sstevel@tonic-gate 			if (sharedp->rsmsi_mapcnt == 0) {
88220Sstevel@tonic-gate 				/* unmap the shared RSMPI mapping */
88230Sstevel@tonic-gate 				ASSERT(sharedp->rsmsi_handle != NULL);
88240Sstevel@tonic-gate 				(void) adapter->rsmpi_ops->
88257656SSherry.Moore@Sun.COM 				    rsm_unmap(sharedp->rsmsi_handle);
88260Sstevel@tonic-gate 				rsm_free_mapinfo(sharedp->rsmsi_mapinfo);
88270Sstevel@tonic-gate 				sharedp->rsmsi_mapinfo = NULL;
88280Sstevel@tonic-gate 				sharedp->rsmsi_state = RSMSI_STATE_CONNECTED;
88290Sstevel@tonic-gate 			}
88300Sstevel@tonic-gate 
88310Sstevel@tonic-gate 			rsmsharelock_release(seg);
88320Sstevel@tonic-gate 			seg->s_state = old_state;
88330Sstevel@tonic-gate 			DBG_PRINTF((category, RSM_ERR,
88340Sstevel@tonic-gate 			    "rsm: devmap_setup failed %d\n", error));
88350Sstevel@tonic-gate 		}
88360Sstevel@tonic-gate 		cv_broadcast(&seg->s_cv);
88370Sstevel@tonic-gate 		rsmseglock_release(seg);
88380Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_DEBUG_LVL2, "rsm_segmap done: %d\n",
88390Sstevel@tonic-gate 		    error));
88400Sstevel@tonic-gate 		return (error);
88410Sstevel@tonic-gate 	} else {
88420Sstevel@tonic-gate 		/*
88430Sstevel@tonic-gate 		 * For loopback, the export segment mapping cookie (s_cookie)
88440Sstevel@tonic-gate 		 * is also used as the s_cookie value for its import segments
88450Sstevel@tonic-gate 		 * during mapping.
88460Sstevel@tonic-gate 		 * Note that reference counting for s_cookie of the export
88470Sstevel@tonic-gate 		 * segment is not required due to the following:
88480Sstevel@tonic-gate 		 * We never have a case of the export segment being destroyed,
88490Sstevel@tonic-gate 		 * leaving the import segments with a stale value for the
88500Sstevel@tonic-gate 		 * s_cookie field, since a force disconnect is done prior to a
88510Sstevel@tonic-gate 		 * destroy of an export segment. The force disconnect causes
88520Sstevel@tonic-gate 		 * the s_cookie value to be reset to NULL. Also for the
88530Sstevel@tonic-gate 		 * rsm_rebind operation, we change the s_cookie value of the
88540Sstevel@tonic-gate 		 * export segment as well as of all its local (loopback)
88550Sstevel@tonic-gate 		 * importers.
88560Sstevel@tonic-gate 		 */
88570Sstevel@tonic-gate 		DBG_ADDCATEGORY(category, RSM_LOOPBACK);
88580Sstevel@tonic-gate 
88590Sstevel@tonic-gate 		rsmsharelock_release(seg);
88600Sstevel@tonic-gate 		/*
88610Sstevel@tonic-gate 		 * In order to maintain the lock ordering between the export
88620Sstevel@tonic-gate 		 * and import segment locks, we need to acquire the export
88630Sstevel@tonic-gate 		 * segment lock first and only then acquire the import
88640Sstevel@tonic-gate 		 * segment lock.
88650Sstevel@tonic-gate 		 * The above is necessary to avoid any deadlock scenarios
88660Sstevel@tonic-gate 		 * with rsm_rebind which also acquires both the export
88670Sstevel@tonic-gate 		 * and import segment locks in the above mentioned order.
88680Sstevel@tonic-gate 		 * Based on code inspection, there seem to be no other
88690Sstevel@tonic-gate 		 * situations in which both the export and import segment
88700Sstevel@tonic-gate 		 * locks are acquired either in the same or opposite order
88710Sstevel@tonic-gate 		 * as mentioned above.
88720Sstevel@tonic-gate 		 * Thus in order to conform to the above lock order, we
88730Sstevel@tonic-gate 		 * need to change the state of the import segment to
88740Sstevel@tonic-gate 		 * RSM_STATE_MAPPING, release the lock. Once this is done we
88750Sstevel@tonic-gate 		 * can now safely acquire the export segment lock first
88760Sstevel@tonic-gate 		 * followed by the import segment lock which is as per
88770Sstevel@tonic-gate 		 * the lock order mentioned above.
88780Sstevel@tonic-gate 		 */
88790Sstevel@tonic-gate 		/* move to an intermediate mapping state */
88800Sstevel@tonic-gate 		seg->s_state = RSM_STATE_MAPPING;
88810Sstevel@tonic-gate 		rsmseglock_release(seg);
88820Sstevel@tonic-gate 
88830Sstevel@tonic-gate 		eseg = rsmexport_lookup(seg->s_key);
88840Sstevel@tonic-gate 
88850Sstevel@tonic-gate 		if (eseg == NULL) {
88860Sstevel@tonic-gate 			rsmseglock_acquire(seg);
88870Sstevel@tonic-gate 			/*
88880Sstevel@tonic-gate 			 * Revert to old_state and signal any waiters
88890Sstevel@tonic-gate 			 * The shared state is not changed
88900Sstevel@tonic-gate 			 */
88910Sstevel@tonic-gate 
88920Sstevel@tonic-gate 			seg->s_state = old_state;
88930Sstevel@tonic-gate 			cv_broadcast(&seg->s_cv);
88940Sstevel@tonic-gate 			rsmseglock_release(seg);
88950Sstevel@tonic-gate 			DBG_PRINTF((category, RSM_DEBUG,
88960Sstevel@tonic-gate 			    "rsm_segmap done: key %d not found\n", seg->s_key));
88970Sstevel@tonic-gate 			return (ENODEV);
88980Sstevel@tonic-gate 		}
88990Sstevel@tonic-gate 
89000Sstevel@tonic-gate 		rsmsharelock_acquire(seg);
89010Sstevel@tonic-gate 		ASSERT(sharedp->rsmsi_state == RSMSI_STATE_CONNECTED ||
89020Sstevel@tonic-gate 		    sharedp->rsmsi_state == RSMSI_STATE_MAPPED);
89030Sstevel@tonic-gate 
89040Sstevel@tonic-gate 		sharedp->rsmsi_mapcnt++;
89050Sstevel@tonic-gate 		sharedp->rsmsi_state = RSMSI_STATE_MAPPED;
89060Sstevel@tonic-gate 		rsmsharelock_release(seg);
89070Sstevel@tonic-gate 
89080Sstevel@tonic-gate 		ASSERT(eseg->s_cookie != NULL);
89090Sstevel@tonic-gate 
89100Sstevel@tonic-gate 		/*
89110Sstevel@tonic-gate 		 * It is not required or necessary to acquire the import
89120Sstevel@tonic-gate 		 * segment lock here to change the value of s_cookie since
89130Sstevel@tonic-gate 		 * no one will touch the import segment as long as it is
89140Sstevel@tonic-gate 		 * in the RSM_STATE_MAPPING state.
89150Sstevel@tonic-gate 		 */
89160Sstevel@tonic-gate 		seg->s_cookie = eseg->s_cookie;
89170Sstevel@tonic-gate 
89180Sstevel@tonic-gate 		rsmseglock_release(eseg);
89190Sstevel@tonic-gate 
89200Sstevel@tonic-gate 		error = devmap_setup(dev, (offset_t)off, as, addrp, (size_t)len,
89210Sstevel@tonic-gate 		    prot, maxprot, flags, cred);
89220Sstevel@tonic-gate 
89230Sstevel@tonic-gate 		rsmseglock_acquire(seg);
89240Sstevel@tonic-gate 		ASSERT(seg->s_state == RSM_STATE_MAPPING);
89250Sstevel@tonic-gate 		if (error == 0) {
89260Sstevel@tonic-gate 			seg->s_state = RSM_STATE_ACTIVE;
89270Sstevel@tonic-gate 		} else {
89280Sstevel@tonic-gate 			rsmsharelock_acquire(seg);
89290Sstevel@tonic-gate 
89300Sstevel@tonic-gate 			ASSERT(sharedp->rsmsi_state == RSMSI_STATE_MAPPED);
89310Sstevel@tonic-gate 
89320Sstevel@tonic-gate 			sharedp->rsmsi_mapcnt--;
89330Sstevel@tonic-gate 			if (sharedp->rsmsi_mapcnt == 0) {
89340Sstevel@tonic-gate 				sharedp->rsmsi_mapinfo = NULL;
89350Sstevel@tonic-gate 				sharedp->rsmsi_state = RSMSI_STATE_CONNECTED;
89360Sstevel@tonic-gate 			}
89370Sstevel@tonic-gate 			rsmsharelock_release(seg);
89380Sstevel@tonic-gate 			seg->s_state = old_state;
89390Sstevel@tonic-gate 			seg->s_cookie = NULL;
89400Sstevel@tonic-gate 		}
89410Sstevel@tonic-gate 		cv_broadcast(&seg->s_cv);
89420Sstevel@tonic-gate 		rsmseglock_release(seg);
89430Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_DEBUG_LVL2,
89440Sstevel@tonic-gate 		    "rsm_segmap done: %d\n", error));
89450Sstevel@tonic-gate 		return (error);
89460Sstevel@tonic-gate 	}
89470Sstevel@tonic-gate }
89480Sstevel@tonic-gate 
89490Sstevel@tonic-gate int
rsmka_null_seg_create(rsm_controller_handle_t argcp,rsm_memseg_export_handle_t * handle,size_t size,uint_t flags,rsm_memory_local_t * memory,rsm_resource_callback_t callback,rsm_resource_callback_arg_t callback_arg)89500Sstevel@tonic-gate rsmka_null_seg_create(
89510Sstevel@tonic-gate     rsm_controller_handle_t argcp,
89520Sstevel@tonic-gate     rsm_memseg_export_handle_t *handle,
89530Sstevel@tonic-gate     size_t size,
89540Sstevel@tonic-gate     uint_t flags,
89550Sstevel@tonic-gate     rsm_memory_local_t *memory,
89560Sstevel@tonic-gate     rsm_resource_callback_t callback,
89570Sstevel@tonic-gate     rsm_resource_callback_arg_t callback_arg	/*ARGSUSED*/)
89580Sstevel@tonic-gate {
89590Sstevel@tonic-gate 	return (RSM_SUCCESS);
89600Sstevel@tonic-gate }
89610Sstevel@tonic-gate 
89620Sstevel@tonic-gate 
89630Sstevel@tonic-gate int
rsmka_null_seg_destroy(rsm_memseg_export_handle_t argmemseg)89640Sstevel@tonic-gate rsmka_null_seg_destroy(
89650Sstevel@tonic-gate     rsm_memseg_export_handle_t argmemseg	/*ARGSUSED*/)
89660Sstevel@tonic-gate {
89670Sstevel@tonic-gate 	return (RSM_SUCCESS);
89680Sstevel@tonic-gate }
89690Sstevel@tonic-gate 
89700Sstevel@tonic-gate 
89710Sstevel@tonic-gate int
rsmka_null_bind(rsm_memseg_export_handle_t argmemseg,off_t offset,rsm_memory_local_t * argmemory,rsm_resource_callback_t callback,rsm_resource_callback_arg_t callback_arg)89720Sstevel@tonic-gate rsmka_null_bind(
89730Sstevel@tonic-gate     rsm_memseg_export_handle_t argmemseg,
89740Sstevel@tonic-gate     off_t offset,
89750Sstevel@tonic-gate     rsm_memory_local_t *argmemory,
89760Sstevel@tonic-gate     rsm_resource_callback_t callback,
89770Sstevel@tonic-gate     rsm_resource_callback_arg_t callback_arg	/*ARGSUSED*/)
89780Sstevel@tonic-gate {
89790Sstevel@tonic-gate 	return (RSM_SUCCESS);
89800Sstevel@tonic-gate }
89810Sstevel@tonic-gate 
89820Sstevel@tonic-gate 
89830Sstevel@tonic-gate int
rsmka_null_unbind(rsm_memseg_export_handle_t argmemseg,off_t offset,size_t length)89840Sstevel@tonic-gate rsmka_null_unbind(
89850Sstevel@tonic-gate     rsm_memseg_export_handle_t argmemseg,
89860Sstevel@tonic-gate     off_t offset,
89870Sstevel@tonic-gate     size_t length	/*ARGSUSED*/)
89880Sstevel@tonic-gate {
89890Sstevel@tonic-gate 	return (DDI_SUCCESS);
89900Sstevel@tonic-gate }
89910Sstevel@tonic-gate 
89920Sstevel@tonic-gate int
rsmka_null_rebind(rsm_memseg_export_handle_t argmemseg,off_t offset,rsm_memory_local_t * memory,rsm_resource_callback_t callback,rsm_resource_callback_arg_t callback_arg)89930Sstevel@tonic-gate rsmka_null_rebind(
89940Sstevel@tonic-gate     rsm_memseg_export_handle_t argmemseg,
89950Sstevel@tonic-gate     off_t offset,
89960Sstevel@tonic-gate     rsm_memory_local_t *memory,
89970Sstevel@tonic-gate     rsm_resource_callback_t callback,
89980Sstevel@tonic-gate     rsm_resource_callback_arg_t callback_arg	/*ARGSUSED*/)
89990Sstevel@tonic-gate {
90000Sstevel@tonic-gate 	return (RSM_SUCCESS);
90010Sstevel@tonic-gate }
90020Sstevel@tonic-gate 
90030Sstevel@tonic-gate int
rsmka_null_publish(rsm_memseg_export_handle_t argmemseg,rsm_access_entry_t access_list[],uint_t access_list_length,rsm_memseg_id_t segment_id,rsm_resource_callback_t callback,rsm_resource_callback_arg_t callback_arg)90040Sstevel@tonic-gate rsmka_null_publish(
90050Sstevel@tonic-gate     rsm_memseg_export_handle_t argmemseg,
90060Sstevel@tonic-gate     rsm_access_entry_t access_list[],
90070Sstevel@tonic-gate     uint_t access_list_length,
90080Sstevel@tonic-gate     rsm_memseg_id_t segment_id,
90090Sstevel@tonic-gate     rsm_resource_callback_t callback,
90100Sstevel@tonic-gate     rsm_resource_callback_arg_t callback_arg	/*ARGSUSED*/)
90110Sstevel@tonic-gate {
90120Sstevel@tonic-gate 	return (RSM_SUCCESS);
90130Sstevel@tonic-gate }
90140Sstevel@tonic-gate 
90150Sstevel@tonic-gate 
90160Sstevel@tonic-gate int
rsmka_null_republish(rsm_memseg_export_handle_t memseg,rsm_access_entry_t access_list[],uint_t access_list_length,rsm_resource_callback_t callback,rsm_resource_callback_arg_t callback_arg)90170Sstevel@tonic-gate rsmka_null_republish(
90180Sstevel@tonic-gate     rsm_memseg_export_handle_t memseg,
90190Sstevel@tonic-gate     rsm_access_entry_t access_list[],
90200Sstevel@tonic-gate     uint_t access_list_length,
90210Sstevel@tonic-gate     rsm_resource_callback_t callback,
90220Sstevel@tonic-gate     rsm_resource_callback_arg_t callback_arg	/*ARGSUSED*/)
90230Sstevel@tonic-gate {
90240Sstevel@tonic-gate 	return (RSM_SUCCESS);
90250Sstevel@tonic-gate }
90260Sstevel@tonic-gate 
90270Sstevel@tonic-gate int
rsmka_null_unpublish(rsm_memseg_export_handle_t argmemseg)90280Sstevel@tonic-gate rsmka_null_unpublish(
90290Sstevel@tonic-gate     rsm_memseg_export_handle_t argmemseg	/*ARGSUSED*/)
90300Sstevel@tonic-gate {
90310Sstevel@tonic-gate 	return (RSM_SUCCESS);
90320Sstevel@tonic-gate }
90330Sstevel@tonic-gate 
90340Sstevel@tonic-gate 
90350Sstevel@tonic-gate void
rsmka_init_loopback()90360Sstevel@tonic-gate rsmka_init_loopback()
90370Sstevel@tonic-gate {
90380Sstevel@tonic-gate 	rsm_ops_t	*ops = &null_rsmpi_ops;
90390Sstevel@tonic-gate 	DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_FUNC_ALL | RSM_LOOPBACK);
90400Sstevel@tonic-gate 
90410Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
90420Sstevel@tonic-gate 	    "rsmka_init_loopback enter\n"));
90430Sstevel@tonic-gate 
90440Sstevel@tonic-gate 	/* initialize null ops vector */
90450Sstevel@tonic-gate 	ops->rsm_seg_create = rsmka_null_seg_create;
90460Sstevel@tonic-gate 	ops->rsm_seg_destroy = rsmka_null_seg_destroy;
90470Sstevel@tonic-gate 	ops->rsm_bind = rsmka_null_bind;
90480Sstevel@tonic-gate 	ops->rsm_unbind = rsmka_null_unbind;
90490Sstevel@tonic-gate 	ops->rsm_rebind = rsmka_null_rebind;
90500Sstevel@tonic-gate 	ops->rsm_publish = rsmka_null_publish;
90510Sstevel@tonic-gate 	ops->rsm_unpublish = rsmka_null_unpublish;
90520Sstevel@tonic-gate 	ops->rsm_republish = rsmka_null_republish;
90530Sstevel@tonic-gate 
90540Sstevel@tonic-gate 	/* initialize attributes for loopback adapter */
90550Sstevel@tonic-gate 	loopback_attr.attr_name = loopback_str;
90560Sstevel@tonic-gate 	loopback_attr.attr_page_size = 0x8; /* 8K */
90570Sstevel@tonic-gate 
90580Sstevel@tonic-gate 	/* initialize loopback adapter */
90590Sstevel@tonic-gate 	loopback_adapter.rsm_attr = loopback_attr;
90600Sstevel@tonic-gate 	loopback_adapter.rsmpi_ops = &null_rsmpi_ops;
90610Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
90620Sstevel@tonic-gate 	    "rsmka_init_loopback done\n"));
90630Sstevel@tonic-gate }
90640Sstevel@tonic-gate 
90650Sstevel@tonic-gate /* ************** DR functions ********************************** */
90660Sstevel@tonic-gate static void
rsm_quiesce_exp_seg(rsmresource_t * resp)90670Sstevel@tonic-gate rsm_quiesce_exp_seg(rsmresource_t *resp)
90680Sstevel@tonic-gate {
90690Sstevel@tonic-gate 	int		recheck_state;
90700Sstevel@tonic-gate 	rsmseg_t	*segp = (rsmseg_t *)resp;
90710Sstevel@tonic-gate 	DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_FUNC_ALL);
90720Sstevel@tonic-gate 	DBG_DEFINE_STR(function, "rsm_unquiesce_exp_seg");
90730Sstevel@tonic-gate 
90740Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
90750Sstevel@tonic-gate 	    "%s enter: key=%u\n", function, segp->s_key));
90760Sstevel@tonic-gate 
90770Sstevel@tonic-gate 	rsmseglock_acquire(segp);
90780Sstevel@tonic-gate 	do {
90790Sstevel@tonic-gate 		recheck_state = 0;
90800Sstevel@tonic-gate 		if ((segp->s_state == RSM_STATE_NEW_QUIESCED) ||
90810Sstevel@tonic-gate 		    (segp->s_state == RSM_STATE_BIND_QUIESCED) ||
90820Sstevel@tonic-gate 		    (segp->s_state == RSM_STATE_EXPORT_QUIESCING) ||
90830Sstevel@tonic-gate 		    (segp->s_state == RSM_STATE_EXPORT_QUIESCED)) {
90840Sstevel@tonic-gate 			rsmseglock_release(segp);
90850Sstevel@tonic-gate 			DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
90860Sstevel@tonic-gate 			    "%s done:state =%d\n", function,
90870Sstevel@tonic-gate 			    segp->s_state));
90880Sstevel@tonic-gate 			return;
90890Sstevel@tonic-gate 		}
90900Sstevel@tonic-gate 
90910Sstevel@tonic-gate 		if (segp->s_state == RSM_STATE_NEW) {
90920Sstevel@tonic-gate 			segp->s_state = RSM_STATE_NEW_QUIESCED;
90930Sstevel@tonic-gate 			rsmseglock_release(segp);
90940Sstevel@tonic-gate 			DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
90950Sstevel@tonic-gate 			    "%s done:state =%d\n", function,
90960Sstevel@tonic-gate 			    segp->s_state));
90970Sstevel@tonic-gate 			return;
90980Sstevel@tonic-gate 		}
90990Sstevel@tonic-gate 
91000Sstevel@tonic-gate 		if (segp->s_state == RSM_STATE_BIND) {
91010Sstevel@tonic-gate 			/* unbind */
91020Sstevel@tonic-gate 			(void) rsm_unbind_pages(segp);
91030Sstevel@tonic-gate 			segp->s_state = RSM_STATE_BIND_QUIESCED;
91040Sstevel@tonic-gate 			rsmseglock_release(segp);
91050Sstevel@tonic-gate 			DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
91060Sstevel@tonic-gate 			    "%s done:state =%d\n", function,
91070Sstevel@tonic-gate 			    segp->s_state));
91080Sstevel@tonic-gate 			return;
91090Sstevel@tonic-gate 		}
91100Sstevel@tonic-gate 
91110Sstevel@tonic-gate 		if (segp->s_state == RSM_STATE_EXPORT) {
91120Sstevel@tonic-gate 			/*
91130Sstevel@tonic-gate 			 * wait for putv/getv to complete if the segp is
91140Sstevel@tonic-gate 			 * a local memory handle
91150Sstevel@tonic-gate 			 */
91160Sstevel@tonic-gate 			while ((segp->s_state == RSM_STATE_EXPORT) &&
91170Sstevel@tonic-gate 			    (segp->s_rdmacnt != 0)) {
91180Sstevel@tonic-gate 				cv_wait(&segp->s_cv, &segp->s_lock);
91190Sstevel@tonic-gate 			}
91200Sstevel@tonic-gate 
91210Sstevel@tonic-gate 			if (segp->s_state != RSM_STATE_EXPORT) {
91220Sstevel@tonic-gate 				/*
91230Sstevel@tonic-gate 				 * state changed need to see what it
91240Sstevel@tonic-gate 				 * should be changed to.
91250Sstevel@tonic-gate 				 */
91260Sstevel@tonic-gate 				recheck_state = 1;
91270Sstevel@tonic-gate 				continue;
91280Sstevel@tonic-gate 			}
91290Sstevel@tonic-gate 
91300Sstevel@tonic-gate 			segp->s_state = RSM_STATE_EXPORT_QUIESCING;
91310Sstevel@tonic-gate 			rsmseglock_release(segp);
91320Sstevel@tonic-gate 			/*
91330Sstevel@tonic-gate 			 * send SUSPEND messages - currently it will be
91340Sstevel@tonic-gate 			 * done at the end
91350Sstevel@tonic-gate 			 */
91360Sstevel@tonic-gate 			DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
91370Sstevel@tonic-gate 			    "%s done:state =%d\n", function,
91380Sstevel@tonic-gate 			    segp->s_state));
91390Sstevel@tonic-gate 			return;
91400Sstevel@tonic-gate 		}
91410Sstevel@tonic-gate 	} while (recheck_state);
91420Sstevel@tonic-gate 
91430Sstevel@tonic-gate 	rsmseglock_release(segp);
91440Sstevel@tonic-gate }
91450Sstevel@tonic-gate 
91460Sstevel@tonic-gate static void
rsm_unquiesce_exp_seg(rsmresource_t * resp)91470Sstevel@tonic-gate rsm_unquiesce_exp_seg(rsmresource_t *resp)
91480Sstevel@tonic-gate {
91490Sstevel@tonic-gate 	int			ret;
91500Sstevel@tonic-gate 	rsmseg_t		*segp = (rsmseg_t *)resp;
91510Sstevel@tonic-gate 	rsmapi_access_entry_t	*acl;
91520Sstevel@tonic-gate 	rsm_access_entry_t	*rsmpi_acl;
91530Sstevel@tonic-gate 	int			acl_len;
91540Sstevel@tonic-gate 	int			create_flags = 0;
91550Sstevel@tonic-gate 	struct buf		*xbuf;
91560Sstevel@tonic-gate 	rsm_memory_local_t	mem;
91570Sstevel@tonic-gate 	adapter_t		*adapter;
91580Sstevel@tonic-gate 	dev_t			sdev = 0;
91590Sstevel@tonic-gate 	rsm_resource_callback_t callback_flag;
91600Sstevel@tonic-gate 	DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_FUNC_ALL);
91610Sstevel@tonic-gate 	DBG_DEFINE_STR(function, "rsm_unquiesce_exp_seg");
91620Sstevel@tonic-gate 
91630Sstevel@tonic-gate 	rsmseglock_acquire(segp);
91640Sstevel@tonic-gate 
91650Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
91660Sstevel@tonic-gate 	    "%s enter: key=%u, state=%d\n", function, segp->s_key,
91670Sstevel@tonic-gate 	    segp->s_state));
91680Sstevel@tonic-gate 
91690Sstevel@tonic-gate 	if ((segp->s_state == RSM_STATE_NEW) ||
91700Sstevel@tonic-gate 	    (segp->s_state == RSM_STATE_BIND) ||
91710Sstevel@tonic-gate 	    (segp->s_state == RSM_STATE_EXPORT)) {
91720Sstevel@tonic-gate 		rsmseglock_release(segp);
91730Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "%s done:state=%d\n",
91740Sstevel@tonic-gate 		    function, segp->s_state));
91750Sstevel@tonic-gate 		return;
91760Sstevel@tonic-gate 	}
91770Sstevel@tonic-gate 
91780Sstevel@tonic-gate 	if (segp->s_state == RSM_STATE_NEW_QUIESCED) {
91790Sstevel@tonic-gate 		segp->s_state = RSM_STATE_NEW;
91800Sstevel@tonic-gate 		cv_broadcast(&segp->s_cv);
91810Sstevel@tonic-gate 		rsmseglock_release(segp);
91820Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "%s done:state=%d\n",
91830Sstevel@tonic-gate 		    function, segp->s_state));
91840Sstevel@tonic-gate 		return;
91850Sstevel@tonic-gate 	}
91860Sstevel@tonic-gate 
91870Sstevel@tonic-gate 	if (segp->s_state == RSM_STATE_BIND_QUIESCED) {
91880Sstevel@tonic-gate 		/* bind the segment */
91890Sstevel@tonic-gate 		ret = rsm_bind_pages(&segp->s_cookie, segp->s_region.r_vaddr,
91900Sstevel@tonic-gate 		    segp->s_len, segp->s_proc);
91910Sstevel@tonic-gate 		if (ret == RSM_SUCCESS) { /* bind successful */
91920Sstevel@tonic-gate 			segp->s_state = RSM_STATE_BIND;
91930Sstevel@tonic-gate 		} else { /* bind failed - resource unavailable */
91940Sstevel@tonic-gate 			segp->s_state = RSM_STATE_NEW;
91950Sstevel@tonic-gate 		}
91960Sstevel@tonic-gate 		cv_broadcast(&segp->s_cv);
91970Sstevel@tonic-gate 		rsmseglock_release(segp);
91980Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
91990Sstevel@tonic-gate 		    "%s done: bind_qscd bind = %d\n", function, ret));
92000Sstevel@tonic-gate 		return;
92010Sstevel@tonic-gate 	}
92020Sstevel@tonic-gate 
92030Sstevel@tonic-gate 	while (segp->s_state == RSM_STATE_EXPORT_QUIESCING) {
92040Sstevel@tonic-gate 		/* wait for the segment to move to EXPORT_QUIESCED state */
92050Sstevel@tonic-gate 		cv_wait(&segp->s_cv, &segp->s_lock);
92060Sstevel@tonic-gate 	}
92070Sstevel@tonic-gate 
92080Sstevel@tonic-gate 	if (segp->s_state == RSM_STATE_EXPORT_QUIESCED) {
92090Sstevel@tonic-gate 		/* bind the segment */
92100Sstevel@tonic-gate 		ret = rsm_bind_pages(&segp->s_cookie, segp->s_region.r_vaddr,
92110Sstevel@tonic-gate 		    segp->s_len, segp->s_proc);
92120Sstevel@tonic-gate 
92130Sstevel@tonic-gate 		if (ret != RSM_SUCCESS) {
92140Sstevel@tonic-gate 			/* bind failed - resource unavailable */
92150Sstevel@tonic-gate 			acl_len = segp->s_acl_len;
92160Sstevel@tonic-gate 			acl = segp->s_acl;
92170Sstevel@tonic-gate 			rsmpi_acl = segp->s_acl_in;
92180Sstevel@tonic-gate 			segp->s_acl_len = 0;
92190Sstevel@tonic-gate 			segp->s_acl = NULL;
92200Sstevel@tonic-gate 			segp->s_acl_in = NULL;
92210Sstevel@tonic-gate 			rsmseglock_release(segp);
92220Sstevel@tonic-gate 
92230Sstevel@tonic-gate 			rsmexport_rm(segp);
92240Sstevel@tonic-gate 			rsmacl_free(acl, acl_len);
92250Sstevel@tonic-gate 			rsmpiacl_free(rsmpi_acl, acl_len);
92260Sstevel@tonic-gate 
92270Sstevel@tonic-gate 			rsmseglock_acquire(segp);
92280Sstevel@tonic-gate 			segp->s_state = RSM_STATE_NEW;
92290Sstevel@tonic-gate 			cv_broadcast(&segp->s_cv);
92300Sstevel@tonic-gate 			rsmseglock_release(segp);
92310Sstevel@tonic-gate 			DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
92320Sstevel@tonic-gate 			    "%s done: exp_qscd bind failed = %d\n",
92330Sstevel@tonic-gate 			    function, ret));
92340Sstevel@tonic-gate 			return;
92350Sstevel@tonic-gate 		}
92360Sstevel@tonic-gate 		/*
92370Sstevel@tonic-gate 		 * publish the segment
92380Sstevel@tonic-gate 		 * if  successful
92390Sstevel@tonic-gate 		 *   segp->s_state = RSM_STATE_EXPORT;
92400Sstevel@tonic-gate 		 * else failed
92410Sstevel@tonic-gate 		 *   segp->s_state = RSM_STATE_BIND;
92420Sstevel@tonic-gate 		 */
92430Sstevel@tonic-gate 
92440Sstevel@tonic-gate 		/* check whether it is a local_memory_handle */
92450Sstevel@tonic-gate 		if (segp->s_acl != (rsmapi_access_entry_t *)NULL) {
92460Sstevel@tonic-gate 			if ((segp->s_acl[0].ae_node == my_nodeid) &&
92470Sstevel@tonic-gate 			    (segp->s_acl[0].ae_permission == 0)) {
92480Sstevel@tonic-gate 				segp->s_state = RSM_STATE_EXPORT;
92490Sstevel@tonic-gate 				cv_broadcast(&segp->s_cv);
92500Sstevel@tonic-gate 				rsmseglock_release(segp);
92510Sstevel@tonic-gate 				DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
92520Sstevel@tonic-gate 				    "%s done:exp_qscd\n", function));
92530Sstevel@tonic-gate 				return;
92540Sstevel@tonic-gate 			}
92550Sstevel@tonic-gate 		}
92560Sstevel@tonic-gate 		xbuf = ddi_umem_iosetup(segp->s_cookie, 0, segp->s_len, B_WRITE,
92570Sstevel@tonic-gate 		    sdev, 0, NULL, DDI_UMEM_SLEEP);
92580Sstevel@tonic-gate 		ASSERT(xbuf != NULL);
92590Sstevel@tonic-gate 
92600Sstevel@tonic-gate 		mem.ms_type = RSM_MEM_BUF;
92610Sstevel@tonic-gate 		mem.ms_bp = xbuf;
92620Sstevel@tonic-gate 
92630Sstevel@tonic-gate 		adapter = segp->s_adapter;
92640Sstevel@tonic-gate 
92650Sstevel@tonic-gate 		if (segp->s_flags & RSMKA_ALLOW_UNBIND_REBIND) {
92660Sstevel@tonic-gate 			create_flags = RSM_ALLOW_UNBIND_REBIND;
92670Sstevel@tonic-gate 		}
92680Sstevel@tonic-gate 
92690Sstevel@tonic-gate 		if (segp->s_flags & RSMKA_SET_RESOURCE_DONTWAIT) {
92700Sstevel@tonic-gate 			callback_flag  = RSM_RESOURCE_DONTWAIT;
92710Sstevel@tonic-gate 		} else {
92720Sstevel@tonic-gate 			callback_flag  = RSM_RESOURCE_SLEEP;
92730Sstevel@tonic-gate 		}
92740Sstevel@tonic-gate 
92750Sstevel@tonic-gate 		ret = adapter->rsmpi_ops->rsm_seg_create(
92760Sstevel@tonic-gate 		    adapter->rsmpi_handle, &segp->s_handle.out,
92770Sstevel@tonic-gate 		    segp->s_len, create_flags, &mem,
92780Sstevel@tonic-gate 		    callback_flag, NULL);
92790Sstevel@tonic-gate 
92800Sstevel@tonic-gate 		if (ret != RSM_SUCCESS) {
92810Sstevel@tonic-gate 			acl_len = segp->s_acl_len;
92820Sstevel@tonic-gate 			acl = segp->s_acl;
92830Sstevel@tonic-gate 			rsmpi_acl = segp->s_acl_in;
92840Sstevel@tonic-gate 			segp->s_acl_len = 0;
92850Sstevel@tonic-gate 			segp->s_acl = NULL;
92860Sstevel@tonic-gate 			segp->s_acl_in = NULL;
92870Sstevel@tonic-gate 			rsmseglock_release(segp);
92880Sstevel@tonic-gate 
92890Sstevel@tonic-gate 			rsmexport_rm(segp);
92900Sstevel@tonic-gate 			rsmacl_free(acl, acl_len);
92910Sstevel@tonic-gate 			rsmpiacl_free(rsmpi_acl, acl_len);
92920Sstevel@tonic-gate 
92930Sstevel@tonic-gate 			rsmseglock_acquire(segp);
92940Sstevel@tonic-gate 			segp->s_state = RSM_STATE_BIND;
92950Sstevel@tonic-gate 			cv_broadcast(&segp->s_cv);
92960Sstevel@tonic-gate 			rsmseglock_release(segp);
92970Sstevel@tonic-gate 			DBG_PRINTF((category, RSM_ERR,
92980Sstevel@tonic-gate 			    "%s done: exp_qscd create failed = %d\n",
92990Sstevel@tonic-gate 			    function, ret));
93000Sstevel@tonic-gate 			return;
93010Sstevel@tonic-gate 		}
93020Sstevel@tonic-gate 
93030Sstevel@tonic-gate 		ret = adapter->rsmpi_ops->rsm_publish(
93040Sstevel@tonic-gate 		    segp->s_handle.out, segp->s_acl_in, segp->s_acl_len,
93050Sstevel@tonic-gate 		    segp->s_segid, RSM_RESOURCE_DONTWAIT, NULL);
93060Sstevel@tonic-gate 
93070Sstevel@tonic-gate 		if (ret != RSM_SUCCESS) {
93080Sstevel@tonic-gate 			acl_len = segp->s_acl_len;
93090Sstevel@tonic-gate 			acl = segp->s_acl;
93100Sstevel@tonic-gate 			rsmpi_acl = segp->s_acl_in;
93110Sstevel@tonic-gate 			segp->s_acl_len = 0;
93120Sstevel@tonic-gate 			segp->s_acl = NULL;
93130Sstevel@tonic-gate 			segp->s_acl_in = NULL;
93140Sstevel@tonic-gate 			adapter->rsmpi_ops->rsm_seg_destroy(segp->s_handle.out);
93150Sstevel@tonic-gate 			rsmseglock_release(segp);
93160Sstevel@tonic-gate 
93170Sstevel@tonic-gate 			rsmexport_rm(segp);
93180Sstevel@tonic-gate 			rsmacl_free(acl, acl_len);
93190Sstevel@tonic-gate 			rsmpiacl_free(rsmpi_acl, acl_len);
93200Sstevel@tonic-gate 
93210Sstevel@tonic-gate 			rsmseglock_acquire(segp);
93220Sstevel@tonic-gate 			segp->s_state = RSM_STATE_BIND;
93230Sstevel@tonic-gate 			cv_broadcast(&segp->s_cv);
93240Sstevel@tonic-gate 			rsmseglock_release(segp);
93250Sstevel@tonic-gate 			DBG_PRINTF((category, RSM_ERR,
93260Sstevel@tonic-gate 			    "%s done: exp_qscd publish failed = %d\n",
93270Sstevel@tonic-gate 			    function, ret));
93280Sstevel@tonic-gate 			return;
93290Sstevel@tonic-gate 		}
93300Sstevel@tonic-gate 
93310Sstevel@tonic-gate 		segp->s_state = RSM_STATE_EXPORT;
93320Sstevel@tonic-gate 		cv_broadcast(&segp->s_cv);
93330Sstevel@tonic-gate 		rsmseglock_release(segp);
93340Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "%s done: exp_qscd\n",
93350Sstevel@tonic-gate 		    function));
93360Sstevel@tonic-gate 		return;
93370Sstevel@tonic-gate 	}
93380Sstevel@tonic-gate 
93390Sstevel@tonic-gate 	rsmseglock_release(segp);
93400Sstevel@tonic-gate 
93410Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "%s done\n", function));
93420Sstevel@tonic-gate }
93430Sstevel@tonic-gate 
93440Sstevel@tonic-gate static void
rsm_quiesce_imp_seg(rsmresource_t * resp)93450Sstevel@tonic-gate rsm_quiesce_imp_seg(rsmresource_t *resp)
93460Sstevel@tonic-gate {
93470Sstevel@tonic-gate 	rsmseg_t	*segp = (rsmseg_t *)resp;
93480Sstevel@tonic-gate 	DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_FUNC_ALL);
93490Sstevel@tonic-gate 	DBG_DEFINE_STR(function, "rsm_quiesce_imp_seg");
93500Sstevel@tonic-gate 
93510Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
93520Sstevel@tonic-gate 	    "%s enter: key=%u\n", function, segp->s_key));
93530Sstevel@tonic-gate 
93540Sstevel@tonic-gate 	rsmseglock_acquire(segp);
93550Sstevel@tonic-gate 	segp->s_flags |= RSM_DR_INPROGRESS;
93560Sstevel@tonic-gate 
93570Sstevel@tonic-gate 	while (segp->s_rdmacnt != 0) {
93580Sstevel@tonic-gate 		/* wait for the RDMA to complete */
93590Sstevel@tonic-gate 		cv_wait(&segp->s_cv, &segp->s_lock);
93600Sstevel@tonic-gate 	}
93610Sstevel@tonic-gate 
93620Sstevel@tonic-gate 	rsmseglock_release(segp);
93630Sstevel@tonic-gate 
93640Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "%s done\n", function));
93650Sstevel@tonic-gate 
93660Sstevel@tonic-gate }
93670Sstevel@tonic-gate 
93680Sstevel@tonic-gate static void
rsm_unquiesce_imp_seg(rsmresource_t * resp)93690Sstevel@tonic-gate rsm_unquiesce_imp_seg(rsmresource_t *resp)
93700Sstevel@tonic-gate {
93710Sstevel@tonic-gate 	rsmseg_t	*segp = (rsmseg_t *)resp;
93720Sstevel@tonic-gate 	DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_FUNC_ALL);
93730Sstevel@tonic-gate 	DBG_DEFINE_STR(function, "rsm_unquiesce_imp_seg");
93740Sstevel@tonic-gate 
93750Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
93760Sstevel@tonic-gate 	    "%s enter: key=%u\n", function, segp->s_key));
93770Sstevel@tonic-gate 
93780Sstevel@tonic-gate 	rsmseglock_acquire(segp);
93790Sstevel@tonic-gate 
93800Sstevel@tonic-gate 	segp->s_flags &= ~RSM_DR_INPROGRESS;
93810Sstevel@tonic-gate 	/* wake up any waiting putv/getv ops */
93820Sstevel@tonic-gate 	cv_broadcast(&segp->s_cv);
93830Sstevel@tonic-gate 
93840Sstevel@tonic-gate 	rsmseglock_release(segp);
93850Sstevel@tonic-gate 
93860Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "%s done\n", function));
93870Sstevel@tonic-gate 
93880Sstevel@tonic-gate 
93890Sstevel@tonic-gate }
93900Sstevel@tonic-gate 
93910Sstevel@tonic-gate static void
rsm_process_exp_seg(rsmresource_t * resp,int event)93920Sstevel@tonic-gate rsm_process_exp_seg(rsmresource_t *resp, int event)
93930Sstevel@tonic-gate {
93940Sstevel@tonic-gate 	if (event == RSM_DR_QUIESCE)
93950Sstevel@tonic-gate 		rsm_quiesce_exp_seg(resp);
93960Sstevel@tonic-gate 	else /* UNQUIESCE */
93970Sstevel@tonic-gate 		rsm_unquiesce_exp_seg(resp);
93980Sstevel@tonic-gate }
93990Sstevel@tonic-gate 
94000Sstevel@tonic-gate static void
rsm_process_imp_seg(rsmresource_t * resp,int event)94010Sstevel@tonic-gate rsm_process_imp_seg(rsmresource_t *resp, int event)
94020Sstevel@tonic-gate {
94030Sstevel@tonic-gate 	if (event == RSM_DR_QUIESCE)
94040Sstevel@tonic-gate 		rsm_quiesce_imp_seg(resp);
94050Sstevel@tonic-gate 	else /* UNQUIESCE */
94060Sstevel@tonic-gate 		rsm_unquiesce_imp_seg(resp);
94070Sstevel@tonic-gate }
94080Sstevel@tonic-gate 
94090Sstevel@tonic-gate static void
rsm_dr_process_local_segments(int event)94100Sstevel@tonic-gate rsm_dr_process_local_segments(int event)
94110Sstevel@tonic-gate {
94120Sstevel@tonic-gate 
94130Sstevel@tonic-gate 	int i, j;
94140Sstevel@tonic-gate 	rsmresource_blk_t	*blk;
94150Sstevel@tonic-gate 	rsmresource_t		*p;
94160Sstevel@tonic-gate 	DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_FUNC_ALL);
94170Sstevel@tonic-gate 
94180Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
94190Sstevel@tonic-gate 	    "rsm_dr_process_local_segments enter\n"));
94200Sstevel@tonic-gate 
94210Sstevel@tonic-gate 	/* iterate through the resource structure */
94220Sstevel@tonic-gate 
94230Sstevel@tonic-gate 	rw_enter(&rsm_resource.rsmrc_lock, RW_READER);
94240Sstevel@tonic-gate 
94250Sstevel@tonic-gate 	for (i = 0; i < rsm_resource.rsmrc_len; i++) {
94260Sstevel@tonic-gate 		blk = rsm_resource.rsmrc_root[i];
94270Sstevel@tonic-gate 		if (blk != NULL) {
94280Sstevel@tonic-gate 			for (j = 0; j < RSMRC_BLKSZ; j++) {
94290Sstevel@tonic-gate 				p = blk->rsmrcblk_blks[j];
94300Sstevel@tonic-gate 				if ((p != NULL) && (p != RSMRC_RESERVED)) {
94310Sstevel@tonic-gate 					/* valid resource */
94320Sstevel@tonic-gate 					if (p->rsmrc_type ==
94330Sstevel@tonic-gate 					    RSM_RESOURCE_EXPORT_SEGMENT)
94340Sstevel@tonic-gate 						rsm_process_exp_seg(p, event);
94350Sstevel@tonic-gate 					else if (p->rsmrc_type ==
94360Sstevel@tonic-gate 					    RSM_RESOURCE_IMPORT_SEGMENT)
94370Sstevel@tonic-gate 						rsm_process_imp_seg(p, event);
94380Sstevel@tonic-gate 				}
94390Sstevel@tonic-gate 			}
94400Sstevel@tonic-gate 		}
94410Sstevel@tonic-gate 	}
94420Sstevel@tonic-gate 
94430Sstevel@tonic-gate 	rw_exit(&rsm_resource.rsmrc_lock);
94440Sstevel@tonic-gate 
94450Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
94460Sstevel@tonic-gate 	    "rsm_dr_process_local_segments done\n"));
94470Sstevel@tonic-gate }
94480Sstevel@tonic-gate 
94490Sstevel@tonic-gate /* *************** DR callback functions ************ */
94500Sstevel@tonic-gate static void
rsm_dr_callback_post_add(void * arg,pgcnt_t delta)94510Sstevel@tonic-gate rsm_dr_callback_post_add(void *arg, pgcnt_t delta /* ARGSUSED */)
94520Sstevel@tonic-gate {
94530Sstevel@tonic-gate 	DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_FUNC_ALL);
94540Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
94550Sstevel@tonic-gate 	    "rsm_dr_callback_post_add is a no-op\n"));
94560Sstevel@tonic-gate 	/* Noop */
94570Sstevel@tonic-gate }
94580Sstevel@tonic-gate 
94590Sstevel@tonic-gate static int
rsm_dr_callback_pre_del(void * arg,pgcnt_t delta)94600Sstevel@tonic-gate rsm_dr_callback_pre_del(void *arg, pgcnt_t delta /* ARGSUSED */)
94610Sstevel@tonic-gate {
94620Sstevel@tonic-gate 	int	recheck_state = 0;
94630Sstevel@tonic-gate 	DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_FUNC_ALL);
94640Sstevel@tonic-gate 
94650Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
94660Sstevel@tonic-gate 	    "rsm_dr_callback_pre_del enter\n"));
94670Sstevel@tonic-gate 
94680Sstevel@tonic-gate 	mutex_enter(&rsm_drv_data.drv_lock);
94690Sstevel@tonic-gate 
94700Sstevel@tonic-gate 	do {
94710Sstevel@tonic-gate 		recheck_state = 0;
94720Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
94730Sstevel@tonic-gate 		    "rsm_dr_callback_pre_del:state=%d\n",
94740Sstevel@tonic-gate 		    rsm_drv_data.drv_state));
94750Sstevel@tonic-gate 
94760Sstevel@tonic-gate 		switch (rsm_drv_data.drv_state) {
94770Sstevel@tonic-gate 		case RSM_DRV_NEW:
94780Sstevel@tonic-gate 			/*
94790Sstevel@tonic-gate 			 * The state should usually never be RSM_DRV_NEW
94800Sstevel@tonic-gate 			 * since in this state the callbacks have not yet
94810Sstevel@tonic-gate 			 * been registered. So, ASSERT.
94820Sstevel@tonic-gate 			 */
94830Sstevel@tonic-gate 			ASSERT(0);
94840Sstevel@tonic-gate 			return (0);
94850Sstevel@tonic-gate 		case RSM_DRV_REG_PROCESSING:
94860Sstevel@tonic-gate 			/*
94870Sstevel@tonic-gate 			 * The driver is in the process of registering
94880Sstevel@tonic-gate 			 * with the DR framework. So, wait till the
94890Sstevel@tonic-gate 			 * registration process is complete.
94900Sstevel@tonic-gate 			 */
94910Sstevel@tonic-gate 			recheck_state = 1;
94920Sstevel@tonic-gate 			cv_wait(&rsm_drv_data.drv_cv, &rsm_drv_data.drv_lock);
94930Sstevel@tonic-gate 			break;
94940Sstevel@tonic-gate 		case RSM_DRV_UNREG_PROCESSING:
94950Sstevel@tonic-gate 			/*
94960Sstevel@tonic-gate 			 * If the state is RSM_DRV_UNREG_PROCESSING, the
94970Sstevel@tonic-gate 			 * module is in the process of detaching and
94980Sstevel@tonic-gate 			 * unregistering the callbacks from the DR
94990Sstevel@tonic-gate 			 * framework. So, simply return.
95000Sstevel@tonic-gate 			 */
95010Sstevel@tonic-gate 			mutex_exit(&rsm_drv_data.drv_lock);
95020Sstevel@tonic-gate 			DBG_PRINTF((category, RSM_DEBUG,
95030Sstevel@tonic-gate 			    "rsm_dr_callback_pre_del:"
95040Sstevel@tonic-gate 			    "pre-del on NEW/UNREG\n"));
95050Sstevel@tonic-gate 			return (0);
95060Sstevel@tonic-gate 		case RSM_DRV_OK:
95070Sstevel@tonic-gate 			rsm_drv_data.drv_state = RSM_DRV_PREDEL_STARTED;
95080Sstevel@tonic-gate 			break;
95090Sstevel@tonic-gate 		case RSM_DRV_PREDEL_STARTED:
95100Sstevel@tonic-gate 			/* FALLTHRU */
95110Sstevel@tonic-gate 		case RSM_DRV_PREDEL_COMPLETED:
95120Sstevel@tonic-gate 			/* FALLTHRU */
95130Sstevel@tonic-gate 		case RSM_DRV_POSTDEL_IN_PROGRESS:
95140Sstevel@tonic-gate 			recheck_state = 1;
95150Sstevel@tonic-gate 			cv_wait(&rsm_drv_data.drv_cv, &rsm_drv_data.drv_lock);
95160Sstevel@tonic-gate 			break;
95170Sstevel@tonic-gate 		case RSM_DRV_DR_IN_PROGRESS:
95180Sstevel@tonic-gate 			rsm_drv_data.drv_memdel_cnt++;
95190Sstevel@tonic-gate 			mutex_exit(&rsm_drv_data.drv_lock);
95200Sstevel@tonic-gate 			DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
95210Sstevel@tonic-gate 			    "rsm_dr_callback_pre_del done\n"));
95220Sstevel@tonic-gate 			return (0);
95230Sstevel@tonic-gate 			/* break; */
95240Sstevel@tonic-gate 		default:
95250Sstevel@tonic-gate 			ASSERT(0);
95260Sstevel@tonic-gate 			break;
95270Sstevel@tonic-gate 		}
95280Sstevel@tonic-gate 
95290Sstevel@tonic-gate 	} while (recheck_state);
95300Sstevel@tonic-gate 
95310Sstevel@tonic-gate 	rsm_drv_data.drv_memdel_cnt++;
95320Sstevel@tonic-gate 
95330Sstevel@tonic-gate 	mutex_exit(&rsm_drv_data.drv_lock);
95340Sstevel@tonic-gate 
95350Sstevel@tonic-gate 	/* Do all the quiescing stuff here */
95360Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG,
95370Sstevel@tonic-gate 	    "rsm_dr_callback_pre_del: quiesce things now\n"));
95380Sstevel@tonic-gate 
95390Sstevel@tonic-gate 	rsm_dr_process_local_segments(RSM_DR_QUIESCE);
95400Sstevel@tonic-gate 
95410Sstevel@tonic-gate 	/*
95420Sstevel@tonic-gate 	 * now that all local segments have been quiesced lets inform
95430Sstevel@tonic-gate 	 * the importers
95440Sstevel@tonic-gate 	 */
95450Sstevel@tonic-gate 	rsm_send_suspend();
95460Sstevel@tonic-gate 
95470Sstevel@tonic-gate 	/*
95480Sstevel@tonic-gate 	 * In response to the suspend message the remote node(s) will process
95490Sstevel@tonic-gate 	 * the segments and send a suspend_complete message. Till all
95500Sstevel@tonic-gate 	 * the nodes send the suspend_complete message we wait in the
95510Sstevel@tonic-gate 	 * RSM_DRV_PREDEL_STARTED state. In the exporter_quiesce
95520Sstevel@tonic-gate 	 * function we transition to the RSM_DRV_PREDEL_COMPLETED state.
95530Sstevel@tonic-gate 	 */
95540Sstevel@tonic-gate 	mutex_enter(&rsm_drv_data.drv_lock);
95550Sstevel@tonic-gate 
95560Sstevel@tonic-gate 	while (rsm_drv_data.drv_state == RSM_DRV_PREDEL_STARTED) {
95570Sstevel@tonic-gate 		cv_wait(&rsm_drv_data.drv_cv, &rsm_drv_data.drv_lock);
95580Sstevel@tonic-gate 	}
95590Sstevel@tonic-gate 
95600Sstevel@tonic-gate 	ASSERT(rsm_drv_data.drv_state == RSM_DRV_PREDEL_COMPLETED);
95610Sstevel@tonic-gate 
95620Sstevel@tonic-gate 	rsm_drv_data.drv_state = RSM_DRV_DR_IN_PROGRESS;
95630Sstevel@tonic-gate 	cv_broadcast(&rsm_drv_data.drv_cv);
95640Sstevel@tonic-gate 
95650Sstevel@tonic-gate 	mutex_exit(&rsm_drv_data.drv_lock);
95660Sstevel@tonic-gate 
95670Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
95680Sstevel@tonic-gate 	    "rsm_dr_callback_pre_del done\n"));
95690Sstevel@tonic-gate 
95700Sstevel@tonic-gate 	return (0);
95710Sstevel@tonic-gate }
95720Sstevel@tonic-gate 
95730Sstevel@tonic-gate static void
rsm_dr_callback_post_del(void * arg,pgcnt_t delta,int cancelled)95740Sstevel@tonic-gate rsm_dr_callback_post_del(void *arg, pgcnt_t delta, int cancelled /* ARGSUSED */)
95750Sstevel@tonic-gate {
95760Sstevel@tonic-gate 	int	recheck_state = 0;
95770Sstevel@tonic-gate 	DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_FUNC_ALL);
95780Sstevel@tonic-gate 
95790Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
95800Sstevel@tonic-gate 	    "rsm_dr_callback_post_del enter\n"));
95810Sstevel@tonic-gate 
95820Sstevel@tonic-gate 	mutex_enter(&rsm_drv_data.drv_lock);
95830Sstevel@tonic-gate 
95840Sstevel@tonic-gate 	do {
95850Sstevel@tonic-gate 		recheck_state = 0;
95860Sstevel@tonic-gate 		DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
95870Sstevel@tonic-gate 		    "rsm_dr_callback_post_del:state=%d\n",
95880Sstevel@tonic-gate 		    rsm_drv_data.drv_state));
95890Sstevel@tonic-gate 
95900Sstevel@tonic-gate 		switch (rsm_drv_data.drv_state) {
95910Sstevel@tonic-gate 		case RSM_DRV_NEW:
95920Sstevel@tonic-gate 			/*
95930Sstevel@tonic-gate 			 * The driver state cannot not be RSM_DRV_NEW
95940Sstevel@tonic-gate 			 * since in this state the callbacks have not
95950Sstevel@tonic-gate 			 * yet been registered.
95960Sstevel@tonic-gate 			 */
95970Sstevel@tonic-gate 			ASSERT(0);
95980Sstevel@tonic-gate 			return;
95990Sstevel@tonic-gate 		case RSM_DRV_REG_PROCESSING:
96000Sstevel@tonic-gate 			/*
96010Sstevel@tonic-gate 			 * The driver is in the process of registering with
96020Sstevel@tonic-gate 			 * the DR framework. Wait till the registration is
96030Sstevel@tonic-gate 			 * complete.
96040Sstevel@tonic-gate 			 */
96050Sstevel@tonic-gate 			recheck_state = 1;
96060Sstevel@tonic-gate 			cv_wait(&rsm_drv_data.drv_cv, &rsm_drv_data.drv_lock);
96070Sstevel@tonic-gate 			break;
96080Sstevel@tonic-gate 		case RSM_DRV_UNREG_PROCESSING:
96090Sstevel@tonic-gate 			/*
96100Sstevel@tonic-gate 			 * RSM_DRV_UNREG_PROCESSING state means the module
96110Sstevel@tonic-gate 			 * is detaching and unregistering the callbacks
96120Sstevel@tonic-gate 			 * from the DR framework. So simply return.
96130Sstevel@tonic-gate 			 */
96140Sstevel@tonic-gate 			/* FALLTHRU */
96150Sstevel@tonic-gate 		case RSM_DRV_OK:
96160Sstevel@tonic-gate 			/*
96170Sstevel@tonic-gate 			 * RSM_DRV_OK means we missed the pre-del
96180Sstevel@tonic-gate 			 * corresponding to this post-del coz we had not
96190Sstevel@tonic-gate 			 * registered yet, so simply return.
96200Sstevel@tonic-gate 			 */
96210Sstevel@tonic-gate 			mutex_exit(&rsm_drv_data.drv_lock);
96220Sstevel@tonic-gate 			DBG_PRINTF((category, RSM_DEBUG,
96230Sstevel@tonic-gate 			    "rsm_dr_callback_post_del:"
96240Sstevel@tonic-gate 			    "post-del on OK/UNREG\n"));
96250Sstevel@tonic-gate 			return;
96260Sstevel@tonic-gate 			/* break; */
96270Sstevel@tonic-gate 		case RSM_DRV_PREDEL_STARTED:
96280Sstevel@tonic-gate 			/* FALLTHRU */
96290Sstevel@tonic-gate 		case RSM_DRV_PREDEL_COMPLETED:
96300Sstevel@tonic-gate 			/* FALLTHRU */
96310Sstevel@tonic-gate 		case RSM_DRV_POSTDEL_IN_PROGRESS:
96320Sstevel@tonic-gate 			recheck_state = 1;
96330Sstevel@tonic-gate 			cv_wait(&rsm_drv_data.drv_cv, &rsm_drv_data.drv_lock);
96340Sstevel@tonic-gate 			break;
96350Sstevel@tonic-gate 		case RSM_DRV_DR_IN_PROGRESS:
96360Sstevel@tonic-gate 			rsm_drv_data.drv_memdel_cnt--;
96370Sstevel@tonic-gate 			if (rsm_drv_data.drv_memdel_cnt > 0) {
96380Sstevel@tonic-gate 				mutex_exit(&rsm_drv_data.drv_lock);
96390Sstevel@tonic-gate 				DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
96400Sstevel@tonic-gate 				    "rsm_dr_callback_post_del done:\n"));
96410Sstevel@tonic-gate 				return;
96420Sstevel@tonic-gate 			}
96430Sstevel@tonic-gate 			rsm_drv_data.drv_state = RSM_DRV_POSTDEL_IN_PROGRESS;
96440Sstevel@tonic-gate 			break;
96450Sstevel@tonic-gate 		default:
96460Sstevel@tonic-gate 			ASSERT(0);
96470Sstevel@tonic-gate 			return;
96480Sstevel@tonic-gate 			/* break; */
96490Sstevel@tonic-gate 		}
96500Sstevel@tonic-gate 	} while (recheck_state);
96510Sstevel@tonic-gate 
96520Sstevel@tonic-gate 	mutex_exit(&rsm_drv_data.drv_lock);
96530Sstevel@tonic-gate 
96540Sstevel@tonic-gate 	/* Do all the unquiescing stuff here */
96550Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG,
96560Sstevel@tonic-gate 	    "rsm_dr_callback_post_del: unquiesce things now\n"));
96570Sstevel@tonic-gate 
96580Sstevel@tonic-gate 	rsm_dr_process_local_segments(RSM_DR_UNQUIESCE);
96590Sstevel@tonic-gate 
96600Sstevel@tonic-gate 	/*
96610Sstevel@tonic-gate 	 * now that all local segments have been unquiesced lets inform
96620Sstevel@tonic-gate 	 * the importers
96630Sstevel@tonic-gate 	 */
96640Sstevel@tonic-gate 	rsm_send_resume();
96650Sstevel@tonic-gate 
96660Sstevel@tonic-gate 	mutex_enter(&rsm_drv_data.drv_lock);
96670Sstevel@tonic-gate 
96680Sstevel@tonic-gate 	rsm_drv_data.drv_state = RSM_DRV_OK;
96690Sstevel@tonic-gate 
96700Sstevel@tonic-gate 	cv_broadcast(&rsm_drv_data.drv_cv);
96710Sstevel@tonic-gate 
96720Sstevel@tonic-gate 	mutex_exit(&rsm_drv_data.drv_lock);
96730Sstevel@tonic-gate 
96740Sstevel@tonic-gate 	DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
96750Sstevel@tonic-gate 	    "rsm_dr_callback_post_del done\n"));
96760Sstevel@tonic-gate 
96770Sstevel@tonic-gate 	return;
96780Sstevel@tonic-gate 
96790Sstevel@tonic-gate }
9680