1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 * Copyright 2012 Milan Jurik. All rights reserved.
25 * Copyright (c) 2016 by Delphix. All rights reserved.
26 * Copyright 2017 Joyent, Inc.
27 */
28
29
30 /*
31 * Overview of the RSM Kernel Agent:
32 * ---------------------------------
33 *
34 * rsm.c constitutes the implementation of the RSM kernel agent. The RSM
35 * kernel agent is a pseudo device driver which makes use of the RSMPI
36 * interface on behalf of the RSMAPI user library.
37 *
38 * The kernel agent functionality can be categorized into the following
39 * components:
40 * 1. Driver Infrastructure
41 * 2. Export/Import Segment Management
42 * 3. Internal resource allocation/deallocation
43 *
44 * The driver infrastructure includes the basic module loading entry points
45 * like _init, _info, _fini to load, unload and report information about
46 * the driver module. The driver infrastructure also includes the
47 * autoconfiguration entry points namely, attach, detach and getinfo for
48 * the device autoconfiguration.
49 *
50 * The kernel agent is a pseudo character device driver and exports
51 * a cb_ops structure which defines the driver entry points for character
52 * device access. This includes the open and close entry points. The
53 * other entry points provided include ioctl, devmap and segmap and chpoll.
54 * read and write entry points are not used since the device is memory
55 * mapped. Also ddi_prop_op is used for the prop_op entry point.
56 *
57 * The ioctl entry point supports a number of commands, which are used by
58 * the RSMAPI library in order to export and import segments. These
59 * commands include commands for binding and rebinding the physical pages
60 * allocated to the virtual address range, publishing the export segment,
61 * unpublishing and republishing an export segment, creating an
62 * import segment and a virtual connection from this import segment to
63 * an export segment, performing scatter-gather data transfer, barrier
64 * operations.
65 *
66 *
67 * Export and Import segments:
68 * ---------------------------
69 *
70 * In order to create an RSM export segment a process allocates a range in its
71 * virtual address space for the segment using standard Solaris interfaces.
72 * The process then calls RSMAPI, which in turn makes an ioctl call to the
73 * RSM kernel agent for an allocation of physical memory pages and for
74 * creation of the export segment by binding these pages to the virtual
75 * address range. These pages are locked in memory so that remote accesses
76 * are always applied to the correct page. Then the RSM segment is published,
77 * again via RSMAPI making an ioctl to the RSM kernel agent, and a segment id
78 * is assigned to it.
79 *
80 * In order to import a published RSM segment, RSMAPI creates an import
81 * segment and forms a virtual connection across the interconnect to the
82 * export segment, via an ioctl into the kernel agent with the connect
83 * command. The import segment setup is completed by mapping the
84 * local device memory into the importers virtual address space. The
85 * mapping of the import segment is handled by the segmap/devmap
86 * infrastructure described as follows.
87 *
88 * Segmap and Devmap interfaces:
89 *
90 * The RSM kernel agent allows device memory to be directly accessed by user
91 * threads via memory mapping. In order to do so, the RSM kernel agent
92 * supports the devmap and segmap entry points.
93 *
94 * The segmap entry point(rsm_segmap) is responsible for setting up a memory
95 * mapping as requested by mmap. The devmap entry point(rsm_devmap) is
96 * responsible for exporting the device memory to the user applications.
97 * rsm_segmap calls RSMPI rsm_map to allocate device memory. Then the
98 * control is transfered to the devmap_setup call which calls rsm_devmap.
99 *
100 * rsm_devmap validates the user mapping to the device or kernel memory
101 * and passes the information to the system for setting up the mapping. The
102 * actual setting up of the mapping is done by devmap_devmem_setup(for
103 * device memory) or devmap_umem_setup(for kernel memory). Callbacks are
104 * registered for device context management via the devmap_devmem_setup
105 * or devmap_umem_setup calls. The callbacks are rsmmap_map, rsmmap_unmap,
106 * rsmmap_access, rsmmap_dup. The callbacks are called when a new mapping
107 * is created, a mapping is freed, a mapping is accessed or an existing
108 * mapping is duplicated respectively. These callbacks allow the RSM kernel
109 * agent to maintain state information associated with the mappings.
110 * The state information is mainly in the form of a cookie list for the import
111 * segment for which mapping has been done.
112 *
113 * Forced disconnect of import segments:
114 *
115 * When an exported segment is unpublished, the exporter sends a forced
116 * disconnect message to all its importers. The importer segments are
117 * unloaded and disconnected. This involves unloading the original
118 * mappings and remapping to a preallocated kernel trash page. This is
119 * done by devmap_umem_remap. The trash/dummy page is a kernel page,
120 * preallocated by the kernel agent during attach using ddi_umem_alloc with
121 * the DDI_UMEM_TRASH flag set. This avoids a core dump in the application
122 * due to unloading of the original mappings.
123 *
124 * Additionally every segment has a mapping generation number associated
125 * with it. This is an entry in the barrier generation page, created
126 * during attach time. This mapping generation number for the import
127 * segments is incremented on a force disconnect to notify the application
128 * of the force disconnect. On this notification, the application needs
129 * to reconnect the segment to establish a new legitimate mapping.
130 *
131 *
132 * Locks used in the kernel agent:
133 * -------------------------------
134 *
135 * The kernel agent uses a variety of mutexes and condition variables for
136 * mutual exclusion of the shared data structures and for synchronization
137 * between the various threads. Some of the locks are described as follows.
138 *
139 * Each resource structure, which represents either an export/import segment
140 * has a lock associated with it. The lock is the resource mutex, rsmrc_lock.
141 * This is used directly by RSMRC_LOCK and RSMRC_UNLOCK macros and in the
142 * rsmseglock_acquire and rsmseglock_release macros. An additional
143 * lock called the rsmsi_lock is used for the shared import data structure
144 * that is relevant for resources representing import segments. There is
145 * also a condition variable associated with the resource called s_cv. This
146 * is used to wait for events like the segment state change etc.
147 *
148 * The resource structures are allocated from a pool of resource structures,
149 * called rsm_resource. This pool is protected via a reader-writer lock,
150 * called rsmrc_lock.
151 *
152 * There are two separate hash tables, one for the export segments and
153 * one for the import segments. The export segments are inserted into the
154 * export segment hash table only after they have been published and the
155 * import segments are inserted in the import segments list only after they
156 * have successfully connected to an exported segment. These tables are
157 * protected via reader-writer locks.
158 *
159 * Debug Support in the kernel agent:
160 * ----------------------------------
161 *
162 * Debugging support in the kernel agent is provided by the following
163 * macros.
164 *
165 * DBG_PRINTF((category, level, message)) is a macro which logs a debug
166 * message to the kernel agents debug buffer, rsmka_dbg. This debug buffer
167 * can be viewed in kmdb as *rsmka_dbg/s. The message is logged based
168 * on the definition of the category and level. All messages that belong to
169 * the specified category(rsmdbg_category) and are of an equal or greater
170 * severity than the specified level(rsmdbg_level) are logged. The message
171 * is a string which uses the same formatting rules as the strings used in
172 * printf.
173 *
174 * The category defines which component of the kernel agent has logged this
175 * message. There are a number of categories that have been defined such as
176 * RSM_KERNEL_AGENT, RSM_OPS, RSM_IMPORT, RSM_EXPORT etc. A macro,
177 * DBG_ADDCATEGORY is used to add in another category to the currently
178 * specified category value so that the component using this new category
179 * can also effectively log debug messages. Thus, the category of a specific
180 * message is some combination of the available categories and we can define
181 * sub-categories if we want a finer level of granularity.
182 *
183 * The level defines the severity of the message. Different level values are
184 * defined, with RSM_ERR being the most severe and RSM_DEBUG_VERBOSE being
185 * the least severe(debug level is 0).
186 *
187 * DBG_DEFINE and DBG_DEFINE_STR are macros provided to declare a debug
188 * variable or a string respectively.
189 *
190 *
191 * NOTES:
192 *
193 * Special Fork and Exec Handling:
194 * -------------------------------
195 *
196 * The backing physical pages of an exported segment are always locked down.
197 * Thus, there are two cases in which a process having exported segments
198 * will cause a cpu to hang: (1) the process invokes exec; (2) a process
199 * forks and invokes exit before the duped file descriptors for the export
200 * segments are closed in the child process. The hang is caused because the
201 * address space release algorithm in Solaris VM subsystem is based on a
202 * non-blocking loop which does not terminate while segments are locked
203 * down. In addition to this, Solaris VM subsystem lacks a callback
204 * mechanism to the rsm kernel agent to allow unlocking these export
205 * segment pages.
206 *
207 * In order to circumvent this problem, the kernel agent does the following.
208 * The Solaris VM subsystem keeps memory segments in increasing order of
209 * virtual addressses. Thus a special page(special_exit_offset) is allocated
210 * by the kernel agent and is mmapped into the heap area of the process address
211 * space(the mmap is done by the RSMAPI library). During the mmap processing
212 * of this special page by the devmap infrastructure, a callback(the same
213 * devmap context management callbacks discussed above) is registered for an
214 * unmap.
215 *
216 * As discussed above, this page is processed by the Solaris address space
217 * release code before any of the exported segments pages(which are allocated
218 * from high memory). It is during this processing that the unmap callback gets
219 * called and this callback is responsible for force destroying the exported
220 * segments and thus eliminating the problem of locked pages.
221 *
222 * Flow-control:
223 * ------------
224 *
225 * A credit based flow control algorithm is used for messages whose
226 * processing cannot be done in the interrupt context because it might
227 * involve invoking rsmpi calls, or might take a long time to complete
228 * or might need to allocate resources. The algorithm operates on a per
229 * path basis. To send a message the pathend needs to have a credit and
230 * it consumes one for every message that is flow controlled. On the
231 * receiving pathend the message is put on a msgbuf_queue and a task is
232 * dispatched on the worker thread - recv_taskq where it is processed.
233 * After processing the message, the receiving pathend dequeues the message,
234 * and if it has processed > RSMIPC_LOTSFREE_MSGBUFS messages sends
235 * credits to the sender pathend.
236 *
237 * RSM_DRTEST:
238 * -----------
239 *
240 * This is used to enable the DR testing using a test driver on test
241 * platforms which do not supported DR.
242 *
243 */
244
245 #include <sys/types.h>
246 #include <sys/param.h>
247 #include <sys/user.h>
248 #include <sys/buf.h>
249 #include <sys/systm.h>
250 #include <sys/cred.h>
251 #include <sys/vm.h>
252 #include <sys/uio.h>
253 #include <vm/seg.h>
254 #include <vm/page.h>
255 #include <sys/stat.h>
256
257 #include <sys/time.h>
258 #include <sys/errno.h>
259
260 #include <sys/file.h>
261 #include <sys/uio.h>
262 #include <sys/proc.h>
263 #include <sys/mman.h>
264 #include <sys/open.h>
265 #include <sys/atomic.h>
266 #include <sys/mem_config.h>
267
268
269 #include <sys/ddi.h>
270 #include <sys/devops.h>
271 #include <sys/ddidevmap.h>
272 #include <sys/sunddi.h>
273 #include <sys/esunddi.h>
274 #include <sys/ddi_impldefs.h>
275
276 #include <sys/kmem.h>
277 #include <sys/conf.h>
278 #include <sys/devops.h>
279 #include <sys/ddi_impldefs.h>
280
281 #include <sys/modctl.h>
282
283 #include <sys/policy.h>
284 #include <sys/types.h>
285 #include <sys/conf.h>
286 #include <sys/param.h>
287
288 #include <sys/taskq.h>
289
290 #include <sys/rsm/rsm_common.h>
291 #include <sys/rsm/rsmapi_common.h>
292 #include <sys/rsm/rsm.h>
293 #include <rsm_in.h>
294 #include <sys/rsm/rsmka_path_int.h>
295 #include <sys/rsm/rsmpi.h>
296
297 #include <sys/modctl.h>
298 #include <sys/debug.h>
299
300 #include <sys/tuneable.h>
301
302 #ifdef RSM_DRTEST
303 extern int rsm_kphysm_setup_func_register(kphysm_setup_vector_t *vec,
304 void *arg);
305 extern void rsm_kphysm_setup_func_unregister(kphysm_setup_vector_t *vec,
306 void *arg);
307 #endif
308
309 extern void dbg_printf(int category, int level, char *fmt, ...);
310 extern void rsmka_pathmanager_init();
311 extern void rsmka_pathmanager_cleanup();
312 extern void rele_sendq_token(sendq_token_t *);
313 extern rsm_addr_t get_remote_hwaddr(adapter_t *, rsm_node_id_t);
314 extern rsm_node_id_t get_remote_nodeid(adapter_t *, rsm_addr_t);
315 extern int rsmka_topology_ioctl(caddr_t, int, int);
316
317 extern pri_t maxclsyspri;
318 extern work_queue_t work_queue;
319 extern kmutex_t ipc_info_lock;
320 extern kmutex_t ipc_info_cvlock;
321 extern kcondvar_t ipc_info_cv;
322 extern kmutex_t path_hold_cvlock;
323 extern kcondvar_t path_hold_cv;
324
325 extern kmutex_t rsmka_buf_lock;
326
327 extern path_t *rsm_find_path(char *, int, rsm_addr_t);
328 extern adapter_t *rsmka_lookup_adapter(char *, int);
329 extern sendq_token_t *rsmka_get_sendq_token(rsm_node_id_t, sendq_token_t *);
330 extern boolean_t rsmka_do_path_active(path_t *, int);
331 extern boolean_t rsmka_check_node_alive(rsm_node_id_t);
332 extern void rsmka_release_adapter(adapter_t *);
333 extern void rsmka_enqueue_msgbuf(path_t *path, void *data);
334 extern void rsmka_dequeue_msgbuf(path_t *path);
335 extern msgbuf_elem_t *rsmka_gethead_msgbuf(path_t *path);
336 /* lint -w2 */
337
338 static int rsm_open(dev_t *, int, int, cred_t *);
339 static int rsm_close(dev_t, int, int, cred_t *);
340 static int rsm_ioctl(dev_t dev, int cmd, intptr_t arg, int mode,
341 cred_t *credp, int *rvalp);
342 static int rsm_devmap(dev_t, devmap_cookie_t, offset_t, size_t, size_t *,
343 uint_t);
344 static int rsm_segmap(dev_t, off_t, struct as *, caddr_t *, off_t, uint_t,
345 uint_t, uint_t, cred_t *);
346 static int rsm_chpoll(dev_t dev, short events, int anyyet, short *reventsp,
347 struct pollhead **phpp);
348
349 static int rsm_info(dev_info_t *, ddi_info_cmd_t, void *, void **);
350 static int rsm_attach(dev_info_t *, ddi_attach_cmd_t);
351 static int rsm_detach(dev_info_t *, ddi_detach_cmd_t);
352
353 static int rsmipc_send(rsm_node_id_t, rsmipc_request_t *, rsmipc_reply_t *);
354 static void rsm_force_unload(rsm_node_id_t, rsm_memseg_id_t, boolean_t);
355 static void rsm_send_importer_disconnects(rsm_memseg_id_t, rsm_node_id_t);
356 static void rsm_send_republish(rsm_memseg_id_t, rsmapi_access_entry_t *, int,
357 rsm_permission_t);
358 static void rsm_export_force_destroy(ddi_umem_cookie_t *);
359 static void rsmacl_free(rsmapi_access_entry_t *, int);
360 static void rsmpiacl_free(rsm_access_entry_t *, int);
361
362 static int rsm_inc_pgcnt(pgcnt_t);
363 static void rsm_dec_pgcnt(pgcnt_t);
364 static void rsm_free_mapinfo(rsm_mapinfo_t *mapinfop);
365 static rsm_mapinfo_t *rsm_get_mapinfo(rsmseg_t *, off_t, size_t, off_t *,
366 size_t *);
367 static void exporter_quiesce();
368 static void rsmseg_suspend(rsmseg_t *, int *);
369 static void rsmsegshare_suspend(rsmseg_t *);
370 static int rsmseg_resume(rsmseg_t *, void **);
371 static int rsmsegshare_resume(rsmseg_t *);
372
373 static struct cb_ops rsm_cb_ops = {
374 rsm_open, /* open */
375 rsm_close, /* close */
376 nodev, /* strategy */
377 nodev, /* print */
378 nodev, /* dump */
379 nodev, /* read */
380 nodev, /* write */
381 rsm_ioctl, /* ioctl */
382 rsm_devmap, /* devmap */
383 NULL, /* mmap */
384 rsm_segmap, /* segmap */
385 rsm_chpoll, /* poll */
386 ddi_prop_op, /* cb_prop_op */
387 0, /* streamtab */
388 D_NEW|D_MP|D_DEVMAP, /* Driver compatibility flag */
389 0,
390 0,
391 0
392 };
393
394 static struct dev_ops rsm_ops = {
395 DEVO_REV, /* devo_rev, */
396 0, /* refcnt */
397 rsm_info, /* get_dev_info */
398 nulldev, /* identify */
399 nulldev, /* probe */
400 rsm_attach, /* attach */
401 rsm_detach, /* detach */
402 nodev, /* reset */
403 &rsm_cb_ops, /* driver operations */
404 (struct bus_ops *)0, /* bus operations */
405 0,
406 ddi_quiesce_not_needed, /* quiesce */
407 };
408
409 /*
410 * Module linkage information for the kernel.
411 */
412
413 static struct modldrv modldrv = {
414 &mod_driverops, /* Type of module. This one is a pseudo driver */
415 "Remote Shared Memory Driver",
416 &rsm_ops, /* driver ops */
417 };
418
419 static struct modlinkage modlinkage = {
420 MODREV_1,
421 (void *)&modldrv,
422 0,
423 0,
424 0
425 };
426
427 static void rsm_dr_callback_post_add(void *arg, pgcnt_t delta);
428 static int rsm_dr_callback_pre_del(void *arg, pgcnt_t delta);
429 static void rsm_dr_callback_post_del(void *arg, pgcnt_t delta, int cancelled);
430
431 static kphysm_setup_vector_t rsm_dr_callback_vec = {
432 KPHYSM_SETUP_VECTOR_VERSION,
433 rsm_dr_callback_post_add,
434 rsm_dr_callback_pre_del,
435 rsm_dr_callback_post_del
436 };
437
438 /* This flag can be changed to 0 to help with PIT testing */
439 int rsmka_modunloadok = 1;
440 int no_reply_cnt = 0;
441
442 uint64_t rsm_ctrlmsg_errcnt = 0;
443 uint64_t rsm_ipcsend_errcnt = 0;
444
445 #define MAX_NODES 64
446
447 static struct rsm_driver_data rsm_drv_data;
448 static struct rsmresource_table rsm_resource;
449
450 static void rsmresource_insert(minor_t, rsmresource_t *, rsm_resource_type_t);
451 static void rsmresource_destroy(void);
452 static int rsmresource_alloc(minor_t *);
453 static rsmresource_t *rsmresource_free(minor_t rnum);
454 static int rsm_closeconnection(rsmseg_t *seg, void **cookie);
455 static int rsm_unpublish(rsmseg_t *seg, int mode);
456 static int rsm_unbind(rsmseg_t *seg);
457 static uint_t rsmhash(rsm_memseg_id_t key);
458 static void rsmhash_alloc(rsmhash_table_t *rhash, int size);
459 static void rsmhash_free(rsmhash_table_t *rhash, int size);
460 static void *rsmhash_getbkt(rsmhash_table_t *rhash, uint_t hashval);
461 static void **rsmhash_bktaddr(rsmhash_table_t *rhash, uint_t hashval);
462 static int rsm_send_notimporting(rsm_node_id_t dest, rsm_memseg_id_t segid,
463 void *cookie);
464 int rsm_disconnect(rsmseg_t *seg);
465 void rsmseg_unload(rsmseg_t *);
466 void rsm_suspend_complete(rsm_node_id_t src_node, int flag);
467
468 rsm_intr_hand_ret_t rsm_srv_func(rsm_controller_object_t *chd,
469 rsm_intr_q_op_t opcode, rsm_addr_t src,
470 void *data, size_t size, rsm_intr_hand_arg_t arg);
471
472 static void rsm_intr_callback(void *, rsm_addr_t, rsm_intr_hand_arg_t);
473
474 rsm_node_id_t my_nodeid;
475
476 /* cookie, va, offsets and length for the barrier */
477 static rsm_gnum_t *bar_va;
478 static ddi_umem_cookie_t bar_cookie;
479 static off_t barrier_offset;
480 static size_t barrier_size;
481 static int max_segs;
482
483 /* cookie for the trash memory */
484 static ddi_umem_cookie_t remap_cookie;
485
486 static rsm_memseg_id_t rsm_nextavail_segmentid;
487
488 extern taskq_t *work_taskq;
489 extern char *taskq_name;
490
491 static dev_info_t *rsm_dip; /* private copy of devinfo pointer */
492
493 static rsmhash_table_t rsm_export_segs; /* list of exported segs */
494 rsmhash_table_t rsm_import_segs; /* list of imported segs */
495 static rsmhash_table_t rsm_event_queues; /* list of event queues */
496
497 static rsm_ipc_t rsm_ipc; /* ipc info */
498
499 /* list of nodes to which RSMIPC_MSG_SUSPEND has been sent */
500 static list_head_t rsm_suspend_list;
501
502 /* list of descriptors for remote importers */
503 static importers_table_t importer_list;
504
505 kmutex_t rsm_suspend_cvlock;
506 kcondvar_t rsm_suspend_cv;
507
508 static kmutex_t rsm_lock;
509
510 adapter_t loopback_adapter;
511 rsm_controller_attr_t loopback_attr;
512
513 int rsmipc_send_controlmsg(path_t *path, int msgtype);
514
515 void rsmka_init_loopback();
516
517 int rsmka_null_seg_create(
518 rsm_controller_handle_t,
519 rsm_memseg_export_handle_t *,
520 size_t,
521 uint_t,
522 rsm_memory_local_t *,
523 rsm_resource_callback_t,
524 rsm_resource_callback_arg_t);
525
526 int rsmka_null_seg_destroy(
527 rsm_memseg_export_handle_t);
528
529 int rsmka_null_bind(
530 rsm_memseg_export_handle_t,
531 off_t,
532 rsm_memory_local_t *,
533 rsm_resource_callback_t,
534 rsm_resource_callback_arg_t);
535
536 int rsmka_null_unbind(
537 rsm_memseg_export_handle_t,
538 off_t,
539 size_t);
540
541 int rsmka_null_rebind(
542 rsm_memseg_export_handle_t,
543 off_t,
544 rsm_memory_local_t *,
545 rsm_resource_callback_t,
546 rsm_resource_callback_arg_t);
547
548 int rsmka_null_publish(
549 rsm_memseg_export_handle_t,
550 rsm_access_entry_t [],
551 uint_t,
552 rsm_memseg_id_t,
553 rsm_resource_callback_t,
554 rsm_resource_callback_arg_t);
555
556
557 int rsmka_null_republish(
558 rsm_memseg_export_handle_t,
559 rsm_access_entry_t [],
560 uint_t,
561 rsm_resource_callback_t,
562 rsm_resource_callback_arg_t);
563
564 int rsmka_null_unpublish(
565 rsm_memseg_export_handle_t);
566
567 rsm_ops_t null_rsmpi_ops;
568
569 /*
570 * data and locks to keep track of total amount of exported memory
571 */
572 static pgcnt_t rsm_pgcnt;
573 static pgcnt_t rsm_pgcnt_max; /* max allowed */
574 static kmutex_t rsm_pgcnt_lock;
575
576 static int rsm_enable_dr;
577
578 static char loopback_str[] = "loopback";
579
580 int rsm_hash_size;
581
582 /*
583 * The locking model is as follows:
584 *
585 * Local operations:
586 * find resource - grab reader lock on resouce list
587 * insert rc - grab writer lock
588 * delete rc - grab writer lock and resource mutex
589 * read/write - no lock
590 *
591 * Remote invocations:
592 * find resource - grab read lock and resource mutex
593 *
594 * State:
595 * resource state - grab resource mutex
596 */
597
598 int
_init(void)599 _init(void)
600 {
601 int e;
602
603 e = mod_install(&modlinkage);
604 if (e != 0) {
605 return (e);
606 }
607
608 mutex_init(&rsm_lock, NULL, MUTEX_DRIVER, NULL);
609
610 mutex_init(&rsmka_buf_lock, NULL, MUTEX_DEFAULT, NULL);
611
612
613 rw_init(&rsm_resource.rsmrc_lock, NULL, RW_DRIVER, NULL);
614
615 rsm_hash_size = RSM_HASHSZ;
616
617 rw_init(&rsm_export_segs.rsmhash_rw, NULL, RW_DRIVER, NULL);
618
619 rw_init(&rsm_import_segs.rsmhash_rw, NULL, RW_DRIVER, NULL);
620
621 mutex_init(&importer_list.lock, NULL, MUTEX_DRIVER, NULL);
622
623 mutex_init(&rsm_ipc.lock, NULL, MUTEX_DRIVER, NULL);
624 cv_init(&rsm_ipc.cv, NULL, CV_DRIVER, 0);
625
626 mutex_init(&rsm_suspend_cvlock, NULL, MUTEX_DRIVER, NULL);
627 cv_init(&rsm_suspend_cv, NULL, CV_DRIVER, 0);
628
629 mutex_init(&rsm_drv_data.drv_lock, NULL, MUTEX_DRIVER, NULL);
630 cv_init(&rsm_drv_data.drv_cv, NULL, CV_DRIVER, 0);
631
632 rsm_ipc.count = RSMIPC_SZ;
633 rsm_ipc.wanted = 0;
634 rsm_ipc.sequence = 0;
635
636 (void) mutex_init(&rsm_pgcnt_lock, NULL, MUTEX_DRIVER, NULL);
637
638 for (e = 0; e < RSMIPC_SZ; e++) {
639 rsmipc_slot_t *slot = &rsm_ipc.slots[e];
640
641 RSMIPC_SET(slot, RSMIPC_FREE);
642 mutex_init(&slot->rsmipc_lock, NULL, MUTEX_DRIVER, NULL);
643 cv_init(&slot->rsmipc_cv, NULL, CV_DRIVER, 0);
644 }
645
646 /*
647 * Initialize the suspend message list
648 */
649 rsm_suspend_list.list_head = NULL;
650 mutex_init(&rsm_suspend_list.list_lock, NULL, MUTEX_DRIVER, NULL);
651
652 /*
653 * It is assumed here that configuration data is available
654 * during system boot since _init may be called at that time.
655 */
656
657 rsmka_pathmanager_init();
658
659 DBG_PRINTF((RSM_KERNEL_AGENT, RSM_DEBUG_VERBOSE,
660 "rsm: _init done\n"));
661
662 return (DDI_SUCCESS);
663
664 }
665
666 int
_info(struct modinfo * modinfop)667 _info(struct modinfo *modinfop)
668 {
669
670 return (mod_info(&modlinkage, modinfop));
671 }
672
673 int
_fini(void)674 _fini(void)
675 {
676 int e;
677
678 DBG_PRINTF((RSM_KERNEL_AGENT, RSM_DEBUG_VERBOSE,
679 "rsm: _fini enter\n"));
680
681 /*
682 * The rsmka_modunloadok flag is simply used to help with
683 * the PIT testing. Make this flag 0 to disallow modunload.
684 */
685 if (rsmka_modunloadok == 0)
686 return (EBUSY);
687
688 /* rsm_detach will be called as a result of mod_remove */
689 e = mod_remove(&modlinkage);
690 if (e) {
691 DBG_PRINTF((RSM_KERNEL_AGENT, RSM_ERR,
692 "Unable to fini RSM %x\n", e));
693 return (e);
694 }
695
696 rsmka_pathmanager_cleanup();
697
698 rw_destroy(&rsm_resource.rsmrc_lock);
699
700 rw_destroy(&rsm_export_segs.rsmhash_rw);
701 rw_destroy(&rsm_import_segs.rsmhash_rw);
702 rw_destroy(&rsm_event_queues.rsmhash_rw);
703
704 mutex_destroy(&importer_list.lock);
705
706 mutex_destroy(&rsm_ipc.lock);
707 cv_destroy(&rsm_ipc.cv);
708
709 (void) mutex_destroy(&rsm_suspend_list.list_lock);
710
711 (void) mutex_destroy(&rsm_pgcnt_lock);
712
713 DBG_PRINTF((RSM_KERNEL_AGENT, RSM_DEBUG_VERBOSE, "_fini done\n"));
714
715 return (DDI_SUCCESS);
716
717 }
718
719 /*ARGSUSED1*/
720 static int
rsm_attach(dev_info_t * devi,ddi_attach_cmd_t cmd)721 rsm_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
722 {
723 minor_t rnum;
724 int percent;
725 int ret;
726 DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_DDI);
727
728 DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_attach enter\n"));
729
730 switch (cmd) {
731 case DDI_ATTACH:
732 break;
733 case DDI_RESUME:
734 default:
735 DBG_PRINTF((category, RSM_ERR,
736 "rsm:rsm_attach - cmd not supported\n"));
737 return (DDI_FAILURE);
738 }
739
740 if (rsm_dip != NULL) {
741 DBG_PRINTF((category, RSM_ERR,
742 "rsm:rsm_attach - supports only "
743 "one instance\n"));
744 return (DDI_FAILURE);
745 }
746
747 rsm_enable_dr = ddi_prop_get_int(DDI_DEV_T_ANY, devi,
748 DDI_PROP_DONTPASS | DDI_PROP_NOTPROM,
749 "enable-dynamic-reconfiguration", 1);
750
751 mutex_enter(&rsm_drv_data.drv_lock);
752 rsm_drv_data.drv_state = RSM_DRV_REG_PROCESSING;
753 mutex_exit(&rsm_drv_data.drv_lock);
754
755 if (rsm_enable_dr) {
756 #ifdef RSM_DRTEST
757 ret = rsm_kphysm_setup_func_register(&rsm_dr_callback_vec,
758 (void *)NULL);
759 #else
760 ret = kphysm_setup_func_register(&rsm_dr_callback_vec,
761 (void *)NULL);
762 #endif
763 if (ret != 0) {
764 mutex_exit(&rsm_drv_data.drv_lock);
765 cmn_err(CE_CONT, "rsm:rsm_attach - Dynamic "
766 "reconfiguration setup failed\n");
767 return (DDI_FAILURE);
768 }
769 }
770
771 mutex_enter(&rsm_drv_data.drv_lock);
772 ASSERT(rsm_drv_data.drv_state == RSM_DRV_REG_PROCESSING);
773 rsm_drv_data.drv_state = RSM_DRV_OK;
774 cv_broadcast(&rsm_drv_data.drv_cv);
775 mutex_exit(&rsm_drv_data.drv_lock);
776
777 /*
778 * page_list_read_lock();
779 * xx_setup();
780 * page_list_read_unlock();
781 */
782
783 rsm_hash_size = ddi_prop_get_int(DDI_DEV_T_ANY, devi,
784 DDI_PROP_DONTPASS | DDI_PROP_NOTPROM,
785 "segment-hashtable-size", RSM_HASHSZ);
786 if (rsm_hash_size == 0) {
787 DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
788 "rsm: segment-hashtable-size in rsm.conf "
789 "must be greater than 0, defaulting to 128\n"));
790 rsm_hash_size = RSM_HASHSZ;
791 }
792
793 DBG_PRINTF((category, RSM_DEBUG, "rsm_attach rsm_hash_size: %d\n",
794 rsm_hash_size));
795
796 rsm_pgcnt = 0;
797
798 percent = ddi_prop_get_int(DDI_DEV_T_ANY, devi,
799 DDI_PROP_DONTPASS | DDI_PROP_NOTPROM,
800 "max-exported-memory", 0);
801 if (percent < 0) {
802 DBG_PRINTF((category, RSM_ERR,
803 "rsm:rsm_attach not enough memory available to "
804 "export, or max-exported-memory set incorrectly.\n"));
805 return (DDI_FAILURE);
806 }
807 /* 0 indicates no fixed upper limit. maxmem is the max */
808 /* available pageable physical mem */
809 rsm_pgcnt_max = (percent*maxmem)/100;
810
811 if (rsm_pgcnt_max > 0) {
812 DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
813 "rsm: Available physical memory = %lu pages, "
814 "Max exportable memory = %lu pages",
815 maxmem, rsm_pgcnt_max));
816 }
817
818 /*
819 * Create minor number
820 */
821 if (rsmresource_alloc(&rnum) != RSM_SUCCESS) {
822 DBG_PRINTF((category, RSM_ERR,
823 "rsm: rsm_attach - Unable to get "
824 "minor number\n"));
825 return (DDI_FAILURE);
826 }
827
828 ASSERT(rnum == RSM_DRIVER_MINOR);
829
830 if (ddi_create_minor_node(devi, DRIVER_NAME, S_IFCHR,
831 rnum, DDI_PSEUDO, 0) == DDI_FAILURE) {
832 DBG_PRINTF((category, RSM_ERR,
833 "rsm: rsm_attach - unable to allocate "
834 "minor #\n"));
835 return (DDI_FAILURE);
836 }
837
838 rsm_dip = devi;
839 /*
840 * Allocate the hashtables
841 */
842 rsmhash_alloc(&rsm_export_segs, rsm_hash_size);
843 rsmhash_alloc(&rsm_import_segs, rsm_hash_size);
844
845 importer_list.bucket = (importing_token_t **)
846 kmem_zalloc(rsm_hash_size * sizeof (importing_token_t *), KM_SLEEP);
847
848 /*
849 * Allocate a resource struct
850 */
851 {
852 rsmresource_t *p;
853
854 p = (rsmresource_t *)kmem_zalloc(sizeof (*p), KM_SLEEP);
855
856 mutex_init(&p->rsmrc_lock, NULL, MUTEX_DRIVER, (void *) NULL);
857
858 rsmresource_insert(rnum, p, RSM_RESOURCE_BAR);
859 }
860
861 /*
862 * Based on the rsm.conf property max-segments, determine the maximum
863 * number of segments that can be exported/imported. This is then used
864 * to determine the size for barrier failure pages.
865 */
866
867 /* First get the max number of segments from the rsm.conf file */
868 max_segs = ddi_prop_get_int(DDI_DEV_T_ANY, devi,
869 DDI_PROP_DONTPASS | DDI_PROP_NOTPROM,
870 "max-segments", 0);
871 if (max_segs == 0) {
872 /* Use default number of segments */
873 max_segs = RSM_MAX_NUM_SEG;
874 }
875
876 /*
877 * Based on the max number of segments allowed, determine the barrier
878 * page size. add 1 to max_segs since the barrier page itself uses
879 * a slot
880 */
881 barrier_size = roundup((max_segs + 1) * sizeof (rsm_gnum_t),
882 PAGESIZE);
883
884 /*
885 * allocation of the barrier failure page
886 */
887 bar_va = (rsm_gnum_t *)ddi_umem_alloc(barrier_size,
888 DDI_UMEM_SLEEP, &bar_cookie);
889
890 /*
891 * Set the barrier_offset
892 */
893 barrier_offset = 0;
894
895 /*
896 * Allocate a trash memory and get a cookie for it. This will be used
897 * when remapping segments during force disconnects. Allocate the
898 * trash memory with a large size which is page aligned.
899 */
900 (void) ddi_umem_alloc((size_t)TRASHSIZE,
901 DDI_UMEM_TRASH, &remap_cookie);
902
903 /* initialize user segment id allocation variable */
904 rsm_nextavail_segmentid = (rsm_memseg_id_t)RSM_USER_APP_ID_BASE;
905
906 /*
907 * initialize the null_rsmpi_ops vector and the loopback adapter
908 */
909 rsmka_init_loopback();
910
911
912 ddi_report_dev(devi);
913
914 DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_attach done\n"));
915
916 return (DDI_SUCCESS);
917 }
918
919 /*
920 * The call to mod_remove in the _fine routine will cause the system
921 * to call rsm_detach
922 */
923 /*ARGSUSED*/
924 static int
rsm_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)925 rsm_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
926 {
927 DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_DDI);
928
929 DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_detach enter\n"));
930
931 switch (cmd) {
932 case DDI_DETACH:
933 break;
934 default:
935 DBG_PRINTF((category, RSM_ERR,
936 "rsm:rsm_detach - cmd %x not supported\n",
937 cmd));
938 return (DDI_FAILURE);
939 }
940
941 mutex_enter(&rsm_drv_data.drv_lock);
942 while (rsm_drv_data.drv_state != RSM_DRV_OK)
943 cv_wait(&rsm_drv_data.drv_cv, &rsm_drv_data.drv_lock);
944 rsm_drv_data.drv_state = RSM_DRV_UNREG_PROCESSING;
945 mutex_exit(&rsm_drv_data.drv_lock);
946
947 /*
948 * Unregister the DR callback functions
949 */
950 if (rsm_enable_dr) {
951 #ifdef RSM_DRTEST
952 rsm_kphysm_setup_func_unregister(&rsm_dr_callback_vec,
953 (void *)NULL);
954 #else
955 kphysm_setup_func_unregister(&rsm_dr_callback_vec,
956 (void *)NULL);
957 #endif
958 }
959
960 mutex_enter(&rsm_drv_data.drv_lock);
961 ASSERT(rsm_drv_data.drv_state == RSM_DRV_UNREG_PROCESSING);
962 rsm_drv_data.drv_state = RSM_DRV_NEW;
963 mutex_exit(&rsm_drv_data.drv_lock);
964
965 ASSERT(rsm_suspend_list.list_head == NULL);
966
967 /*
968 * Release all resources, seglist, controller, ...
969 */
970
971 /* remove intersend queues */
972 /* remove registered services */
973
974
975 ddi_remove_minor_node(dip, DRIVER_NAME);
976 rsm_dip = NULL;
977
978 /*
979 * Free minor zero resource
980 */
981 {
982 rsmresource_t *p;
983
984 p = rsmresource_free(RSM_DRIVER_MINOR);
985 if (p) {
986 mutex_destroy(&p->rsmrc_lock);
987 kmem_free((void *)p, sizeof (*p));
988 }
989 }
990
991 /*
992 * Free resource table
993 */
994
995 rsmresource_destroy();
996
997 /*
998 * Free the hash tables
999 */
1000 rsmhash_free(&rsm_export_segs, rsm_hash_size);
1001 rsmhash_free(&rsm_import_segs, rsm_hash_size);
1002
1003 kmem_free((void *)importer_list.bucket,
1004 rsm_hash_size * sizeof (importing_token_t *));
1005 importer_list.bucket = NULL;
1006
1007
1008 /* free barrier page */
1009 if (bar_cookie != NULL) {
1010 ddi_umem_free(bar_cookie);
1011 }
1012 bar_va = NULL;
1013 bar_cookie = NULL;
1014
1015 /*
1016 * Free the memory allocated for the trash
1017 */
1018 if (remap_cookie != NULL) {
1019 ddi_umem_free(remap_cookie);
1020 }
1021 remap_cookie = NULL;
1022
1023 DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_detach done\n"));
1024
1025 return (DDI_SUCCESS);
1026 }
1027
1028 /*ARGSUSED*/
1029 static int
rsm_info(dev_info_t * dip,ddi_info_cmd_t infocmd,void * arg,void ** result)1030 rsm_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
1031 {
1032 register int error;
1033 DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_DDI);
1034
1035 DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_info enter\n"));
1036
1037 switch (infocmd) {
1038 case DDI_INFO_DEVT2DEVINFO:
1039 if (rsm_dip == NULL)
1040 error = DDI_FAILURE;
1041 else {
1042 *result = (void *)rsm_dip;
1043 error = DDI_SUCCESS;
1044 }
1045 break;
1046 case DDI_INFO_DEVT2INSTANCE:
1047 *result = (void *)0;
1048 error = DDI_SUCCESS;
1049 break;
1050 default:
1051 error = DDI_FAILURE;
1052 }
1053
1054 DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_info done\n"));
1055 return (error);
1056 }
1057
1058 adapter_t *
rsm_getadapter(rsm_ioctlmsg_t * msg,int mode)1059 rsm_getadapter(rsm_ioctlmsg_t *msg, int mode)
1060 {
1061 adapter_t *adapter;
1062 char adapter_devname[MAXNAMELEN];
1063 int instance;
1064 DBG_DEFINE(category,
1065 RSM_KERNEL_AGENT | RSM_IMPORT | RSM_EXPORT | RSM_IOCTL);
1066
1067 DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_getadapter enter\n"));
1068
1069 instance = msg->cnum;
1070
1071 if ((msg->cname_len <= 0) || (msg->cname_len > MAXNAMELEN)) {
1072 return (NULL);
1073 }
1074
1075 if (ddi_copyin(msg->cname, adapter_devname, msg->cname_len, mode))
1076 return (NULL);
1077
1078 if (strcmp(adapter_devname, "loopback") == 0)
1079 return (&loopback_adapter);
1080
1081 adapter = rsmka_lookup_adapter(adapter_devname, instance);
1082
1083 DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_getadapter done\n"));
1084
1085 return (adapter);
1086 }
1087
1088
1089 /*
1090 * *********************** Resource Number Management ********************
1091 * All resources are stored in a simple hash table. The table is an array
1092 * of pointers to resource blks. Each blk contains:
1093 * base - base number of this blk
1094 * used - number of used slots in this blk.
1095 * blks - array of pointers to resource items.
1096 * An entry in a resource blk is empty if it's NULL.
1097 *
1098 * We start with no resource array. Each time we run out of slots, we
1099 * reallocate a new larger array and copy the pointer to the new array and
1100 * a new resource blk is allocated and added to the hash table.
1101 *
1102 * The resource control block contains:
1103 * root - array of pointer of resource blks
1104 * sz - current size of array.
1105 * len - last valid entry in array.
1106 *
1107 * A search operation based on a resource number is as follows:
1108 * index = rnum / RESOURCE_BLKSZ;
1109 * ASSERT(index < resource_block.len);
1110 * ASSERT(index < resource_block.sz);
1111 * offset = rnum % RESOURCE_BLKSZ;
1112 * ASSERT(offset >= resource_block.root[index]->base);
1113 * ASSERT(offset < resource_block.root[index]->base + RESOURCE_BLKSZ);
1114 * return resource_block.root[index]->blks[offset];
1115 *
1116 * A resource blk is freed with its used count reachs zero.
1117 */
1118 static int
rsmresource_alloc(minor_t * rnum)1119 rsmresource_alloc(minor_t *rnum)
1120 {
1121
1122 /* search for available resource slot */
1123 int i, j, empty = -1;
1124 rsmresource_blk_t *blk;
1125
1126 DBG_PRINTF((RSM_KERNEL_ALL, RSM_DEBUG_VERBOSE,
1127 "rsmresource_alloc enter\n"));
1128
1129 rw_enter(&rsm_resource.rsmrc_lock, RW_WRITER);
1130
1131 /* Try to find an empty slot */
1132 for (i = 0; i < rsm_resource.rsmrc_len; i++) {
1133 blk = rsm_resource.rsmrc_root[i];
1134 if (blk != NULL && blk->rsmrcblk_avail > 0) {
1135 /* found an empty slot in this blk */
1136 for (j = 0; j < RSMRC_BLKSZ; j++) {
1137 if (blk->rsmrcblk_blks[j] == NULL) {
1138 *rnum = (minor_t)
1139 (j + (i * RSMRC_BLKSZ));
1140 /*
1141 * obey gen page limits
1142 */
1143 if (*rnum >= max_segs + 1) {
1144 if (empty < 0) {
1145 rw_exit(&rsm_resource.
1146 rsmrc_lock);
1147 DBG_PRINTF((
1148 RSM_KERNEL_ALL,
1149 RSM_ERR,
1150 "rsmresource"
1151 "_alloc failed:"
1152 "not enough res"
1153 "%d\n", *rnum));
1154 return (RSMERR_INSUFFICIENT_RESOURCES);
1155 } else {
1156 /* use empty slot */
1157 break;
1158 }
1159
1160 }
1161
1162 blk->rsmrcblk_blks[j] = RSMRC_RESERVED;
1163 blk->rsmrcblk_avail--;
1164 rw_exit(&rsm_resource.rsmrc_lock);
1165 DBG_PRINTF((RSM_KERNEL_ALL,
1166 RSM_DEBUG_VERBOSE,
1167 "rsmresource_alloc done\n"));
1168 return (RSM_SUCCESS);
1169 }
1170 }
1171 } else if (blk == NULL && empty < 0) {
1172 /* remember first empty slot */
1173 empty = i;
1174 }
1175 }
1176
1177 /* Couldn't find anything, allocate a new blk */
1178 /*
1179 * Do we need to reallocate the root array
1180 */
1181 if (empty < 0) {
1182 if (rsm_resource.rsmrc_len == rsm_resource.rsmrc_sz) {
1183 /*
1184 * Allocate new array and copy current stuff into it
1185 */
1186 rsmresource_blk_t **p;
1187 uint_t newsz = (uint_t)rsm_resource.rsmrc_sz +
1188 RSMRC_BLKSZ;
1189 /*
1190 * Don't allocate more that max valid rnum
1191 */
1192 if (rsm_resource.rsmrc_len*RSMRC_BLKSZ >=
1193 max_segs + 1) {
1194 rw_exit(&rsm_resource.rsmrc_lock);
1195 return (RSMERR_INSUFFICIENT_RESOURCES);
1196 }
1197
1198 p = (rsmresource_blk_t **)kmem_zalloc(
1199 newsz * sizeof (*p),
1200 KM_SLEEP);
1201
1202 if (rsm_resource.rsmrc_root) {
1203 uint_t oldsz;
1204
1205 oldsz = (uint_t)(rsm_resource.rsmrc_sz *
1206 (int)sizeof (*p));
1207
1208 /*
1209 * Copy old data into new space and
1210 * free old stuff
1211 */
1212 bcopy(rsm_resource.rsmrc_root, p, oldsz);
1213 kmem_free(rsm_resource.rsmrc_root, oldsz);
1214 }
1215
1216 rsm_resource.rsmrc_root = p;
1217 rsm_resource.rsmrc_sz = (int)newsz;
1218 }
1219
1220 empty = rsm_resource.rsmrc_len;
1221 rsm_resource.rsmrc_len++;
1222 }
1223
1224 /*
1225 * Allocate a new blk
1226 */
1227 blk = (rsmresource_blk_t *)kmem_zalloc(sizeof (*blk), KM_SLEEP);
1228 ASSERT(rsm_resource.rsmrc_root[empty] == NULL);
1229 rsm_resource.rsmrc_root[empty] = blk;
1230 blk->rsmrcblk_avail = RSMRC_BLKSZ - 1;
1231
1232 /*
1233 * Allocate slot
1234 */
1235
1236 *rnum = (minor_t)(empty * RSMRC_BLKSZ);
1237
1238 /*
1239 * watch out not to exceed bounds of barrier page
1240 */
1241 if (*rnum >= max_segs + 1) {
1242 rw_exit(&rsm_resource.rsmrc_lock);
1243 DBG_PRINTF((RSM_KERNEL_ALL, RSM_ERR,
1244 "rsmresource_alloc failed %d\n", *rnum));
1245
1246 return (RSMERR_INSUFFICIENT_RESOURCES);
1247 }
1248 blk->rsmrcblk_blks[0] = RSMRC_RESERVED;
1249
1250
1251 rw_exit(&rsm_resource.rsmrc_lock);
1252
1253 DBG_PRINTF((RSM_KERNEL_ALL, RSM_DEBUG_VERBOSE,
1254 "rsmresource_alloc done\n"));
1255
1256 return (RSM_SUCCESS);
1257 }
1258
1259 static rsmresource_t *
rsmresource_free(minor_t rnum)1260 rsmresource_free(minor_t rnum)
1261 {
1262
1263 /* search for available resource slot */
1264 int i, j;
1265 rsmresource_blk_t *blk;
1266 rsmresource_t *p;
1267
1268 DBG_PRINTF((RSM_KERNEL_ALL, RSM_DEBUG_VERBOSE,
1269 "rsmresource_free enter\n"));
1270
1271 i = (int)(rnum / RSMRC_BLKSZ);
1272 j = (int)(rnum % RSMRC_BLKSZ);
1273
1274 if (i >= rsm_resource.rsmrc_len) {
1275 DBG_PRINTF((RSM_KERNEL_ALL, RSM_DEBUG_VERBOSE,
1276 "rsmresource_free done\n"));
1277 return (NULL);
1278 }
1279
1280 rw_enter(&rsm_resource.rsmrc_lock, RW_WRITER);
1281
1282 ASSERT(rsm_resource.rsmrc_root);
1283 ASSERT(i < rsm_resource.rsmrc_len);
1284 ASSERT(i < rsm_resource.rsmrc_sz);
1285 blk = rsm_resource.rsmrc_root[i];
1286 if (blk == NULL) {
1287 rw_exit(&rsm_resource.rsmrc_lock);
1288 DBG_PRINTF((RSM_KERNEL_ALL, RSM_DEBUG_VERBOSE,
1289 "rsmresource_free done\n"));
1290 return (NULL);
1291 }
1292
1293 ASSERT(blk->rsmrcblk_blks[j]); /* reserved or full */
1294
1295 p = blk->rsmrcblk_blks[j];
1296 if (p == RSMRC_RESERVED) {
1297 p = NULL;
1298 }
1299
1300 blk->rsmrcblk_blks[j] = NULL;
1301 blk->rsmrcblk_avail++;
1302 if (blk->rsmrcblk_avail == RSMRC_BLKSZ) {
1303 /* free this blk */
1304 kmem_free(blk, sizeof (*blk));
1305 rsm_resource.rsmrc_root[i] = NULL;
1306 }
1307
1308 rw_exit(&rsm_resource.rsmrc_lock);
1309
1310 DBG_PRINTF((RSM_KERNEL_ALL, RSM_DEBUG_VERBOSE,
1311 "rsmresource_free done\n"));
1312
1313 return (p);
1314 }
1315
1316 static rsmresource_t *
rsmresource_lookup(minor_t rnum,int lock)1317 rsmresource_lookup(minor_t rnum, int lock)
1318 {
1319 int i, j;
1320 rsmresource_blk_t *blk;
1321 rsmresource_t *p;
1322
1323 DBG_PRINTF((RSM_KERNEL_ALL, RSM_DEBUG_VERBOSE,
1324 "rsmresource_lookup enter\n"));
1325
1326 /* Find resource and lock it in READER mode */
1327 /* search for available resource slot */
1328
1329 i = (int)(rnum / RSMRC_BLKSZ);
1330 j = (int)(rnum % RSMRC_BLKSZ);
1331
1332 if (i >= rsm_resource.rsmrc_len) {
1333 DBG_PRINTF((RSM_KERNEL_ALL, RSM_DEBUG_VERBOSE,
1334 "rsmresource_lookup done\n"));
1335 return (NULL);
1336 }
1337
1338 rw_enter(&rsm_resource.rsmrc_lock, RW_READER);
1339
1340 blk = rsm_resource.rsmrc_root[i];
1341 if (blk != NULL) {
1342 ASSERT(i < rsm_resource.rsmrc_len);
1343 ASSERT(i < rsm_resource.rsmrc_sz);
1344
1345 p = blk->rsmrcblk_blks[j];
1346 if (lock == RSM_LOCK) {
1347 if (p != RSMRC_RESERVED) {
1348 mutex_enter(&p->rsmrc_lock);
1349 } else {
1350 p = NULL;
1351 }
1352 }
1353 } else {
1354 p = NULL;
1355 }
1356 rw_exit(&rsm_resource.rsmrc_lock);
1357
1358 DBG_PRINTF((RSM_KERNEL_ALL, RSM_DEBUG_VERBOSE,
1359 "rsmresource_lookup done\n"));
1360
1361 return (p);
1362 }
1363
1364 static void
rsmresource_insert(minor_t rnum,rsmresource_t * p,rsm_resource_type_t type)1365 rsmresource_insert(minor_t rnum, rsmresource_t *p, rsm_resource_type_t type)
1366 {
1367 /* Find resource and lock it in READER mode */
1368 /* Caller can upgrade if need be */
1369 /* search for available resource slot */
1370 int i, j;
1371 rsmresource_blk_t *blk;
1372
1373 DBG_PRINTF((RSM_KERNEL_ALL, RSM_DEBUG_VERBOSE,
1374 "rsmresource_insert enter\n"));
1375
1376 i = (int)(rnum / RSMRC_BLKSZ);
1377 j = (int)(rnum % RSMRC_BLKSZ);
1378
1379 p->rsmrc_type = type;
1380 p->rsmrc_num = rnum;
1381
1382 rw_enter(&rsm_resource.rsmrc_lock, RW_READER);
1383
1384 ASSERT(rsm_resource.rsmrc_root);
1385 ASSERT(i < rsm_resource.rsmrc_len);
1386 ASSERT(i < rsm_resource.rsmrc_sz);
1387
1388 blk = rsm_resource.rsmrc_root[i];
1389 ASSERT(blk);
1390
1391 ASSERT(blk->rsmrcblk_blks[j] == RSMRC_RESERVED);
1392
1393 blk->rsmrcblk_blks[j] = p;
1394
1395 DBG_PRINTF((RSM_KERNEL_ALL, RSM_DEBUG_VERBOSE,
1396 "rsmresource_insert done\n"));
1397
1398 rw_exit(&rsm_resource.rsmrc_lock);
1399 }
1400
1401 static void
rsmresource_destroy()1402 rsmresource_destroy()
1403 {
1404 int i, j;
1405
1406 DBG_PRINTF((RSM_KERNEL_ALL, RSM_DEBUG_VERBOSE,
1407 "rsmresource_destroy enter\n"));
1408
1409 rw_enter(&rsm_resource.rsmrc_lock, RW_WRITER);
1410
1411 for (i = 0; i < rsm_resource.rsmrc_len; i++) {
1412 rsmresource_blk_t *blk;
1413
1414 blk = rsm_resource.rsmrc_root[i];
1415 if (blk == NULL) {
1416 continue;
1417 }
1418 for (j = 0; j < RSMRC_BLKSZ; j++) {
1419 if (blk->rsmrcblk_blks[j] != NULL) {
1420 DBG_PRINTF((RSM_KERNEL_ALL, RSM_DEBUG_VERBOSE,
1421 "Not null slot %d, %lx\n", j,
1422 (size_t)blk->rsmrcblk_blks[j]));
1423 }
1424 }
1425 kmem_free(blk, sizeof (*blk));
1426 rsm_resource.rsmrc_root[i] = NULL;
1427 }
1428 if (rsm_resource.rsmrc_root) {
1429 i = rsm_resource.rsmrc_sz * (int)sizeof (rsmresource_blk_t *);
1430 kmem_free(rsm_resource.rsmrc_root, (uint_t)i);
1431 rsm_resource.rsmrc_root = NULL;
1432 rsm_resource.rsmrc_len = 0;
1433 rsm_resource.rsmrc_sz = 0;
1434 }
1435
1436 DBG_PRINTF((RSM_KERNEL_ALL, RSM_DEBUG_VERBOSE,
1437 "rsmresource_destroy done\n"));
1438
1439 rw_exit(&rsm_resource.rsmrc_lock);
1440 }
1441
1442
1443 /* ******************** Generic Key Hash Table Management ********* */
1444 static rsmresource_t *
rsmhash_lookup(rsmhash_table_t * rhash,rsm_memseg_id_t key,rsm_resource_state_t state)1445 rsmhash_lookup(rsmhash_table_t *rhash, rsm_memseg_id_t key,
1446 rsm_resource_state_t state)
1447 {
1448 rsmresource_t *p;
1449 uint_t hashval;
1450 DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_FUNC_ALL);
1451
1452 DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmhash_lookup enter\n"));
1453
1454 hashval = rsmhash(key);
1455
1456 DBG_PRINTF((category, RSM_DEBUG_LVL2, "rsmhash_lookup %u=%d\n",
1457 key, hashval));
1458
1459 rw_enter(&rhash->rsmhash_rw, RW_READER);
1460
1461 p = (rsmresource_t *)rsmhash_getbkt(rhash, hashval);
1462
1463 for (; p; p = p->rsmrc_next) {
1464 if (p->rsmrc_key == key) {
1465 /* acquire resource lock */
1466 RSMRC_LOCK(p);
1467 break;
1468 }
1469 }
1470
1471 rw_exit(&rhash->rsmhash_rw);
1472
1473 if (p != NULL && p->rsmrc_state != state) {
1474 /* state changed, release lock and return null */
1475 RSMRC_UNLOCK(p);
1476 DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
1477 "rsmhash_lookup done: state changed\n"));
1478 return (NULL);
1479 }
1480
1481 DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmhash_lookup done\n"));
1482
1483 return (p);
1484 }
1485
1486 static void
rsmhash_rm(rsmhash_table_t * rhash,rsmresource_t * rcelm)1487 rsmhash_rm(rsmhash_table_t *rhash, rsmresource_t *rcelm)
1488 {
1489 rsmresource_t *p, **back;
1490 uint_t hashval;
1491 DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_FUNC_ALL);
1492
1493 DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmhash_rm enter\n"));
1494
1495 hashval = rsmhash(rcelm->rsmrc_key);
1496
1497 DBG_PRINTF((category, RSM_DEBUG_LVL2, "rsmhash_rm %u=%d\n",
1498 rcelm->rsmrc_key, hashval));
1499
1500 /*
1501 * It's ok not to find the segment.
1502 */
1503 rw_enter(&rhash->rsmhash_rw, RW_WRITER);
1504
1505 back = (rsmresource_t **)rsmhash_bktaddr(rhash, hashval);
1506
1507 for (; (p = *back) != NULL; back = &p->rsmrc_next) {
1508 if (p == rcelm) {
1509 *back = rcelm->rsmrc_next;
1510 break;
1511 }
1512 }
1513
1514 DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmhash_rm done\n"));
1515
1516 rw_exit(&rhash->rsmhash_rw);
1517 }
1518
1519 static int
rsmhash_add(rsmhash_table_t * rhash,rsmresource_t * new,rsm_memseg_id_t key,int dup_check,rsm_resource_state_t state)1520 rsmhash_add(rsmhash_table_t *rhash, rsmresource_t *new, rsm_memseg_id_t key,
1521 int dup_check, rsm_resource_state_t state)
1522 {
1523 rsmresource_t *p = NULL, **bktp;
1524 uint_t hashval;
1525 DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_FUNC_ALL);
1526
1527 DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmhash_add enter\n"));
1528
1529 /* lock table */
1530 rw_enter(&rhash->rsmhash_rw, RW_WRITER);
1531
1532 /*
1533 * If the current resource state is other than the state passed in
1534 * then the resource is (probably) already on the list. eg. for an
1535 * import segment if the state is not RSM_STATE_NEW then it's on the
1536 * list already.
1537 */
1538 RSMRC_LOCK(new);
1539 if (new->rsmrc_state != state) {
1540 RSMRC_UNLOCK(new);
1541 rw_exit(&rhash->rsmhash_rw);
1542 return (RSMERR_BAD_SEG_HNDL);
1543 }
1544
1545 hashval = rsmhash(key);
1546 DBG_PRINTF((category, RSM_DEBUG_LVL2, "rsmhash_add %d\n", hashval));
1547
1548 if (dup_check) {
1549 /*
1550 * Used for checking export segments; don't want to have
1551 * the same key used for multiple segments.
1552 */
1553
1554 p = (rsmresource_t *)rsmhash_getbkt(rhash, hashval);
1555
1556 for (; p; p = p->rsmrc_next) {
1557 if (p->rsmrc_key == key) {
1558 RSMRC_UNLOCK(new);
1559 break;
1560 }
1561 }
1562 }
1563
1564 if (p == NULL) {
1565 /* Key doesn't exist, add it */
1566
1567 bktp = (rsmresource_t **)rsmhash_bktaddr(rhash, hashval);
1568
1569 new->rsmrc_key = key;
1570 new->rsmrc_next = *bktp;
1571 *bktp = new;
1572 }
1573
1574 rw_exit(&rhash->rsmhash_rw);
1575
1576 DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmhash_add done\n"));
1577
1578 return (p == NULL ? RSM_SUCCESS : RSMERR_SEGID_IN_USE);
1579 }
1580
1581 /*
1582 * XOR each byte of the key.
1583 */
1584 static uint_t
rsmhash(rsm_memseg_id_t key)1585 rsmhash(rsm_memseg_id_t key)
1586 {
1587 uint_t hash = key;
1588
1589 hash ^= (key >> 8);
1590 hash ^= (key >> 16);
1591 hash ^= (key >> 24);
1592
1593 return (hash % rsm_hash_size);
1594
1595 }
1596
1597 /*
1598 * generic function to get a specific bucket
1599 */
1600 static void *
rsmhash_getbkt(rsmhash_table_t * rhash,uint_t hashval)1601 rsmhash_getbkt(rsmhash_table_t *rhash, uint_t hashval)
1602 {
1603
1604 if (rhash->bucket == NULL)
1605 return (NULL);
1606 else
1607 return ((void *)rhash->bucket[hashval]);
1608 }
1609
1610 /*
1611 * generic function to get a specific bucket's address
1612 */
1613 static void **
rsmhash_bktaddr(rsmhash_table_t * rhash,uint_t hashval)1614 rsmhash_bktaddr(rsmhash_table_t *rhash, uint_t hashval)
1615 {
1616 if (rhash->bucket == NULL)
1617 return (NULL);
1618 else
1619 return ((void **)&(rhash->bucket[hashval]));
1620 }
1621
1622 /*
1623 * generic function to alloc a hash table
1624 */
1625 static void
rsmhash_alloc(rsmhash_table_t * rhash,int size)1626 rsmhash_alloc(rsmhash_table_t *rhash, int size)
1627 {
1628 rhash->bucket = (rsmresource_t **)
1629 kmem_zalloc(size * sizeof (rsmresource_t *), KM_SLEEP);
1630 }
1631
1632 /*
1633 * generic function to free a hash table
1634 */
1635 static void
rsmhash_free(rsmhash_table_t * rhash,int size)1636 rsmhash_free(rsmhash_table_t *rhash, int size)
1637 {
1638
1639 kmem_free((void *)rhash->bucket, size * sizeof (caddr_t));
1640 rhash->bucket = NULL;
1641
1642 }
1643 /* *********************** Exported Segment Key Management ************ */
1644
1645 #define rsmexport_add(new, key) \
1646 rsmhash_add(&rsm_export_segs, (rsmresource_t *)new, key, 1, \
1647 RSM_STATE_BIND)
1648
1649 #define rsmexport_rm(arg) \
1650 rsmhash_rm(&rsm_export_segs, (rsmresource_t *)(arg))
1651
1652 #define rsmexport_lookup(key) \
1653 (rsmseg_t *)rsmhash_lookup(&rsm_export_segs, key, RSM_STATE_EXPORT)
1654
1655 /* ************************** Import Segment List Management ********** */
1656
1657 /*
1658 * Add segment to import list. This will be useful for paging and loopback
1659 * segment unloading.
1660 */
1661 #define rsmimport_add(arg, key) \
1662 rsmhash_add(&rsm_import_segs, (rsmresource_t *)(arg), (key), 0, \
1663 RSM_STATE_NEW)
1664
1665 #define rsmimport_rm(arg) \
1666 rsmhash_rm(&rsm_import_segs, (rsmresource_t *)(arg))
1667
1668 /*
1669 * #define rsmimport_lookup(key) \
1670 * (rsmseg_t *)rsmhash_lookup(&rsm_import_segs, (key), RSM_STATE_CONNECT)
1671 */
1672
1673 /*
1674 * increase the ref count and make the import segment point to the
1675 * shared data structure. Return a pointer to the share data struct
1676 * and the shared data struct is locked upon return
1677 */
1678 static rsm_import_share_t *
rsmshare_get(rsm_memseg_id_t key,rsm_node_id_t node,adapter_t * adapter,rsmseg_t * segp)1679 rsmshare_get(rsm_memseg_id_t key, rsm_node_id_t node, adapter_t *adapter,
1680 rsmseg_t *segp)
1681 {
1682 uint_t hash;
1683 rsmresource_t *p;
1684 rsm_import_share_t *shdatap;
1685 DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_FUNC_ALL);
1686
1687 DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmshare_get enter\n"));
1688
1689 hash = rsmhash(key);
1690 /* lock table */
1691 rw_enter(&rsm_import_segs.rsmhash_rw, RW_WRITER);
1692 DBG_PRINTF((category, RSM_DEBUG_LVL2, "rsmshare_get:key=%u, hash=%d\n",
1693 key, hash));
1694
1695 p = (rsmresource_t *)rsmhash_getbkt(&rsm_import_segs, hash);
1696
1697 for (; p; p = p->rsmrc_next) {
1698 /*
1699 * Look for an entry that is importing the same exporter
1700 * with the share data structure allocated.
1701 */
1702 if ((p->rsmrc_key == key) &&
1703 (p->rsmrc_node == node) &&
1704 (p->rsmrc_adapter == adapter) &&
1705 (((rsmseg_t *)p)->s_share != NULL)) {
1706 shdatap = ((rsmseg_t *)p)->s_share;
1707 break;
1708 }
1709 }
1710
1711 if (p == NULL) {
1712 /* we are the first importer, create the shared data struct */
1713 shdatap = kmem_zalloc(sizeof (rsm_import_share_t), KM_SLEEP);
1714 shdatap->rsmsi_state = RSMSI_STATE_NEW;
1715 shdatap->rsmsi_segid = key;
1716 shdatap->rsmsi_node = node;
1717 mutex_init(&shdatap->rsmsi_lock, NULL, MUTEX_DRIVER, NULL);
1718 cv_init(&shdatap->rsmsi_cv, NULL, CV_DRIVER, 0);
1719 }
1720
1721 rsmseglock_acquire(segp);
1722
1723 /* we grab the shared lock before returning from this function */
1724 mutex_enter(&shdatap->rsmsi_lock);
1725
1726 shdatap->rsmsi_refcnt++;
1727 segp->s_share = shdatap;
1728
1729 rsmseglock_release(segp);
1730
1731 rw_exit(&rsm_import_segs.rsmhash_rw);
1732
1733 DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmshare_get done\n"));
1734
1735 return (shdatap);
1736 }
1737
1738 /*
1739 * the shared data structure should be locked before calling
1740 * rsmsharecv_signal().
1741 * Change the state and signal any waiting segments.
1742 */
1743 void
rsmsharecv_signal(rsmseg_t * seg,int oldstate,int newstate)1744 rsmsharecv_signal(rsmseg_t *seg, int oldstate, int newstate)
1745 {
1746 ASSERT(rsmsharelock_held(seg));
1747
1748 if (seg->s_share->rsmsi_state == oldstate) {
1749 seg->s_share->rsmsi_state = newstate;
1750 cv_broadcast(&seg->s_share->rsmsi_cv);
1751 }
1752 }
1753
1754 /*
1755 * Add to the hash table
1756 */
1757 static void
importer_list_add(rsm_node_id_t node,rsm_memseg_id_t key,rsm_addr_t hwaddr,void * cookie)1758 importer_list_add(rsm_node_id_t node, rsm_memseg_id_t key, rsm_addr_t hwaddr,
1759 void *cookie)
1760 {
1761
1762 importing_token_t *head;
1763 importing_token_t *new_token;
1764 int index;
1765
1766 DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_FUNC_ALL);
1767
1768 DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "importer_list_add enter\n"));
1769
1770 new_token = kmem_zalloc(sizeof (importing_token_t), KM_SLEEP);
1771 new_token->importing_node = node;
1772 new_token->key = key;
1773 new_token->import_segment_cookie = cookie;
1774 new_token->importing_adapter_hwaddr = hwaddr;
1775
1776 index = rsmhash(key);
1777
1778 mutex_enter(&importer_list.lock);
1779
1780 head = importer_list.bucket[index];
1781 importer_list.bucket[index] = new_token;
1782 new_token->next = head;
1783 mutex_exit(&importer_list.lock);
1784
1785 DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "importer_list_add done\n"));
1786 }
1787
1788 static void
importer_list_rm(rsm_node_id_t node,rsm_memseg_id_t key,void * cookie)1789 importer_list_rm(rsm_node_id_t node, rsm_memseg_id_t key, void *cookie)
1790 {
1791
1792 importing_token_t *prev, *token = NULL;
1793 int index;
1794 DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_FUNC_ALL);
1795
1796 DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "importer_list_rm enter\n"));
1797
1798 index = rsmhash(key);
1799
1800 mutex_enter(&importer_list.lock);
1801
1802 token = importer_list.bucket[index];
1803
1804 prev = token;
1805 while (token != NULL) {
1806 if (token->importing_node == node &&
1807 token->import_segment_cookie == cookie) {
1808 if (prev == token)
1809 importer_list.bucket[index] = token->next;
1810 else
1811 prev->next = token->next;
1812 kmem_free((void *)token, sizeof (*token));
1813 break;
1814 } else {
1815 prev = token;
1816 token = token->next;
1817 }
1818 }
1819
1820 mutex_exit(&importer_list.lock);
1821
1822 DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "importer_list_rm done\n"));
1823
1824
1825 }
1826
1827 /* **************************Segment Structure Management ************* */
1828
1829 /*
1830 * Free segment structure
1831 */
1832 static void
rsmseg_free(rsmseg_t * seg)1833 rsmseg_free(rsmseg_t *seg)
1834 {
1835
1836 DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_FUNC_ALL);
1837
1838 DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmseg_free enter\n"));
1839
1840 /* need to take seglock here to avoid race with rsmmap_unmap() */
1841 rsmseglock_acquire(seg);
1842 if (seg->s_ckl != NULL) {
1843 /* Segment is still busy */
1844 seg->s_state = RSM_STATE_END;
1845 rsmseglock_release(seg);
1846 DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
1847 "rsmseg_free done\n"));
1848 return;
1849 }
1850
1851 rsmseglock_release(seg);
1852
1853 ASSERT(seg->s_state == RSM_STATE_END || seg->s_state == RSM_STATE_NEW);
1854
1855 /*
1856 * If it's an importer decrement the refcount
1857 * and if its down to zero free the shared data structure.
1858 * This is where failures during rsm_connect() are unrefcounted
1859 */
1860 if (seg->s_share != NULL) {
1861
1862 ASSERT(seg->s_type == RSM_RESOURCE_IMPORT_SEGMENT);
1863
1864 rsmsharelock_acquire(seg);
1865
1866 ASSERT(seg->s_share->rsmsi_refcnt > 0);
1867
1868 seg->s_share->rsmsi_refcnt--;
1869
1870 if (seg->s_share->rsmsi_refcnt == 0) {
1871 rsmsharelock_release(seg);
1872 mutex_destroy(&seg->s_share->rsmsi_lock);
1873 cv_destroy(&seg->s_share->rsmsi_cv);
1874 kmem_free((void *)(seg->s_share),
1875 sizeof (rsm_import_share_t));
1876 } else {
1877 rsmsharelock_release(seg);
1878 }
1879 /*
1880 * The following needs to be done after any
1881 * rsmsharelock calls which use seg->s_share.
1882 */
1883 seg->s_share = NULL;
1884 }
1885
1886 cv_destroy(&seg->s_cv);
1887 mutex_destroy(&seg->s_lock);
1888 rsmacl_free(seg->s_acl, seg->s_acl_len);
1889 rsmpiacl_free(seg->s_acl_in, seg->s_acl_len);
1890 if (seg->s_adapter)
1891 rsmka_release_adapter(seg->s_adapter);
1892
1893 kmem_free((void *)seg, sizeof (*seg));
1894
1895 DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmseg_free done\n"));
1896
1897 }
1898
1899
1900 static rsmseg_t *
rsmseg_alloc(minor_t num,struct cred * cred)1901 rsmseg_alloc(minor_t num, struct cred *cred)
1902 {
1903 rsmseg_t *new;
1904 DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_FUNC_ALL);
1905
1906 DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmseg_alloc enter\n"));
1907 /*
1908 * allocate memory for new segment. This should be a segkmem cache.
1909 */
1910 new = (rsmseg_t *)kmem_zalloc(sizeof (*new), KM_SLEEP);
1911
1912 new->s_state = RSM_STATE_NEW;
1913 new->s_minor = num;
1914 new->s_acl_len = 0;
1915 new->s_cookie = NULL;
1916 new->s_adapter = NULL;
1917
1918 new->s_mode = 0777 & ~PTOU((ttoproc(curthread)))->u_cmask;
1919 /* we don't have a key yet, will set at export/connect */
1920 new->s_uid = crgetuid(cred);
1921 new->s_gid = crgetgid(cred);
1922
1923 mutex_init(&new->s_lock, NULL, MUTEX_DRIVER, (void *)NULL);
1924 cv_init(&new->s_cv, NULL, CV_DRIVER, 0);
1925
1926 DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmseg_alloc done\n"));
1927
1928 return (new);
1929 }
1930
1931 /* ******************************** Driver Open/Close/Poll *************** */
1932
1933 /*ARGSUSED1*/
1934 static int
rsm_open(dev_t * devp,int flag,int otyp,struct cred * cred)1935 rsm_open(dev_t *devp, int flag, int otyp, struct cred *cred)
1936 {
1937 minor_t rnum;
1938 DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_FUNC_ALL| RSM_DDI);
1939
1940 DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_open enter\n"));
1941 /*
1942 * Char only
1943 */
1944 if (otyp != OTYP_CHR) {
1945 DBG_PRINTF((category, RSM_ERR, "rsm_open: bad otyp\n"));
1946 return (EINVAL);
1947 }
1948
1949 /*
1950 * Only zero can be opened, clones are used for resources.
1951 */
1952 if (getminor(*devp) != RSM_DRIVER_MINOR) {
1953 DBG_PRINTF((category, RSM_ERR,
1954 "rsm_open: bad minor %d\n", getminor(*devp)));
1955 return (ENODEV);
1956 }
1957
1958 if ((flag & FEXCL) != 0 && secpolicy_excl_open(cred) != 0) {
1959 DBG_PRINTF((category, RSM_ERR, "rsm_open: bad perm\n"));
1960 return (EPERM);
1961 }
1962
1963 if (!(flag & FWRITE)) {
1964 /*
1965 * The library function _rsm_librsm_init calls open for
1966 * /dev/rsm with flag set to O_RDONLY. We want a valid
1967 * file descriptor to be returned for minor device zero.
1968 */
1969
1970 DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
1971 "rsm_open RDONLY done\n"));
1972 return (DDI_SUCCESS);
1973 }
1974
1975 /*
1976 * - allocate new minor number and segment.
1977 * - add segment to list of all segments.
1978 * - set minordev data to segment
1979 * - update devp argument to new device
1980 * - update s_cred to cred; make sure you do crhold(cred);
1981 */
1982
1983 /* allocate a new resource number */
1984 if (rsmresource_alloc(&rnum) == RSM_SUCCESS) {
1985 /*
1986 * We will bind this minor to a specific resource in first
1987 * ioctl
1988 */
1989 *devp = makedevice(getmajor(*devp), rnum);
1990 } else {
1991 return (EAGAIN);
1992 }
1993
1994 DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_open done\n"));
1995 return (DDI_SUCCESS);
1996 }
1997
1998 static void
rsmseg_close(rsmseg_t * seg,int force_flag)1999 rsmseg_close(rsmseg_t *seg, int force_flag)
2000 {
2001 int e = RSM_SUCCESS;
2002
2003 DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_FUNC_ALL| RSM_DDI);
2004
2005 DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmseg_close enter\n"));
2006
2007 rsmseglock_acquire(seg);
2008 if (!force_flag && (seg->s_hdr.rsmrc_type ==
2009 RSM_RESOURCE_EXPORT_SEGMENT)) {
2010 /*
2011 * If we are processing rsm_close wait for force_destroy
2012 * processing to complete since force_destroy processing
2013 * needs to finish first before we can free the segment.
2014 * force_destroy is only for export segments
2015 */
2016 while (seg->s_flags & RSM_FORCE_DESTROY_WAIT) {
2017 cv_wait(&seg->s_cv, &seg->s_lock);
2018 }
2019 }
2020 rsmseglock_release(seg);
2021
2022 /* It's ok to read the state without a lock */
2023 switch (seg->s_state) {
2024 case RSM_STATE_EXPORT:
2025 case RSM_STATE_EXPORT_QUIESCING:
2026 case RSM_STATE_EXPORT_QUIESCED:
2027 e = rsm_unpublish(seg, 1);
2028 /* FALLTHRU */
2029 case RSM_STATE_BIND_QUIESCED:
2030 /* FALLTHRU */
2031 case RSM_STATE_BIND:
2032 e = rsm_unbind(seg);
2033 if (e != RSM_SUCCESS && force_flag == 1)
2034 return;
2035 ASSERT(seg->s_hdr.rsmrc_type == RSM_RESOURCE_EXPORT_SEGMENT);
2036 /* FALLTHRU */
2037 case RSM_STATE_NEW_QUIESCED:
2038 rsmseglock_acquire(seg);
2039 seg->s_state = RSM_STATE_NEW;
2040 cv_broadcast(&seg->s_cv);
2041 rsmseglock_release(seg);
2042 break;
2043 case RSM_STATE_NEW:
2044 break;
2045 case RSM_STATE_ZOMBIE:
2046 /*
2047 * Segments in this state have been removed off the
2048 * exported segments list and have been unpublished
2049 * and unbind. These segments have been removed during
2050 * a callback to the rsm_export_force_destroy, which
2051 * is called for the purpose of unlocking these
2052 * exported memory segments when a process exits but
2053 * leaves the segments locked down since rsm_close is
2054 * is not called for the segments. This can happen
2055 * when a process calls fork or exec and then exits.
2056 * Once the segments are in the ZOMBIE state, all that
2057 * remains is to destroy them when rsm_close is called.
2058 * This is done here. Thus, for such segments the
2059 * the state is changed to new so that later in this
2060 * function rsmseg_free is called.
2061 */
2062 rsmseglock_acquire(seg);
2063 seg->s_state = RSM_STATE_NEW;
2064 rsmseglock_release(seg);
2065 break;
2066 case RSM_STATE_MAP_QUIESCE:
2067 case RSM_STATE_ACTIVE:
2068 /* Disconnect will handle the unmap */
2069 case RSM_STATE_CONN_QUIESCE:
2070 case RSM_STATE_CONNECT:
2071 case RSM_STATE_DISCONNECT:
2072 ASSERT(seg->s_hdr.rsmrc_type == RSM_RESOURCE_IMPORT_SEGMENT);
2073 (void) rsm_disconnect(seg);
2074 break;
2075 case RSM_STATE_MAPPING:
2076 /*FALLTHRU*/
2077 case RSM_STATE_END:
2078 DBG_PRINTF((category, RSM_ERR,
2079 "Invalid segment state %d in rsm_close\n", seg->s_state));
2080 break;
2081 default:
2082 DBG_PRINTF((category, RSM_ERR,
2083 "Invalid segment state %d in rsm_close\n", seg->s_state));
2084 break;
2085 }
2086
2087 /*
2088 * check state.
2089 * - make sure you do crfree(s_cred);
2090 * release segment and minor number
2091 */
2092 ASSERT(seg->s_state == RSM_STATE_NEW);
2093
2094 /*
2095 * The export_force_destroy callback is created to unlock
2096 * the exported segments of a process
2097 * when the process does a fork or exec and then exits calls this
2098 * function with the force flag set to 1 which indicates that the
2099 * segment state must be converted to ZOMBIE. This state means that the
2100 * segments still exist and have been unlocked and most importantly the
2101 * only operation allowed is to destroy them on an rsm_close.
2102 */
2103 if (force_flag) {
2104 rsmseglock_acquire(seg);
2105 seg->s_state = RSM_STATE_ZOMBIE;
2106 rsmseglock_release(seg);
2107 } else {
2108 rsmseg_free(seg);
2109 }
2110
2111 DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmseg_close done\n"));
2112 }
2113
2114 static int
rsm_close(dev_t dev,int flag,int otyp,cred_t * cred)2115 rsm_close(dev_t dev, int flag, int otyp, cred_t *cred)
2116 {
2117 minor_t rnum = getminor(dev);
2118 rsmresource_t *res;
2119 DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_FUNC_ALL| RSM_DDI);
2120
2121 DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_close enter\n"));
2122
2123 flag = flag; cred = cred;
2124
2125 if (otyp != OTYP_CHR)
2126 return (EINVAL);
2127
2128 DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rnum = %d\n", rnum));
2129
2130 /*
2131 * At this point we are the last reference to the resource.
2132 * Free resource number from resource table.
2133 * It's ok to remove number before we free the segment.
2134 * We need to lock the resource to protect against remote calls.
2135 */
2136 if (rnum == RSM_DRIVER_MINOR ||
2137 (res = rsmresource_free(rnum)) == NULL) {
2138 DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_close done\n"));
2139 return (DDI_SUCCESS);
2140 }
2141
2142 switch (res->rsmrc_type) {
2143 case RSM_RESOURCE_EXPORT_SEGMENT:
2144 case RSM_RESOURCE_IMPORT_SEGMENT:
2145 rsmseg_close((rsmseg_t *)res, 0);
2146 break;
2147 case RSM_RESOURCE_BAR:
2148 DBG_PRINTF((category, RSM_ERR, "bad resource in rsm_close\n"));
2149 break;
2150 default:
2151 break;
2152 }
2153
2154 DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_close done\n"));
2155
2156 return (DDI_SUCCESS);
2157 }
2158
2159 /*
2160 * rsm_inc_pgcnt
2161 *
2162 * Description: increment rsm page counter.
2163 *
2164 * Parameters: pgcnt_t pnum; number of pages to be used
2165 *
2166 * Returns: RSM_SUCCESS if memory limit not exceeded
2167 * ENOSPC if memory limit exceeded. In this case, the
2168 * page counter remains unchanged.
2169 *
2170 */
2171 static int
rsm_inc_pgcnt(pgcnt_t pnum)2172 rsm_inc_pgcnt(pgcnt_t pnum)
2173 {
2174 DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_EXPORT);
2175 if (rsm_pgcnt_max == 0) { /* no upper limit has been set */
2176 return (RSM_SUCCESS);
2177 }
2178
2179 mutex_enter(&rsm_pgcnt_lock);
2180
2181 if (rsm_pgcnt + pnum > rsm_pgcnt_max) {
2182 /* ensure that limits have not been exceeded */
2183 mutex_exit(&rsm_pgcnt_lock);
2184 return (RSMERR_INSUFFICIENT_MEM);
2185 }
2186
2187 rsm_pgcnt += pnum;
2188 DBG_PRINTF((category, RSM_DEBUG, "rsm_pgcnt incr to %d.\n",
2189 rsm_pgcnt));
2190 mutex_exit(&rsm_pgcnt_lock);
2191
2192 return (RSM_SUCCESS);
2193 }
2194
2195 /*
2196 * rsm_dec_pgcnt
2197 *
2198 * Description: decrement rsm page counter.
2199 *
2200 * Parameters: pgcnt_t pnum; number of pages freed
2201 *
2202 */
2203 static void
rsm_dec_pgcnt(pgcnt_t pnum)2204 rsm_dec_pgcnt(pgcnt_t pnum)
2205 {
2206 DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_EXPORT);
2207
2208 if (rsm_pgcnt_max == 0) { /* no upper limit has been set */
2209 return;
2210 }
2211
2212 mutex_enter(&rsm_pgcnt_lock);
2213 ASSERT(rsm_pgcnt >= pnum);
2214 rsm_pgcnt -= pnum;
2215 DBG_PRINTF((category, RSM_DEBUG, "rsm_pgcnt decr to %d.\n",
2216 rsm_pgcnt));
2217 mutex_exit(&rsm_pgcnt_lock);
2218 }
2219
2220 static struct umem_callback_ops rsm_as_ops = {
2221 UMEM_CALLBACK_VERSION, /* version number */
2222 rsm_export_force_destroy,
2223 };
2224
2225 static int
rsm_bind_pages(ddi_umem_cookie_t * cookie,caddr_t vaddr,size_t len,proc_t * procp)2226 rsm_bind_pages(ddi_umem_cookie_t *cookie, caddr_t vaddr, size_t len,
2227 proc_t *procp)
2228 {
2229 int error = RSM_SUCCESS;
2230 ulong_t pnum;
2231 struct umem_callback_ops *callbackops = &rsm_as_ops;
2232
2233 DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_EXPORT);
2234
2235 DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_bind_pages enter\n"));
2236
2237 /*
2238 * Make sure vaddr and len are aligned on a page boundary
2239 */
2240 if ((uintptr_t)vaddr & (PAGESIZE - 1)) {
2241 return (RSMERR_BAD_ADDR);
2242 }
2243
2244 if (len & (PAGESIZE - 1)) {
2245 return (RSMERR_BAD_LENGTH);
2246 }
2247
2248 /*
2249 * Find number of pages
2250 */
2251 pnum = btopr(len);
2252 error = rsm_inc_pgcnt(pnum);
2253 if (error != RSM_SUCCESS) {
2254 DBG_PRINTF((category, RSM_ERR,
2255 "rsm_bind_pages:mem limit exceeded\n"));
2256 return (RSMERR_INSUFFICIENT_MEM);
2257 }
2258
2259 error = umem_lockmemory(vaddr, len,
2260 DDI_UMEMLOCK_WRITE|DDI_UMEMLOCK_READ|DDI_UMEMLOCK_LONGTERM,
2261 cookie,
2262 callbackops, procp);
2263
2264 if (error) {
2265 rsm_dec_pgcnt(pnum);
2266 DBG_PRINTF((category, RSM_ERR,
2267 "rsm_bind_pages:ddi_umem_lock failed\n"));
2268 /*
2269 * ddi_umem_lock, in the case of failure, returns one of
2270 * the following three errors. These are translated into
2271 * the RSMERR namespace and returned.
2272 */
2273 if (error == EFAULT)
2274 return (RSMERR_BAD_ADDR);
2275 else if (error == EACCES)
2276 return (RSMERR_PERM_DENIED);
2277 else
2278 return (RSMERR_INSUFFICIENT_MEM);
2279 }
2280
2281 DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_bind_pages done\n"));
2282
2283 return (error);
2284
2285 }
2286
2287 static int
rsm_unbind_pages(rsmseg_t * seg)2288 rsm_unbind_pages(rsmseg_t *seg)
2289 {
2290 DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_EXPORT);
2291
2292 DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_unbind_pages enter\n"));
2293
2294 ASSERT(rsmseglock_held(seg));
2295
2296 if (seg->s_cookie != NULL) {
2297 /* unlock address range */
2298 ddi_umem_unlock(seg->s_cookie);
2299 rsm_dec_pgcnt(btopr(seg->s_len));
2300 seg->s_cookie = NULL;
2301 }
2302
2303 DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_unbind_pages done\n"));
2304
2305 return (RSM_SUCCESS);
2306 }
2307
2308
2309 static int
rsm_bind(rsmseg_t * seg,rsm_ioctlmsg_t * msg,intptr_t dataptr,int mode)2310 rsm_bind(rsmseg_t *seg, rsm_ioctlmsg_t *msg, intptr_t dataptr, int mode)
2311 {
2312 int e;
2313 adapter_t *adapter;
2314 DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_EXPORT);
2315
2316 DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_bind enter\n"));
2317
2318 adapter = rsm_getadapter(msg, mode);
2319 if (adapter == NULL) {
2320 DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
2321 "rsm_bind done:no adapter\n"));
2322 return (RSMERR_CTLR_NOT_PRESENT);
2323 }
2324
2325 /* lock address range */
2326 if (msg->vaddr == NULL) {
2327 rsmka_release_adapter(adapter);
2328 DBG_PRINTF((category, RSM_ERR,
2329 "rsm: rsm_bind done: invalid vaddr\n"));
2330 return (RSMERR_BAD_ADDR);
2331 }
2332 if (msg->len <= 0) {
2333 rsmka_release_adapter(adapter);
2334 DBG_PRINTF((category, RSM_ERR,
2335 "rsm_bind: invalid length\n"));
2336 return (RSMERR_BAD_LENGTH);
2337 }
2338
2339 /* Lock segment */
2340 rsmseglock_acquire(seg);
2341
2342 while (seg->s_state == RSM_STATE_NEW_QUIESCED) {
2343 if (cv_wait_sig(&seg->s_cv, &seg->s_lock) == 0) {
2344 DBG_PRINTF((category, RSM_DEBUG,
2345 "rsm_bind done: cv_wait INTERRUPTED"));
2346 rsmka_release_adapter(adapter);
2347 rsmseglock_release(seg);
2348 return (RSMERR_INTERRUPTED);
2349 }
2350 }
2351
2352 ASSERT(seg->s_state == RSM_STATE_NEW);
2353
2354 ASSERT(seg->s_cookie == NULL);
2355
2356 e = rsm_bind_pages(&seg->s_cookie, msg->vaddr, msg->len, curproc);
2357 if (e == RSM_SUCCESS) {
2358 seg->s_flags |= RSM_USER_MEMORY;
2359 if (msg->perm & RSM_ALLOW_REBIND) {
2360 seg->s_flags |= RSMKA_ALLOW_UNBIND_REBIND;
2361 }
2362 if (msg->perm & RSM_CREATE_SEG_DONTWAIT) {
2363 seg->s_flags |= RSMKA_SET_RESOURCE_DONTWAIT;
2364 }
2365 seg->s_region.r_vaddr = msg->vaddr;
2366 /*
2367 * Set the s_pid value in the segment structure. This is used
2368 * to identify exported segments belonging to a particular
2369 * process so that when the process exits, these segments can
2370 * be unlocked forcefully even if rsm_close is not called on
2371 * process exit since there maybe other processes referencing
2372 * them (for example on a fork or exec).
2373 * The s_pid value is also used to authenticate the process
2374 * doing a publish or unpublish on the export segment. Only
2375 * the creator of the export segment has a right to do a
2376 * publish or unpublish and unbind on the segment.
2377 */
2378 seg->s_pid = ddi_get_pid();
2379 seg->s_len = msg->len;
2380 seg->s_state = RSM_STATE_BIND;
2381 seg->s_adapter = adapter;
2382 seg->s_proc = curproc;
2383 } else {
2384 rsmka_release_adapter(adapter);
2385 DBG_PRINTF((category, RSM_WARNING,
2386 "unable to lock down pages\n"));
2387 }
2388
2389 msg->rnum = seg->s_minor;
2390 /* Unlock segment */
2391 rsmseglock_release(seg);
2392
2393 if (e == RSM_SUCCESS) {
2394 /* copyout the resource number */
2395 #ifdef _MULTI_DATAMODEL
2396 if ((mode & DATAMODEL_MASK) == DATAMODEL_ILP32) {
2397 rsm_ioctlmsg32_t msg32;
2398
2399 msg32.rnum = msg->rnum;
2400 if (ddi_copyout((caddr_t)&msg32.rnum,
2401 (caddr_t)&((rsm_ioctlmsg32_t *)dataptr)->rnum,
2402 sizeof (minor_t), mode)) {
2403 rsmka_release_adapter(adapter);
2404 e = RSMERR_BAD_ADDR;
2405 }
2406 }
2407 #endif
2408 if (ddi_copyout((caddr_t)&msg->rnum,
2409 (caddr_t)&((rsm_ioctlmsg_t *)dataptr)->rnum,
2410 sizeof (minor_t), mode)) {
2411 rsmka_release_adapter(adapter);
2412 e = RSMERR_BAD_ADDR;
2413 }
2414 }
2415
2416 DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_bind done\n"));
2417
2418 return (e);
2419 }
2420
2421 static void
rsm_remap_local_importers(rsm_node_id_t src_nodeid,rsm_memseg_id_t ex_segid,ddi_umem_cookie_t cookie)2422 rsm_remap_local_importers(rsm_node_id_t src_nodeid,
2423 rsm_memseg_id_t ex_segid, ddi_umem_cookie_t cookie)
2424 {
2425 rsmresource_t *p = NULL;
2426 rsmhash_table_t *rhash = &rsm_import_segs;
2427 uint_t index;
2428
2429 DBG_PRINTF((RSM_KERNEL_AGENT | RSM_FUNC_ALL, RSM_DEBUG_VERBOSE,
2430 "rsm_remap_local_importers enter\n"));
2431
2432 index = rsmhash(ex_segid);
2433
2434 rw_enter(&rhash->rsmhash_rw, RW_READER);
2435
2436 p = rsmhash_getbkt(rhash, index);
2437
2438 for (; p; p = p->rsmrc_next) {
2439 rsmseg_t *seg = (rsmseg_t *)p;
2440 rsmseglock_acquire(seg);
2441 /*
2442 * Change the s_cookie value of only the local importers
2443 * which have been mapped (in state RSM_STATE_ACTIVE).
2444 * Note that there is no need to change the s_cookie value
2445 * if the imported segment is in RSM_STATE_MAPPING since
2446 * eventually the s_cookie will be updated via the mapping
2447 * functionality.
2448 */
2449 if ((seg->s_segid == ex_segid) && (seg->s_node == src_nodeid) &&
2450 (seg->s_state == RSM_STATE_ACTIVE)) {
2451 seg->s_cookie = cookie;
2452 }
2453 rsmseglock_release(seg);
2454 }
2455 rw_exit(&rhash->rsmhash_rw);
2456
2457 DBG_PRINTF((RSM_KERNEL_AGENT | RSM_FUNC_ALL, RSM_DEBUG_VERBOSE,
2458 "rsm_remap_local_importers done\n"));
2459 }
2460
2461 static int
rsm_rebind(rsmseg_t * seg,rsm_ioctlmsg_t * msg)2462 rsm_rebind(rsmseg_t *seg, rsm_ioctlmsg_t *msg)
2463 {
2464 int e;
2465 adapter_t *adapter;
2466 ddi_umem_cookie_t cookie;
2467 DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_EXPORT);
2468
2469 DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_rebind enter\n"));
2470
2471 /* Check for permissions to rebind */
2472 if (!(seg->s_flags & RSMKA_ALLOW_UNBIND_REBIND)) {
2473 return (RSMERR_REBIND_NOT_ALLOWED);
2474 }
2475
2476 if (seg->s_pid != ddi_get_pid() &&
2477 ddi_get_pid() != 0) {
2478 DBG_PRINTF((category, RSM_ERR, "rsm_rebind: Not owner\n"));
2479 return (RSMERR_NOT_CREATOR);
2480 }
2481
2482 /*
2483 * We will not be allowing partial rebind and hence length passed
2484 * in must be same as segment length
2485 */
2486 if (msg->vaddr == NULL) {
2487 DBG_PRINTF((category, RSM_ERR,
2488 "rsm_rebind done: null msg->vaddr\n"));
2489 return (RSMERR_BAD_ADDR);
2490 }
2491 if (msg->len != seg->s_len) {
2492 DBG_PRINTF((category, RSM_ERR,
2493 "rsm_rebind: invalid length\n"));
2494 return (RSMERR_BAD_LENGTH);
2495 }
2496
2497 /* Lock segment */
2498 rsmseglock_acquire(seg);
2499
2500 while ((seg->s_state == RSM_STATE_BIND_QUIESCED) ||
2501 (seg->s_state == RSM_STATE_EXPORT_QUIESCING) ||
2502 (seg->s_state == RSM_STATE_EXPORT_QUIESCED)) {
2503 if (cv_wait_sig(&seg->s_cv, &seg->s_lock) == 0) {
2504 rsmseglock_release(seg);
2505 DBG_PRINTF((category, RSM_DEBUG,
2506 "rsm_rebind done: cv_wait INTERRUPTED"));
2507 return (RSMERR_INTERRUPTED);
2508 }
2509 }
2510
2511 /* verify segment state */
2512 if ((seg->s_state != RSM_STATE_BIND) &&
2513 (seg->s_state != RSM_STATE_EXPORT)) {
2514 /* Unlock segment */
2515 rsmseglock_release(seg);
2516 DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
2517 "rsm_rebind done: invalid state\n"));
2518 return (RSMERR_BAD_SEG_HNDL);
2519 }
2520
2521 ASSERT(seg->s_cookie != NULL);
2522
2523 if (msg->vaddr == seg->s_region.r_vaddr) {
2524 rsmseglock_release(seg);
2525 DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_rebind done\n"));
2526 return (RSM_SUCCESS);
2527 }
2528
2529 e = rsm_bind_pages(&cookie, msg->vaddr, msg->len, curproc);
2530 if (e == RSM_SUCCESS) {
2531 struct buf *xbuf;
2532 dev_t sdev = 0;
2533 rsm_memory_local_t mem;
2534
2535 xbuf = ddi_umem_iosetup(cookie, 0, msg->len, B_WRITE,
2536 sdev, 0, NULL, DDI_UMEM_SLEEP);
2537 ASSERT(xbuf != NULL);
2538
2539 mem.ms_type = RSM_MEM_BUF;
2540 mem.ms_bp = xbuf;
2541
2542 adapter = seg->s_adapter;
2543 e = adapter->rsmpi_ops->rsm_rebind(
2544 seg->s_handle.out, 0, &mem,
2545 RSM_RESOURCE_DONTWAIT, NULL);
2546
2547 if (e == RSM_SUCCESS) {
2548 /*
2549 * unbind the older pages, and unload local importers;
2550 * but don't disconnect importers
2551 */
2552 (void) rsm_unbind_pages(seg);
2553 seg->s_cookie = cookie;
2554 seg->s_region.r_vaddr = msg->vaddr;
2555 rsm_remap_local_importers(my_nodeid, seg->s_segid,
2556 cookie);
2557 } else {
2558 /*
2559 * Unbind the pages associated with "cookie" by the
2560 * rsm_bind_pages calls prior to this. This is
2561 * similar to what is done in the rsm_unbind_pages
2562 * routine for the seg->s_cookie.
2563 */
2564 ddi_umem_unlock(cookie);
2565 rsm_dec_pgcnt(btopr(msg->len));
2566 DBG_PRINTF((category, RSM_ERR,
2567 "rsm_rebind failed with %d\n", e));
2568 }
2569 /*
2570 * At present there is no dependency on the existence of xbuf.
2571 * So we can free it here. If in the future this changes, it can
2572 * be freed sometime during the segment destroy.
2573 */
2574 freerbuf(xbuf);
2575 }
2576
2577 /* Unlock segment */
2578 rsmseglock_release(seg);
2579
2580 DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_rebind done\n"));
2581
2582 return (e);
2583 }
2584
2585 static int
rsm_unbind(rsmseg_t * seg)2586 rsm_unbind(rsmseg_t *seg)
2587 {
2588 DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_EXPORT);
2589
2590 DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_unbind enter\n"));
2591
2592 rsmseglock_acquire(seg);
2593
2594 /* verify segment state */
2595 if ((seg->s_state != RSM_STATE_BIND) &&
2596 (seg->s_state != RSM_STATE_BIND_QUIESCED)) {
2597 rsmseglock_release(seg);
2598 DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
2599 "rsm_unbind: invalid state\n"));
2600 return (RSMERR_BAD_SEG_HNDL);
2601 }
2602
2603 /* unlock current range */
2604 (void) rsm_unbind_pages(seg);
2605
2606 if (seg->s_state == RSM_STATE_BIND) {
2607 seg->s_state = RSM_STATE_NEW;
2608 } else if (seg->s_state == RSM_STATE_BIND_QUIESCED) {
2609 seg->s_state = RSM_STATE_NEW_QUIESCED;
2610 }
2611
2612 rsmseglock_release(seg);
2613
2614 DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_unbind done\n"));
2615
2616 return (RSM_SUCCESS);
2617 }
2618
2619 /* **************************** Exporter Access List Management ******* */
2620 static void
rsmacl_free(rsmapi_access_entry_t * acl,int acl_len)2621 rsmacl_free(rsmapi_access_entry_t *acl, int acl_len)
2622 {
2623 int acl_sz;
2624 DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_EXPORT);
2625
2626 DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmacl_free enter\n"));
2627
2628 /* acl could be NULL */
2629
2630 if (acl != NULL && acl_len > 0) {
2631 acl_sz = acl_len * sizeof (rsmapi_access_entry_t);
2632 kmem_free((void *)acl, acl_sz);
2633 }
2634
2635 DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmacl_free done\n"));
2636 }
2637
2638 static void
rsmpiacl_free(rsm_access_entry_t * acl,int acl_len)2639 rsmpiacl_free(rsm_access_entry_t *acl, int acl_len)
2640 {
2641 int acl_sz;
2642 DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_EXPORT);
2643
2644 DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmpiacl_free enter\n"));
2645
2646 if (acl != NULL && acl_len > 0) {
2647 acl_sz = acl_len * sizeof (rsm_access_entry_t);
2648 kmem_free((void *)acl, acl_sz);
2649 }
2650
2651 DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmpiacl_free done\n"));
2652
2653 }
2654
2655 static int
rsmacl_build(rsm_ioctlmsg_t * msg,int mode,rsmapi_access_entry_t ** list,int * len,int loopback)2656 rsmacl_build(rsm_ioctlmsg_t *msg, int mode,
2657 rsmapi_access_entry_t **list, int *len, int loopback)
2658 {
2659 rsmapi_access_entry_t *acl;
2660 int acl_len;
2661 int i;
2662 DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_EXPORT);
2663
2664 DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmacl_build enter\n"));
2665
2666 *len = 0;
2667 *list = NULL;
2668
2669 acl_len = msg->acl_len;
2670 if ((loopback && acl_len > 1) || (acl_len < 0) ||
2671 (acl_len > MAX_NODES)) {
2672 DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
2673 "rsmacl_build done: acl invalid\n"));
2674 return (RSMERR_BAD_ACL);
2675 }
2676
2677 if (acl_len > 0 && acl_len <= MAX_NODES) {
2678 size_t acl_size = acl_len * sizeof (rsmapi_access_entry_t);
2679
2680 acl = kmem_alloc(acl_size, KM_SLEEP);
2681
2682 if (ddi_copyin((caddr_t)msg->acl, (caddr_t)acl,
2683 acl_size, mode)) {
2684 kmem_free((void *) acl, acl_size);
2685 DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
2686 "rsmacl_build done: BAD_ADDR\n"));
2687 return (RSMERR_BAD_ADDR);
2688 }
2689
2690 /*
2691 * Verify access list
2692 */
2693 for (i = 0; i < acl_len; i++) {
2694 if (acl[i].ae_node > MAX_NODES ||
2695 (loopback && (acl[i].ae_node != my_nodeid)) ||
2696 acl[i].ae_permission > RSM_ACCESS_TRUSTED) {
2697 /* invalid entry */
2698 kmem_free((void *) acl, acl_size);
2699 DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
2700 "rsmacl_build done: EINVAL\n"));
2701 return (RSMERR_BAD_ACL);
2702 }
2703 }
2704
2705 *len = acl_len;
2706 *list = acl;
2707 }
2708
2709 DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmacl_build done\n"));
2710
2711 return (DDI_SUCCESS);
2712 }
2713
2714 static int
rsmpiacl_create(rsmapi_access_entry_t * src,rsm_access_entry_t ** dest,int acl_len,adapter_t * adapter)2715 rsmpiacl_create(rsmapi_access_entry_t *src, rsm_access_entry_t **dest,
2716 int acl_len, adapter_t *adapter)
2717 {
2718 rsm_access_entry_t *acl;
2719 rsm_addr_t hwaddr;
2720 int i;
2721 DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_EXPORT);
2722
2723 DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmpiacl_create enter\n"));
2724
2725 if (src != NULL) {
2726 size_t acl_size = acl_len * sizeof (rsm_access_entry_t);
2727 acl = kmem_alloc(acl_size, KM_SLEEP);
2728
2729 /*
2730 * translate access list
2731 */
2732 for (i = 0; i < acl_len; i++) {
2733 if (src[i].ae_node == my_nodeid) {
2734 acl[i].ae_addr = adapter->hwaddr;
2735 } else {
2736 hwaddr = get_remote_hwaddr(adapter,
2737 src[i].ae_node);
2738 if ((int64_t)hwaddr < 0) {
2739 /* invalid hwaddr */
2740 kmem_free((void *) acl, acl_size);
2741 DBG_PRINTF((category,
2742 RSM_DEBUG_VERBOSE,
2743 "rsmpiacl_create done:"
2744 "EINVAL hwaddr\n"));
2745 return (RSMERR_INTERNAL_ERROR);
2746 }
2747 acl[i].ae_addr = hwaddr;
2748 }
2749 /* rsmpi understands only RSM_PERM_XXXX */
2750 acl[i].ae_permission =
2751 src[i].ae_permission & RSM_PERM_RDWR;
2752 }
2753 *dest = acl;
2754 } else {
2755 *dest = NULL;
2756 }
2757
2758 DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmpiacl_create done\n"));
2759
2760 return (RSM_SUCCESS);
2761 }
2762
2763 static int
rsmsegacl_validate(rsmipc_request_t * req,rsm_node_id_t rnode,rsmipc_reply_t * reply)2764 rsmsegacl_validate(rsmipc_request_t *req, rsm_node_id_t rnode,
2765 rsmipc_reply_t *reply)
2766 {
2767
2768 int i;
2769 rsmseg_t *seg;
2770 rsm_memseg_id_t key = req->rsmipc_key;
2771 rsm_permission_t perm = req->rsmipc_perm;
2772 DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_EXPORT);
2773
2774 DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
2775 "rsmsegacl_validate enter\n"));
2776
2777 /*
2778 * Find segment and grab its lock. The reason why we grab the segment
2779 * lock in side the search is to avoid the race when the segment is
2780 * being deleted and we already have a pointer to it.
2781 */
2782 seg = rsmexport_lookup(key);
2783 if (!seg) {
2784 DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
2785 "rsmsegacl_validate done: %u ENXIO\n", key));
2786 return (RSMERR_SEG_NOT_PUBLISHED);
2787 }
2788
2789 ASSERT(rsmseglock_held(seg));
2790 ASSERT(seg->s_state == RSM_STATE_EXPORT);
2791
2792 /*
2793 * We implement a 2-level protection scheme.
2794 * First, we check if local/remote host has access rights.
2795 * Second, we check if the user has access rights.
2796 *
2797 * This routine only validates the rnode access_list
2798 */
2799 if (seg->s_acl_len > 0) {
2800 /*
2801 * Check host access list
2802 */
2803 ASSERT(seg->s_acl != NULL);
2804 for (i = 0; i < seg->s_acl_len; i++) {
2805 if (seg->s_acl[i].ae_node == rnode) {
2806 perm &= seg->s_acl[i].ae_permission;
2807 goto found;
2808 }
2809 }
2810 /* rnode is not found in the list */
2811 rsmseglock_release(seg);
2812 DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
2813 "rsmsegacl_validate done: EPERM\n"));
2814 return (RSMERR_SEG_NOT_PUBLISHED_TO_NODE);
2815 } else {
2816 /* use default owner creation umask */
2817 perm &= seg->s_mode;
2818 }
2819
2820 found:
2821 /* update perm for this node */
2822 reply->rsmipc_mode = perm;
2823 reply->rsmipc_uid = seg->s_uid;
2824 reply->rsmipc_gid = seg->s_gid;
2825 reply->rsmipc_segid = seg->s_segid;
2826 reply->rsmipc_seglen = seg->s_len;
2827
2828 /*
2829 * Perm of requesting node is valid; source will validate user
2830 */
2831 rsmseglock_release(seg);
2832
2833 /*
2834 * Add the importer to the list right away, if connect fails
2835 * the importer will ask the exporter to remove it.
2836 */
2837 importer_list_add(rnode, key, req->rsmipc_adapter_hwaddr,
2838 req->rsmipc_segment_cookie);
2839
2840 DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmsegacl_validate done\n"));
2841
2842 return (RSM_SUCCESS);
2843 }
2844
2845
2846 /* ************************** Exporter Calls ************************* */
2847
2848 static int
rsm_publish(rsmseg_t * seg,rsm_ioctlmsg_t * msg,intptr_t dataptr,int mode)2849 rsm_publish(rsmseg_t *seg, rsm_ioctlmsg_t *msg, intptr_t dataptr, int mode)
2850 {
2851 int e;
2852 int acl_len;
2853 rsmapi_access_entry_t *acl;
2854 rsm_access_entry_t *rsmpi_acl;
2855 rsm_memory_local_t mem;
2856 struct buf *xbuf;
2857 dev_t sdev = 0;
2858 adapter_t *adapter;
2859 rsm_memseg_id_t segment_id = 0;
2860 int loopback_flag = 0;
2861 int create_flags = 0;
2862 rsm_resource_callback_t callback_flag;
2863 DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_EXPORT);
2864
2865 DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_publish enter\n"));
2866
2867 if (seg->s_adapter == &loopback_adapter)
2868 loopback_flag = 1;
2869
2870 if (seg->s_pid != ddi_get_pid() &&
2871 ddi_get_pid() != 0) {
2872 DBG_PRINTF((category, RSM_ERR,
2873 "rsm_publish: Not creator\n"));
2874 return (RSMERR_NOT_CREATOR);
2875 }
2876
2877 /*
2878 * Get per node access list
2879 */
2880 e = rsmacl_build(msg, mode, &acl, &acl_len, loopback_flag);
2881 if (e != DDI_SUCCESS) {
2882 DBG_PRINTF((category, RSM_ERR,
2883 "rsm_publish done: rsmacl_build failed\n"));
2884 return (e);
2885 }
2886
2887 /*
2888 * The application provided msg->key is used for resolving a
2889 * segment id according to the following:
2890 * key = 0 Kernel Agent selects the segment id
2891 * key <= RSM_DLPI_ID_END Reserved for system usage except
2892 * RSMLIB range
2893 * key < RSM_USER_APP_ID_BASE segment id = key
2894 * key >= RSM_USER_APP_ID_BASE Reserved for KA selections
2895 *
2896 * rsm_nextavail_segmentid is initialized to 0x80000000 and
2897 * overflows to zero after 0x80000000 allocations.
2898 * An algorithm is needed which allows reinitialization and provides
2899 * for reallocation after overflow. For now, ENOMEM is returned
2900 * once the overflow condition has occurred.
2901 */
2902 if (msg->key == 0) {
2903 mutex_enter(&rsm_lock);
2904 segment_id = rsm_nextavail_segmentid;
2905 if (segment_id != 0) {
2906 rsm_nextavail_segmentid++;
2907 mutex_exit(&rsm_lock);
2908 } else {
2909 mutex_exit(&rsm_lock);
2910 DBG_PRINTF((category, RSM_ERR,
2911 "rsm_publish done: no more keys avlbl\n"));
2912 return (RSMERR_INSUFFICIENT_RESOURCES);
2913 }
2914 } else if BETWEEN(msg->key, RSM_RSMLIB_ID_BASE, RSM_RSMLIB_ID_END)
2915 /* range reserved for internal use by base/ndi libraries */
2916 segment_id = msg->key;
2917 else if (msg->key <= RSM_DLPI_ID_END)
2918 return (RSMERR_RESERVED_SEGID);
2919 else if (msg->key <= (uint_t)RSM_USER_APP_ID_BASE -1)
2920 segment_id = msg->key;
2921 else {
2922 DBG_PRINTF((category, RSM_ERR,
2923 "rsm_publish done: invalid key %u\n", msg->key));
2924 return (RSMERR_RESERVED_SEGID);
2925 }
2926
2927 /* Add key to exportlist; The segment lock is held on success */
2928 e = rsmexport_add(seg, segment_id);
2929 if (e) {
2930 rsmacl_free(acl, acl_len);
2931 DBG_PRINTF((category, RSM_ERR,
2932 "rsm_publish done: export_add failed: %d\n", e));
2933 return (e);
2934 }
2935
2936 seg->s_segid = segment_id;
2937
2938 if ((seg->s_state != RSM_STATE_BIND) &&
2939 (seg->s_state != RSM_STATE_BIND_QUIESCED)) {
2940 /* state changed since then, free acl and return */
2941 rsmseglock_release(seg);
2942 rsmexport_rm(seg);
2943 rsmacl_free(acl, acl_len);
2944 DBG_PRINTF((category, RSM_ERR,
2945 "rsm_publish done: segment in wrong state: %d\n",
2946 seg->s_state));
2947 return (RSMERR_BAD_SEG_HNDL);
2948 }
2949
2950 /*
2951 * If this is for a local memory handle and permissions are zero,
2952 * then the surrogate segment is very large and we want to skip
2953 * allocation of DVMA space.
2954 *
2955 * Careful! If the user didn't use an ACL list, acl will be a NULL
2956 * pointer. Check that before dereferencing it.
2957 */
2958 if (acl != (rsmapi_access_entry_t *)NULL) {
2959 if (acl[0].ae_node == my_nodeid && acl[0].ae_permission == 0)
2960 goto skipdriver;
2961 }
2962
2963 /* create segment */
2964 xbuf = ddi_umem_iosetup(seg->s_cookie, 0, seg->s_len, B_WRITE,
2965 sdev, 0, NULL, DDI_UMEM_SLEEP);
2966 ASSERT(xbuf != NULL);
2967
2968 mem.ms_type = RSM_MEM_BUF;
2969 mem.ms_bp = xbuf;
2970
2971 /* This call includes a bind operations */
2972
2973 adapter = seg->s_adapter;
2974 /*
2975 * create a acl list with hwaddr for RSMPI publish
2976 */
2977 e = rsmpiacl_create(acl, &rsmpi_acl, acl_len, adapter);
2978
2979 if (e != RSM_SUCCESS) {
2980 rsmseglock_release(seg);
2981 rsmexport_rm(seg);
2982 rsmacl_free(acl, acl_len);
2983 freerbuf(xbuf);
2984 DBG_PRINTF((category, RSM_ERR,
2985 "rsm_publish done: rsmpiacl_create failed: %d\n", e));
2986 return (e);
2987 }
2988
2989 if (seg->s_state == RSM_STATE_BIND) {
2990 /* create segment */
2991
2992 /* This call includes a bind operations */
2993
2994 if (seg->s_flags & RSMKA_ALLOW_UNBIND_REBIND) {
2995 create_flags = RSM_ALLOW_UNBIND_REBIND;
2996 }
2997
2998 if (seg->s_flags & RSMKA_SET_RESOURCE_DONTWAIT) {
2999 callback_flag = RSM_RESOURCE_DONTWAIT;
3000 } else {
3001 callback_flag = RSM_RESOURCE_SLEEP;
3002 }
3003
3004 e = adapter->rsmpi_ops->rsm_seg_create(
3005 adapter->rsmpi_handle,
3006 &seg->s_handle.out, seg->s_len,
3007 create_flags, &mem,
3008 callback_flag, NULL);
3009 /*
3010 * At present there is no dependency on the existence of xbuf.
3011 * So we can free it here. If in the future this changes, it can
3012 * be freed sometime during the segment destroy.
3013 */
3014 freerbuf(xbuf);
3015
3016 if (e != RSM_SUCCESS) {
3017 rsmseglock_release(seg);
3018 rsmexport_rm(seg);
3019 rsmacl_free(acl, acl_len);
3020 rsmpiacl_free(rsmpi_acl, acl_len);
3021 DBG_PRINTF((category, RSM_ERR,
3022 "rsm_publish done: export_create failed: %d\n", e));
3023 /*
3024 * The following assertion ensures that the two errors
3025 * related to the length and its alignment do not occur
3026 * since they have been checked during export_create
3027 */
3028 ASSERT(e != RSMERR_BAD_MEM_ALIGNMENT &&
3029 e != RSMERR_BAD_LENGTH);
3030 if (e == RSMERR_NOT_MEM)
3031 e = RSMERR_INSUFFICIENT_MEM;
3032
3033 return (e);
3034 }
3035 /* export segment, this should create an IMMU mapping */
3036 e = adapter->rsmpi_ops->rsm_publish(
3037 seg->s_handle.out,
3038 rsmpi_acl, acl_len,
3039 seg->s_segid,
3040 RSM_RESOURCE_DONTWAIT, NULL);
3041
3042 if (e != RSM_SUCCESS) {
3043 adapter->rsmpi_ops->rsm_seg_destroy(seg->s_handle.out);
3044 rsmseglock_release(seg);
3045 rsmexport_rm(seg);
3046 rsmacl_free(acl, acl_len);
3047 rsmpiacl_free(rsmpi_acl, acl_len);
3048 DBG_PRINTF((category, RSM_ERR,
3049 "rsm_publish done: export_publish failed: %d\n",
3050 e));
3051 return (e);
3052 }
3053 }
3054
3055 seg->s_acl_in = rsmpi_acl;
3056
3057 skipdriver:
3058 /* defer s_acl/s_acl_len -> avoid crash in rsmseg_free */
3059 seg->s_acl_len = acl_len;
3060 seg->s_acl = acl;
3061
3062 if (seg->s_state == RSM_STATE_BIND) {
3063 seg->s_state = RSM_STATE_EXPORT;
3064 } else if (seg->s_state == RSM_STATE_BIND_QUIESCED) {
3065 seg->s_state = RSM_STATE_EXPORT_QUIESCED;
3066 cv_broadcast(&seg->s_cv);
3067 }
3068
3069 rsmseglock_release(seg);
3070
3071 /*
3072 * If the segment id was solicited, then return it in
3073 * the original incoming message.
3074 */
3075 if (msg->key == 0) {
3076 msg->key = segment_id;
3077 #ifdef _MULTI_DATAMODEL
3078 if ((mode & DATAMODEL_MASK) == DATAMODEL_ILP32) {
3079 rsm_ioctlmsg32_t msg32;
3080
3081 msg32.key = msg->key;
3082 DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
3083 "rsm_publish done\n"));
3084 return (ddi_copyout((caddr_t)&msg32,
3085 (caddr_t)dataptr, sizeof (msg32), mode));
3086 }
3087 #endif
3088 DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
3089 "rsm_publish done\n"));
3090 return (ddi_copyout((caddr_t)msg,
3091 (caddr_t)dataptr, sizeof (*msg), mode));
3092 }
3093
3094 DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_publish done\n"));
3095 return (DDI_SUCCESS);
3096 }
3097
3098 /*
3099 * This function modifies the access control list of an already published
3100 * segment. There is no effect on import segments which are already
3101 * connected.
3102 */
3103 static int
rsm_republish(rsmseg_t * seg,rsm_ioctlmsg_t * msg,int mode)3104 rsm_republish(rsmseg_t *seg, rsm_ioctlmsg_t *msg, int mode)
3105 {
3106 rsmapi_access_entry_t *new_acl, *old_acl, *tmp_acl;
3107 rsm_access_entry_t *rsmpi_new_acl, *rsmpi_old_acl;
3108 int new_acl_len, old_acl_len, tmp_acl_len;
3109 int e, i;
3110 adapter_t *adapter;
3111 int loopback_flag = 0;
3112 rsm_memseg_id_t key;
3113 rsm_permission_t permission;
3114 DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_EXPORT);
3115
3116 DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_republish enter\n"));
3117
3118 if ((seg->s_state != RSM_STATE_EXPORT) &&
3119 (seg->s_state != RSM_STATE_EXPORT_QUIESCED) &&
3120 (seg->s_state != RSM_STATE_EXPORT_QUIESCING))
3121 return (RSMERR_SEG_NOT_PUBLISHED);
3122
3123 if (seg->s_pid != ddi_get_pid() &&
3124 ddi_get_pid() != 0) {
3125 DBG_PRINTF((category, RSM_ERR,
3126 "rsm_republish: Not owner\n"));
3127 return (RSMERR_NOT_CREATOR);
3128 }
3129
3130 if (seg->s_adapter == &loopback_adapter)
3131 loopback_flag = 1;
3132
3133 /*
3134 * Build new list first
3135 */
3136 e = rsmacl_build(msg, mode, &new_acl, &new_acl_len, loopback_flag);
3137 if (e) {
3138 DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
3139 "rsm_republish done: rsmacl_build failed %d", e));
3140 return (e);
3141 }
3142
3143 /* Lock segment */
3144 rsmseglock_acquire(seg);
3145 /*
3146 * a republish is in progress - REPUBLISH message is being
3147 * sent to the importers so wait for it to complete OR
3148 * wait till DR completes
3149 */
3150 while (((seg->s_state == RSM_STATE_EXPORT) &&
3151 (seg->s_flags & RSM_REPUBLISH_WAIT)) ||
3152 (seg->s_state == RSM_STATE_EXPORT_QUIESCED) ||
3153 (seg->s_state == RSM_STATE_EXPORT_QUIESCING)) {
3154 if (cv_wait_sig(&seg->s_cv, &seg->s_lock) == 0) {
3155 DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
3156 "rsm_republish done: cv_wait INTERRUPTED"));
3157 rsmseglock_release(seg);
3158 rsmacl_free(new_acl, new_acl_len);
3159 return (RSMERR_INTERRUPTED);
3160 }
3161 }
3162
3163 /* recheck if state is valid */
3164 if (seg->s_state != RSM_STATE_EXPORT) {
3165 rsmseglock_release(seg);
3166 rsmacl_free(new_acl, new_acl_len);
3167 return (RSMERR_SEG_NOT_PUBLISHED);
3168 }
3169
3170 key = seg->s_key;
3171 old_acl = seg->s_acl;
3172 old_acl_len = seg->s_acl_len;
3173
3174 seg->s_acl = new_acl;
3175 seg->s_acl_len = new_acl_len;
3176
3177 /*
3178 * This call will only be meaningful if and when the interconnect
3179 * layer makes use of the access list
3180 */
3181 adapter = seg->s_adapter;
3182 /*
3183 * create a acl list with hwaddr for RSMPI publish
3184 */
3185 e = rsmpiacl_create(new_acl, &rsmpi_new_acl, new_acl_len, adapter);
3186
3187 if (e != RSM_SUCCESS) {
3188 seg->s_acl = old_acl;
3189 seg->s_acl_len = old_acl_len;
3190 rsmseglock_release(seg);
3191 rsmacl_free(new_acl, new_acl_len);
3192 DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
3193 "rsm_republish done: rsmpiacl_create failed %d", e));
3194 return (e);
3195 }
3196 rsmpi_old_acl = seg->s_acl_in;
3197 seg->s_acl_in = rsmpi_new_acl;
3198
3199 e = adapter->rsmpi_ops->rsm_republish(seg->s_handle.out,
3200 seg->s_acl_in, seg->s_acl_len,
3201 RSM_RESOURCE_DONTWAIT, NULL);
3202
3203 if (e != RSM_SUCCESS) {
3204 seg->s_acl = old_acl;
3205 seg->s_acl_in = rsmpi_old_acl;
3206 seg->s_acl_len = old_acl_len;
3207 rsmseglock_release(seg);
3208 rsmacl_free(new_acl, new_acl_len);
3209 rsmpiacl_free(rsmpi_new_acl, new_acl_len);
3210
3211 DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
3212 "rsm_republish done: rsmpi republish failed %d\n", e));
3213 return (e);
3214 }
3215
3216 /* create a tmp copy of the new acl */
3217 tmp_acl_len = new_acl_len;
3218 if (tmp_acl_len > 0) {
3219 tmp_acl = kmem_zalloc(new_acl_len*sizeof (*tmp_acl), KM_SLEEP);
3220 for (i = 0; i < tmp_acl_len; i++) {
3221 tmp_acl[i].ae_node = new_acl[i].ae_node;
3222 tmp_acl[i].ae_permission = new_acl[i].ae_permission;
3223 }
3224 /*
3225 * The default permission of a node which was in the old
3226 * ACL but not in the new ACL is 0 ie no access.
3227 */
3228 permission = 0;
3229 } else {
3230 /*
3231 * NULL acl means all importers can connect and
3232 * default permission will be owner creation umask
3233 */
3234 tmp_acl = NULL;
3235 permission = seg->s_mode;
3236 }
3237
3238 /* make other republishers to wait for republish to complete */
3239 seg->s_flags |= RSM_REPUBLISH_WAIT;
3240
3241 rsmseglock_release(seg);
3242
3243 /* send the new perms to the importing nodes */
3244 rsm_send_republish(key, tmp_acl, tmp_acl_len, permission);
3245
3246 rsmseglock_acquire(seg);
3247 seg->s_flags &= ~RSM_REPUBLISH_WAIT;
3248 /* wake up any one waiting for republish to complete */
3249 cv_broadcast(&seg->s_cv);
3250 rsmseglock_release(seg);
3251
3252 rsmacl_free(tmp_acl, tmp_acl_len);
3253 rsmacl_free(old_acl, old_acl_len);
3254 rsmpiacl_free(rsmpi_old_acl, old_acl_len);
3255
3256 DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_republish done\n"));
3257 return (DDI_SUCCESS);
3258 }
3259
3260 static int
rsm_unpublish(rsmseg_t * seg,int mode)3261 rsm_unpublish(rsmseg_t *seg, int mode)
3262 {
3263 rsmapi_access_entry_t *acl;
3264 rsm_access_entry_t *rsmpi_acl;
3265 int acl_len;
3266 int e;
3267 adapter_t *adapter;
3268 DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_EXPORT);
3269
3270 DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_unpublish enter\n"));
3271
3272 if (seg->s_pid != ddi_get_pid() &&
3273 ddi_get_pid() != 0) {
3274 DBG_PRINTF((category, RSM_ERR,
3275 "rsm_unpublish: Not creator\n"));
3276 return (RSMERR_NOT_CREATOR);
3277 }
3278
3279 rsmseglock_acquire(seg);
3280 /*
3281 * wait for QUIESCING to complete here before rsmexport_rm
3282 * is called because the SUSPEND_COMPLETE mesg which changes
3283 * the seg state from EXPORT_QUIESCING to EXPORT_QUIESCED and
3284 * signals the cv_wait needs to find it in the hashtable.
3285 */
3286 while ((seg->s_state == RSM_STATE_EXPORT_QUIESCING) ||
3287 ((seg->s_state == RSM_STATE_EXPORT) && (seg->s_rdmacnt > 0))) {
3288 if (cv_wait_sig(&seg->s_cv, &seg->s_lock) == 0) {
3289 rsmseglock_release(seg);
3290 DBG_PRINTF((category, RSM_ERR,
3291 "rsm_unpublish done: cv_wait INTR qscing"
3292 "getv/putv in progress"));
3293 return (RSMERR_INTERRUPTED);
3294 }
3295 }
3296
3297 /* verify segment state */
3298 if ((seg->s_state != RSM_STATE_EXPORT) &&
3299 (seg->s_state != RSM_STATE_EXPORT_QUIESCED)) {
3300 rsmseglock_release(seg);
3301 DBG_PRINTF((category, RSM_ERR,
3302 "rsm_unpublish done: bad state %x\n", seg->s_state));
3303 return (RSMERR_SEG_NOT_PUBLISHED);
3304 }
3305
3306 rsmseglock_release(seg);
3307
3308 rsmexport_rm(seg);
3309
3310 rsm_send_importer_disconnects(seg->s_segid, my_nodeid);
3311
3312 rsmseglock_acquire(seg);
3313 /*
3314 * wait for republish to complete
3315 */
3316 while ((seg->s_state == RSM_STATE_EXPORT) &&
3317 (seg->s_flags & RSM_REPUBLISH_WAIT)) {
3318 if (cv_wait_sig(&seg->s_cv, &seg->s_lock) == 0) {
3319 DBG_PRINTF((category, RSM_ERR,
3320 "rsm_unpublish done: cv_wait INTR repubing"));
3321 rsmseglock_release(seg);
3322 return (RSMERR_INTERRUPTED);
3323 }
3324 }
3325
3326 if ((seg->s_state != RSM_STATE_EXPORT) &&
3327 (seg->s_state != RSM_STATE_EXPORT_QUIESCED)) {
3328 DBG_PRINTF((category, RSM_ERR,
3329 "rsm_unpublish done: invalid state"));
3330 rsmseglock_release(seg);
3331 return (RSMERR_SEG_NOT_PUBLISHED);
3332 }
3333
3334 /*
3335 * check for putv/get surrogate segment which was not published
3336 * to the driver.
3337 *
3338 * Be certain to see if there is an ACL first! If this segment was
3339 * not published with an ACL, acl will be a null pointer. Check
3340 * that before dereferencing it.
3341 */
3342 acl = seg->s_acl;
3343 if (acl != (rsmapi_access_entry_t *)NULL) {
3344 if (acl[0].ae_node == my_nodeid && acl[0].ae_permission == 0)
3345 goto bypass;
3346 }
3347
3348 /* The RSMPI unpublish/destroy has been done if seg is QUIESCED */
3349 if (seg->s_state == RSM_STATE_EXPORT_QUIESCED)
3350 goto bypass;
3351
3352 adapter = seg->s_adapter;
3353 for (;;) {
3354 if (seg->s_state != RSM_STATE_EXPORT) {
3355 rsmseglock_release(seg);
3356 DBG_PRINTF((category, RSM_ERR,
3357 "rsm_unpublish done: bad state %x\n",
3358 seg->s_state));
3359 return (RSMERR_SEG_NOT_PUBLISHED);
3360 }
3361
3362 /* unpublish from adapter */
3363 e = adapter->rsmpi_ops->rsm_unpublish(seg->s_handle.out);
3364
3365 if (e == RSM_SUCCESS) {
3366 break;
3367 }
3368
3369 if (e == RSMERR_SEG_IN_USE && mode == 1) {
3370 /*
3371 * wait for unpublish to succeed, it's busy.
3372 */
3373 seg->s_flags |= RSM_EXPORT_WAIT;
3374
3375 /* wait for a max of 1 ms - this is an empirical */
3376 /* value that was found by some minimal testing */
3377 /* can be fine tuned when we have better numbers */
3378 /* A long term fix would be to send cv_signal */
3379 /* from the intr callback routine */
3380 /* currently nobody signals this wait */
3381 (void) cv_reltimedwait(&seg->s_cv, &seg->s_lock,
3382 drv_usectohz(1000), TR_CLOCK_TICK);
3383
3384 DBG_PRINTF((category, RSM_ERR,
3385 "rsm_unpublish: SEG_IN_USE\n"));
3386
3387 seg->s_flags &= ~RSM_EXPORT_WAIT;
3388 } else {
3389 if (mode == 1) {
3390 DBG_PRINTF((category, RSM_ERR,
3391 "rsm:rsmpi unpublish err %x\n", e));
3392 seg->s_state = RSM_STATE_BIND;
3393 }
3394 rsmseglock_release(seg);
3395 return (e);
3396 }
3397 }
3398
3399 /* Free segment */
3400 e = adapter->rsmpi_ops->rsm_seg_destroy(seg->s_handle.out);
3401
3402 if (e != RSM_SUCCESS) {
3403 DBG_PRINTF((category, RSM_ERR,
3404 "rsm_unpublish: rsmpi destroy key=%x failed %x\n",
3405 seg->s_key, e));
3406 }
3407
3408 bypass:
3409 acl = seg->s_acl;
3410 rsmpi_acl = seg->s_acl_in;
3411 acl_len = seg->s_acl_len;
3412
3413 seg->s_acl = NULL;
3414 seg->s_acl_in = NULL;
3415 seg->s_acl_len = 0;
3416
3417 if (seg->s_state == RSM_STATE_EXPORT) {
3418 seg->s_state = RSM_STATE_BIND;
3419 } else if (seg->s_state == RSM_STATE_EXPORT_QUIESCED) {
3420 seg->s_state = RSM_STATE_BIND_QUIESCED;
3421 cv_broadcast(&seg->s_cv);
3422 }
3423
3424 rsmseglock_release(seg);
3425
3426 rsmacl_free(acl, acl_len);
3427 rsmpiacl_free(rsmpi_acl, acl_len);
3428
3429 DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_unpublish done\n"));
3430
3431 return (DDI_SUCCESS);
3432 }
3433
3434 /*
3435 * Called from rsm_unpublish to force an unload and disconnection of all
3436 * importers of the unpublished segment.
3437 *
3438 * First build the list of segments requiring a force disconnect, then
3439 * send a request for each.
3440 */
3441 static void
rsm_send_importer_disconnects(rsm_memseg_id_t ex_segid,rsm_node_id_t ex_nodeid)3442 rsm_send_importer_disconnects(rsm_memseg_id_t ex_segid,
3443 rsm_node_id_t ex_nodeid)
3444 {
3445 rsmipc_request_t request;
3446 importing_token_t *prev_token, *token, *tmp_token, *tokp;
3447 importing_token_t *force_disconnect_list = NULL;
3448 int index;
3449
3450 DBG_PRINTF((RSM_KERNEL_AGENT | RSM_EXPORT, RSM_DEBUG_VERBOSE,
3451 "rsm_send_importer_disconnects enter\n"));
3452
3453 index = rsmhash(ex_segid);
3454
3455 mutex_enter(&importer_list.lock);
3456
3457 prev_token = NULL;
3458 token = importer_list.bucket[index];
3459
3460 while (token != NULL) {
3461 if (token->key == ex_segid) {
3462 /*
3463 * take it off the importer list and add it
3464 * to the force disconnect list.
3465 */
3466 if (prev_token == NULL)
3467 importer_list.bucket[index] = token->next;
3468 else
3469 prev_token->next = token->next;
3470 tmp_token = token;
3471 token = token->next;
3472 if (force_disconnect_list == NULL) {
3473 force_disconnect_list = tmp_token;
3474 tmp_token->next = NULL;
3475 } else {
3476 tokp = force_disconnect_list;
3477 /*
3478 * make sure that the tmp_token's node
3479 * is not already on the force disconnect
3480 * list.
3481 */
3482 while (tokp != NULL) {
3483 if (tokp->importing_node ==
3484 tmp_token->importing_node) {
3485 break;
3486 }
3487 tokp = tokp->next;
3488 }
3489 if (tokp == NULL) {
3490 tmp_token->next =
3491 force_disconnect_list;
3492 force_disconnect_list = tmp_token;
3493 } else {
3494 kmem_free((void *)tmp_token,
3495 sizeof (*token));
3496 }
3497 }
3498
3499 } else {
3500 prev_token = token;
3501 token = token->next;
3502 }
3503 }
3504 mutex_exit(&importer_list.lock);
3505
3506 token = force_disconnect_list;
3507 while (token != NULL) {
3508 if (token->importing_node == my_nodeid) {
3509 rsm_force_unload(ex_nodeid, ex_segid,
3510 DISCONNECT);
3511 } else {
3512 request.rsmipc_hdr.rsmipc_type =
3513 RSMIPC_MSG_DISCONNECT;
3514 request.rsmipc_key = token->key;
3515 for (;;) {
3516 if (rsmipc_send(token->importing_node,
3517 &request,
3518 RSM_NO_REPLY) == RSM_SUCCESS) {
3519 break;
3520 } else {
3521 delay(drv_usectohz(10000));
3522 }
3523 }
3524 }
3525 tmp_token = token;
3526 token = token->next;
3527 kmem_free((void *)tmp_token, sizeof (*token));
3528 }
3529
3530 DBG_PRINTF((RSM_KERNEL_AGENT | RSM_EXPORT, RSM_DEBUG_VERBOSE,
3531 "rsm_send_importer_disconnects done\n"));
3532 }
3533
3534 /*
3535 * This function is used as a callback for unlocking the pages locked
3536 * down by a process which then does a fork or an exec.
3537 * It marks the export segments corresponding to umem cookie given by
3538 * the *arg to be in a ZOMBIE state(by calling rsmseg_close to be
3539 * destroyed later when an rsm_close occurs).
3540 */
3541 static void
rsm_export_force_destroy(ddi_umem_cookie_t * ck)3542 rsm_export_force_destroy(ddi_umem_cookie_t *ck)
3543 {
3544 rsmresource_blk_t *blk;
3545 rsmresource_t *p;
3546 rsmseg_t *eseg = NULL;
3547 int i, j;
3548 int found = 0;
3549
3550 DBG_PRINTF((RSM_KERNEL_AGENT | RSM_EXPORT, RSM_DEBUG_VERBOSE,
3551 "rsm_export_force_destroy enter\n"));
3552
3553 /*
3554 * Walk the resource list and locate the export segment (either
3555 * in the BIND or the EXPORT state) which corresponds to the
3556 * ddi_umem_cookie_t being freed up, and call rsmseg_close.
3557 * Change the state to ZOMBIE by calling rsmseg_close with the
3558 * force_flag argument (the second argument) set to 1. Also,
3559 * unpublish and unbind the segment, but don't free it. Free it
3560 * only on a rsm_close call for the segment.
3561 */
3562 rw_enter(&rsm_resource.rsmrc_lock, RW_READER);
3563
3564 for (i = 0; i < rsm_resource.rsmrc_len; i++) {
3565 blk = rsm_resource.rsmrc_root[i];
3566 if (blk == NULL) {
3567 continue;
3568 }
3569
3570 for (j = 0; j < RSMRC_BLKSZ; j++) {
3571 p = blk->rsmrcblk_blks[j];
3572 if ((p != NULL) && (p != RSMRC_RESERVED) &&
3573 (p->rsmrc_type == RSM_RESOURCE_EXPORT_SEGMENT)) {
3574 eseg = (rsmseg_t *)p;
3575 if (eseg->s_cookie != ck)
3576 continue; /* continue searching */
3577 /*
3578 * Found the segment, set flag to indicate
3579 * force destroy processing is in progress
3580 */
3581 rsmseglock_acquire(eseg);
3582 eseg->s_flags |= RSM_FORCE_DESTROY_WAIT;
3583 rsmseglock_release(eseg);
3584 found = 1;
3585 break;
3586 }
3587 }
3588
3589 if (found)
3590 break;
3591 }
3592
3593 rw_exit(&rsm_resource.rsmrc_lock);
3594
3595 if (found) {
3596 ASSERT(eseg != NULL);
3597 /* call rsmseg_close with force flag set to 1 */
3598 rsmseg_close(eseg, 1);
3599 /*
3600 * force destroy processing done, clear flag and signal any
3601 * thread waiting in rsmseg_close.
3602 */
3603 rsmseglock_acquire(eseg);
3604 eseg->s_flags &= ~RSM_FORCE_DESTROY_WAIT;
3605 cv_broadcast(&eseg->s_cv);
3606 rsmseglock_release(eseg);
3607 }
3608
3609 DBG_PRINTF((RSM_KERNEL_AGENT | RSM_EXPORT, RSM_DEBUG_VERBOSE,
3610 "rsm_export_force_destroy done\n"));
3611 }
3612
3613 /* ******************************* Remote Calls *********************** */
3614 static void
rsm_intr_segconnect(rsm_node_id_t src,rsmipc_request_t * req)3615 rsm_intr_segconnect(rsm_node_id_t src, rsmipc_request_t *req)
3616 {
3617 rsmipc_reply_t reply;
3618 DBG_DEFINE(category,
3619 RSM_KERNEL_AGENT | RSM_FUNC_ALL | RSM_INTR_CALLBACK);
3620
3621 DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
3622 "rsm_intr_segconnect enter\n"));
3623
3624 reply.rsmipc_status = (short)rsmsegacl_validate(req, src, &reply);
3625
3626 reply.rsmipc_hdr.rsmipc_type = RSMIPC_MSG_REPLY;
3627 reply.rsmipc_hdr.rsmipc_cookie = req->rsmipc_hdr.rsmipc_cookie;
3628
3629 (void) rsmipc_send(src, NULL, &reply);
3630
3631 DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
3632 "rsm_intr_segconnect done\n"));
3633 }
3634
3635
3636 /*
3637 * When an exported segment is unpublished the exporter sends an ipc
3638 * message (RSMIPC_MSG_DISCONNECT) to all importers. The recv ipc dispatcher
3639 * calls this function. The import list is scanned; segments which match the
3640 * exported segment id are unloaded and disconnected.
3641 *
3642 * Will also be called from rsm_rebind with disconnect_flag FALSE.
3643 *
3644 */
3645 static void
rsm_force_unload(rsm_node_id_t src_nodeid,rsm_memseg_id_t ex_segid,boolean_t disconnect_flag)3646 rsm_force_unload(rsm_node_id_t src_nodeid, rsm_memseg_id_t ex_segid,
3647 boolean_t disconnect_flag)
3648 {
3649 rsmresource_t *p = NULL;
3650 rsmhash_table_t *rhash = &rsm_import_segs;
3651 uint_t index;
3652 DBG_DEFINE(category,
3653 RSM_KERNEL_AGENT | RSM_FUNC_ALL | RSM_INTR_CALLBACK);
3654
3655 DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_force_unload enter\n"));
3656
3657 index = rsmhash(ex_segid);
3658
3659 rw_enter(&rhash->rsmhash_rw, RW_READER);
3660
3661 p = rsmhash_getbkt(rhash, index);
3662
3663 for (; p; p = p->rsmrc_next) {
3664 rsmseg_t *seg = (rsmseg_t *)p;
3665 if ((seg->s_segid == ex_segid) && (seg->s_node == src_nodeid)) {
3666 /*
3667 * In order to make rsmseg_unload and rsm_force_unload
3668 * thread safe, acquire the segment lock here.
3669 * rsmseg_unload is responsible for releasing the lock.
3670 * rsmseg_unload releases the lock just before a call
3671 * to rsmipc_send or in case of an early exit which
3672 * occurs if the segment was in the state
3673 * RSM_STATE_CONNECTING or RSM_STATE_NEW.
3674 */
3675 rsmseglock_acquire(seg);
3676 if (disconnect_flag)
3677 seg->s_flags |= RSM_FORCE_DISCONNECT;
3678 rsmseg_unload(seg);
3679 }
3680 }
3681 rw_exit(&rhash->rsmhash_rw);
3682
3683 DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_force_unload done\n"));
3684 }
3685
3686 static void
rsm_intr_reply(rsmipc_msghdr_t * msg)3687 rsm_intr_reply(rsmipc_msghdr_t *msg)
3688 {
3689 /*
3690 * Find slot for cookie in reply.
3691 * Match sequence with sequence in cookie
3692 * If no match; return
3693 * Try to grap lock of slot, if locked return
3694 * copy data into reply slot area
3695 * signal waiter
3696 */
3697 rsmipc_slot_t *slot;
3698 rsmipc_cookie_t *cookie;
3699 void *data = (void *) msg;
3700 size_t size = sizeof (rsmipc_reply_t);
3701 DBG_DEFINE(category,
3702 RSM_KERNEL_AGENT | RSM_FUNC_ALL | RSM_INTR_CALLBACK);
3703
3704 DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_intr_reply enter\n"));
3705
3706 cookie = &msg->rsmipc_cookie;
3707 if (cookie->ic.index >= RSMIPC_SZ) {
3708 DBG_PRINTF((category, RSM_ERR,
3709 "rsm: rsm_intr_reply bad cookie %d\n", cookie->ic.index));
3710 return;
3711 }
3712
3713 ASSERT(cookie->ic.index < RSMIPC_SZ);
3714 slot = &rsm_ipc.slots[cookie->ic.index];
3715 mutex_enter(&slot->rsmipc_lock);
3716 if (slot->rsmipc_cookie.value == cookie->value) {
3717 /* found a match */
3718 if (RSMIPC_GET(slot, RSMIPC_PENDING)) {
3719 bcopy(data, slot->rsmipc_data, size);
3720 RSMIPC_CLEAR(slot, RSMIPC_PENDING);
3721 cv_signal(&slot->rsmipc_cv);
3722 }
3723 } else {
3724 DBG_PRINTF((category, RSM_DEBUG,
3725 "rsm: rsm_intr_reply mismatched reply %d\n",
3726 cookie->ic.index));
3727 }
3728 mutex_exit(&slot->rsmipc_lock);
3729 DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_intr_reply done\n"));
3730 }
3731
3732 /*
3733 * This function gets dispatched on the worker thread when we receive
3734 * the SQREADY message. This function sends the SQREADY_ACK message.
3735 */
3736 static void
rsm_sqready_ack_deferred(void * arg)3737 rsm_sqready_ack_deferred(void *arg)
3738 {
3739 path_t *path = (path_t *)arg;
3740 DBG_DEFINE(category,
3741 RSM_KERNEL_AGENT | RSM_FUNC_ALL | RSM_INTR_CALLBACK);
3742
3743 DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
3744 "rsm_sqready_ack_deferred enter\n"));
3745
3746 mutex_enter(&path->mutex);
3747
3748 /*
3749 * If path is not active no point in sending the ACK
3750 * because the whole SQREADY protocol will again start
3751 * when the path becomes active.
3752 */
3753 if (path->state != RSMKA_PATH_ACTIVE) {
3754 /*
3755 * decrement the path refcnt incremented in rsm_proc_sqready
3756 */
3757 PATH_RELE_NOLOCK(path);
3758 mutex_exit(&path->mutex);
3759 DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
3760 "rsm_sqready_ack_deferred done:!ACTIVE\n"));
3761 return;
3762 }
3763
3764 /* send an SQREADY_ACK message */
3765 (void) rsmipc_send_controlmsg(path, RSMIPC_MSG_SQREADY_ACK);
3766
3767 /* initialize credits to the max level */
3768 path->sendq_token.msgbuf_avail = RSMIPC_MAX_MESSAGES;
3769
3770 /* wake up any send that is waiting for credits */
3771 cv_broadcast(&path->sendq_token.sendq_cv);
3772
3773 /*
3774 * decrement the path refcnt since we incremented it in
3775 * rsm_proc_sqready
3776 */
3777 PATH_RELE_NOLOCK(path);
3778
3779 mutex_exit(&path->mutex);
3780
3781 DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
3782 "rsm_sqready_ack_deferred done\n"));
3783 }
3784
3785 /*
3786 * Process the SQREADY message
3787 */
3788 static void
rsm_proc_sqready(rsmipc_controlmsg_t * msg,rsm_addr_t src_hwaddr,rsm_intr_hand_arg_t arg)3789 rsm_proc_sqready(rsmipc_controlmsg_t *msg, rsm_addr_t src_hwaddr,
3790 rsm_intr_hand_arg_t arg)
3791 {
3792 rsmipc_msghdr_t *msghdr = (rsmipc_msghdr_t *)msg;
3793 srv_handler_arg_t *hdlr_argp = (srv_handler_arg_t *)arg;
3794 path_t *path;
3795 DBG_DEFINE(category,
3796 RSM_KERNEL_AGENT | RSM_FUNC_ALL | RSM_INTR_CALLBACK);
3797
3798 DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_proc_sqready enter\n"));
3799
3800 /* look up the path - incr the path refcnt */
3801 path = rsm_find_path(hdlr_argp->adapter_name,
3802 hdlr_argp->adapter_instance, src_hwaddr);
3803
3804 /*
3805 * No path exists or path is not active - drop the message
3806 */
3807 if (path == NULL) {
3808 DBG_PRINTF((category, RSM_DEBUG,
3809 "rsm_proc_sqready done: msg dropped no path\n"));
3810 return;
3811 }
3812
3813 mutex_exit(&path->mutex);
3814
3815 /* drain any tasks from the previous incarnation */
3816 taskq_wait(path->recv_taskq);
3817
3818 mutex_enter(&path->mutex);
3819 /*
3820 * If we'd sent an SQREADY message and were waiting for SQREADY_ACK
3821 * in the meanwhile we received an SQREADY message, blindly reset
3822 * the WAIT_FOR_SQACK flag because we'll just send SQREADY_ACK
3823 * and forget about the SQREADY that we sent.
3824 */
3825 path->flags &= ~RSMKA_WAIT_FOR_SQACK;
3826
3827 if (path->state != RSMKA_PATH_ACTIVE) {
3828 /* decr refcnt and drop the mutex */
3829 PATH_RELE_NOLOCK(path);
3830 mutex_exit(&path->mutex);
3831 DBG_PRINTF((category, RSM_DEBUG,
3832 "rsm_proc_sqready done: msg dropped path !ACTIVE\n"));
3833 return;
3834 }
3835
3836 DBG_PRINTF((category, RSM_DEBUG, "rsm_proc_sqready:path=%lx "
3837 " src=%lx:%llx\n", path, msghdr->rsmipc_src, src_hwaddr));
3838
3839 /*
3840 * The sender's local incarnation number is our remote incarnation
3841 * number save it in the path data structure
3842 */
3843 path->remote_incn = msg->rsmipc_local_incn;
3844 path->sendq_token.msgbuf_avail = 0;
3845 path->procmsg_cnt = 0;
3846
3847 /*
3848 * path is active - dispatch task to send SQREADY_ACK - remember
3849 * RSMPI calls can't be done in interrupt context
3850 *
3851 * We can use the recv_taskq to send because the remote endpoint
3852 * cannot start sending messages till it receives SQREADY_ACK hence
3853 * at this point there are no tasks on recv_taskq.
3854 *
3855 * The path refcnt will be decremented in rsm_sqready_ack_deferred.
3856 */
3857 (void) taskq_dispatch(path->recv_taskq,
3858 rsm_sqready_ack_deferred, path, KM_NOSLEEP);
3859
3860 mutex_exit(&path->mutex);
3861
3862
3863 DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_proc_sqready done\n"));
3864 }
3865
3866 /*
3867 * Process the SQREADY_ACK message
3868 */
3869 static void
rsm_proc_sqready_ack(rsmipc_controlmsg_t * msg,rsm_addr_t src_hwaddr,rsm_intr_hand_arg_t arg)3870 rsm_proc_sqready_ack(rsmipc_controlmsg_t *msg, rsm_addr_t src_hwaddr,
3871 rsm_intr_hand_arg_t arg)
3872 {
3873 rsmipc_msghdr_t *msghdr = (rsmipc_msghdr_t *)msg;
3874 srv_handler_arg_t *hdlr_argp = (srv_handler_arg_t *)arg;
3875 path_t *path;
3876 DBG_DEFINE(category,
3877 RSM_KERNEL_AGENT | RSM_FUNC_ALL | RSM_INTR_CALLBACK);
3878
3879 DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
3880 "rsm_proc_sqready_ack enter\n"));
3881
3882 /* look up the path - incr the path refcnt */
3883 path = rsm_find_path(hdlr_argp->adapter_name,
3884 hdlr_argp->adapter_instance, src_hwaddr);
3885
3886 /*
3887 * drop the message if - no path exists or path is not active
3888 * or if its not waiting for SQREADY_ACK message
3889 */
3890 if (path == NULL) {
3891 DBG_PRINTF((category, RSM_DEBUG,
3892 "rsm_proc_sqready_ack done: msg dropped no path\n"));
3893 return;
3894 }
3895
3896 if ((path->state != RSMKA_PATH_ACTIVE) ||
3897 !(path->flags & RSMKA_WAIT_FOR_SQACK)) {
3898 /* decrement the refcnt */
3899 PATH_RELE_NOLOCK(path);
3900 mutex_exit(&path->mutex);
3901 DBG_PRINTF((category, RSM_DEBUG,
3902 "rsm_proc_sqready_ack done: msg dropped\n"));
3903 return;
3904 }
3905
3906 /*
3907 * Check if this message is in response to the last RSMIPC_MSG_SQREADY
3908 * sent, if not drop it.
3909 */
3910 if (path->local_incn != msghdr->rsmipc_incn) {
3911 /* decrement the refcnt */
3912 PATH_RELE_NOLOCK(path);
3913 mutex_exit(&path->mutex);
3914 DBG_PRINTF((category, RSM_DEBUG,
3915 "rsm_proc_sqready_ack done: msg old incn %lld\n",
3916 msghdr->rsmipc_incn));
3917 return;
3918 }
3919
3920 DBG_PRINTF((category, RSM_DEBUG, "rsm_proc_sqready_ack:path=%lx "
3921 " src=%lx:%llx\n", path, msghdr->rsmipc_src, src_hwaddr));
3922
3923 /*
3924 * clear the WAIT_FOR_SQACK flag since we have recvd the ack
3925 */
3926 path->flags &= ~RSMKA_WAIT_FOR_SQACK;
3927
3928 /* save the remote sendq incn number */
3929 path->remote_incn = msg->rsmipc_local_incn;
3930
3931 /* initialize credits to the max level */
3932 path->sendq_token.msgbuf_avail = RSMIPC_MAX_MESSAGES;
3933
3934 /* wake up any send that is waiting for credits */
3935 cv_broadcast(&path->sendq_token.sendq_cv);
3936
3937 /* decrement the refcnt */
3938 PATH_RELE_NOLOCK(path);
3939
3940 mutex_exit(&path->mutex);
3941
3942 DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
3943 "rsm_proc_sqready_ack done\n"));
3944 }
3945
3946 /*
3947 * process the RSMIPC_MSG_CREDIT message
3948 */
3949 static void
rsm_add_credits(rsmipc_controlmsg_t * msg,rsm_addr_t src_hwaddr,rsm_intr_hand_arg_t arg)3950 rsm_add_credits(rsmipc_controlmsg_t *msg, rsm_addr_t src_hwaddr,
3951 rsm_intr_hand_arg_t arg)
3952 {
3953 rsmipc_msghdr_t *msghdr = (rsmipc_msghdr_t *)msg;
3954 srv_handler_arg_t *hdlr_argp = (srv_handler_arg_t *)arg;
3955 path_t *path;
3956 DBG_DEFINE(category,
3957 RSM_KERNEL_AGENT | RSM_FUNC_ALL |
3958 RSM_INTR_CALLBACK | RSM_FLOWCONTROL);
3959
3960 DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_add_credits enter\n"));
3961
3962 /* look up the path - incr the path refcnt */
3963 path = rsm_find_path(hdlr_argp->adapter_name,
3964 hdlr_argp->adapter_instance, src_hwaddr);
3965
3966 if (path == NULL) {
3967 DBG_PRINTF((category, RSM_DEBUG,
3968 "rsm_add_credits enter: path not found\n"));
3969 return;
3970 }
3971
3972 /* the path is not active - discard credits */
3973 if (path->state != RSMKA_PATH_ACTIVE) {
3974 PATH_RELE_NOLOCK(path);
3975 mutex_exit(&path->mutex);
3976 DBG_PRINTF((category, RSM_DEBUG,
3977 "rsm_add_credits enter:path=%lx !ACTIVE\n", path));
3978 return;
3979 }
3980
3981 /*
3982 * Check if these credits are for current incarnation of the path.
3983 */
3984 if (path->local_incn != msghdr->rsmipc_incn) {
3985 /* decrement the refcnt */
3986 PATH_RELE_NOLOCK(path);
3987 mutex_exit(&path->mutex);
3988 DBG_PRINTF((category, RSM_DEBUG,
3989 "rsm_add_credits enter: old incn %lld\n",
3990 msghdr->rsmipc_incn));
3991 return;
3992 }
3993
3994 DBG_PRINTF((category, RSM_DEBUG,
3995 "rsm_add_credits:path=%lx new-creds=%d "
3996 "curr credits=%d src=%lx:%llx\n", path, msg->rsmipc_credits,
3997 path->sendq_token.msgbuf_avail, msghdr->rsmipc_src,
3998 src_hwaddr));
3999
4000
4001 /* add credits to the path's sendq */
4002 path->sendq_token.msgbuf_avail += msg->rsmipc_credits;
4003
4004 ASSERT(path->sendq_token.msgbuf_avail <= RSMIPC_MAX_MESSAGES);
4005
4006 /* wake up any send that is waiting for credits */
4007 cv_broadcast(&path->sendq_token.sendq_cv);
4008
4009 /* decrement the refcnt */
4010 PATH_RELE_NOLOCK(path);
4011
4012 mutex_exit(&path->mutex);
4013
4014 DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_add_credits done\n"));
4015 }
4016
4017 static void
rsm_intr_event(rsmipc_request_t * msg)4018 rsm_intr_event(rsmipc_request_t *msg)
4019 {
4020 rsmseg_t *seg;
4021 rsmresource_t *p;
4022 rsm_node_id_t src_node;
4023 DBG_DEFINE(category,
4024 RSM_KERNEL_AGENT | RSM_FUNC_ALL | RSM_INTR_CALLBACK);
4025
4026 DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_intr_event enter\n"));
4027
4028 src_node = msg->rsmipc_hdr.rsmipc_src;
4029
4030 if ((seg = msg->rsmipc_segment_cookie) != NULL) {
4031 /* This is for an import segment */
4032 uint_t hashval = rsmhash(msg->rsmipc_key);
4033
4034 rw_enter(&rsm_import_segs.rsmhash_rw, RW_READER);
4035
4036 p = (rsmresource_t *)rsmhash_getbkt(&rsm_import_segs, hashval);
4037
4038 for (; p; p = p->rsmrc_next) {
4039 if ((p->rsmrc_key == msg->rsmipc_key) &&
4040 (p->rsmrc_node == src_node)) {
4041 seg = (rsmseg_t *)p;
4042 rsmseglock_acquire(seg);
4043
4044 atomic_inc_32(&seg->s_pollevent);
4045
4046 if (seg->s_pollflag & RSM_SEGMENT_POLL)
4047 pollwakeup(&seg->s_poll, POLLRDNORM);
4048
4049 rsmseglock_release(seg);
4050 }
4051 }
4052
4053 rw_exit(&rsm_import_segs.rsmhash_rw);
4054 } else {
4055 /* This is for an export segment */
4056 seg = rsmexport_lookup(msg->rsmipc_key);
4057 if (!seg) {
4058 DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
4059 "rsm_intr_event done: exp seg not found\n"));
4060 return;
4061 }
4062
4063 ASSERT(rsmseglock_held(seg));
4064
4065 atomic_inc_32(&seg->s_pollevent);
4066
4067 /*
4068 * We must hold the segment lock here, or else the segment
4069 * can be freed while pollwakeup is using it. This implies
4070 * that we MUST NOT grab the segment lock during rsm_chpoll,
4071 * as outlined in the chpoll(2) man page.
4072 */
4073 if (seg->s_pollflag & RSM_SEGMENT_POLL)
4074 pollwakeup(&seg->s_poll, POLLRDNORM);
4075
4076 rsmseglock_release(seg);
4077 }
4078
4079 DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_intr_event done\n"));
4080 }
4081
4082 /*
4083 * The exporter did a republish and changed the ACL - this change is only
4084 * visible to new importers.
4085 */
4086 static void
importer_update(rsm_node_id_t src_node,rsm_memseg_id_t key,rsm_permission_t perm)4087 importer_update(rsm_node_id_t src_node, rsm_memseg_id_t key,
4088 rsm_permission_t perm)
4089 {
4090
4091 rsmresource_t *p;
4092 rsmseg_t *seg;
4093 uint_t hashval = rsmhash(key);
4094 DBG_DEFINE(category,
4095 RSM_KERNEL_AGENT | RSM_FUNC_ALL | RSM_INTR_CALLBACK);
4096
4097 DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "importer_update enter\n"));
4098
4099 rw_enter(&rsm_import_segs.rsmhash_rw, RW_READER);
4100
4101 p = (rsmresource_t *)rsmhash_getbkt(&rsm_import_segs, hashval);
4102
4103 for (; p; p = p->rsmrc_next) {
4104 /*
4105 * find the importer and update the permission in the shared
4106 * data structure. Any new importers will use the new perms
4107 */
4108 if ((p->rsmrc_key == key) && (p->rsmrc_node == src_node)) {
4109 seg = (rsmseg_t *)p;
4110
4111 rsmseglock_acquire(seg);
4112 rsmsharelock_acquire(seg);
4113 seg->s_share->rsmsi_mode = perm;
4114 rsmsharelock_release(seg);
4115 rsmseglock_release(seg);
4116
4117 break;
4118 }
4119 }
4120
4121 rw_exit(&rsm_import_segs.rsmhash_rw);
4122
4123 DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "importer_update done\n"));
4124 }
4125
4126 void
rsm_suspend_complete(rsm_node_id_t src_node,int flag)4127 rsm_suspend_complete(rsm_node_id_t src_node, int flag)
4128 {
4129 int done = 1; /* indicate all SUSPENDS have been acked */
4130 list_element_t *elem;
4131 DBG_DEFINE(category,
4132 RSM_KERNEL_AGENT | RSM_FUNC_ALL | RSM_INTR_CALLBACK);
4133
4134 DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
4135 "rsm_suspend_complete enter\n"));
4136
4137 mutex_enter(&rsm_suspend_list.list_lock);
4138
4139 if (rsm_suspend_list.list_head == NULL) {
4140 DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
4141 "rsm_suspend_complete done: suspend_list is empty\n"));
4142 mutex_exit(&rsm_suspend_list.list_lock);
4143 return;
4144 }
4145
4146 elem = rsm_suspend_list.list_head;
4147 while (elem != NULL) {
4148 if (elem->nodeid == src_node) {
4149 /* clear the pending flag for the node */
4150 elem->flags &= ~RSM_SUSPEND_ACKPENDING;
4151 elem->flags |= flag;
4152 }
4153
4154 if (done && (elem->flags & RSM_SUSPEND_ACKPENDING))
4155 done = 0; /* still some nodes have not yet ACKED */
4156
4157 elem = elem->next;
4158 }
4159
4160 mutex_exit(&rsm_suspend_list.list_lock);
4161
4162 if (!done) {
4163 DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
4164 "rsm_suspend_complete done: acks pending\n"));
4165 return;
4166 }
4167 /*
4168 * Now that we are done with suspending all the remote importers
4169 * time to quiesce the local exporters
4170 */
4171 exporter_quiesce();
4172
4173 DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
4174 "rsm_suspend_complete done\n"));
4175 }
4176
4177 static void
exporter_quiesce()4178 exporter_quiesce()
4179 {
4180 int i, e;
4181 rsmresource_t *current;
4182 rsmseg_t *seg;
4183 adapter_t *adapter;
4184 DBG_DEFINE(category,
4185 RSM_KERNEL_AGENT | RSM_FUNC_ALL | RSM_INTR_CALLBACK);
4186
4187 DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "exporter_quiesce enter\n"));
4188 /*
4189 * The importers send a SUSPEND_COMPLETE to the exporter node
4190 * Unpublish, unbind the export segment and
4191 * move the segments to the EXPORT_QUIESCED state
4192 */
4193
4194 rw_enter(&rsm_export_segs.rsmhash_rw, RW_READER);
4195
4196 for (i = 0; i < rsm_hash_size; i++) {
4197 current = rsm_export_segs.bucket[i];
4198 while (current != NULL) {
4199 seg = (rsmseg_t *)current;
4200 rsmseglock_acquire(seg);
4201 if (current->rsmrc_state ==
4202 RSM_STATE_EXPORT_QUIESCING) {
4203 adapter = seg->s_adapter;
4204 /*
4205 * some local memory handles are not published
4206 * check if it was published
4207 */
4208 if ((seg->s_acl == NULL) ||
4209 (seg->s_acl[0].ae_node != my_nodeid) ||
4210 (seg->s_acl[0].ae_permission != 0)) {
4211
4212 e = adapter->rsmpi_ops->rsm_unpublish(
4213 seg->s_handle.out);
4214 DBG_PRINTF((category, RSM_DEBUG,
4215 "exporter_quiesce:unpub %d\n", e));
4216
4217 e = adapter->rsmpi_ops->rsm_seg_destroy(
4218 seg->s_handle.out);
4219
4220 DBG_PRINTF((category, RSM_DEBUG,
4221 "exporter_quiesce:destroy %d\n",
4222 e));
4223 }
4224
4225 (void) rsm_unbind_pages(seg);
4226 seg->s_state = RSM_STATE_EXPORT_QUIESCED;
4227 cv_broadcast(&seg->s_cv);
4228 }
4229 rsmseglock_release(seg);
4230 current = current->rsmrc_next;
4231 }
4232 }
4233 rw_exit(&rsm_export_segs.rsmhash_rw);
4234
4235 /*
4236 * All the local segments we are done with the pre-del processing
4237 * - time to move to PREDEL_COMPLETED.
4238 */
4239
4240 mutex_enter(&rsm_drv_data.drv_lock);
4241
4242 ASSERT(rsm_drv_data.drv_state == RSM_DRV_PREDEL_STARTED);
4243
4244 rsm_drv_data.drv_state = RSM_DRV_PREDEL_COMPLETED;
4245
4246 cv_broadcast(&rsm_drv_data.drv_cv);
4247
4248 mutex_exit(&rsm_drv_data.drv_lock);
4249
4250 DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "exporter_quiesce done\n"));
4251 }
4252
4253 static void
importer_suspend(rsm_node_id_t src_node)4254 importer_suspend(rsm_node_id_t src_node)
4255 {
4256 int i;
4257 int susp_flg; /* true means already suspended */
4258 int num_importers;
4259 rsmresource_t *p = NULL, *curp;
4260 rsmhash_table_t *rhash = &rsm_import_segs;
4261 rsmseg_t *seg;
4262 rsmipc_request_t request;
4263 DBG_DEFINE(category,
4264 RSM_KERNEL_AGENT | RSM_FUNC_ALL | RSM_INTR_CALLBACK);
4265
4266 DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "importer_suspend enter\n"));
4267
4268 rw_enter(&rhash->rsmhash_rw, RW_READER);
4269 for (i = 0; i < rsm_hash_size; i++) {
4270 p = rhash->bucket[i];
4271
4272 /*
4273 * Suspend all importers with same <node, key> pair.
4274 * After the last one of the shared importers has been
4275 * suspended - suspend the shared mappings/connection.
4276 */
4277 for (; p; p = p->rsmrc_next) {
4278 rsmseg_t *first = (rsmseg_t *)p;
4279 if ((first->s_node != src_node) ||
4280 (first->s_state == RSM_STATE_DISCONNECT))
4281 continue; /* go to next entry */
4282 /*
4283 * search the rest of the bucket for
4284 * other siblings (imprtrs with the same key)
4285 * of "first" and suspend them.
4286 * All importers with same key fall in
4287 * the same bucket.
4288 */
4289 num_importers = 0;
4290 for (curp = p; curp; curp = curp->rsmrc_next) {
4291 seg = (rsmseg_t *)curp;
4292
4293 rsmseglock_acquire(seg);
4294
4295 if ((seg->s_node != first->s_node) ||
4296 (seg->s_key != first->s_key) ||
4297 (seg->s_state == RSM_STATE_DISCONNECT)) {
4298 /*
4299 * either not a peer segment or its a
4300 * disconnected segment - skip it
4301 */
4302 rsmseglock_release(seg);
4303 continue;
4304 }
4305
4306 rsmseg_suspend(seg, &susp_flg);
4307
4308 if (susp_flg) { /* seg already suspended */
4309 rsmseglock_release(seg);
4310 break; /* the inner for loop */
4311 }
4312
4313 num_importers++;
4314 rsmsharelock_acquire(seg);
4315 /*
4316 * we've processed all importers that are
4317 * siblings of "first"
4318 */
4319 if (num_importers ==
4320 seg->s_share->rsmsi_refcnt) {
4321 rsmsharelock_release(seg);
4322 rsmseglock_release(seg);
4323 break;
4324 }
4325 rsmsharelock_release(seg);
4326 rsmseglock_release(seg);
4327 }
4328
4329 /*
4330 * All the importers with the same key and
4331 * nodeid as "first" have been suspended.
4332 * Now suspend the shared connect/mapping.
4333 * This is done only once.
4334 */
4335 if (!susp_flg) {
4336 rsmsegshare_suspend(seg);
4337 }
4338 }
4339 }
4340
4341 rw_exit(&rhash->rsmhash_rw);
4342
4343 /* send an ACK for SUSPEND message */
4344 request.rsmipc_hdr.rsmipc_type = RSMIPC_MSG_SUSPEND_DONE;
4345 (void) rsmipc_send(src_node, &request, RSM_NO_REPLY);
4346
4347
4348 DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "importer_suspend done\n"));
4349
4350 }
4351
4352 static void
rsmseg_suspend(rsmseg_t * seg,int * susp_flg)4353 rsmseg_suspend(rsmseg_t *seg, int *susp_flg)
4354 {
4355 int recheck_state;
4356 rsmcookie_t *hdl;
4357 DBG_DEFINE(category,
4358 RSM_KERNEL_AGENT | RSM_FUNC_ALL | RSM_INTR_CALLBACK);
4359
4360 DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
4361 "rsmseg_suspend enter: key=%u\n", seg->s_key));
4362
4363 *susp_flg = 0;
4364
4365 ASSERT(rsmseglock_held(seg));
4366 /* wait if putv/getv is in progress */
4367 while (seg->s_rdmacnt > 0)
4368 cv_wait(&seg->s_cv, &seg->s_lock);
4369
4370 do {
4371 recheck_state = 0;
4372
4373 DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
4374 "rsmseg_suspend:segment %x state=%d\n",
4375 seg->s_key, seg->s_state));
4376
4377 switch (seg->s_state) {
4378 case RSM_STATE_NEW:
4379 /* not a valid state */
4380 break;
4381 case RSM_STATE_CONNECTING:
4382 seg->s_state = RSM_STATE_ABORT_CONNECT;
4383 break;
4384 case RSM_STATE_ABORT_CONNECT:
4385 break;
4386 case RSM_STATE_CONNECT:
4387 seg->s_handle.in = NULL;
4388 seg->s_state = RSM_STATE_CONN_QUIESCE;
4389 break;
4390 case RSM_STATE_MAPPING:
4391 /* wait until segment leaves the mapping state */
4392 while (seg->s_state == RSM_STATE_MAPPING)
4393 cv_wait(&seg->s_cv, &seg->s_lock);
4394 recheck_state = 1;
4395 break;
4396 case RSM_STATE_ACTIVE:
4397 /* unload the mappings */
4398 if (seg->s_ckl != NULL) {
4399 hdl = seg->s_ckl;
4400 for (; hdl != NULL; hdl = hdl->c_next) {
4401 (void) devmap_unload(hdl->c_dhp,
4402 hdl->c_off, hdl->c_len);
4403 }
4404 }
4405 seg->s_mapinfo = NULL;
4406 seg->s_state = RSM_STATE_MAP_QUIESCE;
4407 break;
4408 case RSM_STATE_CONN_QUIESCE:
4409 /* FALLTHRU */
4410 case RSM_STATE_MAP_QUIESCE:
4411 /* rsmseg_suspend already done for seg */
4412 *susp_flg = 1;
4413 break;
4414 case RSM_STATE_DISCONNECT:
4415 break;
4416 default:
4417 ASSERT(0); /* invalid state */
4418 }
4419 } while (recheck_state);
4420
4421 DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmseg_suspend done\n"));
4422 }
4423
4424 static void
rsmsegshare_suspend(rsmseg_t * seg)4425 rsmsegshare_suspend(rsmseg_t *seg)
4426 {
4427 int e;
4428 adapter_t *adapter;
4429 rsm_import_share_t *sharedp;
4430 DBG_DEFINE(category,
4431 RSM_KERNEL_AGENT | RSM_FUNC_ALL | RSM_INTR_CALLBACK);
4432
4433 DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
4434 "rsmsegshare_suspend enter\n"));
4435
4436 rsmseglock_acquire(seg);
4437 rsmsharelock_acquire(seg);
4438
4439 sharedp = seg->s_share;
4440 adapter = seg->s_adapter;
4441 switch (sharedp->rsmsi_state) {
4442 case RSMSI_STATE_NEW:
4443 break;
4444 case RSMSI_STATE_CONNECTING:
4445 sharedp->rsmsi_state = RSMSI_STATE_ABORT_CONNECT;
4446 break;
4447 case RSMSI_STATE_ABORT_CONNECT:
4448 break;
4449 case RSMSI_STATE_CONNECTED:
4450 /* do the rsmpi disconnect */
4451 if (sharedp->rsmsi_node != my_nodeid) {
4452 e = adapter->rsmpi_ops->
4453 rsm_disconnect(sharedp->rsmsi_handle);
4454
4455 DBG_PRINTF((category, RSM_DEBUG,
4456 "rsm:rsmpi disconnect seg=%x:err=%d\n",
4457 sharedp->rsmsi_segid, e));
4458 }
4459
4460 sharedp->rsmsi_handle = NULL;
4461
4462 sharedp->rsmsi_state = RSMSI_STATE_CONN_QUIESCE;
4463 break;
4464 case RSMSI_STATE_CONN_QUIESCE:
4465 break;
4466 case RSMSI_STATE_MAPPED:
4467 /* do the rsmpi unmap and disconnect */
4468 if (sharedp->rsmsi_node != my_nodeid) {
4469 e = adapter->rsmpi_ops->rsm_unmap(seg->s_handle.in);
4470
4471 DBG_PRINTF((category, RSM_DEBUG,
4472 "rsmshare_suspend: rsmpi unmap %d\n", e));
4473
4474 e = adapter->rsmpi_ops->
4475 rsm_disconnect(sharedp->rsmsi_handle);
4476 DBG_PRINTF((category, RSM_DEBUG,
4477 "rsm:rsmpi disconnect seg=%x:err=%d\n",
4478 sharedp->rsmsi_segid, e));
4479 }
4480
4481 sharedp->rsmsi_handle = NULL;
4482
4483 sharedp->rsmsi_state = RSMSI_STATE_MAP_QUIESCE;
4484 break;
4485 case RSMSI_STATE_MAP_QUIESCE:
4486 break;
4487 case RSMSI_STATE_DISCONNECTED:
4488 break;
4489 default:
4490 ASSERT(0); /* invalid state */
4491 }
4492
4493 rsmsharelock_release(seg);
4494 rsmseglock_release(seg);
4495
4496 DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
4497 "rsmsegshare_suspend done\n"));
4498 }
4499
4500 /*
4501 * This should get called on receiving a RESUME message or from
4502 * the pathmanger if the node undergoing DR dies.
4503 */
4504 static void
importer_resume(rsm_node_id_t src_node)4505 importer_resume(rsm_node_id_t src_node)
4506 {
4507 int i;
4508 rsmresource_t *p = NULL;
4509 rsmhash_table_t *rhash = &rsm_import_segs;
4510 void *cookie;
4511 DBG_DEFINE(category,
4512 RSM_KERNEL_AGENT | RSM_FUNC_ALL | RSM_INTR_CALLBACK);
4513
4514 DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "importer_resume enter\n"));
4515
4516 rw_enter(&rhash->rsmhash_rw, RW_READER);
4517
4518 for (i = 0; i < rsm_hash_size; i++) {
4519 p = rhash->bucket[i];
4520
4521 for (; p; p = p->rsmrc_next) {
4522 rsmseg_t *seg = (rsmseg_t *)p;
4523
4524 rsmseglock_acquire(seg);
4525
4526 /* process only importers of node undergoing DR */
4527 if (seg->s_node != src_node) {
4528 rsmseglock_release(seg);
4529 continue;
4530 }
4531
4532 if (rsmseg_resume(seg, &cookie) != RSM_SUCCESS) {
4533 rsmipc_request_t request;
4534 /*
4535 * rsmpi map/connect failed
4536 * inform the exporter so that it can
4537 * remove the importer.
4538 */
4539 request.rsmipc_hdr.rsmipc_type =
4540 RSMIPC_MSG_NOTIMPORTING;
4541 request.rsmipc_key = seg->s_segid;
4542 request.rsmipc_segment_cookie = cookie;
4543 rsmseglock_release(seg);
4544 (void) rsmipc_send(seg->s_node, &request,
4545 RSM_NO_REPLY);
4546 } else {
4547 rsmseglock_release(seg);
4548 }
4549 }
4550 }
4551
4552 rw_exit(&rhash->rsmhash_rw);
4553
4554 DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "importer_resume done\n"));
4555 }
4556
4557 static int
rsmseg_resume(rsmseg_t * seg,void ** cookie)4558 rsmseg_resume(rsmseg_t *seg, void **cookie)
4559 {
4560 int e;
4561 int retc;
4562 off_t dev_offset;
4563 size_t maplen;
4564 uint_t maxprot;
4565 rsm_mapinfo_t *p;
4566 rsmcookie_t *hdl;
4567 rsm_import_share_t *sharedp;
4568 DBG_DEFINE(category,
4569 RSM_KERNEL_AGENT | RSM_FUNC_ALL | RSM_INTR_CALLBACK);
4570
4571 DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
4572 "rsmseg_resume enter: key=%u\n", seg->s_key));
4573
4574 *cookie = NULL;
4575
4576 ASSERT(rsmseglock_held(seg));
4577
4578 if ((seg->s_state != RSM_STATE_CONN_QUIESCE) &&
4579 (seg->s_state != RSM_STATE_MAP_QUIESCE)) {
4580 return (RSM_SUCCESS);
4581 }
4582
4583 sharedp = seg->s_share;
4584
4585 rsmsharelock_acquire(seg);
4586
4587 /* resume the shared connection and/or mapping */
4588 retc = rsmsegshare_resume(seg);
4589
4590 if (seg->s_state == RSM_STATE_CONN_QUIESCE) {
4591 /* shared state can either be connected or mapped */
4592 if ((sharedp->rsmsi_state == RSMSI_STATE_CONNECTED) ||
4593 (sharedp->rsmsi_state == RSMSI_STATE_MAPPED)) {
4594 ASSERT(retc == RSM_SUCCESS);
4595 seg->s_handle.in = sharedp->rsmsi_handle;
4596 rsmsharelock_release(seg);
4597 seg->s_state = RSM_STATE_CONNECT;
4598
4599 } else { /* error in rsmpi connect during resume */
4600 seg->s_handle.in = NULL;
4601 seg->s_state = RSM_STATE_DISCONNECT;
4602
4603 sharedp->rsmsi_refcnt--;
4604 cookie = (void *)sharedp->rsmsi_cookie;
4605
4606 if (sharedp->rsmsi_refcnt == 0) {
4607 ASSERT(sharedp->rsmsi_mapcnt == 0);
4608 rsmsharelock_release(seg);
4609
4610 /* clean up the shared data structure */
4611 mutex_destroy(&sharedp->rsmsi_lock);
4612 cv_destroy(&sharedp->rsmsi_cv);
4613 kmem_free((void *)(sharedp),
4614 sizeof (rsm_import_share_t));
4615
4616 } else {
4617 rsmsharelock_release(seg);
4618 }
4619 /*
4620 * The following needs to be done after any
4621 * rsmsharelock calls which use seg->s_share.
4622 */
4623 seg->s_share = NULL;
4624 }
4625
4626 /* signal any waiting segment */
4627 cv_broadcast(&seg->s_cv);
4628
4629 DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
4630 "rsmseg_resume done:state=%d\n", seg->s_state));
4631 return (retc);
4632 }
4633
4634 ASSERT(seg->s_state == RSM_STATE_MAP_QUIESCE);
4635
4636 /* Setup protections for remap */
4637 maxprot = PROT_USER;
4638 if (seg->s_mode & RSM_PERM_READ) {
4639 maxprot |= PROT_READ;
4640 }
4641 if (seg->s_mode & RSM_PERM_WRITE) {
4642 maxprot |= PROT_WRITE;
4643 }
4644
4645 if (sharedp->rsmsi_state != RSMSI_STATE_MAPPED) {
4646 /* error in rsmpi connect or map during resume */
4647
4648 /* remap to trash page */
4649 ASSERT(seg->s_ckl != NULL);
4650
4651 for (hdl = seg->s_ckl; hdl != NULL; hdl = hdl->c_next) {
4652 e = devmap_umem_remap(hdl->c_dhp, rsm_dip,
4653 remap_cookie, hdl->c_off, hdl->c_len,
4654 maxprot, 0, NULL);
4655
4656 DBG_PRINTF((category, RSM_ERR,
4657 "rsmseg_resume:remap=%d\n", e));
4658 }
4659
4660 seg->s_handle.in = NULL;
4661 seg->s_state = RSM_STATE_DISCONNECT;
4662
4663 sharedp->rsmsi_refcnt--;
4664
4665 sharedp->rsmsi_mapcnt--;
4666 seg->s_mapinfo = NULL;
4667
4668 if (sharedp->rsmsi_refcnt == 0) {
4669 ASSERT(sharedp->rsmsi_mapcnt == 0);
4670 rsmsharelock_release(seg);
4671
4672 /* clean up the shared data structure */
4673 mutex_destroy(&sharedp->rsmsi_lock);
4674 cv_destroy(&sharedp->rsmsi_cv);
4675 kmem_free((void *)(sharedp),
4676 sizeof (rsm_import_share_t));
4677
4678 } else {
4679 rsmsharelock_release(seg);
4680 }
4681 /*
4682 * The following needs to be done after any
4683 * rsmsharelock calls which use seg->s_share.
4684 */
4685 seg->s_share = NULL;
4686
4687 /* signal any waiting segment */
4688 cv_broadcast(&seg->s_cv);
4689
4690 DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
4691 "rsmseg_resume done:seg=%x,err=%d\n",
4692 seg->s_key, retc));
4693 return (retc);
4694
4695 }
4696
4697 seg->s_handle.in = sharedp->rsmsi_handle;
4698
4699 if (seg->s_node == my_nodeid) { /* loopback */
4700 ASSERT(seg->s_mapinfo == NULL);
4701
4702 for (hdl = seg->s_ckl; hdl != NULL; hdl = hdl->c_next) {
4703 e = devmap_umem_remap(hdl->c_dhp,
4704 rsm_dip, seg->s_cookie,
4705 hdl->c_off, hdl->c_len,
4706 maxprot, 0, NULL);
4707
4708 DBG_PRINTF((category, RSM_ERR,
4709 "rsmseg_resume:remap=%d\n", e));
4710 }
4711 } else { /* remote exporter */
4712 /* remap to the new rsmpi maps */
4713 seg->s_mapinfo = sharedp->rsmsi_mapinfo;
4714
4715 for (hdl = seg->s_ckl; hdl != NULL; hdl = hdl->c_next) {
4716 p = rsm_get_mapinfo(seg, hdl->c_off, hdl->c_len,
4717 &dev_offset, &maplen);
4718 e = devmap_devmem_remap(hdl->c_dhp,
4719 p->dip, p->dev_register, dev_offset,
4720 maplen, maxprot, 0, NULL);
4721
4722 DBG_PRINTF((category, RSM_ERR,
4723 "rsmseg_resume:remap=%d\n", e));
4724 }
4725 }
4726
4727 rsmsharelock_release(seg);
4728
4729 seg->s_state = RSM_STATE_ACTIVE;
4730 cv_broadcast(&seg->s_cv);
4731
4732 DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmseg_resume done\n"));
4733
4734 return (retc);
4735 }
4736
4737 static int
rsmsegshare_resume(rsmseg_t * seg)4738 rsmsegshare_resume(rsmseg_t *seg)
4739 {
4740 int e = RSM_SUCCESS;
4741 adapter_t *adapter;
4742 rsm_import_share_t *sharedp;
4743 DBG_DEFINE(category,
4744 RSM_KERNEL_AGENT | RSM_FUNC_ALL | RSM_INTR_CALLBACK);
4745
4746 DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmsegshare_resume enter\n"));
4747
4748 ASSERT(rsmseglock_held(seg));
4749 ASSERT(rsmsharelock_held(seg));
4750
4751 sharedp = seg->s_share;
4752
4753 /*
4754 * If we are not in a xxxx_QUIESCE state that means shared
4755 * connect/mapping processing has been already been done
4756 * so return success.
4757 */
4758 if ((sharedp->rsmsi_state != RSMSI_STATE_CONN_QUIESCE) &&
4759 (sharedp->rsmsi_state != RSMSI_STATE_MAP_QUIESCE)) {
4760 return (RSM_SUCCESS);
4761 }
4762
4763 adapter = seg->s_adapter;
4764
4765 if (sharedp->rsmsi_node != my_nodeid) {
4766 rsm_addr_t hwaddr;
4767 hwaddr = get_remote_hwaddr(adapter, sharedp->rsmsi_node);
4768
4769 e = adapter->rsmpi_ops->rsm_connect(
4770 adapter->rsmpi_handle, hwaddr,
4771 sharedp->rsmsi_segid, &sharedp->rsmsi_handle);
4772
4773 DBG_PRINTF((category, RSM_DEBUG,
4774 "rsmsegshare_resume:rsmpi connect seg=%x:err=%d\n",
4775 sharedp->rsmsi_segid, e));
4776
4777 if (e != RSM_SUCCESS) {
4778 /* when do we send the NOT_IMPORTING message */
4779 sharedp->rsmsi_handle = NULL;
4780 sharedp->rsmsi_state = RSMSI_STATE_DISCONNECTED;
4781 /* signal any waiting segment */
4782 cv_broadcast(&sharedp->rsmsi_cv);
4783 return (e);
4784 }
4785 }
4786
4787 if (sharedp->rsmsi_state == RSMSI_STATE_CONN_QUIESCE) {
4788 sharedp->rsmsi_state = RSMSI_STATE_CONNECTED;
4789 /* signal any waiting segment */
4790 cv_broadcast(&sharedp->rsmsi_cv);
4791 return (e);
4792 }
4793
4794 ASSERT(sharedp->rsmsi_state == RSMSI_STATE_MAP_QUIESCE);
4795
4796 /* do the rsmpi map of the whole segment here */
4797 if (sharedp->rsmsi_node != my_nodeid) {
4798 size_t mapped_len;
4799 rsm_mapinfo_t *p;
4800
4801 /*
4802 * We need to do rsmpi maps with <off, lens> identical to
4803 * the old mapinfo list because the segment mapping handles
4804 * dhp and such need the fragmentation of rsmpi maps to be
4805 * identical to what it was during the mmap of the segment
4806 */
4807 p = sharedp->rsmsi_mapinfo;
4808
4809 while (p != NULL) {
4810 mapped_len = 0;
4811
4812 e = adapter->rsmpi_ops->rsm_map(
4813 sharedp->rsmsi_handle, p->start_offset,
4814 p->individual_len, &mapped_len,
4815 &p->dip, &p->dev_register, &p->dev_offset,
4816 NULL, NULL);
4817
4818 if (e != 0) {
4819 DBG_PRINTF((category, RSM_ERR,
4820 "rsmsegshare_resume: rsmpi map err=%d\n",
4821 e));
4822 break;
4823 }
4824
4825 if (mapped_len != p->individual_len) {
4826 DBG_PRINTF((category, RSM_ERR,
4827 "rsmsegshare_resume: rsmpi maplen"
4828 "< reqlen=%lx\n", mapped_len));
4829 e = RSMERR_BAD_LENGTH;
4830 break;
4831 }
4832
4833 p = p->next;
4834
4835 }
4836
4837
4838 if (e != RSM_SUCCESS) { /* rsmpi map failed */
4839 int err;
4840 /* Check if this is the first rsm_map */
4841 if (p != sharedp->rsmsi_mapinfo) {
4842 /*
4843 * A single rsm_unmap undoes multiple rsm_maps.
4844 */
4845 (void) seg->s_adapter->rsmpi_ops->
4846 rsm_unmap(sharedp->rsmsi_handle);
4847 }
4848
4849 rsm_free_mapinfo(sharedp->rsmsi_mapinfo);
4850 sharedp->rsmsi_mapinfo = NULL;
4851
4852 err = adapter->rsmpi_ops->
4853 rsm_disconnect(sharedp->rsmsi_handle);
4854
4855 DBG_PRINTF((category, RSM_DEBUG,
4856 "rsmsegshare_resume:disconn seg=%x:err=%d\n",
4857 sharedp->rsmsi_segid, err));
4858
4859 sharedp->rsmsi_handle = NULL;
4860 sharedp->rsmsi_state = RSMSI_STATE_DISCONNECTED;
4861
4862 /* signal the waiting segments */
4863 cv_broadcast(&sharedp->rsmsi_cv);
4864 DBG_PRINTF((category, RSM_DEBUG,
4865 "rsmsegshare_resume done: rsmpi map err\n"));
4866 return (e);
4867 }
4868 }
4869
4870 sharedp->rsmsi_state = RSMSI_STATE_MAPPED;
4871
4872 /* signal any waiting segment */
4873 cv_broadcast(&sharedp->rsmsi_cv);
4874
4875 DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmsegshare_resume done\n"));
4876
4877 return (e);
4878 }
4879
4880 /*
4881 * this is the routine that gets called by recv_taskq which is the
4882 * thread that processes messages that are flow-controlled.
4883 */
4884 static void
rsm_intr_proc_deferred(void * arg)4885 rsm_intr_proc_deferred(void *arg)
4886 {
4887 path_t *path = (path_t *)arg;
4888 rsmipc_request_t *msg;
4889 rsmipc_msghdr_t *msghdr;
4890 rsm_node_id_t src_node;
4891 msgbuf_elem_t *head;
4892 int e;
4893 DBG_DEFINE(category,
4894 RSM_KERNEL_AGENT | RSM_FUNC_ALL | RSM_INTR_CALLBACK);
4895
4896 DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
4897 "rsm_intr_proc_deferred enter\n"));
4898
4899 mutex_enter(&path->mutex);
4900
4901 /* use the head of the msgbuf_queue */
4902 head = rsmka_gethead_msgbuf(path);
4903
4904 mutex_exit(&path->mutex);
4905
4906 msg = (rsmipc_request_t *)&(head->msg);
4907 msghdr = (rsmipc_msghdr_t *)msg;
4908
4909 src_node = msghdr->rsmipc_src;
4910
4911 /*
4912 * messages that need to send a reply should check the message version
4913 * before processing the message. And all messages that need to
4914 * send a reply should be processed here by the worker thread.
4915 */
4916 switch (msghdr->rsmipc_type) {
4917 case RSMIPC_MSG_SEGCONNECT:
4918 if (msghdr->rsmipc_version != RSM_VERSION) {
4919 rsmipc_reply_t reply;
4920 reply.rsmipc_status = RSMERR_BAD_DRIVER_VERSION;
4921 reply.rsmipc_hdr.rsmipc_type = RSMIPC_MSG_REPLY;
4922 reply.rsmipc_hdr.rsmipc_cookie = msghdr->rsmipc_cookie;
4923 (void) rsmipc_send(msghdr->rsmipc_src, NULL, &reply);
4924 } else {
4925 rsm_intr_segconnect(src_node, msg);
4926 }
4927 break;
4928 case RSMIPC_MSG_DISCONNECT:
4929 rsm_force_unload(src_node, msg->rsmipc_key, DISCONNECT);
4930 break;
4931 case RSMIPC_MSG_SUSPEND:
4932 importer_suspend(src_node);
4933 break;
4934 case RSMIPC_MSG_SUSPEND_DONE:
4935 rsm_suspend_complete(src_node, 0);
4936 break;
4937 case RSMIPC_MSG_RESUME:
4938 importer_resume(src_node);
4939 break;
4940 default:
4941 ASSERT(0);
4942 }
4943
4944 mutex_enter(&path->mutex);
4945
4946 rsmka_dequeue_msgbuf(path);
4947
4948 /* incr procmsg_cnt can be at most RSMIPC_MAX_MESSAGES */
4949 if (path->procmsg_cnt < RSMIPC_MAX_MESSAGES)
4950 path->procmsg_cnt++;
4951
4952 ASSERT(path->procmsg_cnt <= RSMIPC_MAX_MESSAGES);
4953
4954 /* No need to send credits if path is going down */
4955 if ((path->state == RSMKA_PATH_ACTIVE) &&
4956 (path->procmsg_cnt >= RSMIPC_LOTSFREE_MSGBUFS)) {
4957 /*
4958 * send credits and reset procmsg_cnt if success otherwise
4959 * credits will be sent after processing the next message
4960 */
4961 e = rsmipc_send_controlmsg(path, RSMIPC_MSG_CREDIT);
4962 if (e == 0)
4963 path->procmsg_cnt = 0;
4964 else
4965 DBG_PRINTF((category, RSM_ERR,
4966 "rsm_intr_proc_deferred:send credits err=%d\n", e));
4967 }
4968
4969 /*
4970 * decrement the path refcnt since we incremented it in
4971 * rsm_intr_callback_dispatch
4972 */
4973 PATH_RELE_NOLOCK(path);
4974
4975 mutex_exit(&path->mutex);
4976
4977 DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
4978 "rsm_intr_proc_deferred done\n"));
4979 }
4980
4981 /*
4982 * Flow-controlled messages are enqueued and dispatched onto a taskq here
4983 */
4984 static void
rsm_intr_callback_dispatch(void * data,rsm_addr_t src_hwaddr,rsm_intr_hand_arg_t arg)4985 rsm_intr_callback_dispatch(void *data, rsm_addr_t src_hwaddr,
4986 rsm_intr_hand_arg_t arg)
4987 {
4988 srv_handler_arg_t *hdlr_argp = (srv_handler_arg_t *)arg;
4989 path_t *path;
4990 rsmipc_msghdr_t *msghdr = (rsmipc_msghdr_t *)data;
4991 DBG_DEFINE(category,
4992 RSM_KERNEL_AGENT | RSM_FUNC_ALL | RSM_INTR_CALLBACK);
4993
4994 DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
4995 "rsm_intr_callback_dispatch enter\n"));
4996 ASSERT(data && hdlr_argp);
4997
4998 /* look up the path - incr the path refcnt */
4999 path = rsm_find_path(hdlr_argp->adapter_name,
5000 hdlr_argp->adapter_instance, src_hwaddr);
5001
5002 /* the path has been removed - drop this message */
5003 if (path == NULL) {
5004 DBG_PRINTF((category, RSM_DEBUG,
5005 "rsm_intr_callback_dispatch done: msg dropped\n"));
5006 return;
5007 }
5008 /* the path is not active - don't accept new messages */
5009 if (path->state != RSMKA_PATH_ACTIVE) {
5010 PATH_RELE_NOLOCK(path);
5011 mutex_exit(&path->mutex);
5012 DBG_PRINTF((category, RSM_DEBUG,
5013 "rsm_intr_callback_dispatch done: msg dropped"
5014 " path=%lx !ACTIVE\n", path));
5015 return;
5016 }
5017
5018 /*
5019 * Check if this message was sent to an older incarnation
5020 * of the path/sendq.
5021 */
5022 if (path->local_incn != msghdr->rsmipc_incn) {
5023 /* decrement the refcnt */
5024 PATH_RELE_NOLOCK(path);
5025 mutex_exit(&path->mutex);
5026 DBG_PRINTF((category, RSM_DEBUG,
5027 "rsm_intr_callback_dispatch done: old incn %lld\n",
5028 msghdr->rsmipc_incn));
5029 return;
5030 }
5031
5032 /* copy and enqueue msg on the path's msgbuf queue */
5033 rsmka_enqueue_msgbuf(path, data);
5034
5035 /*
5036 * schedule task to process messages - ignore retval from
5037 * task_dispatch because we sender cannot send more than
5038 * what receiver can handle.
5039 */
5040 (void) taskq_dispatch(path->recv_taskq,
5041 rsm_intr_proc_deferred, path, KM_NOSLEEP);
5042
5043 mutex_exit(&path->mutex);
5044
5045 DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
5046 "rsm_intr_callback_dispatch done\n"));
5047 }
5048
5049 /*
5050 * This procedure is called from rsm_srv_func when a remote node creates a
5051 * a send queue. This event is used as a hint that an earlier failed
5052 * attempt to create a send queue to that remote node may now succeed and
5053 * should be retried. Indication of an earlier failed attempt is provided
5054 * by the RSMKA_SQCREATE_PENDING flag.
5055 */
5056 static void
rsm_sqcreateop_callback(rsm_addr_t src_hwaddr,rsm_intr_hand_arg_t arg)5057 rsm_sqcreateop_callback(rsm_addr_t src_hwaddr, rsm_intr_hand_arg_t arg)
5058 {
5059 srv_handler_arg_t *hdlr_argp = (srv_handler_arg_t *)arg;
5060 path_t *path;
5061 DBG_DEFINE(category,
5062 RSM_KERNEL_AGENT | RSM_FUNC_ALL | RSM_INTR_CALLBACK);
5063
5064 DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
5065 "rsm_sqcreateop_callback enter\n"));
5066
5067 /* look up the path - incr the path refcnt */
5068 path = rsm_find_path(hdlr_argp->adapter_name,
5069 hdlr_argp->adapter_instance, src_hwaddr);
5070
5071 if (path == NULL) {
5072 DBG_PRINTF((category, RSM_DEBUG,
5073 "rsm_sqcreateop_callback done: no path\n"));
5074 return;
5075 }
5076
5077 if ((path->state == RSMKA_PATH_UP) &&
5078 (path->flags & RSMKA_SQCREATE_PENDING)) {
5079 /*
5080 * previous attempt to create sendq had failed, retry
5081 * it and move to RSMKA_PATH_ACTIVE state if successful.
5082 * the refcnt will be decremented in the do_deferred_work
5083 */
5084 (void) rsmka_do_path_active(path, RSMKA_NO_SLEEP);
5085 } else {
5086 /* decrement the refcnt */
5087 PATH_RELE_NOLOCK(path);
5088 }
5089 mutex_exit(&path->mutex);
5090
5091 DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
5092 "rsm_sqcreateop_callback done\n"));
5093 }
5094
5095 static void
rsm_intr_callback(void * data,rsm_addr_t src_hwaddr,rsm_intr_hand_arg_t arg)5096 rsm_intr_callback(void *data, rsm_addr_t src_hwaddr, rsm_intr_hand_arg_t arg)
5097 {
5098 rsmipc_msghdr_t *msghdr = (rsmipc_msghdr_t *)data;
5099 rsmipc_request_t *msg = (rsmipc_request_t *)data;
5100 rsmipc_controlmsg_t *ctrlmsg = (rsmipc_controlmsg_t *)data;
5101 rsm_node_id_t src_node;
5102 DBG_DEFINE(category,
5103 RSM_KERNEL_AGENT | RSM_FUNC_ALL | RSM_INTR_CALLBACK);
5104
5105 DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_intr_callback enter:"
5106 "src=%d, type=%d\n", msghdr->rsmipc_src,
5107 msghdr->rsmipc_type));
5108
5109 /*
5110 * Check for the version number in the msg header. If it is not
5111 * RSM_VERSION, drop the message. In the future, we need to manage
5112 * incompatible version numbers in some way
5113 */
5114 if (msghdr->rsmipc_version != RSM_VERSION) {
5115 DBG_PRINTF((category, RSM_ERR, "wrong KA version\n"));
5116 /*
5117 * Drop requests that don't have a reply right here
5118 * Request with reply will send a BAD_VERSION reply
5119 * when they get processed by the worker thread.
5120 */
5121 if (msghdr->rsmipc_type != RSMIPC_MSG_SEGCONNECT) {
5122 return;
5123 }
5124
5125 }
5126
5127 src_node = msghdr->rsmipc_src;
5128
5129 switch (msghdr->rsmipc_type) {
5130 case RSMIPC_MSG_SEGCONNECT:
5131 case RSMIPC_MSG_DISCONNECT:
5132 case RSMIPC_MSG_SUSPEND:
5133 case RSMIPC_MSG_SUSPEND_DONE:
5134 case RSMIPC_MSG_RESUME:
5135 /*
5136 * These message types are handled by a worker thread using
5137 * the flow-control algorithm.
5138 * Any message processing that does one or more of the
5139 * following should be handled in a worker thread.
5140 * - allocates resources and might sleep
5141 * - makes RSMPI calls down to the interconnect driver
5142 * this by defn include requests with reply.
5143 * - takes a long duration of time
5144 */
5145 rsm_intr_callback_dispatch(data, src_hwaddr, arg);
5146 break;
5147 case RSMIPC_MSG_NOTIMPORTING:
5148 importer_list_rm(src_node, msg->rsmipc_key,
5149 msg->rsmipc_segment_cookie);
5150 break;
5151 case RSMIPC_MSG_SQREADY:
5152 rsm_proc_sqready(data, src_hwaddr, arg);
5153 break;
5154 case RSMIPC_MSG_SQREADY_ACK:
5155 rsm_proc_sqready_ack(data, src_hwaddr, arg);
5156 break;
5157 case RSMIPC_MSG_CREDIT:
5158 rsm_add_credits(ctrlmsg, src_hwaddr, arg);
5159 break;
5160 case RSMIPC_MSG_REPLY:
5161 rsm_intr_reply(msghdr);
5162 break;
5163 case RSMIPC_MSG_BELL:
5164 rsm_intr_event(msg);
5165 break;
5166 case RSMIPC_MSG_IMPORTING:
5167 importer_list_add(src_node, msg->rsmipc_key,
5168 msg->rsmipc_adapter_hwaddr,
5169 msg->rsmipc_segment_cookie);
5170 break;
5171 case RSMIPC_MSG_REPUBLISH:
5172 importer_update(src_node, msg->rsmipc_key, msg->rsmipc_perm);
5173 break;
5174 default:
5175 DBG_PRINTF((category, RSM_DEBUG,
5176 "rsm_intr_callback: bad msg %lx type %d data %lx\n",
5177 (size_t)msg, (int)(msghdr->rsmipc_type), (size_t)data));
5178 }
5179
5180 DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_intr_callback done\n"));
5181
5182 }
5183
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)5184 rsm_intr_hand_ret_t rsm_srv_func(rsm_controller_object_t *chd,
5185 rsm_intr_q_op_t opcode, rsm_addr_t src,
5186 void *data, size_t size, rsm_intr_hand_arg_t arg)
5187 {
5188 DBG_DEFINE(category,
5189 RSM_KERNEL_AGENT | RSM_FUNC_ALL | RSM_INTR_CALLBACK);
5190
5191 DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_srv_func enter\n"));
5192
5193 switch (opcode) {
5194 case RSM_INTR_Q_OP_CREATE:
5195 DBG_PRINTF((category, RSM_DEBUG, "rsm_srv_func:OP_CREATE\n"));
5196 rsm_sqcreateop_callback(src, arg);
5197 break;
5198 case RSM_INTR_Q_OP_DESTROY:
5199 DBG_PRINTF((category, RSM_DEBUG, "rsm_srv_func:OP_DESTROY\n"));
5200 break;
5201 case RSM_INTR_Q_OP_RECEIVE:
5202 rsm_intr_callback(data, src, arg);
5203 break;
5204 default:
5205 DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
5206 "rsm_srv_func: unknown opcode = %x\n", opcode));
5207 }
5208
5209 chd = chd;
5210 size = size;
5211
5212 DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_srv_func done\n"));
5213
5214 return (RSM_INTR_HAND_CLAIMED);
5215 }
5216
5217 /* *************************** IPC slots ************************* */
5218 static rsmipc_slot_t *
rsmipc_alloc()5219 rsmipc_alloc()
5220 {
5221 int i;
5222 rsmipc_slot_t *slot;
5223 DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_FUNC_ALL);
5224
5225 DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmipc_alloc enter\n"));
5226
5227 /* try to find a free slot, if not wait */
5228 mutex_enter(&rsm_ipc.lock);
5229
5230 while (rsm_ipc.count == 0) {
5231 rsm_ipc.wanted = 1;
5232 cv_wait(&rsm_ipc.cv, &rsm_ipc.lock);
5233 }
5234
5235 /* An empty slot is available, find it */
5236 slot = &rsm_ipc.slots[0];
5237 for (i = 0; i < RSMIPC_SZ; i++, slot++) {
5238 if (RSMIPC_GET(slot, RSMIPC_FREE)) {
5239 RSMIPC_CLEAR(slot, RSMIPC_FREE);
5240 break;
5241 }
5242 }
5243
5244 ASSERT(i < RSMIPC_SZ);
5245 rsm_ipc.count--; /* one less is available */
5246 rsm_ipc.sequence++; /* new sequence */
5247
5248 slot->rsmipc_cookie.ic.sequence = (uint_t)rsm_ipc.sequence;
5249 slot->rsmipc_cookie.ic.index = (uint_t)i;
5250
5251 mutex_exit(&rsm_ipc.lock);
5252
5253 DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmipc_alloc done\n"));
5254
5255 return (slot);
5256 }
5257
5258 static void
rsmipc_free(rsmipc_slot_t * slot)5259 rsmipc_free(rsmipc_slot_t *slot)
5260 {
5261 DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_FUNC_ALL);
5262
5263 DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmipc_free enter\n"));
5264
5265 ASSERT(MUTEX_HELD(&slot->rsmipc_lock));
5266 ASSERT(&rsm_ipc.slots[slot->rsmipc_cookie.ic.index] == slot);
5267
5268 mutex_enter(&rsm_ipc.lock);
5269
5270 RSMIPC_SET(slot, RSMIPC_FREE);
5271
5272 slot->rsmipc_cookie.ic.sequence = 0;
5273
5274 mutex_exit(&slot->rsmipc_lock);
5275 rsm_ipc.count++;
5276 ASSERT(rsm_ipc.count <= RSMIPC_SZ);
5277 if (rsm_ipc.wanted) {
5278 rsm_ipc.wanted = 0;
5279 cv_broadcast(&rsm_ipc.cv);
5280 }
5281
5282 mutex_exit(&rsm_ipc.lock);
5283
5284 DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmipc_free done\n"));
5285 }
5286
5287 static int
rsmipc_send(rsm_node_id_t dest,rsmipc_request_t * req,rsmipc_reply_t * reply)5288 rsmipc_send(rsm_node_id_t dest, rsmipc_request_t *req, rsmipc_reply_t *reply)
5289 {
5290 int e = 0;
5291 int credit_check = 0;
5292 int retry_cnt = 0;
5293 int min_retry_cnt = 10;
5294 rsm_send_t is;
5295 rsmipc_slot_t *rslot;
5296 adapter_t *adapter;
5297 path_t *path;
5298 sendq_token_t *sendq_token;
5299 sendq_token_t *used_sendq_token = NULL;
5300 rsm_send_q_handle_t ipc_handle;
5301 DBG_DEFINE(category,
5302 RSM_KERNEL_AGENT | RSM_FUNC_ALL | RSM_INTR_CALLBACK);
5303
5304 DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmipc_send enter:dest=%d",
5305 dest));
5306
5307 /*
5308 * Check if this is a local case
5309 */
5310 if (dest == my_nodeid) {
5311 switch (req->rsmipc_hdr.rsmipc_type) {
5312 case RSMIPC_MSG_SEGCONNECT:
5313 reply->rsmipc_status = (short)rsmsegacl_validate(
5314 req, dest, reply);
5315 break;
5316 case RSMIPC_MSG_BELL:
5317 req->rsmipc_hdr.rsmipc_src = dest;
5318 rsm_intr_event(req);
5319 break;
5320 case RSMIPC_MSG_IMPORTING:
5321 importer_list_add(dest, req->rsmipc_key,
5322 req->rsmipc_adapter_hwaddr,
5323 req->rsmipc_segment_cookie);
5324 break;
5325 case RSMIPC_MSG_NOTIMPORTING:
5326 importer_list_rm(dest, req->rsmipc_key,
5327 req->rsmipc_segment_cookie);
5328 break;
5329 case RSMIPC_MSG_REPUBLISH:
5330 importer_update(dest, req->rsmipc_key,
5331 req->rsmipc_perm);
5332 break;
5333 case RSMIPC_MSG_SUSPEND:
5334 importer_suspend(dest);
5335 break;
5336 case RSMIPC_MSG_SUSPEND_DONE:
5337 rsm_suspend_complete(dest, 0);
5338 break;
5339 case RSMIPC_MSG_RESUME:
5340 importer_resume(dest);
5341 break;
5342 default:
5343 ASSERT(0);
5344 }
5345 DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
5346 "rsmipc_send done\n"));
5347 return (0);
5348 }
5349
5350 if (dest >= MAX_NODES) {
5351 DBG_PRINTF((category, RSM_ERR,
5352 "rsm: rsmipc_send bad node number %x\n", dest));
5353 return (RSMERR_REMOTE_NODE_UNREACHABLE);
5354 }
5355
5356 /*
5357 * Oh boy! we are going remote.
5358 */
5359
5360 /*
5361 * identify if we need to have credits to send this message
5362 * - only selected requests are flow controlled
5363 */
5364 if (req != NULL) {
5365 DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
5366 "rsmipc_send:request type=%d\n",
5367 req->rsmipc_hdr.rsmipc_type));
5368
5369 switch (req->rsmipc_hdr.rsmipc_type) {
5370 case RSMIPC_MSG_SEGCONNECT:
5371 case RSMIPC_MSG_DISCONNECT:
5372 case RSMIPC_MSG_IMPORTING:
5373 case RSMIPC_MSG_SUSPEND:
5374 case RSMIPC_MSG_SUSPEND_DONE:
5375 case RSMIPC_MSG_RESUME:
5376 credit_check = 1;
5377 break;
5378 default:
5379 credit_check = 0;
5380 }
5381 }
5382
5383 again:
5384 if (retry_cnt++ == min_retry_cnt) {
5385 /* backoff before further retries for 10ms */
5386 delay(drv_usectohz(10000));
5387 retry_cnt = 0; /* reset retry_cnt */
5388 }
5389 sendq_token = rsmka_get_sendq_token(dest, used_sendq_token);
5390 if (sendq_token == NULL) {
5391 DBG_PRINTF((category, RSM_ERR,
5392 "rsm: rsmipc_send no device to reach node %d\n", dest));
5393 return (RSMERR_REMOTE_NODE_UNREACHABLE);
5394 }
5395
5396 if ((sendq_token == used_sendq_token) &&
5397 ((e == RSMERR_CONN_ABORTED) || (e == RSMERR_TIMEOUT) ||
5398 (e == RSMERR_COMM_ERR_MAYBE_DELIVERED))) {
5399 rele_sendq_token(sendq_token);
5400 DBG_PRINTF((category, RSM_DEBUG, "rsmipc_send done=%d\n", e));
5401 return (RSMERR_CONN_ABORTED);
5402 } else
5403 used_sendq_token = sendq_token;
5404
5405 /* lint -save -e413 */
5406 path = SQ_TOKEN_TO_PATH(sendq_token);
5407 adapter = path->local_adapter;
5408 /* lint -restore */
5409 ipc_handle = sendq_token->rsmpi_sendq_handle;
5410
5411 DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
5412 "rsmipc_send: path=%lx sendq_hdl=%lx\n", path, ipc_handle));
5413
5414 if (reply == NULL) {
5415 /* Send request without ack */
5416 /*
5417 * Set the rsmipc_version number in the msghdr for KA
5418 * communication versioning
5419 */
5420 req->rsmipc_hdr.rsmipc_version = RSM_VERSION;
5421 req->rsmipc_hdr.rsmipc_src = my_nodeid;
5422 /*
5423 * remote endpoints incn should match the value in our
5424 * path's remote_incn field. No need to grab any lock
5425 * since we have refcnted the path in rsmka_get_sendq_token
5426 */
5427 req->rsmipc_hdr.rsmipc_incn = path->remote_incn;
5428
5429 is.is_data = (void *)req;
5430 is.is_size = sizeof (*req);
5431 is.is_flags = RSM_INTR_SEND_DELIVER | RSM_INTR_SEND_SLEEP;
5432 is.is_wait = 0;
5433
5434 if (credit_check) {
5435 mutex_enter(&path->mutex);
5436 /*
5437 * wait till we recv credits or path goes down. If path
5438 * goes down rsm_send will fail and we handle the error
5439 * then
5440 */
5441 while ((sendq_token->msgbuf_avail == 0) &&
5442 (path->state == RSMKA_PATH_ACTIVE)) {
5443 e = cv_wait_sig(&sendq_token->sendq_cv,
5444 &path->mutex);
5445 if (e == 0) {
5446 mutex_exit(&path->mutex);
5447 no_reply_cnt++;
5448 rele_sendq_token(sendq_token);
5449 DBG_PRINTF((category, RSM_DEBUG,
5450 "rsmipc_send done: "
5451 "cv_wait INTERRUPTED"));
5452 return (RSMERR_INTERRUPTED);
5453 }
5454 }
5455
5456 /*
5457 * path is not active retry on another path.
5458 */
5459 if (path->state != RSMKA_PATH_ACTIVE) {
5460 mutex_exit(&path->mutex);
5461 rele_sendq_token(sendq_token);
5462 e = RSMERR_CONN_ABORTED;
5463 DBG_PRINTF((category, RSM_ERR,
5464 "rsm: rsmipc_send: path !ACTIVE"));
5465 goto again;
5466 }
5467
5468 ASSERT(sendq_token->msgbuf_avail > 0);
5469
5470 /*
5471 * reserve a msgbuf
5472 */
5473 sendq_token->msgbuf_avail--;
5474
5475 mutex_exit(&path->mutex);
5476
5477 e = adapter->rsmpi_ops->rsm_send(ipc_handle, &is,
5478 NULL);
5479
5480 if (e != RSM_SUCCESS) {
5481 mutex_enter(&path->mutex);
5482 /*
5483 * release the reserved msgbuf since
5484 * the send failed
5485 */
5486 sendq_token->msgbuf_avail++;
5487 cv_broadcast(&sendq_token->sendq_cv);
5488 mutex_exit(&path->mutex);
5489 }
5490 } else
5491 e = adapter->rsmpi_ops->rsm_send(ipc_handle, &is,
5492 NULL);
5493
5494 no_reply_cnt++;
5495 rele_sendq_token(sendq_token);
5496 if (e != RSM_SUCCESS) {
5497 DBG_PRINTF((category, RSM_ERR,
5498 "rsm: rsmipc_send no reply send"
5499 " err = %d no reply count = %d\n",
5500 e, no_reply_cnt));
5501 ASSERT(e != RSMERR_QUEUE_FENCE_UP &&
5502 e != RSMERR_BAD_BARRIER_HNDL);
5503 atomic_inc_64(&rsm_ipcsend_errcnt);
5504 goto again;
5505 } else {
5506 DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
5507 "rsmipc_send done\n"));
5508 return (e);
5509 }
5510
5511 }
5512
5513 if (req == NULL) {
5514 /* Send reply - No flow control is done for reply */
5515 /*
5516 * Set the version in the msg header for KA communication
5517 * versioning
5518 */
5519 reply->rsmipc_hdr.rsmipc_version = RSM_VERSION;
5520 reply->rsmipc_hdr.rsmipc_src = my_nodeid;
5521 /* incn number is not used for reply msgs currently */
5522 reply->rsmipc_hdr.rsmipc_incn = path->remote_incn;
5523
5524 is.is_data = (void *)reply;
5525 is.is_size = sizeof (*reply);
5526 is.is_flags = RSM_INTR_SEND_DELIVER | RSM_INTR_SEND_SLEEP;
5527 is.is_wait = 0;
5528 e = adapter->rsmpi_ops->rsm_send(ipc_handle, &is, NULL);
5529 rele_sendq_token(sendq_token);
5530 if (e != RSM_SUCCESS) {
5531 DBG_PRINTF((category, RSM_ERR,
5532 "rsm: rsmipc_send reply send"
5533 " err = %d\n", e));
5534 atomic_inc_64(&rsm_ipcsend_errcnt);
5535 goto again;
5536 } else {
5537 DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
5538 "rsmipc_send done\n"));
5539 return (e);
5540 }
5541 }
5542
5543 /* Reply needed */
5544 rslot = rsmipc_alloc(); /* allocate a new ipc slot */
5545
5546 mutex_enter(&rslot->rsmipc_lock);
5547
5548 rslot->rsmipc_data = (void *)reply;
5549 RSMIPC_SET(rslot, RSMIPC_PENDING);
5550
5551 while (RSMIPC_GET(rslot, RSMIPC_PENDING)) {
5552 /*
5553 * Set the rsmipc_version number in the msghdr for KA
5554 * communication versioning
5555 */
5556 req->rsmipc_hdr.rsmipc_version = RSM_VERSION;
5557 req->rsmipc_hdr.rsmipc_src = my_nodeid;
5558 req->rsmipc_hdr.rsmipc_cookie = rslot->rsmipc_cookie;
5559 /*
5560 * remote endpoints incn should match the value in our
5561 * path's remote_incn field. No need to grab any lock
5562 * since we have refcnted the path in rsmka_get_sendq_token
5563 */
5564 req->rsmipc_hdr.rsmipc_incn = path->remote_incn;
5565
5566 is.is_data = (void *)req;
5567 is.is_size = sizeof (*req);
5568 is.is_flags = RSM_INTR_SEND_DELIVER | RSM_INTR_SEND_SLEEP;
5569 is.is_wait = 0;
5570 if (credit_check) {
5571
5572 mutex_enter(&path->mutex);
5573 /*
5574 * wait till we recv credits or path goes down. If path
5575 * goes down rsm_send will fail and we handle the error
5576 * then.
5577 */
5578 while ((sendq_token->msgbuf_avail == 0) &&
5579 (path->state == RSMKA_PATH_ACTIVE)) {
5580 e = cv_wait_sig(&sendq_token->sendq_cv,
5581 &path->mutex);
5582 if (e == 0) {
5583 mutex_exit(&path->mutex);
5584 RSMIPC_CLEAR(rslot, RSMIPC_PENDING);
5585 rsmipc_free(rslot);
5586 rele_sendq_token(sendq_token);
5587 DBG_PRINTF((category, RSM_DEBUG,
5588 "rsmipc_send done: "
5589 "cv_wait INTERRUPTED"));
5590 return (RSMERR_INTERRUPTED);
5591 }
5592 }
5593
5594 /*
5595 * path is not active retry on another path.
5596 */
5597 if (path->state != RSMKA_PATH_ACTIVE) {
5598 mutex_exit(&path->mutex);
5599 RSMIPC_CLEAR(rslot, RSMIPC_PENDING);
5600 rsmipc_free(rslot);
5601 rele_sendq_token(sendq_token);
5602 e = RSMERR_CONN_ABORTED;
5603 DBG_PRINTF((category, RSM_ERR,
5604 "rsm: rsmipc_send: path !ACTIVE"));
5605 goto again;
5606 }
5607
5608 ASSERT(sendq_token->msgbuf_avail > 0);
5609
5610 /*
5611 * reserve a msgbuf
5612 */
5613 sendq_token->msgbuf_avail--;
5614
5615 mutex_exit(&path->mutex);
5616
5617 e = adapter->rsmpi_ops->rsm_send(ipc_handle, &is,
5618 NULL);
5619
5620 if (e != RSM_SUCCESS) {
5621 mutex_enter(&path->mutex);
5622 /*
5623 * release the reserved msgbuf since
5624 * the send failed
5625 */
5626 sendq_token->msgbuf_avail++;
5627 cv_broadcast(&sendq_token->sendq_cv);
5628 mutex_exit(&path->mutex);
5629 }
5630 } else
5631 e = adapter->rsmpi_ops->rsm_send(ipc_handle, &is,
5632 NULL);
5633
5634 if (e != RSM_SUCCESS) {
5635 DBG_PRINTF((category, RSM_ERR,
5636 "rsm: rsmipc_send rsmpi send err = %d\n", e));
5637 RSMIPC_CLEAR(rslot, RSMIPC_PENDING);
5638 rsmipc_free(rslot);
5639 rele_sendq_token(sendq_token);
5640 atomic_inc_64(&rsm_ipcsend_errcnt);
5641 goto again;
5642 }
5643
5644 /* wait for a reply signal, a SIGINT, or 5 sec. timeout */
5645 e = cv_reltimedwait_sig(&rslot->rsmipc_cv, &rslot->rsmipc_lock,
5646 drv_usectohz(5000000), TR_CLOCK_TICK);
5647 if (e < 0) {
5648 /* timed out - retry */
5649 e = RSMERR_TIMEOUT;
5650 } else if (e == 0) {
5651 /* signalled - return error */
5652 e = RSMERR_INTERRUPTED;
5653 break;
5654 } else {
5655 e = RSM_SUCCESS;
5656 }
5657 }
5658
5659 RSMIPC_CLEAR(rslot, RSMIPC_PENDING);
5660 rsmipc_free(rslot);
5661 rele_sendq_token(sendq_token);
5662
5663 DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmipc_send done=%d\n", e));
5664 return (e);
5665 }
5666
5667 static int
rsm_send_notimporting(rsm_node_id_t dest,rsm_memseg_id_t segid,void * cookie)5668 rsm_send_notimporting(rsm_node_id_t dest, rsm_memseg_id_t segid, void *cookie)
5669 {
5670 rsmipc_request_t request;
5671
5672 /*
5673 * inform the exporter to delete this importer
5674 */
5675 request.rsmipc_hdr.rsmipc_type = RSMIPC_MSG_NOTIMPORTING;
5676 request.rsmipc_key = segid;
5677 request.rsmipc_segment_cookie = cookie;
5678 return (rsmipc_send(dest, &request, RSM_NO_REPLY));
5679 }
5680
5681 static void
rsm_send_republish(rsm_memseg_id_t segid,rsmapi_access_entry_t * acl,int acl_len,rsm_permission_t default_permission)5682 rsm_send_republish(rsm_memseg_id_t segid, rsmapi_access_entry_t *acl,
5683 int acl_len, rsm_permission_t default_permission)
5684 {
5685 int i;
5686 importing_token_t *token;
5687 rsmipc_request_t request;
5688 republish_token_t *republish_list = NULL;
5689 republish_token_t *rp;
5690 rsm_permission_t permission;
5691 int index;
5692
5693 /*
5694 * send the new access mode to all the nodes that have imported
5695 * this segment.
5696 * If the new acl does not have a node that was present in
5697 * the old acl a access permission of 0 is sent.
5698 */
5699
5700 index = rsmhash(segid);
5701
5702 /*
5703 * create a list of node/permissions to send the republish message
5704 */
5705 mutex_enter(&importer_list.lock);
5706
5707 token = importer_list.bucket[index];
5708 while (token != NULL) {
5709 if (segid == token->key) {
5710 permission = default_permission;
5711
5712 for (i = 0; i < acl_len; i++) {
5713 if (token->importing_node == acl[i].ae_node) {
5714 permission = acl[i].ae_permission;
5715 break;
5716 }
5717 }
5718 rp = kmem_zalloc(sizeof (republish_token_t), KM_SLEEP);
5719
5720 rp->key = segid;
5721 rp->importing_node = token->importing_node;
5722 rp->permission = permission;
5723 rp->next = republish_list;
5724 republish_list = rp;
5725 }
5726 token = token->next;
5727 }
5728
5729 mutex_exit(&importer_list.lock);
5730
5731 request.rsmipc_hdr.rsmipc_type = RSMIPC_MSG_REPUBLISH;
5732 request.rsmipc_key = segid;
5733
5734 while (republish_list != NULL) {
5735 request.rsmipc_perm = republish_list->permission;
5736 (void) rsmipc_send(republish_list->importing_node,
5737 &request, RSM_NO_REPLY);
5738 rp = republish_list;
5739 republish_list = republish_list->next;
5740 kmem_free(rp, sizeof (republish_token_t));
5741 }
5742 }
5743
5744 static void
rsm_send_suspend()5745 rsm_send_suspend()
5746 {
5747 int i, e;
5748 rsmipc_request_t request;
5749 list_element_t *tokp;
5750 list_element_t *head = NULL;
5751 importing_token_t *token;
5752 DBG_PRINTF((RSM_KERNEL_AGENT | RSM_EXPORT, RSM_DEBUG_VERBOSE,
5753 "rsm_send_suspend enter\n"));
5754
5755 /*
5756 * create a list of node to send the suspend message
5757 *
5758 * Currently the whole importer list is scanned and we obtain
5759 * all the nodes - this basically gets all nodes that at least
5760 * import one segment from the local node.
5761 *
5762 * no need to grab the rsm_suspend_list lock here since we are
5763 * single threaded when suspend is called.
5764 */
5765
5766 mutex_enter(&importer_list.lock);
5767 for (i = 0; i < rsm_hash_size; i++) {
5768
5769 token = importer_list.bucket[i];
5770
5771 while (token != NULL) {
5772
5773 tokp = head;
5774
5775 /*
5776 * make sure that the token's node
5777 * is not already on the suspend list
5778 */
5779 while (tokp != NULL) {
5780 if (tokp->nodeid == token->importing_node) {
5781 break;
5782 }
5783 tokp = tokp->next;
5784 }
5785
5786 if (tokp == NULL) { /* not in suspend list */
5787 tokp = kmem_zalloc(sizeof (list_element_t),
5788 KM_SLEEP);
5789 tokp->nodeid = token->importing_node;
5790 tokp->next = head;
5791 head = tokp;
5792 }
5793
5794 token = token->next;
5795 }
5796 }
5797 mutex_exit(&importer_list.lock);
5798
5799 if (head == NULL) { /* no importers so go ahead and quiesce segments */
5800 exporter_quiesce();
5801 return;
5802 }
5803
5804 mutex_enter(&rsm_suspend_list.list_lock);
5805 ASSERT(rsm_suspend_list.list_head == NULL);
5806 /*
5807 * update the suspend list righaway so that if a node dies the
5808 * pathmanager can set the NODE dead flag
5809 */
5810 rsm_suspend_list.list_head = head;
5811 mutex_exit(&rsm_suspend_list.list_lock);
5812
5813 tokp = head;
5814
5815 while (tokp != NULL) {
5816 request.rsmipc_hdr.rsmipc_type = RSMIPC_MSG_SUSPEND;
5817 e = rsmipc_send(tokp->nodeid, &request, RSM_NO_REPLY);
5818 /*
5819 * Error in rsmipc_send currently happens due to inaccessibility
5820 * of the remote node.
5821 */
5822 if (e == RSM_SUCCESS) { /* send failed - don't wait for ack */
5823 tokp->flags |= RSM_SUSPEND_ACKPENDING;
5824 }
5825
5826 tokp = tokp->next;
5827 }
5828
5829 DBG_PRINTF((RSM_KERNEL_AGENT | RSM_EXPORT, RSM_DEBUG_VERBOSE,
5830 "rsm_send_suspend done\n"));
5831
5832 }
5833
5834 static void
rsm_send_resume()5835 rsm_send_resume()
5836 {
5837 rsmipc_request_t request;
5838 list_element_t *elem, *head;
5839
5840 /*
5841 * save the suspend list so that we know where to send
5842 * the resume messages and make the suspend list head
5843 * NULL.
5844 */
5845 mutex_enter(&rsm_suspend_list.list_lock);
5846 head = rsm_suspend_list.list_head;
5847 rsm_suspend_list.list_head = NULL;
5848 mutex_exit(&rsm_suspend_list.list_lock);
5849
5850 while (head != NULL) {
5851 elem = head;
5852 head = head->next;
5853
5854 request.rsmipc_hdr.rsmipc_type = RSMIPC_MSG_RESUME;
5855
5856 (void) rsmipc_send(elem->nodeid, &request, RSM_NO_REPLY);
5857
5858 kmem_free((void *)elem, sizeof (list_element_t));
5859
5860 }
5861
5862 }
5863
5864 /*
5865 * This function takes path and sends a message using the sendq
5866 * corresponding to it. The RSMIPC_MSG_SQREADY, RSMIPC_MSG_SQREADY_ACK
5867 * and RSMIPC_MSG_CREDIT are sent using this function.
5868 */
5869 int
rsmipc_send_controlmsg(path_t * path,int msgtype)5870 rsmipc_send_controlmsg(path_t *path, int msgtype)
5871 {
5872 int e;
5873 int retry_cnt = 0;
5874 int min_retry_cnt = 10;
5875 adapter_t *adapter;
5876 rsm_send_t is;
5877 rsm_send_q_handle_t ipc_handle;
5878 rsmipc_controlmsg_t msg;
5879 DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_FUNC_ALL | RSM_FLOWCONTROL);
5880
5881 DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
5882 "rsmipc_send_controlmsg enter\n"));
5883
5884 ASSERT(MUTEX_HELD(&path->mutex));
5885
5886 adapter = path->local_adapter;
5887
5888 DBG_PRINTF((category, RSM_DEBUG, "rsmipc_send_controlmsg:path=%lx "
5889 "msgtype=%d %lx:%llx->%lx:%llx procmsg=%d\n", path, msgtype,
5890 my_nodeid, adapter->hwaddr, path->remote_node,
5891 path->remote_hwaddr, path->procmsg_cnt));
5892
5893 if (path->state != RSMKA_PATH_ACTIVE) {
5894 DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
5895 "rsmipc_send_controlmsg done: ! RSMKA_PATH_ACTIVE"));
5896 return (1);
5897 }
5898
5899 ipc_handle = path->sendq_token.rsmpi_sendq_handle;
5900
5901 msg.rsmipc_hdr.rsmipc_version = RSM_VERSION;
5902 msg.rsmipc_hdr.rsmipc_src = my_nodeid;
5903 msg.rsmipc_hdr.rsmipc_type = msgtype;
5904 msg.rsmipc_hdr.rsmipc_incn = path->remote_incn;
5905
5906 if (msgtype == RSMIPC_MSG_CREDIT)
5907 msg.rsmipc_credits = path->procmsg_cnt;
5908
5909 msg.rsmipc_local_incn = path->local_incn;
5910
5911 msg.rsmipc_adapter_hwaddr = adapter->hwaddr;
5912 /* incr the sendq, path refcnt */
5913 PATH_HOLD_NOLOCK(path);
5914 SENDQ_TOKEN_HOLD(path);
5915
5916 do {
5917 /* drop the path lock before doing the rsm_send */
5918 mutex_exit(&path->mutex);
5919
5920 is.is_data = (void *)&msg;
5921 is.is_size = sizeof (msg);
5922 is.is_flags = RSM_INTR_SEND_DELIVER | RSM_INTR_SEND_SLEEP;
5923 is.is_wait = 0;
5924
5925 e = adapter->rsmpi_ops->rsm_send(ipc_handle, &is, NULL);
5926
5927 ASSERT(e != RSMERR_QUEUE_FENCE_UP &&
5928 e != RSMERR_BAD_BARRIER_HNDL);
5929
5930 mutex_enter(&path->mutex);
5931
5932 if (e == RSM_SUCCESS) {
5933 break;
5934 }
5935 /* error counter for statistics */
5936 atomic_inc_64(&rsm_ctrlmsg_errcnt);
5937
5938 DBG_PRINTF((category, RSM_ERR,
5939 "rsmipc_send_controlmsg:rsm_send error=%d", e));
5940
5941 if (++retry_cnt == min_retry_cnt) { /* backoff before retry */
5942 (void) cv_reltimedwait(&path->sendq_token.sendq_cv,
5943 &path->mutex, drv_usectohz(10000), TR_CLOCK_TICK);
5944 retry_cnt = 0;
5945 }
5946 } while (path->state == RSMKA_PATH_ACTIVE);
5947
5948 /* decrement the sendq,path refcnt that we incr before rsm_send */
5949 SENDQ_TOKEN_RELE(path);
5950 PATH_RELE_NOLOCK(path);
5951
5952 DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
5953 "rsmipc_send_controlmsg done=%d", e));
5954 return (e);
5955 }
5956
5957 /*
5958 * Called from rsm_force_unload and path_importer_disconnect. The memory
5959 * mapping for the imported segment is removed and the segment is
5960 * disconnected at the interconnect layer if disconnect_flag is TRUE.
5961 * rsm_force_unload will get disconnect_flag TRUE from rsm_intr_callback
5962 * and FALSE from rsm_rebind.
5963 *
5964 * When subsequent accesses cause page faulting, the dummy page is mapped
5965 * to resolve the fault, and the mapping generation number is incremented
5966 * so that the application can be notified on a close barrier operation.
5967 *
5968 * It is important to note that the caller of rsmseg_unload is responsible for
5969 * acquiring the segment lock before making a call to rsmseg_unload. This is
5970 * required to make the caller and rsmseg_unload thread safe. The segment lock
5971 * will be released by the rsmseg_unload function.
5972 */
5973 void
rsmseg_unload(rsmseg_t * im_seg)5974 rsmseg_unload(rsmseg_t *im_seg)
5975 {
5976 rsmcookie_t *hdl;
5977 void *shared_cookie;
5978 rsmipc_request_t request;
5979 uint_t maxprot;
5980
5981 DBG_DEFINE(category,
5982 RSM_KERNEL_AGENT | RSM_FUNC_ALL | RSM_INTR_CALLBACK);
5983
5984 DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmseg_unload enter\n"));
5985
5986 ASSERT(im_seg->s_hdr.rsmrc_type == RSM_RESOURCE_IMPORT_SEGMENT);
5987
5988 /* wait until segment leaves the mapping state */
5989 while (im_seg->s_state == RSM_STATE_MAPPING)
5990 cv_wait(&im_seg->s_cv, &im_seg->s_lock);
5991 /*
5992 * An unload is only necessary if the segment is connected. However,
5993 * if the segment was on the import list in state RSM_STATE_CONNECTING
5994 * then a connection was in progress. Change to RSM_STATE_NEW
5995 * here to cause an early exit from the connection process.
5996 */
5997 if (im_seg->s_state == RSM_STATE_NEW) {
5998 rsmseglock_release(im_seg);
5999 DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
6000 "rsmseg_unload done: RSM_STATE_NEW\n"));
6001 return;
6002 } else if (im_seg->s_state == RSM_STATE_CONNECTING) {
6003 im_seg->s_state = RSM_STATE_ABORT_CONNECT;
6004 rsmsharelock_acquire(im_seg);
6005 im_seg->s_share->rsmsi_state = RSMSI_STATE_ABORT_CONNECT;
6006 rsmsharelock_release(im_seg);
6007 rsmseglock_release(im_seg);
6008 DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
6009 "rsmseg_unload done: RSM_STATE_CONNECTING\n"));
6010 return;
6011 }
6012
6013 if (im_seg->s_flags & RSM_FORCE_DISCONNECT) {
6014 if (im_seg->s_ckl != NULL) {
6015 int e;
6016 /* Setup protections for remap */
6017 maxprot = PROT_USER;
6018 if (im_seg->s_mode & RSM_PERM_READ) {
6019 maxprot |= PROT_READ;
6020 }
6021 if (im_seg->s_mode & RSM_PERM_WRITE) {
6022 maxprot |= PROT_WRITE;
6023 }
6024 hdl = im_seg->s_ckl;
6025 for (; hdl != NULL; hdl = hdl->c_next) {
6026 e = devmap_umem_remap(hdl->c_dhp, rsm_dip,
6027 remap_cookie,
6028 hdl->c_off, hdl->c_len,
6029 maxprot, 0, NULL);
6030
6031 DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
6032 "remap returns %d\n", e));
6033 }
6034 }
6035
6036 (void) rsm_closeconnection(im_seg, &shared_cookie);
6037
6038 if (shared_cookie != NULL) {
6039 /*
6040 * inform the exporting node so this import
6041 * can be deleted from the list of importers.
6042 */
6043 request.rsmipc_hdr.rsmipc_type =
6044 RSMIPC_MSG_NOTIMPORTING;
6045 request.rsmipc_key = im_seg->s_segid;
6046 request.rsmipc_segment_cookie = shared_cookie;
6047 rsmseglock_release(im_seg);
6048 (void) rsmipc_send(im_seg->s_node, &request,
6049 RSM_NO_REPLY);
6050 } else {
6051 rsmseglock_release(im_seg);
6052 }
6053 }
6054 else
6055 rsmseglock_release(im_seg);
6056
6057 DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmseg_unload done\n"));
6058
6059 }
6060
6061 /* ****************************** Importer Calls ************************ */
6062
6063 static int
rsm_access(uid_t owner,gid_t group,int perm,int mode,const struct cred * cr)6064 rsm_access(uid_t owner, gid_t group, int perm, int mode, const struct cred *cr)
6065 {
6066 int shifts = 0;
6067
6068 if (crgetuid(cr) != owner) {
6069 shifts += 3;
6070 if (!groupmember(group, cr))
6071 shifts += 3;
6072 }
6073
6074 mode &= ~(perm << shifts);
6075
6076 if (mode == 0)
6077 return (0);
6078
6079 return (secpolicy_rsm_access(cr, owner, mode));
6080 }
6081
6082
6083 static int
rsm_connect(rsmseg_t * seg,rsm_ioctlmsg_t * msg,cred_t * cred,intptr_t dataptr,int mode)6084 rsm_connect(rsmseg_t *seg, rsm_ioctlmsg_t *msg, cred_t *cred,
6085 intptr_t dataptr, int mode)
6086 {
6087 int e;
6088 int recheck_state = 0;
6089 void *shared_cookie;
6090 rsmipc_request_t request;
6091 rsmipc_reply_t reply;
6092 rsm_permission_t access;
6093 adapter_t *adapter;
6094 rsm_addr_t addr = 0;
6095 rsm_import_share_t *sharedp;
6096 DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_IMPORT);
6097
6098 DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_connect enter\n"));
6099
6100 adapter = rsm_getadapter(msg, mode);
6101 if (adapter == NULL) {
6102 DBG_PRINTF((category, RSM_ERR,
6103 "rsm_connect done:ENODEV adapter=NULL\n"));
6104 return (RSMERR_CTLR_NOT_PRESENT);
6105 }
6106
6107 if ((adapter == &loopback_adapter) && (msg->nodeid != my_nodeid)) {
6108 rsmka_release_adapter(adapter);
6109 DBG_PRINTF((category, RSM_ERR,
6110 "rsm_connect done:ENODEV loopback\n"));
6111 return (RSMERR_CTLR_NOT_PRESENT);
6112 }
6113
6114
6115 ASSERT(seg->s_hdr.rsmrc_type == RSM_RESOURCE_IMPORT_SEGMENT);
6116 ASSERT(seg->s_state == RSM_STATE_NEW);
6117
6118 /*
6119 * Translate perm to access
6120 */
6121 if (msg->perm & ~RSM_PERM_RDWR) {
6122 rsmka_release_adapter(adapter);
6123 DBG_PRINTF((category, RSM_ERR,
6124 "rsm_connect done:EINVAL invalid perms\n"));
6125 return (RSMERR_BAD_PERMS);
6126 }
6127 access = 0;
6128 if (msg->perm & RSM_PERM_READ)
6129 access |= RSM_ACCESS_READ;
6130 if (msg->perm & RSM_PERM_WRITE)
6131 access |= RSM_ACCESS_WRITE;
6132
6133 seg->s_node = msg->nodeid;
6134
6135 /*
6136 * Adding to the import list locks the segment; release the segment
6137 * lock so we can get the reply for the send.
6138 */
6139 e = rsmimport_add(seg, msg->key);
6140 if (e) {
6141 rsmka_release_adapter(adapter);
6142 DBG_PRINTF((category, RSM_ERR,
6143 "rsm_connect done:rsmimport_add failed %d\n", e));
6144 return (e);
6145 }
6146 seg->s_state = RSM_STATE_CONNECTING;
6147
6148 /*
6149 * Set the s_adapter field here so as to have a valid comparison of
6150 * the adapter and the s_adapter value during rsmshare_get. For
6151 * any error, set s_adapter to NULL before doing a release_adapter
6152 */
6153 seg->s_adapter = adapter;
6154
6155 rsmseglock_release(seg);
6156
6157 /*
6158 * get the pointer to the shared data structure; the
6159 * shared data is locked and refcount has been incremented
6160 */
6161 sharedp = rsmshare_get(msg->key, msg->nodeid, adapter, seg);
6162
6163 ASSERT(rsmsharelock_held(seg));
6164
6165 do {
6166 /* flag indicates whether we need to recheck the state */
6167 recheck_state = 0;
6168 DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
6169 "rsm_connect:RSMSI_STATE=%d\n", sharedp->rsmsi_state));
6170 switch (sharedp->rsmsi_state) {
6171 case RSMSI_STATE_NEW:
6172 sharedp->rsmsi_state = RSMSI_STATE_CONNECTING;
6173 break;
6174 case RSMSI_STATE_CONNECTING:
6175 /* FALLTHRU */
6176 case RSMSI_STATE_CONN_QUIESCE:
6177 /* FALLTHRU */
6178 case RSMSI_STATE_MAP_QUIESCE:
6179 /* wait for the state to change */
6180 while ((sharedp->rsmsi_state ==
6181 RSMSI_STATE_CONNECTING) ||
6182 (sharedp->rsmsi_state ==
6183 RSMSI_STATE_CONN_QUIESCE) ||
6184 (sharedp->rsmsi_state ==
6185 RSMSI_STATE_MAP_QUIESCE)) {
6186 if (cv_wait_sig(&sharedp->rsmsi_cv,
6187 &sharedp->rsmsi_lock) == 0) {
6188 /* signalled - clean up and return */
6189 rsmsharelock_release(seg);
6190 rsmimport_rm(seg);
6191 seg->s_adapter = NULL;
6192 rsmka_release_adapter(adapter);
6193 seg->s_state = RSM_STATE_NEW;
6194 DBG_PRINTF((category, RSM_ERR,
6195 "rsm_connect done: INTERRUPTED\n"));
6196 return (RSMERR_INTERRUPTED);
6197 }
6198 }
6199 /*
6200 * the state changed, loop back and check what it is
6201 */
6202 recheck_state = 1;
6203 break;
6204 case RSMSI_STATE_ABORT_CONNECT:
6205 /* exit the loop and clean up further down */
6206 break;
6207 case RSMSI_STATE_CONNECTED:
6208 /* already connected, good - fall through */
6209 case RSMSI_STATE_MAPPED:
6210 /* already mapped, wow - fall through */
6211 /* access validation etc is done further down */
6212 break;
6213 case RSMSI_STATE_DISCONNECTED:
6214 /* disconnected - so reconnect now */
6215 sharedp->rsmsi_state = RSMSI_STATE_CONNECTING;
6216 break;
6217 default:
6218 ASSERT(0); /* Invalid State */
6219 }
6220 } while (recheck_state);
6221
6222 if (sharedp->rsmsi_state == RSMSI_STATE_CONNECTING) {
6223 /* we are the first to connect */
6224 rsmsharelock_release(seg);
6225
6226 if (msg->nodeid != my_nodeid) {
6227 addr = get_remote_hwaddr(adapter, msg->nodeid);
6228
6229 if ((int64_t)addr < 0) {
6230 rsmsharelock_acquire(seg);
6231 rsmsharecv_signal(seg, RSMSI_STATE_CONNECTING,
6232 RSMSI_STATE_NEW);
6233 rsmsharelock_release(seg);
6234 rsmimport_rm(seg);
6235 seg->s_adapter = NULL;
6236 rsmka_release_adapter(adapter);
6237 seg->s_state = RSM_STATE_NEW;
6238 DBG_PRINTF((category, RSM_ERR,
6239 "rsm_connect done: hwaddr<0\n"));
6240 return (RSMERR_INTERNAL_ERROR);
6241 }
6242 } else {
6243 addr = adapter->hwaddr;
6244 }
6245
6246 /*
6247 * send request to node [src, dest, key, msgid] and get back
6248 * [status, msgid, cookie]
6249 */
6250 request.rsmipc_key = msg->key;
6251 /*
6252 * we need the s_mode of the exporter so pass
6253 * RSM_ACCESS_TRUSTED
6254 */
6255 request.rsmipc_perm = RSM_ACCESS_TRUSTED;
6256 request.rsmipc_hdr.rsmipc_type = RSMIPC_MSG_SEGCONNECT;
6257 request.rsmipc_adapter_hwaddr = addr;
6258 request.rsmipc_segment_cookie = sharedp;
6259
6260 e = (int)rsmipc_send(msg->nodeid, &request, &reply);
6261 if (e) {
6262 rsmsharelock_acquire(seg);
6263 rsmsharecv_signal(seg, RSMSI_STATE_CONNECTING,
6264 RSMSI_STATE_NEW);
6265 rsmsharelock_release(seg);
6266 rsmimport_rm(seg);
6267 seg->s_adapter = NULL;
6268 rsmka_release_adapter(adapter);
6269 seg->s_state = RSM_STATE_NEW;
6270 DBG_PRINTF((category, RSM_ERR,
6271 "rsm_connect done:rsmipc_send failed %d\n", e));
6272 return (e);
6273 }
6274
6275 if (reply.rsmipc_status != RSM_SUCCESS) {
6276 rsmsharelock_acquire(seg);
6277 rsmsharecv_signal(seg, RSMSI_STATE_CONNECTING,
6278 RSMSI_STATE_NEW);
6279 rsmsharelock_release(seg);
6280 rsmimport_rm(seg);
6281 seg->s_adapter = NULL;
6282 rsmka_release_adapter(adapter);
6283 seg->s_state = RSM_STATE_NEW;
6284 DBG_PRINTF((category, RSM_ERR,
6285 "rsm_connect done:rsmipc_send reply err %d\n",
6286 reply.rsmipc_status));
6287 return (reply.rsmipc_status);
6288 }
6289
6290 rsmsharelock_acquire(seg);
6291 /* store the information recvd into the shared data struct */
6292 sharedp->rsmsi_mode = reply.rsmipc_mode;
6293 sharedp->rsmsi_uid = reply.rsmipc_uid;
6294 sharedp->rsmsi_gid = reply.rsmipc_gid;
6295 sharedp->rsmsi_seglen = reply.rsmipc_seglen;
6296 sharedp->rsmsi_cookie = sharedp;
6297 }
6298
6299 rsmsharelock_release(seg);
6300
6301 /*
6302 * Get the segment lock and check for a force disconnect
6303 * from the export side which would have changed the state
6304 * back to RSM_STATE_NEW. Once the segment lock is acquired a
6305 * force disconnect will be held off until the connection
6306 * has completed.
6307 */
6308 rsmseglock_acquire(seg);
6309 rsmsharelock_acquire(seg);
6310 ASSERT(seg->s_state == RSM_STATE_CONNECTING ||
6311 seg->s_state == RSM_STATE_ABORT_CONNECT);
6312
6313 shared_cookie = sharedp->rsmsi_cookie;
6314
6315 if ((seg->s_state == RSM_STATE_ABORT_CONNECT) ||
6316 (sharedp->rsmsi_state == RSMSI_STATE_ABORT_CONNECT)) {
6317 seg->s_state = RSM_STATE_NEW;
6318 seg->s_adapter = NULL;
6319 rsmsharelock_release(seg);
6320 rsmseglock_release(seg);
6321 rsmimport_rm(seg);
6322 rsmka_release_adapter(adapter);
6323
6324 rsmsharelock_acquire(seg);
6325 if (!(sharedp->rsmsi_flags & RSMSI_FLAGS_ABORTDONE)) {
6326 /*
6327 * set a flag indicating abort handling has been
6328 * done
6329 */
6330 sharedp->rsmsi_flags |= RSMSI_FLAGS_ABORTDONE;
6331 rsmsharelock_release(seg);
6332 /* send a message to exporter - only once */
6333 (void) rsm_send_notimporting(msg->nodeid,
6334 msg->key, shared_cookie);
6335 rsmsharelock_acquire(seg);
6336 /*
6337 * wake up any waiting importers and inform that
6338 * connection has been aborted
6339 */
6340 cv_broadcast(&sharedp->rsmsi_cv);
6341 }
6342 rsmsharelock_release(seg);
6343
6344 DBG_PRINTF((category, RSM_ERR,
6345 "rsm_connect done: RSM_STATE_ABORT_CONNECT\n"));
6346 return (RSMERR_INTERRUPTED);
6347 }
6348
6349
6350 /*
6351 * We need to verify that this process has access
6352 */
6353 e = rsm_access(sharedp->rsmsi_uid, sharedp->rsmsi_gid,
6354 access & sharedp->rsmsi_mode,
6355 (int)(msg->perm & RSM_PERM_RDWR), cred);
6356 if (e) {
6357 rsmsharelock_release(seg);
6358 seg->s_state = RSM_STATE_NEW;
6359 seg->s_adapter = NULL;
6360 rsmseglock_release(seg);
6361 rsmimport_rm(seg);
6362 rsmka_release_adapter(adapter);
6363 /*
6364 * No need to lock segment it has been removed
6365 * from the hash table
6366 */
6367 rsmsharelock_acquire(seg);
6368 if (sharedp->rsmsi_state == RSMSI_STATE_CONNECTING) {
6369 rsmsharelock_release(seg);
6370 /* this is the first importer */
6371
6372 (void) rsm_send_notimporting(msg->nodeid, msg->key,
6373 shared_cookie);
6374 rsmsharelock_acquire(seg);
6375 sharedp->rsmsi_state = RSMSI_STATE_NEW;
6376 cv_broadcast(&sharedp->rsmsi_cv);
6377 }
6378 rsmsharelock_release(seg);
6379
6380 DBG_PRINTF((category, RSM_ERR,
6381 "rsm_connect done: ipcaccess failed\n"));
6382 return (RSMERR_PERM_DENIED);
6383 }
6384
6385 /* update state and cookie */
6386 seg->s_segid = sharedp->rsmsi_segid;
6387 seg->s_len = sharedp->rsmsi_seglen;
6388 seg->s_mode = access & sharedp->rsmsi_mode;
6389 seg->s_pid = ddi_get_pid();
6390 seg->s_mapinfo = NULL;
6391
6392 if (seg->s_node != my_nodeid) {
6393 if (sharedp->rsmsi_state == RSMSI_STATE_CONNECTING) {
6394 e = adapter->rsmpi_ops->rsm_connect(
6395 adapter->rsmpi_handle,
6396 addr, seg->s_segid, &sharedp->rsmsi_handle);
6397
6398 if (e != RSM_SUCCESS) {
6399 seg->s_state = RSM_STATE_NEW;
6400 seg->s_adapter = NULL;
6401 rsmsharelock_release(seg);
6402 rsmseglock_release(seg);
6403 rsmimport_rm(seg);
6404 rsmka_release_adapter(adapter);
6405 /*
6406 * inform the exporter to delete this importer
6407 */
6408 (void) rsm_send_notimporting(msg->nodeid,
6409 msg->key, shared_cookie);
6410
6411 /*
6412 * Now inform any waiting importers to
6413 * retry connect. This needs to be done
6414 * after sending notimporting so that
6415 * the notimporting is sent before a waiting
6416 * importer sends a segconnect while retrying
6417 *
6418 * No need to lock segment it has been removed
6419 * from the hash table
6420 */
6421
6422 rsmsharelock_acquire(seg);
6423 sharedp->rsmsi_state = RSMSI_STATE_NEW;
6424 cv_broadcast(&sharedp->rsmsi_cv);
6425 rsmsharelock_release(seg);
6426
6427 DBG_PRINTF((category, RSM_ERR,
6428 "rsm_connect error %d\n", e));
6429 if (e == RSMERR_SEG_NOT_PUBLISHED_TO_RSM_ADDR)
6430 return (
6431 RSMERR_SEG_NOT_PUBLISHED_TO_NODE);
6432 else if ((e == RSMERR_RSM_ADDR_UNREACHABLE) ||
6433 (e == RSMERR_UNKNOWN_RSM_ADDR))
6434 return (RSMERR_REMOTE_NODE_UNREACHABLE);
6435 else
6436 return (e);
6437 }
6438
6439 }
6440 seg->s_handle.in = sharedp->rsmsi_handle;
6441
6442 }
6443
6444 seg->s_state = RSM_STATE_CONNECT;
6445
6446
6447 seg->s_flags &= ~RSM_IMPORT_DUMMY; /* clear dummy flag */
6448 if (bar_va) {
6449 /* increment generation number on barrier page */
6450 atomic_inc_16(bar_va + seg->s_hdr.rsmrc_num);
6451 /* return user off into barrier page where status will be */
6452 msg->off = (int)seg->s_hdr.rsmrc_num;
6453 msg->gnum = bar_va[msg->off]; /* gnum race */
6454 } else {
6455 msg->off = 0;
6456 msg->gnum = 0; /* gnum race */
6457 }
6458
6459 msg->len = (int)sharedp->rsmsi_seglen;
6460 msg->rnum = seg->s_minor;
6461 rsmsharecv_signal(seg, RSMSI_STATE_CONNECTING, RSMSI_STATE_CONNECTED);
6462 rsmsharelock_release(seg);
6463 rsmseglock_release(seg);
6464
6465 /* Return back to user the segment size & perm in case it's needed */
6466
6467 #ifdef _MULTI_DATAMODEL
6468 if ((mode & DATAMODEL_MASK) == DATAMODEL_ILP32) {
6469 rsm_ioctlmsg32_t msg32;
6470
6471 if (msg->len > UINT_MAX)
6472 msg32.len = RSM_MAXSZ_PAGE_ALIGNED;
6473 else
6474 msg32.len = msg->len;
6475 msg32.off = msg->off;
6476 msg32.perm = msg->perm;
6477 msg32.gnum = msg->gnum;
6478 msg32.rnum = msg->rnum;
6479
6480 DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
6481 "rsm_connect done\n"));
6482
6483 if (ddi_copyout((caddr_t)&msg32, (caddr_t)dataptr,
6484 sizeof (msg32), mode))
6485 return (RSMERR_BAD_ADDR);
6486 else
6487 return (RSM_SUCCESS);
6488 }
6489 #endif
6490 DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_connect done\n"));
6491
6492 if (ddi_copyout((caddr_t)msg, (caddr_t)dataptr, sizeof (*msg),
6493 mode))
6494 return (RSMERR_BAD_ADDR);
6495 else
6496 return (RSM_SUCCESS);
6497 }
6498
6499 static int
rsm_unmap(rsmseg_t * seg)6500 rsm_unmap(rsmseg_t *seg)
6501 {
6502 int err;
6503 adapter_t *adapter;
6504 rsm_import_share_t *sharedp;
6505 DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_IMPORT);
6506
6507 DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
6508 "rsm_unmap enter %u\n", seg->s_segid));
6509
6510 ASSERT(seg->s_hdr.rsmrc_type == RSM_RESOURCE_IMPORT_SEGMENT);
6511
6512 /* assert seg is locked */
6513 ASSERT(rsmseglock_held(seg));
6514 ASSERT(seg->s_state != RSM_STATE_MAPPING);
6515
6516 if ((seg->s_state != RSM_STATE_ACTIVE) &&
6517 (seg->s_state != RSM_STATE_MAP_QUIESCE)) {
6518 /* segment unmap has already been done */
6519 DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_unmap done\n"));
6520 return (RSM_SUCCESS);
6521 }
6522
6523 sharedp = seg->s_share;
6524
6525 rsmsharelock_acquire(seg);
6526
6527 /*
6528 * - shared data struct is in MAPPED or MAP_QUIESCE state
6529 */
6530
6531 ASSERT(sharedp->rsmsi_state == RSMSI_STATE_MAPPED ||
6532 sharedp->rsmsi_state == RSMSI_STATE_MAP_QUIESCE);
6533
6534 /*
6535 * Unmap pages - previously rsm_memseg_import_unmap was called only if
6536 * the segment cookie list was NULL; but it is always NULL when
6537 * called from rsmmap_unmap and won't be NULL when called for
6538 * a force disconnect - so the check for NULL cookie list was removed
6539 */
6540
6541 ASSERT(sharedp->rsmsi_mapcnt > 0);
6542
6543 sharedp->rsmsi_mapcnt--;
6544
6545 if (sharedp->rsmsi_mapcnt == 0) {
6546 if (sharedp->rsmsi_state == RSMSI_STATE_MAPPED) {
6547 /* unmap the shared RSMPI mapping */
6548 adapter = seg->s_adapter;
6549 if (seg->s_node != my_nodeid) {
6550 ASSERT(sharedp->rsmsi_handle != NULL);
6551 err = adapter->rsmpi_ops->
6552 rsm_unmap(sharedp->rsmsi_handle);
6553 DBG_PRINTF((category, RSM_DEBUG,
6554 "rsm_unmap: rsmpi unmap %d\n", err));
6555 rsm_free_mapinfo(sharedp->rsmsi_mapinfo);
6556 sharedp->rsmsi_mapinfo = NULL;
6557 }
6558 sharedp->rsmsi_state = RSMSI_STATE_CONNECTED;
6559 } else { /* MAP_QUIESCE --munmap()--> CONN_QUIESCE */
6560 sharedp->rsmsi_state = RSMSI_STATE_CONN_QUIESCE;
6561 }
6562 }
6563
6564 rsmsharelock_release(seg);
6565
6566 /*
6567 * The s_cookie field is used to store the cookie returned from the
6568 * ddi_umem_lock when binding the pages for an export segment. This
6569 * is the primary use of the s_cookie field and does not normally
6570 * pertain to any importing segment except in the loopback case.
6571 * For the loopback case, the import segment and export segment are
6572 * on the same node, the s_cookie field of the segment structure for
6573 * the importer is initialized to the s_cookie field in the exported
6574 * segment during the map operation and is used during the call to
6575 * devmap_umem_setup for the import mapping.
6576 * Thus, during unmap, we simply need to set s_cookie to NULL to
6577 * indicate that the mapping no longer exists.
6578 */
6579 seg->s_cookie = NULL;
6580
6581 seg->s_mapinfo = NULL;
6582
6583 if (seg->s_state == RSM_STATE_ACTIVE)
6584 seg->s_state = RSM_STATE_CONNECT;
6585 else
6586 seg->s_state = RSM_STATE_CONN_QUIESCE;
6587
6588 DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_unmap done\n"));
6589
6590 return (RSM_SUCCESS);
6591 }
6592
6593 /*
6594 * cookie returned here if not null indicates that it is
6595 * the last importer and it can be used in the RSMIPC_NOT_IMPORTING
6596 * message.
6597 */
6598 static int
rsm_closeconnection(rsmseg_t * seg,void ** cookie)6599 rsm_closeconnection(rsmseg_t *seg, void **cookie)
6600 {
6601 int e;
6602 adapter_t *adapter;
6603 rsm_import_share_t *sharedp;
6604 DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_IMPORT);
6605
6606 DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
6607 "rsm_closeconnection enter\n"));
6608
6609 *cookie = (void *)NULL;
6610
6611 ASSERT(seg->s_hdr.rsmrc_type == RSM_RESOURCE_IMPORT_SEGMENT);
6612
6613 /* assert seg is locked */
6614 ASSERT(rsmseglock_held(seg));
6615
6616 if (seg->s_state == RSM_STATE_DISCONNECT) {
6617 DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
6618 "rsm_closeconnection done: already disconnected\n"));
6619 return (RSM_SUCCESS);
6620 }
6621
6622 /* wait for all putv/getv ops to get done */
6623 while (seg->s_rdmacnt > 0) {
6624 cv_wait(&seg->s_cv, &seg->s_lock);
6625 }
6626
6627 (void) rsm_unmap(seg);
6628
6629 ASSERT(seg->s_state == RSM_STATE_CONNECT ||
6630 seg->s_state == RSM_STATE_CONN_QUIESCE);
6631
6632 adapter = seg->s_adapter;
6633 sharedp = seg->s_share;
6634
6635 ASSERT(sharedp != NULL);
6636
6637 rsmsharelock_acquire(seg);
6638
6639 /*
6640 * Disconnect on adapter
6641 *
6642 * The current algorithm is stateless, I don't have to contact
6643 * server when I go away. It only gives me permissions. Of course,
6644 * the adapters will talk to terminate the connect.
6645 *
6646 * disconnect is needed only if we are CONNECTED not in CONN_QUIESCE
6647 */
6648 if ((sharedp->rsmsi_state == RSMSI_STATE_CONNECTED) &&
6649 (sharedp->rsmsi_node != my_nodeid)) {
6650
6651 if (sharedp->rsmsi_refcnt == 1) {
6652 /* this is the last importer */
6653 ASSERT(sharedp->rsmsi_mapcnt == 0);
6654
6655 e = adapter->rsmpi_ops->
6656 rsm_disconnect(sharedp->rsmsi_handle);
6657 if (e != RSM_SUCCESS) {
6658 DBG_PRINTF((category, RSM_DEBUG,
6659 "rsm:disconnect failed seg=%x:err=%d\n",
6660 seg->s_key, e));
6661 }
6662 }
6663 }
6664
6665 seg->s_handle.in = NULL;
6666
6667 sharedp->rsmsi_refcnt--;
6668
6669 if (sharedp->rsmsi_refcnt == 0) {
6670 *cookie = (void *)sharedp->rsmsi_cookie;
6671 sharedp->rsmsi_state = RSMSI_STATE_DISCONNECTED;
6672 sharedp->rsmsi_handle = NULL;
6673 rsmsharelock_release(seg);
6674
6675 /* clean up the shared data structure */
6676 mutex_destroy(&sharedp->rsmsi_lock);
6677 cv_destroy(&sharedp->rsmsi_cv);
6678 kmem_free((void *)(sharedp), sizeof (rsm_import_share_t));
6679
6680 } else {
6681 rsmsharelock_release(seg);
6682 }
6683
6684 /* increment generation number on barrier page */
6685 if (bar_va) {
6686 atomic_inc_16(bar_va + seg->s_hdr.rsmrc_num);
6687 }
6688
6689 /*
6690 * The following needs to be done after any
6691 * rsmsharelock calls which use seg->s_share.
6692 */
6693 seg->s_share = NULL;
6694
6695 seg->s_state = RSM_STATE_DISCONNECT;
6696 /* signal anyone waiting in the CONN_QUIESCE state */
6697 cv_broadcast(&seg->s_cv);
6698
6699 DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
6700 "rsm_closeconnection done\n"));
6701
6702 return (RSM_SUCCESS);
6703 }
6704
6705 int
rsm_disconnect(rsmseg_t * seg)6706 rsm_disconnect(rsmseg_t *seg)
6707 {
6708 rsmipc_request_t request;
6709 void *shared_cookie;
6710 DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_IMPORT);
6711
6712 DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_disconnect enter\n"));
6713
6714 ASSERT(seg->s_hdr.rsmrc_type == RSM_RESOURCE_IMPORT_SEGMENT);
6715
6716 /* assert seg isn't locked */
6717 ASSERT(!rsmseglock_held(seg));
6718
6719
6720 /* Remove segment from imported list */
6721 rsmimport_rm(seg);
6722
6723 /* acquire the segment */
6724 rsmseglock_acquire(seg);
6725
6726 /* wait until segment leaves the mapping state */
6727 while (seg->s_state == RSM_STATE_MAPPING)
6728 cv_wait(&seg->s_cv, &seg->s_lock);
6729
6730 if (seg->s_state == RSM_STATE_DISCONNECT) {
6731 seg->s_state = RSM_STATE_NEW;
6732 rsmseglock_release(seg);
6733 DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
6734 "rsm_disconnect done: already disconnected\n"));
6735 return (RSM_SUCCESS);
6736 }
6737
6738 (void) rsm_closeconnection(seg, &shared_cookie);
6739
6740 /* update state */
6741 seg->s_state = RSM_STATE_NEW;
6742
6743 if (shared_cookie != NULL) {
6744 /*
6745 * This is the last importer so inform the exporting node
6746 * so this import can be deleted from the list of importers.
6747 */
6748 request.rsmipc_hdr.rsmipc_type = RSMIPC_MSG_NOTIMPORTING;
6749 request.rsmipc_key = seg->s_segid;
6750 request.rsmipc_segment_cookie = shared_cookie;
6751 rsmseglock_release(seg);
6752 (void) rsmipc_send(seg->s_node, &request, RSM_NO_REPLY);
6753 } else {
6754 rsmseglock_release(seg);
6755 }
6756
6757 DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_disconnect done\n"));
6758
6759 return (DDI_SUCCESS);
6760 }
6761
6762 static int
rsm_chpoll(dev_t dev,short events,int anyyet,short * reventsp,struct pollhead ** phpp)6763 rsm_chpoll(dev_t dev, short events, int anyyet, short *reventsp,
6764 struct pollhead **phpp)
6765 {
6766 minor_t rnum;
6767 rsmresource_t *res;
6768 rsmseg_t *seg;
6769 DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_FUNC_ALL | RSM_DDI);
6770
6771 DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_chpoll enter\n"));
6772
6773 /* find minor, no lock */
6774 rnum = getminor(dev);
6775 res = rsmresource_lookup(rnum, RSM_NOLOCK);
6776
6777 /* poll is supported only for export/import segments */
6778 if ((res == NULL) || (res == RSMRC_RESERVED) ||
6779 (res->rsmrc_type == RSM_RESOURCE_BAR)) {
6780 return (ENXIO);
6781 }
6782
6783 /*
6784 * An exported segment must be in state RSM_STATE_EXPORT; an
6785 * imported segment must be in state RSM_STATE_ACTIVE.
6786 */
6787 seg = (rsmseg_t *)res;
6788
6789 if (seg->s_pollevent) {
6790 *reventsp = POLLRDNORM;
6791 } else {
6792 *reventsp = 0;
6793 }
6794
6795 if ((*reventsp == 0 && !anyyet) || (events & POLLET)) {
6796 /* cannot take segment lock here */
6797 *phpp = &seg->s_poll;
6798 seg->s_pollflag |= RSM_SEGMENT_POLL;
6799 }
6800 DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_chpoll done\n"));
6801 return (0);
6802 }
6803
6804
6805
6806 /* ************************* IOCTL Commands ********************* */
6807
6808 static rsmseg_t *
rsmresource_seg(rsmresource_t * res,minor_t rnum,cred_t * credp,rsm_resource_type_t type)6809 rsmresource_seg(rsmresource_t *res, minor_t rnum, cred_t *credp,
6810 rsm_resource_type_t type)
6811 {
6812 /* get segment from resource handle */
6813 rsmseg_t *seg;
6814 DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_FUNC_ALL | RSM_IOCTL);
6815
6816 DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmresource_seg enter\n"));
6817
6818
6819 if (res != RSMRC_RESERVED) {
6820 seg = (rsmseg_t *)res;
6821 } else {
6822 /* Allocate segment now and bind it */
6823 seg = rsmseg_alloc(rnum, credp);
6824
6825 /*
6826 * if DR pre-processing is going on or DR is in progress
6827 * then the new export segments should be in the NEW_QSCD state
6828 */
6829 if (type == RSM_RESOURCE_EXPORT_SEGMENT) {
6830 mutex_enter(&rsm_drv_data.drv_lock);
6831 if ((rsm_drv_data.drv_state ==
6832 RSM_DRV_PREDEL_STARTED) ||
6833 (rsm_drv_data.drv_state ==
6834 RSM_DRV_PREDEL_COMPLETED) ||
6835 (rsm_drv_data.drv_state ==
6836 RSM_DRV_DR_IN_PROGRESS)) {
6837 seg->s_state = RSM_STATE_NEW_QUIESCED;
6838 }
6839 mutex_exit(&rsm_drv_data.drv_lock);
6840 }
6841
6842 rsmresource_insert(rnum, (rsmresource_t *)seg, type);
6843 }
6844
6845 DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmresource_seg done\n"));
6846
6847 return (seg);
6848 }
6849
6850 static int
rsmexport_ioctl(rsmseg_t * seg,rsm_ioctlmsg_t * msg,int cmd,intptr_t arg,int mode,cred_t * credp)6851 rsmexport_ioctl(rsmseg_t *seg, rsm_ioctlmsg_t *msg, int cmd, intptr_t arg,
6852 int mode, cred_t *credp)
6853 {
6854 int error;
6855 DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_EXPORT | RSM_IOCTL);
6856
6857 DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmexport_ioctl enter\n"));
6858
6859 arg = arg;
6860 credp = credp;
6861
6862 ASSERT(seg != NULL);
6863
6864 switch (cmd) {
6865 case RSM_IOCTL_BIND:
6866 error = rsm_bind(seg, msg, arg, mode);
6867 break;
6868 case RSM_IOCTL_REBIND:
6869 error = rsm_rebind(seg, msg);
6870 break;
6871 case RSM_IOCTL_UNBIND:
6872 error = ENOTSUP;
6873 break;
6874 case RSM_IOCTL_PUBLISH:
6875 error = rsm_publish(seg, msg, arg, mode);
6876 break;
6877 case RSM_IOCTL_REPUBLISH:
6878 error = rsm_republish(seg, msg, mode);
6879 break;
6880 case RSM_IOCTL_UNPUBLISH:
6881 error = rsm_unpublish(seg, 1);
6882 break;
6883 default:
6884 error = EINVAL;
6885 break;
6886 }
6887
6888 DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmexport_ioctl done: %d\n",
6889 error));
6890
6891 return (error);
6892 }
6893 static int
rsmimport_ioctl(rsmseg_t * seg,rsm_ioctlmsg_t * msg,int cmd,intptr_t arg,int mode,cred_t * credp)6894 rsmimport_ioctl(rsmseg_t *seg, rsm_ioctlmsg_t *msg, int cmd, intptr_t arg,
6895 int mode, cred_t *credp)
6896 {
6897 int error;
6898 DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_IMPORT | RSM_IOCTL);
6899
6900 DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmimport_ioctl enter\n"));
6901
6902 ASSERT(seg);
6903
6904 switch (cmd) {
6905 case RSM_IOCTL_CONNECT:
6906 error = rsm_connect(seg, msg, credp, arg, mode);
6907 break;
6908 default:
6909 error = EINVAL;
6910 break;
6911 }
6912
6913 DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmimport_ioctl done: %d\n",
6914 error));
6915 return (error);
6916 }
6917
6918 static int
rsmbar_ioctl(rsmseg_t * seg,rsm_ioctlmsg_t * msg,int cmd,intptr_t arg,int mode)6919 rsmbar_ioctl(rsmseg_t *seg, rsm_ioctlmsg_t *msg, int cmd, intptr_t arg,
6920 int mode)
6921 {
6922 int e;
6923 adapter_t *adapter;
6924 DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_IMPORT | RSM_IOCTL);
6925
6926 DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmbar_ioctl enter\n"));
6927
6928
6929 if ((seg->s_flags & RSM_IMPORT_DUMMY) != 0) {
6930 DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
6931 "rsmbar_ioctl done: RSM_IMPORT_DUMMY\n"));
6932 return (RSMERR_CONN_ABORTED);
6933 } else if (seg->s_node == my_nodeid) {
6934 DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
6935 "rsmbar_ioctl done: loopback\n"));
6936 return (RSM_SUCCESS);
6937 }
6938
6939 adapter = seg->s_adapter;
6940
6941 switch (cmd) {
6942 case RSM_IOCTL_BAR_CHECK:
6943 DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
6944 "rsmbar_ioctl done: RSM_BAR_CHECK %d\n", bar_va));
6945 return (bar_va ? RSM_SUCCESS : EINVAL);
6946 case RSM_IOCTL_BAR_OPEN:
6947 e = adapter->rsmpi_ops->
6948 rsm_open_barrier_ctrl(adapter->rsmpi_handle, &msg->bar);
6949 break;
6950 case RSM_IOCTL_BAR_ORDER:
6951 e = adapter->rsmpi_ops->rsm_order_barrier(&msg->bar);
6952 break;
6953 case RSM_IOCTL_BAR_CLOSE:
6954 e = adapter->rsmpi_ops->rsm_close_barrier(&msg->bar);
6955 break;
6956 default:
6957 e = EINVAL;
6958 break;
6959 }
6960
6961 if (e == RSM_SUCCESS) {
6962 #ifdef _MULTI_DATAMODEL
6963 if ((mode & DATAMODEL_MASK) == DATAMODEL_ILP32) {
6964 rsm_ioctlmsg32_t msg32;
6965 int i;
6966
6967 for (i = 0; i < 4; i++) {
6968 msg32.bar.comp[i].u64 = msg->bar.comp[i].u64;
6969 }
6970
6971 DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
6972 "rsmbar_ioctl done\n"));
6973 if (ddi_copyout((caddr_t)&msg32, (caddr_t)arg,
6974 sizeof (msg32), mode))
6975 return (RSMERR_BAD_ADDR);
6976 else
6977 return (RSM_SUCCESS);
6978 }
6979 #endif
6980 DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
6981 "rsmbar_ioctl done\n"));
6982 if (ddi_copyout((caddr_t)&msg->bar, (caddr_t)arg,
6983 sizeof (*msg), mode))
6984 return (RSMERR_BAD_ADDR);
6985 else
6986 return (RSM_SUCCESS);
6987 }
6988
6989 DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
6990 "rsmbar_ioctl done: error=%d\n", e));
6991
6992 return (e);
6993 }
6994
6995 /*
6996 * Ring the doorbell of the export segment to which this segment is
6997 * connected.
6998 */
6999 static int
exportbell_ioctl(rsmseg_t * seg,int cmd)7000 exportbell_ioctl(rsmseg_t *seg, int cmd /*ARGSUSED*/)
7001 {
7002 int e = 0;
7003 rsmipc_request_t request;
7004
7005 DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_IMPORT | RSM_IOCTL);
7006
7007 DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "exportbell_ioctl enter\n"));
7008
7009 request.rsmipc_key = seg->s_segid;
7010 request.rsmipc_hdr.rsmipc_type = RSMIPC_MSG_BELL;
7011 request.rsmipc_segment_cookie = NULL;
7012 e = rsmipc_send(seg->s_node, &request, RSM_NO_REPLY);
7013
7014 DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
7015 "exportbell_ioctl done: %d\n", e));
7016
7017 return (e);
7018 }
7019
7020 /*
7021 * Ring the doorbells of all segments importing this segment
7022 */
7023 static int
importbell_ioctl(rsmseg_t * seg,int cmd)7024 importbell_ioctl(rsmseg_t *seg, int cmd /*ARGSUSED*/)
7025 {
7026 importing_token_t *token = NULL;
7027 rsmipc_request_t request;
7028 int index;
7029
7030 DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_EXPORT | RSM_IOCTL);
7031
7032 DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "importbell_ioctl enter\n"));
7033
7034 ASSERT(seg->s_state != RSM_STATE_NEW &&
7035 seg->s_state != RSM_STATE_NEW_QUIESCED);
7036
7037 request.rsmipc_key = seg->s_segid;
7038 request.rsmipc_hdr.rsmipc_type = RSMIPC_MSG_BELL;
7039
7040 index = rsmhash(seg->s_segid);
7041
7042 token = importer_list.bucket[index];
7043
7044 while (token != NULL) {
7045 if (seg->s_key == token->key) {
7046 request.rsmipc_segment_cookie =
7047 token->import_segment_cookie;
7048 (void) rsmipc_send(token->importing_node,
7049 &request, RSM_NO_REPLY);
7050 }
7051 token = token->next;
7052 }
7053
7054 DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
7055 "importbell_ioctl done\n"));
7056 return (RSM_SUCCESS);
7057 }
7058
7059 static int
rsm_consumeevent_copyin(caddr_t arg,rsm_consume_event_msg_t * msgp,rsm_poll_event_t ** eventspp,int mode)7060 rsm_consumeevent_copyin(caddr_t arg, rsm_consume_event_msg_t *msgp,
7061 rsm_poll_event_t **eventspp, int mode)
7062 {
7063 rsm_poll_event_t *evlist = NULL;
7064 size_t evlistsz;
7065 DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_IOCTL);
7066
7067 #ifdef _MULTI_DATAMODEL
7068 if ((mode & DATAMODEL_MASK) == DATAMODEL_ILP32) {
7069 int i;
7070 rsm_consume_event_msg32_t cemsg32 = {0};
7071 rsm_poll_event32_t event32[RSM_MAX_POLLFDS];
7072 rsm_poll_event32_t *evlist32;
7073 size_t evlistsz32;
7074
7075 /* copyin the ioctl message */
7076 if (ddi_copyin(arg, (caddr_t)&cemsg32,
7077 sizeof (rsm_consume_event_msg32_t), mode)) {
7078 DBG_PRINTF((category, RSM_ERR,
7079 "consumeevent_copyin msgp: RSMERR_BAD_ADDR\n"));
7080 return (RSMERR_BAD_ADDR);
7081 }
7082 msgp->seglist = (caddr_t)(uintptr_t)cemsg32.seglist;
7083 msgp->numents = (int)cemsg32.numents;
7084
7085 evlistsz32 = sizeof (rsm_poll_event32_t) * msgp->numents;
7086 /*
7087 * If numents is large alloc events list on heap otherwise
7088 * use the address of array that was passed in.
7089 */
7090 if (msgp->numents > RSM_MAX_POLLFDS) {
7091 if (msgp->numents > max_segs) { /* validate numents */
7092 DBG_PRINTF((category, RSM_ERR,
7093 "consumeevent_copyin: "
7094 "RSMERR_BAD_ARGS_ERRORS\n"));
7095 return (RSMERR_BAD_ARGS_ERRORS);
7096 }
7097 evlist32 = kmem_zalloc(evlistsz32, KM_SLEEP);
7098 } else {
7099 evlist32 = event32;
7100 }
7101
7102 /* copyin the seglist into the rsm_poll_event32_t array */
7103 if (ddi_copyin((caddr_t)msgp->seglist, (caddr_t)evlist32,
7104 evlistsz32, mode)) {
7105 if ((msgp->numents > RSM_MAX_POLLFDS) && evlist32) {
7106 kmem_free(evlist32, evlistsz32);
7107 }
7108 DBG_PRINTF((category, RSM_ERR,
7109 "consumeevent_copyin evlist: RSMERR_BAD_ADDR\n"));
7110 return (RSMERR_BAD_ADDR);
7111 }
7112
7113 /* evlist and evlistsz are based on rsm_poll_event_t type */
7114 evlistsz = sizeof (rsm_poll_event_t)* msgp->numents;
7115
7116 if (msgp->numents > RSM_MAX_POLLFDS) {
7117 evlist = kmem_zalloc(evlistsz, KM_SLEEP);
7118 *eventspp = evlist;
7119 } else {
7120 evlist = *eventspp;
7121 }
7122 /*
7123 * copy the rsm_poll_event32_t array to the rsm_poll_event_t
7124 * array
7125 */
7126 for (i = 0; i < msgp->numents; i++) {
7127 evlist[i].rnum = evlist32[i].rnum;
7128 evlist[i].fdsidx = evlist32[i].fdsidx;
7129 evlist[i].revent = evlist32[i].revent;
7130 }
7131 /* free the temp 32-bit event list */
7132 if ((msgp->numents > RSM_MAX_POLLFDS) && evlist32) {
7133 kmem_free(evlist32, evlistsz32);
7134 }
7135
7136 return (RSM_SUCCESS);
7137 }
7138 #endif
7139 /* copyin the ioctl message */
7140 if (ddi_copyin(arg, (caddr_t)msgp, sizeof (rsm_consume_event_msg_t),
7141 mode)) {
7142 DBG_PRINTF((category, RSM_ERR,
7143 "consumeevent_copyin msgp: RSMERR_BAD_ADDR\n"));
7144 return (RSMERR_BAD_ADDR);
7145 }
7146 /*
7147 * If numents is large alloc events list on heap otherwise
7148 * use the address of array that was passed in.
7149 */
7150 if (msgp->numents > RSM_MAX_POLLFDS) {
7151 if (msgp->numents > max_segs) { /* validate numents */
7152 DBG_PRINTF((category, RSM_ERR,
7153 "consumeevent_copyin: RSMERR_BAD_ARGS_ERRORS\n"));
7154 return (RSMERR_BAD_ARGS_ERRORS);
7155 }
7156 evlistsz = sizeof (rsm_poll_event_t)*msgp->numents;
7157 evlist = kmem_zalloc(evlistsz, KM_SLEEP);
7158 *eventspp = evlist;
7159 }
7160
7161 /* copyin the seglist */
7162 if (ddi_copyin((caddr_t)msgp->seglist, (caddr_t)(*eventspp),
7163 sizeof (rsm_poll_event_t)*msgp->numents, mode)) {
7164 if (evlist) {
7165 kmem_free(evlist, evlistsz);
7166 *eventspp = NULL;
7167 }
7168 DBG_PRINTF((category, RSM_ERR,
7169 "consumeevent_copyin evlist: RSMERR_BAD_ADDR\n"));
7170 return (RSMERR_BAD_ADDR);
7171 }
7172
7173 DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
7174 "consumeevent_copyin done\n"));
7175 return (RSM_SUCCESS);
7176 }
7177
7178 static int
rsm_consumeevent_copyout(rsm_consume_event_msg_t * msgp,rsm_poll_event_t * eventsp,int mode)7179 rsm_consumeevent_copyout(rsm_consume_event_msg_t *msgp,
7180 rsm_poll_event_t *eventsp, int mode)
7181 {
7182 size_t evlistsz;
7183 int err = RSM_SUCCESS;
7184 DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_IOCTL);
7185
7186 DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
7187 "consumeevent_copyout enter: numents(%d) eventsp(%p)\n",
7188 msgp->numents, eventsp));
7189
7190 #ifdef _MULTI_DATAMODEL
7191 if ((mode & DATAMODEL_MASK) == DATAMODEL_ILP32) {
7192 int i;
7193 rsm_poll_event32_t event32[RSM_MAX_POLLFDS];
7194 rsm_poll_event32_t *evlist32;
7195 size_t evlistsz32;
7196
7197 evlistsz32 = sizeof (rsm_poll_event32_t)*msgp->numents;
7198 if (msgp->numents > RSM_MAX_POLLFDS) {
7199 evlist32 = kmem_zalloc(evlistsz32, KM_SLEEP);
7200 } else {
7201 evlist32 = event32;
7202 }
7203
7204 /*
7205 * copy the rsm_poll_event_t array to the rsm_poll_event32_t
7206 * array
7207 */
7208 for (i = 0; i < msgp->numents; i++) {
7209 evlist32[i].rnum = eventsp[i].rnum;
7210 evlist32[i].fdsidx = eventsp[i].fdsidx;
7211 evlist32[i].revent = eventsp[i].revent;
7212 }
7213
7214 if (ddi_copyout((caddr_t)evlist32, (caddr_t)msgp->seglist,
7215 evlistsz32, mode)) {
7216 err = RSMERR_BAD_ADDR;
7217 }
7218
7219 if (msgp->numents > RSM_MAX_POLLFDS) {
7220 if (evlist32) { /* free the temp 32-bit event list */
7221 kmem_free(evlist32, evlistsz32);
7222 }
7223 /*
7224 * eventsp and evlistsz are based on rsm_poll_event_t
7225 * type
7226 */
7227 evlistsz = sizeof (rsm_poll_event_t)*msgp->numents;
7228 /* event list on the heap and needs to be freed here */
7229 if (eventsp) {
7230 kmem_free(eventsp, evlistsz);
7231 }
7232 }
7233
7234 DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
7235 "consumeevent_copyout done: err=%d\n", err));
7236 return (err);
7237 }
7238 #endif
7239 evlistsz = sizeof (rsm_poll_event_t)*msgp->numents;
7240
7241 if (ddi_copyout((caddr_t)eventsp, (caddr_t)msgp->seglist, evlistsz,
7242 mode)) {
7243 err = RSMERR_BAD_ADDR;
7244 }
7245
7246 if ((msgp->numents > RSM_MAX_POLLFDS) && eventsp) {
7247 /* event list on the heap and needs to be freed here */
7248 kmem_free(eventsp, evlistsz);
7249 }
7250
7251 DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
7252 "consumeevent_copyout done: err=%d\n", err));
7253 return (err);
7254 }
7255
7256 static int
rsm_consumeevent_ioctl(caddr_t arg,int mode)7257 rsm_consumeevent_ioctl(caddr_t arg, int mode)
7258 {
7259 int rc;
7260 int i;
7261 minor_t rnum;
7262 rsm_consume_event_msg_t msg = {0};
7263 rsmseg_t *seg;
7264 rsm_poll_event_t *event_list;
7265 rsm_poll_event_t events[RSM_MAX_POLLFDS];
7266 DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_IOCTL);
7267
7268 event_list = events;
7269
7270 if ((rc = rsm_consumeevent_copyin(arg, &msg, &event_list, mode)) !=
7271 RSM_SUCCESS) {
7272 return (rc);
7273 }
7274
7275 for (i = 0; i < msg.numents; i++) {
7276 rnum = event_list[i].rnum;
7277 event_list[i].revent = 0;
7278 /* get the segment structure */
7279 seg = (rsmseg_t *)rsmresource_lookup(rnum, RSM_LOCK);
7280 if (seg) {
7281 DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
7282 "consumeevent_ioctl: rnum(%d) seg(%p)\n", rnum,
7283 seg));
7284 if (seg->s_pollevent) {
7285 /* consume the event */
7286 atomic_dec_32(&seg->s_pollevent);
7287 event_list[i].revent = POLLRDNORM;
7288 }
7289 rsmseglock_release(seg);
7290 }
7291 }
7292
7293 if ((rc = rsm_consumeevent_copyout(&msg, event_list, mode)) !=
7294 RSM_SUCCESS) {
7295 return (rc);
7296 }
7297
7298 return (RSM_SUCCESS);
7299 }
7300
7301 static int
iovec_copyin(caddr_t user_vec,rsmka_iovec_t * iovec,int count,int mode)7302 iovec_copyin(caddr_t user_vec, rsmka_iovec_t *iovec, int count, int mode)
7303 {
7304 int size;
7305 DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_IMPORT | RSM_IOCTL);
7306
7307 DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "iovec_copyin enter\n"));
7308
7309 #ifdef _MULTI_DATAMODEL
7310 if ((mode & DATAMODEL_MASK) == DATAMODEL_ILP32) {
7311 rsmka_iovec32_t *iovec32, *iovec32_base;
7312 int i;
7313
7314 size = count * sizeof (rsmka_iovec32_t);
7315 iovec32_base = iovec32 = kmem_zalloc(size, KM_SLEEP);
7316 if (ddi_copyin((caddr_t)user_vec,
7317 (caddr_t)iovec32, size, mode)) {
7318 kmem_free(iovec32, size);
7319 DBG_PRINTF((category, RSM_DEBUG,
7320 "iovec_copyin: returning RSMERR_BAD_ADDR\n"));
7321 return (RSMERR_BAD_ADDR);
7322 }
7323
7324 for (i = 0; i < count; i++, iovec++, iovec32++) {
7325 iovec->io_type = (int)iovec32->io_type;
7326 if (iovec->io_type == RSM_HANDLE_TYPE)
7327 iovec->local.segid = (rsm_memseg_id_t)
7328 iovec32->local;
7329 else
7330 iovec->local.vaddr =
7331 (caddr_t)(uintptr_t)iovec32->local;
7332 iovec->local_offset = (size_t)iovec32->local_offset;
7333 iovec->remote_offset = (size_t)iovec32->remote_offset;
7334 iovec->transfer_len = (size_t)iovec32->transfer_len;
7335
7336 }
7337 kmem_free(iovec32_base, size);
7338 DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
7339 "iovec_copyin done\n"));
7340 return (DDI_SUCCESS);
7341 }
7342 #endif
7343
7344 size = count * sizeof (rsmka_iovec_t);
7345 if (ddi_copyin((caddr_t)user_vec, (caddr_t)iovec, size, mode)) {
7346 DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
7347 "iovec_copyin done: RSMERR_BAD_ADDR\n"));
7348 return (RSMERR_BAD_ADDR);
7349 }
7350
7351 DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "iovec_copyin done\n"));
7352
7353 return (DDI_SUCCESS);
7354 }
7355
7356
7357 static int
sgio_copyin(caddr_t arg,rsmka_scat_gath_t * sg_io,int mode)7358 sgio_copyin(caddr_t arg, rsmka_scat_gath_t *sg_io, int mode)
7359 {
7360 DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_IMPORT | RSM_IOCTL);
7361
7362 DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "sgio_copyin enter\n"));
7363
7364 #ifdef _MULTI_DATAMODEL
7365 if ((mode & DATAMODEL_MASK) == DATAMODEL_ILP32) {
7366 rsmka_scat_gath32_t sg_io32;
7367
7368 if (ddi_copyin(arg, (caddr_t)&sg_io32, sizeof (sg_io32),
7369 mode)) {
7370 DBG_PRINTF((category, RSM_DEBUG,
7371 "sgio_copyin done: returning EFAULT\n"));
7372 return (RSMERR_BAD_ADDR);
7373 }
7374 sg_io->local_nodeid = (rsm_node_id_t)sg_io32.local_nodeid;
7375 sg_io->io_request_count = (size_t)sg_io32.io_request_count;
7376 sg_io->io_residual_count = (size_t)sg_io32.io_residual_count;
7377 sg_io->flags = (size_t)sg_io32.flags;
7378 sg_io->remote_handle = (rsm_memseg_import_handle_t)
7379 (uintptr_t)sg_io32.remote_handle;
7380 sg_io->iovec = (rsmka_iovec_t *)(uintptr_t)sg_io32.iovec;
7381 DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
7382 "sgio_copyin done\n"));
7383 return (DDI_SUCCESS);
7384 }
7385 #endif
7386 if (ddi_copyin(arg, (caddr_t)sg_io, sizeof (rsmka_scat_gath_t),
7387 mode)) {
7388 DBG_PRINTF((category, RSM_DEBUG,
7389 "sgio_copyin done: returning EFAULT\n"));
7390 return (RSMERR_BAD_ADDR);
7391 }
7392 DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "sgio_copyin done\n"));
7393 return (DDI_SUCCESS);
7394 }
7395
7396 static int
sgio_resid_copyout(caddr_t arg,rsmka_scat_gath_t * sg_io,int mode)7397 sgio_resid_copyout(caddr_t arg, rsmka_scat_gath_t *sg_io, int mode)
7398 {
7399 DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_IMPORT | RSM_IOCTL);
7400
7401 DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
7402 "sgio_resid_copyout enter\n"));
7403
7404 #ifdef _MULTI_DATAMODEL
7405 if ((mode & DATAMODEL_MASK) == DATAMODEL_ILP32) {
7406 rsmka_scat_gath32_t sg_io32;
7407
7408 sg_io32.io_residual_count = sg_io->io_residual_count;
7409 sg_io32.flags = sg_io->flags;
7410
7411 if (ddi_copyout((caddr_t)&sg_io32.io_residual_count,
7412 (caddr_t)&((rsmka_scat_gath32_t *)arg)->io_residual_count,
7413 sizeof (uint32_t), mode)) {
7414
7415 DBG_PRINTF((category, RSM_ERR,
7416 "sgio_resid_copyout error: rescnt\n"));
7417 return (RSMERR_BAD_ADDR);
7418 }
7419
7420 if (ddi_copyout((caddr_t)&sg_io32.flags,
7421 (caddr_t)&((rsmka_scat_gath32_t *)arg)->flags,
7422 sizeof (uint32_t), mode)) {
7423
7424 DBG_PRINTF((category, RSM_ERR,
7425 "sgio_resid_copyout error: flags\n"));
7426 return (RSMERR_BAD_ADDR);
7427 }
7428 DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
7429 "sgio_resid_copyout done\n"));
7430 return (DDI_SUCCESS);
7431 }
7432 #endif
7433 if (ddi_copyout((caddr_t)&sg_io->io_residual_count,
7434 (caddr_t)&((rsmka_scat_gath_t *)arg)->io_residual_count,
7435 sizeof (ulong_t), mode)) {
7436
7437 DBG_PRINTF((category, RSM_ERR,
7438 "sgio_resid_copyout error:rescnt\n"));
7439 return (RSMERR_BAD_ADDR);
7440 }
7441
7442 if (ddi_copyout((caddr_t)&sg_io->flags,
7443 (caddr_t)&((rsmka_scat_gath_t *)arg)->flags,
7444 sizeof (uint_t), mode)) {
7445
7446 DBG_PRINTF((category, RSM_ERR,
7447 "sgio_resid_copyout error:flags\n"));
7448 return (RSMERR_BAD_ADDR);
7449 }
7450
7451 DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "sgio_resid_copyout done\n"));
7452 return (DDI_SUCCESS);
7453 }
7454
7455
7456 static int
rsm_iovec_ioctl(dev_t dev,caddr_t arg,int cmd,int mode,cred_t * credp)7457 rsm_iovec_ioctl(dev_t dev, caddr_t arg, int cmd, int mode, cred_t *credp)
7458 {
7459 rsmka_scat_gath_t sg_io;
7460 rsmka_iovec_t ka_iovec_arr[RSM_MAX_IOVLEN];
7461 rsmka_iovec_t *ka_iovec;
7462 rsmka_iovec_t *ka_iovec_start;
7463 rsmpi_scat_gath_t rsmpi_sg_io;
7464 rsmpi_iovec_t iovec_arr[RSM_MAX_IOVLEN];
7465 rsmpi_iovec_t *iovec;
7466 rsmpi_iovec_t *iovec_start = NULL;
7467 rsmapi_access_entry_t *acl;
7468 rsmresource_t *res;
7469 minor_t rnum;
7470 rsmseg_t *im_seg, *ex_seg;
7471 int e;
7472 int error = 0;
7473 uint_t i;
7474 uint_t iov_proc = 0; /* num of iovecs processed */
7475 size_t size = 0;
7476 size_t ka_size;
7477
7478 DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_IMPORT | RSM_IOCTL);
7479
7480 DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_iovec_ioctl enter\n"));
7481
7482 credp = credp;
7483
7484 /*
7485 * Copyin the scatter/gather structure and build new structure
7486 * for rsmpi.
7487 */
7488 e = sgio_copyin(arg, &sg_io, mode);
7489 if (e != DDI_SUCCESS) {
7490 DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
7491 "rsm_iovec_ioctl done: sgio_copyin %d\n", e));
7492 return (e);
7493 }
7494
7495 if (sg_io.io_request_count > RSM_MAX_SGIOREQS) {
7496 DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
7497 "rsm_iovec_ioctl done: request_count(%d) too large\n",
7498 sg_io.io_request_count));
7499 return (RSMERR_BAD_SGIO);
7500 }
7501
7502 rsmpi_sg_io.io_request_count = sg_io.io_request_count;
7503 rsmpi_sg_io.io_residual_count = sg_io.io_request_count;
7504 rsmpi_sg_io.io_segflg = 0;
7505
7506 /* Allocate memory and copyin io vector array */
7507 if (sg_io.io_request_count > RSM_MAX_IOVLEN) {
7508 ka_size = sg_io.io_request_count * sizeof (rsmka_iovec_t);
7509 ka_iovec_start = ka_iovec = kmem_zalloc(ka_size, KM_SLEEP);
7510 } else {
7511 ka_iovec_start = ka_iovec = ka_iovec_arr;
7512 }
7513 e = iovec_copyin((caddr_t)sg_io.iovec, ka_iovec,
7514 sg_io.io_request_count, mode);
7515 if (e != DDI_SUCCESS) {
7516 if (sg_io.io_request_count > RSM_MAX_IOVLEN)
7517 kmem_free(ka_iovec, ka_size);
7518 DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
7519 "rsm_iovec_ioctl done: iovec_copyin %d\n", e));
7520 return (e);
7521 }
7522
7523 /* get the import segment descriptor */
7524 rnum = getminor(dev);
7525 res = rsmresource_lookup(rnum, RSM_LOCK);
7526
7527 /*
7528 * The following sequence of locking may (or MAY NOT) cause a
7529 * deadlock but this is currently not addressed here since the
7530 * implementation will be changed to incorporate the use of
7531 * reference counting for both the import and the export segments.
7532 */
7533
7534 /* rsmseglock_acquire(im_seg) done in rsmresource_lookup */
7535
7536 im_seg = (rsmseg_t *)res;
7537
7538 if (im_seg == NULL) {
7539 if (sg_io.io_request_count > RSM_MAX_IOVLEN)
7540 kmem_free(ka_iovec, ka_size);
7541 DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
7542 "rsm_iovec_ioctl done: rsmresource_lookup failed\n"));
7543 return (EINVAL);
7544 }
7545 /* putv/getv supported is supported only on import segments */
7546 if (im_seg->s_type != RSM_RESOURCE_IMPORT_SEGMENT) {
7547 rsmseglock_release(im_seg);
7548 if (sg_io.io_request_count > RSM_MAX_IOVLEN)
7549 kmem_free(ka_iovec, ka_size);
7550 DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
7551 "rsm_iovec_ioctl done: not an import segment\n"));
7552 return (EINVAL);
7553 }
7554
7555 /*
7556 * wait for a remote DR to complete ie. for segments to get UNQUIESCED
7557 * as well as wait for a local DR to complete.
7558 */
7559 while ((im_seg->s_state == RSM_STATE_CONN_QUIESCE) ||
7560 (im_seg->s_state == RSM_STATE_MAP_QUIESCE) ||
7561 (im_seg->s_flags & RSM_DR_INPROGRESS)) {
7562 if (cv_wait_sig(&im_seg->s_cv, &im_seg->s_lock) == 0) {
7563 DBG_PRINTF((category, RSM_DEBUG,
7564 "rsm_iovec_ioctl done: cv_wait INTR"));
7565 rsmseglock_release(im_seg);
7566 return (RSMERR_INTERRUPTED);
7567 }
7568 }
7569
7570 if ((im_seg->s_state != RSM_STATE_CONNECT) &&
7571 (im_seg->s_state != RSM_STATE_ACTIVE)) {
7572
7573 ASSERT(im_seg->s_state == RSM_STATE_DISCONNECT ||
7574 im_seg->s_state == RSM_STATE_NEW);
7575
7576 DBG_PRINTF((category, RSM_DEBUG,
7577 "rsm_iovec_ioctl done: im_seg not conn/map"));
7578 rsmseglock_release(im_seg);
7579 e = RSMERR_BAD_SGIO;
7580 goto out;
7581 }
7582
7583 im_seg->s_rdmacnt++;
7584 rsmseglock_release(im_seg);
7585
7586 /*
7587 * Allocate and set up the io vector for rsmpi
7588 */
7589 if (sg_io.io_request_count > RSM_MAX_IOVLEN) {
7590 size = sg_io.io_request_count * sizeof (rsmpi_iovec_t);
7591 iovec_start = iovec = kmem_zalloc(size, KM_SLEEP);
7592 } else {
7593 iovec_start = iovec = iovec_arr;
7594 }
7595
7596 rsmpi_sg_io.iovec = iovec;
7597 for (iov_proc = 0; iov_proc < sg_io.io_request_count; iov_proc++) {
7598 if (ka_iovec->io_type == RSM_HANDLE_TYPE) {
7599 ex_seg = rsmexport_lookup(ka_iovec->local.segid);
7600
7601 if (ex_seg == NULL) {
7602 e = RSMERR_BAD_SGIO;
7603 break;
7604 }
7605 ASSERT(ex_seg->s_state == RSM_STATE_EXPORT);
7606
7607 acl = ex_seg->s_acl;
7608 if (acl[0].ae_permission == 0) {
7609 struct buf *xbuf;
7610 dev_t sdev = 0;
7611
7612 xbuf = ddi_umem_iosetup(ex_seg->s_cookie,
7613 0, ex_seg->s_len, B_WRITE,
7614 sdev, 0, NULL, DDI_UMEM_SLEEP);
7615
7616 ASSERT(xbuf != NULL);
7617
7618 iovec->local_mem.ms_type = RSM_MEM_BUF;
7619 iovec->local_mem.ms_memory.bp = xbuf;
7620 } else {
7621 iovec->local_mem.ms_type = RSM_MEM_HANDLE;
7622 iovec->local_mem.ms_memory.handle =
7623 ex_seg->s_handle.out;
7624 }
7625 ex_seg->s_rdmacnt++; /* refcnt the handle */
7626 rsmseglock_release(ex_seg);
7627 } else {
7628 iovec->local_mem.ms_type = RSM_MEM_VADDR;
7629 iovec->local_mem.ms_memory.vr.vaddr =
7630 ka_iovec->local.vaddr;
7631 }
7632
7633 iovec->local_offset = ka_iovec->local_offset;
7634 iovec->remote_handle = im_seg->s_handle.in;
7635 iovec->remote_offset = ka_iovec->remote_offset;
7636 iovec->transfer_length = ka_iovec->transfer_len;
7637 iovec++;
7638 ka_iovec++;
7639 }
7640
7641 if (iov_proc < sg_io.io_request_count) {
7642 /* error while processing handle */
7643 rsmseglock_acquire(im_seg);
7644 im_seg->s_rdmacnt--; /* decrement the refcnt for importseg */
7645 if (im_seg->s_rdmacnt == 0) {
7646 cv_broadcast(&im_seg->s_cv);
7647 }
7648 rsmseglock_release(im_seg);
7649 goto out;
7650 }
7651
7652 /* call rsmpi */
7653 if (cmd == RSM_IOCTL_PUTV)
7654 e = im_seg->s_adapter->rsmpi_ops->rsm_memseg_import_putv(
7655 im_seg->s_adapter->rsmpi_handle,
7656 &rsmpi_sg_io);
7657 else if (cmd == RSM_IOCTL_GETV)
7658 e = im_seg->s_adapter->rsmpi_ops->rsm_memseg_import_getv(
7659 im_seg->s_adapter->rsmpi_handle,
7660 &rsmpi_sg_io);
7661 else {
7662 e = EINVAL;
7663 DBG_PRINTF((category, RSM_DEBUG,
7664 "iovec_ioctl: bad command = %x\n", cmd));
7665 }
7666
7667
7668 DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
7669 "rsm_iovec_ioctl RSMPI oper done %d\n", e));
7670
7671 sg_io.io_residual_count = rsmpi_sg_io.io_residual_count;
7672
7673 /*
7674 * Check for implicit signal post flag and do the signal
7675 * post if needed
7676 */
7677 if (sg_io.flags & RSM_IMPLICIT_SIGPOST &&
7678 e == RSM_SUCCESS) {
7679 rsmipc_request_t request;
7680
7681 request.rsmipc_key = im_seg->s_segid;
7682 request.rsmipc_hdr.rsmipc_type = RSMIPC_MSG_BELL;
7683 request.rsmipc_segment_cookie = NULL;
7684 e = rsmipc_send(im_seg->s_node, &request, RSM_NO_REPLY);
7685 /*
7686 * Reset the implicit signal post flag to 0 to indicate
7687 * that the signal post has been done and need not be
7688 * done in the RSMAPI library
7689 */
7690 sg_io.flags &= ~RSM_IMPLICIT_SIGPOST;
7691 }
7692
7693 rsmseglock_acquire(im_seg);
7694 im_seg->s_rdmacnt--;
7695 if (im_seg->s_rdmacnt == 0) {
7696 cv_broadcast(&im_seg->s_cv);
7697 }
7698 rsmseglock_release(im_seg);
7699 error = sgio_resid_copyout(arg, &sg_io, mode);
7700 out:
7701 iovec = iovec_start;
7702 ka_iovec = ka_iovec_start;
7703 for (i = 0; i < iov_proc; i++) {
7704 if (ka_iovec->io_type == RSM_HANDLE_TYPE) {
7705 ex_seg = rsmexport_lookup(ka_iovec->local.segid);
7706
7707 ASSERT(ex_seg != NULL);
7708 ASSERT(ex_seg->s_state == RSM_STATE_EXPORT);
7709
7710 ex_seg->s_rdmacnt--; /* unrefcnt the handle */
7711 if (ex_seg->s_rdmacnt == 0) {
7712 cv_broadcast(&ex_seg->s_cv);
7713 }
7714 rsmseglock_release(ex_seg);
7715 }
7716
7717 ASSERT(iovec != NULL); /* true if iov_proc > 0 */
7718
7719 /*
7720 * At present there is no dependency on the existence of xbufs
7721 * created by ddi_umem_iosetup for each of the iovecs. So we
7722 * can these xbufs here.
7723 */
7724 if (iovec->local_mem.ms_type == RSM_MEM_BUF) {
7725 freerbuf(iovec->local_mem.ms_memory.bp);
7726 }
7727
7728 iovec++;
7729 ka_iovec++;
7730 }
7731
7732 if (sg_io.io_request_count > RSM_MAX_IOVLEN) {
7733 if (iovec_start)
7734 kmem_free(iovec_start, size);
7735 kmem_free(ka_iovec_start, ka_size);
7736 }
7737
7738 DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
7739 "rsm_iovec_ioctl done %d\n", e));
7740 /* if RSMPI call fails return that else return copyout's retval */
7741 return ((e != RSM_SUCCESS) ? e : error);
7742
7743 }
7744
7745
7746 static int
rsmaddr_ioctl(int cmd,rsm_ioctlmsg_t * msg,int mode)7747 rsmaddr_ioctl(int cmd, rsm_ioctlmsg_t *msg, int mode)
7748 {
7749 adapter_t *adapter;
7750 rsm_addr_t addr;
7751 rsm_node_id_t node;
7752 int rval = DDI_SUCCESS;
7753 DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_FUNC_ALL | RSM_IOCTL);
7754
7755 DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmaddr_ioctl enter\n"));
7756
7757 adapter = rsm_getadapter(msg, mode);
7758 if (adapter == NULL) {
7759 DBG_PRINTF((category, RSM_DEBUG,
7760 "rsmaddr_ioctl done: adapter not found\n"));
7761 return (RSMERR_CTLR_NOT_PRESENT);
7762 }
7763
7764 switch (cmd) {
7765 case RSM_IOCTL_MAP_TO_ADDR: /* nodeid to hwaddr mapping */
7766 /* returns the hwaddr in msg->hwaddr */
7767 if (msg->nodeid == my_nodeid) {
7768 msg->hwaddr = adapter->hwaddr;
7769 } else {
7770 addr = get_remote_hwaddr(adapter, msg->nodeid);
7771 if ((int64_t)addr < 0) {
7772 rval = RSMERR_INTERNAL_ERROR;
7773 } else {
7774 msg->hwaddr = addr;
7775 }
7776 }
7777 break;
7778 case RSM_IOCTL_MAP_TO_NODEID: /* hwaddr to nodeid mapping */
7779 /* returns the nodeid in msg->nodeid */
7780 if (msg->hwaddr == adapter->hwaddr) {
7781 msg->nodeid = my_nodeid;
7782 } else {
7783 node = get_remote_nodeid(adapter, msg->hwaddr);
7784 if ((int)node < 0) {
7785 rval = RSMERR_INTERNAL_ERROR;
7786 } else {
7787 msg->nodeid = (rsm_node_id_t)node;
7788 }
7789 }
7790 break;
7791 default:
7792 rval = EINVAL;
7793 break;
7794 }
7795
7796 rsmka_release_adapter(adapter);
7797 DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
7798 "rsmaddr_ioctl done: %d\n", rval));
7799 return (rval);
7800 }
7801
7802 static int
rsm_ddi_copyin(caddr_t arg,rsm_ioctlmsg_t * msg,int mode)7803 rsm_ddi_copyin(caddr_t arg, rsm_ioctlmsg_t *msg, int mode)
7804 {
7805 DBG_DEFINE(category,
7806 RSM_KERNEL_AGENT | RSM_FUNC_ALL | RSM_IOCTL | RSM_DDI);
7807
7808 DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_ddi_copyin enter\n"));
7809
7810 #ifdef _MULTI_DATAMODEL
7811
7812 if ((mode & DATAMODEL_MASK) == DATAMODEL_ILP32) {
7813 rsm_ioctlmsg32_t msg32;
7814 int i;
7815
7816 if (ddi_copyin(arg, (caddr_t)&msg32, sizeof (msg32), mode)) {
7817 DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
7818 "rsm_ddi_copyin done: EFAULT\n"));
7819 return (RSMERR_BAD_ADDR);
7820 }
7821 msg->len = msg32.len;
7822 msg->vaddr = (caddr_t)(uintptr_t)msg32.vaddr;
7823 msg->arg = (caddr_t)(uintptr_t)msg32.arg;
7824 msg->key = msg32.key;
7825 msg->acl_len = msg32.acl_len;
7826 msg->acl = (rsmapi_access_entry_t *)(uintptr_t)msg32.acl;
7827 msg->cnum = msg32.cnum;
7828 msg->cname = (caddr_t)(uintptr_t)msg32.cname;
7829 msg->cname_len = msg32.cname_len;
7830 msg->nodeid = msg32.nodeid;
7831 msg->hwaddr = msg32.hwaddr;
7832 msg->perm = msg32.perm;
7833 for (i = 0; i < 4; i++) {
7834 msg->bar.comp[i].u64 = msg32.bar.comp[i].u64;
7835 }
7836 DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
7837 "rsm_ddi_copyin done\n"));
7838 return (RSM_SUCCESS);
7839 }
7840 #endif
7841 DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_ddi_copyin done\n"));
7842 if (ddi_copyin(arg, (caddr_t)msg, sizeof (*msg), mode))
7843 return (RSMERR_BAD_ADDR);
7844 else
7845 return (RSM_SUCCESS);
7846 }
7847
7848 static int
rsmattr_ddi_copyout(adapter_t * adapter,caddr_t arg,int mode)7849 rsmattr_ddi_copyout(adapter_t *adapter, caddr_t arg, int mode)
7850 {
7851 rsmka_int_controller_attr_t rsm_cattr;
7852 DBG_DEFINE(category,
7853 RSM_KERNEL_AGENT | RSM_FUNC_ALL | RSM_IOCTL | RSM_DDI);
7854
7855 DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
7856 "rsmattr_ddi_copyout enter\n"));
7857 /*
7858 * need to copy appropriate data from rsm_controller_attr_t
7859 * to rsmka_int_controller_attr_t
7860 */
7861 #ifdef _MULTI_DATAMODEL
7862 if ((mode & DATAMODEL_MASK) == DATAMODEL_ILP32) {
7863 rsmka_int_controller_attr32_t rsm_cattr32;
7864
7865 rsm_cattr32.attr_direct_access_sizes =
7866 adapter->rsm_attr.attr_direct_access_sizes;
7867 rsm_cattr32.attr_atomic_sizes =
7868 adapter->rsm_attr.attr_atomic_sizes;
7869 rsm_cattr32.attr_page_size =
7870 adapter->rsm_attr.attr_page_size;
7871 if (adapter->rsm_attr.attr_max_export_segment_size >
7872 UINT_MAX)
7873 rsm_cattr32.attr_max_export_segment_size =
7874 RSM_MAXSZ_PAGE_ALIGNED;
7875 else
7876 rsm_cattr32.attr_max_export_segment_size =
7877 adapter->rsm_attr.attr_max_export_segment_size;
7878 if (adapter->rsm_attr.attr_tot_export_segment_size >
7879 UINT_MAX)
7880 rsm_cattr32.attr_tot_export_segment_size =
7881 RSM_MAXSZ_PAGE_ALIGNED;
7882 else
7883 rsm_cattr32.attr_tot_export_segment_size =
7884 adapter->rsm_attr.attr_tot_export_segment_size;
7885 if (adapter->rsm_attr.attr_max_export_segments >
7886 UINT_MAX)
7887 rsm_cattr32.attr_max_export_segments =
7888 UINT_MAX;
7889 else
7890 rsm_cattr32.attr_max_export_segments =
7891 adapter->rsm_attr.attr_max_export_segments;
7892 if (adapter->rsm_attr.attr_max_import_map_size >
7893 UINT_MAX)
7894 rsm_cattr32.attr_max_import_map_size =
7895 RSM_MAXSZ_PAGE_ALIGNED;
7896 else
7897 rsm_cattr32.attr_max_import_map_size =
7898 adapter->rsm_attr.attr_max_import_map_size;
7899 if (adapter->rsm_attr.attr_tot_import_map_size >
7900 UINT_MAX)
7901 rsm_cattr32.attr_tot_import_map_size =
7902 RSM_MAXSZ_PAGE_ALIGNED;
7903 else
7904 rsm_cattr32.attr_tot_import_map_size =
7905 adapter->rsm_attr.attr_tot_import_map_size;
7906 if (adapter->rsm_attr.attr_max_import_segments >
7907 UINT_MAX)
7908 rsm_cattr32.attr_max_import_segments =
7909 UINT_MAX;
7910 else
7911 rsm_cattr32.attr_max_import_segments =
7912 adapter->rsm_attr.attr_max_import_segments;
7913 rsm_cattr32.attr_controller_addr =
7914 adapter->rsm_attr.attr_controller_addr;
7915
7916 DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
7917 "rsmattr_ddi_copyout done\n"));
7918 if (ddi_copyout((caddr_t)&rsm_cattr32, arg,
7919 sizeof (rsmka_int_controller_attr32_t), mode)) {
7920 return (RSMERR_BAD_ADDR);
7921 }
7922 else
7923 return (RSM_SUCCESS);
7924 }
7925 #endif
7926 rsm_cattr.attr_direct_access_sizes =
7927 adapter->rsm_attr.attr_direct_access_sizes;
7928 rsm_cattr.attr_atomic_sizes =
7929 adapter->rsm_attr.attr_atomic_sizes;
7930 rsm_cattr.attr_page_size =
7931 adapter->rsm_attr.attr_page_size;
7932 rsm_cattr.attr_max_export_segment_size =
7933 adapter->rsm_attr.attr_max_export_segment_size;
7934 rsm_cattr.attr_tot_export_segment_size =
7935 adapter->rsm_attr.attr_tot_export_segment_size;
7936 rsm_cattr.attr_max_export_segments =
7937 adapter->rsm_attr.attr_max_export_segments;
7938 rsm_cattr.attr_max_import_map_size =
7939 adapter->rsm_attr.attr_max_import_map_size;
7940 rsm_cattr.attr_tot_import_map_size =
7941 adapter->rsm_attr.attr_tot_import_map_size;
7942 rsm_cattr.attr_max_import_segments =
7943 adapter->rsm_attr.attr_max_import_segments;
7944 rsm_cattr.attr_controller_addr =
7945 adapter->rsm_attr.attr_controller_addr;
7946 DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
7947 "rsmattr_ddi_copyout done\n"));
7948 if (ddi_copyout((caddr_t)&rsm_cattr, arg,
7949 sizeof (rsmka_int_controller_attr_t), mode)) {
7950 return (RSMERR_BAD_ADDR);
7951 }
7952 else
7953 return (RSM_SUCCESS);
7954 }
7955
7956 /*ARGSUSED*/
7957 static int
rsm_ioctl(dev_t dev,int cmd,intptr_t arg,int mode,cred_t * credp,int * rvalp)7958 rsm_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp,
7959 int *rvalp)
7960 {
7961 rsmseg_t *seg;
7962 rsmresource_t *res;
7963 minor_t rnum;
7964 rsm_ioctlmsg_t msg = {0};
7965 int error;
7966 adapter_t *adapter;
7967 DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_FUNC_ALL | RSM_IOCTL);
7968
7969 DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_ioctl enter\n"));
7970
7971 if (cmd == RSM_IOCTL_CONSUMEEVENT) {
7972 error = rsm_consumeevent_ioctl((caddr_t)arg, mode);
7973 DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
7974 "rsm_ioctl RSM_IOCTL_CONSUMEEVENT done: %d\n", error));
7975 return (error);
7976 }
7977
7978 /* topology cmd does not use the arg common to other cmds */
7979 if (RSM_IOCTL_CMDGRP(cmd) == RSM_IOCTL_TOPOLOGY) {
7980 error = rsmka_topology_ioctl((caddr_t)arg, cmd, mode);
7981 DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
7982 "rsm_ioctl done: %d\n", error));
7983 return (error);
7984 }
7985
7986 if (RSM_IOCTL_CMDGRP(cmd) == RSM_IOCTL_IOVEC) {
7987 error = rsm_iovec_ioctl(dev, (caddr_t)arg, cmd, mode, credp);
7988 DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
7989 "rsm_ioctl done: %d\n", error));
7990 return (error);
7991 }
7992
7993 /*
7994 * try to load arguments
7995 */
7996 if (cmd != RSM_IOCTL_RING_BELL &&
7997 rsm_ddi_copyin((caddr_t)arg, &msg, mode)) {
7998 DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
7999 "rsm_ioctl done: EFAULT\n"));
8000 return (RSMERR_BAD_ADDR);
8001 }
8002
8003 if (cmd == RSM_IOCTL_ATTR) {
8004 adapter = rsm_getadapter(&msg, mode);
8005 if (adapter == NULL) {
8006 DBG_PRINTF((category, RSM_DEBUG,
8007 "rsm_ioctl done: ENODEV\n"));
8008 return (RSMERR_CTLR_NOT_PRESENT);
8009 }
8010 error = rsmattr_ddi_copyout(adapter, msg.arg, mode);
8011 rsmka_release_adapter(adapter);
8012 DBG_PRINTF((category, RSM_DEBUG,
8013 "rsm_ioctl:after copyout %d\n", error));
8014 return (error);
8015 }
8016
8017 if (cmd == RSM_IOCTL_BAR_INFO) {
8018 /* Return library off,len of barrier page */
8019 msg.off = barrier_offset;
8020 msg.len = (int)barrier_size;
8021 #ifdef _MULTI_DATAMODEL
8022 if ((mode & DATAMODEL_MASK) == DATAMODEL_ILP32) {
8023 rsm_ioctlmsg32_t msg32;
8024
8025 if (msg.len > UINT_MAX)
8026 msg.len = RSM_MAXSZ_PAGE_ALIGNED;
8027 else
8028 msg32.len = (int32_t)msg.len;
8029 msg32.off = (int32_t)msg.off;
8030 DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
8031 "rsm_ioctl done\n"));
8032 if (ddi_copyout((caddr_t)&msg32, (caddr_t)arg,
8033 sizeof (msg32), mode))
8034 return (RSMERR_BAD_ADDR);
8035 else
8036 return (RSM_SUCCESS);
8037 }
8038 #endif
8039 DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
8040 "rsm_ioctl done\n"));
8041 if (ddi_copyout((caddr_t)&msg, (caddr_t)arg,
8042 sizeof (msg), mode))
8043 return (RSMERR_BAD_ADDR);
8044 else
8045 return (RSM_SUCCESS);
8046 }
8047
8048 if (RSM_IOCTL_CMDGRP(cmd) == RSM_IOCTL_MAP_ADDR) {
8049 /* map the nodeid or hwaddr */
8050 error = rsmaddr_ioctl(cmd, &msg, mode);
8051 if (error == RSM_SUCCESS) {
8052 #ifdef _MULTI_DATAMODEL
8053 if ((mode & DATAMODEL_MASK) == DATAMODEL_ILP32) {
8054 rsm_ioctlmsg32_t msg32;
8055
8056 msg32.hwaddr = (uint64_t)msg.hwaddr;
8057 msg32.nodeid = (uint32_t)msg.nodeid;
8058
8059 DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
8060 "rsm_ioctl done\n"));
8061 if (ddi_copyout((caddr_t)&msg32, (caddr_t)arg,
8062 sizeof (msg32), mode))
8063 return (RSMERR_BAD_ADDR);
8064 else
8065 return (RSM_SUCCESS);
8066 }
8067 #endif
8068 DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
8069 "rsm_ioctl done\n"));
8070 if (ddi_copyout((caddr_t)&msg, (caddr_t)arg,
8071 sizeof (msg), mode))
8072 return (RSMERR_BAD_ADDR);
8073 else
8074 return (RSM_SUCCESS);
8075 }
8076 DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
8077 "rsm_ioctl done: %d\n", error));
8078 return (error);
8079 }
8080
8081 /* Find resource and look it in read mode */
8082 rnum = getminor(dev);
8083 res = rsmresource_lookup(rnum, RSM_NOLOCK);
8084 ASSERT(res != NULL);
8085
8086 /*
8087 * Find command group
8088 */
8089 switch (RSM_IOCTL_CMDGRP(cmd)) {
8090 case RSM_IOCTL_EXPORT_SEG:
8091 /*
8092 * Export list is searched during publish, loopback and
8093 * remote lookup call.
8094 */
8095 seg = rsmresource_seg(res, rnum, credp,
8096 RSM_RESOURCE_EXPORT_SEGMENT);
8097 if (seg->s_type == RSM_RESOURCE_EXPORT_SEGMENT) {
8098 error = rsmexport_ioctl(seg, &msg, cmd, arg, mode,
8099 credp);
8100 } else { /* export ioctl on an import/barrier resource */
8101 error = RSMERR_BAD_SEG_HNDL;
8102 }
8103 break;
8104 case RSM_IOCTL_IMPORT_SEG:
8105 /* Import list is searched during remote unmap call. */
8106 seg = rsmresource_seg(res, rnum, credp,
8107 RSM_RESOURCE_IMPORT_SEGMENT);
8108 if (seg->s_type == RSM_RESOURCE_IMPORT_SEGMENT) {
8109 error = rsmimport_ioctl(seg, &msg, cmd, arg, mode,
8110 credp);
8111 } else { /* import ioctl on an export/barrier resource */
8112 error = RSMERR_BAD_SEG_HNDL;
8113 }
8114 break;
8115 case RSM_IOCTL_BAR:
8116 if (res != RSMRC_RESERVED &&
8117 res->rsmrc_type == RSM_RESOURCE_IMPORT_SEGMENT) {
8118 error = rsmbar_ioctl((rsmseg_t *)res, &msg, cmd, arg,
8119 mode);
8120 } else { /* invalid res value */
8121 error = RSMERR_BAD_SEG_HNDL;
8122 }
8123 break;
8124 case RSM_IOCTL_BELL:
8125 if (res != RSMRC_RESERVED) {
8126 if (res->rsmrc_type == RSM_RESOURCE_IMPORT_SEGMENT)
8127 error = exportbell_ioctl((rsmseg_t *)res, cmd);
8128 else if (res->rsmrc_type == RSM_RESOURCE_EXPORT_SEGMENT)
8129 error = importbell_ioctl((rsmseg_t *)res, cmd);
8130 else /* RSM_RESOURCE_BAR */
8131 error = RSMERR_BAD_SEG_HNDL;
8132 } else { /* invalid res value */
8133 error = RSMERR_BAD_SEG_HNDL;
8134 }
8135 break;
8136 default:
8137 error = EINVAL;
8138 }
8139
8140 DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_ioctl done: %d\n",
8141 error));
8142 return (error);
8143 }
8144
8145
8146 /* **************************** Segment Mapping Operations ********* */
8147 static rsm_mapinfo_t *
rsm_get_mapinfo(rsmseg_t * seg,off_t off,size_t len,off_t * dev_offset,size_t * map_len)8148 rsm_get_mapinfo(rsmseg_t *seg, off_t off, size_t len, off_t *dev_offset,
8149 size_t *map_len)
8150 {
8151 rsm_mapinfo_t *p;
8152 /*
8153 * Find the correct mapinfo structure to use during the mapping
8154 * from the seg->s_mapinfo list.
8155 * The seg->s_mapinfo list contains in reverse order the mappings
8156 * as returned by the RSMPI rsm_map. In rsm_devmap, we need to
8157 * access the correct entry within this list for the mapping
8158 * requested.
8159 *
8160 * The algorithm for selecting a list entry is as follows:
8161 *
8162 * When start_offset of an entry <= off we have found the entry
8163 * we were looking for. Adjust the dev_offset and map_len (needs
8164 * to be PAGESIZE aligned).
8165 */
8166 p = seg->s_mapinfo;
8167 for (; p; p = p->next) {
8168 if (p->start_offset <= off) {
8169 *dev_offset = p->dev_offset + off - p->start_offset;
8170 *map_len = (len > p->individual_len) ?
8171 p->individual_len : ptob(btopr(len));
8172 return (p);
8173 }
8174 p = p->next;
8175 }
8176
8177 return (NULL);
8178 }
8179
8180 static void
rsm_free_mapinfo(rsm_mapinfo_t * mapinfo)8181 rsm_free_mapinfo(rsm_mapinfo_t *mapinfo)
8182 {
8183 rsm_mapinfo_t *p;
8184
8185 while (mapinfo != NULL) {
8186 p = mapinfo;
8187 mapinfo = mapinfo->next;
8188 kmem_free(p, sizeof (*p));
8189 }
8190 }
8191
8192 static int
rsmmap_map(devmap_cookie_t dhp,dev_t dev,uint_t flags,offset_t off,size_t len,void ** pvtp)8193 rsmmap_map(devmap_cookie_t dhp, dev_t dev, uint_t flags, offset_t off,
8194 size_t len, void **pvtp)
8195 {
8196 rsmcookie_t *p;
8197 rsmresource_t *res;
8198 rsmseg_t *seg;
8199 minor_t rnum;
8200 DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_FUNC_ALL | RSM_DDI);
8201
8202 DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmmap_map enter\n"));
8203
8204 DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
8205 "rsmmap_map: dhp = %x\n", dhp));
8206
8207 flags = flags;
8208
8209 rnum = getminor(dev);
8210 res = (rsmresource_t *)rsmresource_lookup(rnum, RSM_NOLOCK);
8211 ASSERT(res != NULL);
8212
8213 seg = (rsmseg_t *)res;
8214
8215 rsmseglock_acquire(seg);
8216
8217 ASSERT(seg->s_hdr.rsmrc_type == RSM_RESOURCE_IMPORT_SEGMENT);
8218
8219 /*
8220 * Allocate structure and add cookie to segment list
8221 */
8222 p = kmem_alloc(sizeof (*p), KM_SLEEP);
8223
8224 p->c_dhp = dhp;
8225 p->c_off = off;
8226 p->c_len = len;
8227 p->c_next = seg->s_ckl;
8228 seg->s_ckl = p;
8229
8230 *pvtp = (void *)seg;
8231
8232 rsmseglock_release(seg);
8233
8234 DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmmap_map done\n"));
8235 return (DDI_SUCCESS);
8236 }
8237
8238 /*
8239 * Page fault handling is done here. The prerequisite mapping setup
8240 * has been done in rsm_devmap with calls to ddi_devmem_setup or
8241 * ddi_umem_setup
8242 */
8243 static int
rsmmap_access(devmap_cookie_t dhp,void * pvt,offset_t offset,size_t len,uint_t type,uint_t rw)8244 rsmmap_access(devmap_cookie_t dhp, void *pvt, offset_t offset, size_t len,
8245 uint_t type, uint_t rw)
8246 {
8247 int e;
8248 rsmseg_t *seg = (rsmseg_t *)pvt;
8249 DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_FUNC_ALL | RSM_DDI);
8250
8251 DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmmap_access enter\n"));
8252
8253 rsmseglock_acquire(seg);
8254
8255 ASSERT(seg->s_hdr.rsmrc_type == RSM_RESOURCE_IMPORT_SEGMENT);
8256
8257 while (seg->s_state == RSM_STATE_MAP_QUIESCE) {
8258 if (cv_wait_sig(&seg->s_cv, &seg->s_lock) == 0) {
8259 DBG_PRINTF((category, RSM_DEBUG,
8260 "rsmmap_access done: cv_wait INTR"));
8261 rsmseglock_release(seg);
8262 return (RSMERR_INTERRUPTED);
8263 }
8264 }
8265
8266 ASSERT(seg->s_state == RSM_STATE_DISCONNECT ||
8267 seg->s_state == RSM_STATE_ACTIVE);
8268
8269 if (seg->s_state == RSM_STATE_DISCONNECT)
8270 seg->s_flags |= RSM_IMPORT_DUMMY;
8271
8272 DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
8273 "rsmmap_access: dhp = %x\n", dhp));
8274
8275 rsmseglock_release(seg);
8276
8277 if (e = devmap_load(dhp, offset, len, type, rw)) {
8278 DBG_PRINTF((category, RSM_ERR, "devmap_load failed\n"));
8279 }
8280
8281
8282 DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmmap_access done\n"));
8283
8284 return (e);
8285 }
8286
8287 static int
rsmmap_dup(devmap_cookie_t dhp,void * oldpvt,devmap_cookie_t new_dhp,void ** newpvt)8288 rsmmap_dup(devmap_cookie_t dhp, void *oldpvt, devmap_cookie_t new_dhp,
8289 void **newpvt)
8290 {
8291 rsmseg_t *seg = (rsmseg_t *)oldpvt;
8292 rsmcookie_t *p, *old;
8293 DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_FUNC_ALL | RSM_DDI);
8294
8295 DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmmap_dup enter\n"));
8296
8297 /*
8298 * Same as map, create an entry to hold cookie and add it to
8299 * connect segment list. The oldpvt is a pointer to segment.
8300 * Return segment pointer in newpvt.
8301 */
8302 rsmseglock_acquire(seg);
8303
8304 ASSERT(seg->s_hdr.rsmrc_type == RSM_RESOURCE_IMPORT_SEGMENT);
8305
8306 /*
8307 * Find old cookie
8308 */
8309 for (old = seg->s_ckl; old != NULL; old = old->c_next) {
8310 if (old->c_dhp == dhp) {
8311 break;
8312 }
8313 }
8314 if (old == NULL) {
8315 DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
8316 "rsmmap_dup done: EINVAL\n"));
8317 rsmseglock_release(seg);
8318 return (EINVAL);
8319 }
8320
8321 p = kmem_alloc(sizeof (*p), KM_SLEEP);
8322
8323 p->c_dhp = new_dhp;
8324 p->c_off = old->c_off;
8325 p->c_len = old->c_len;
8326 p->c_next = seg->s_ckl;
8327 seg->s_ckl = p;
8328
8329 *newpvt = (void *)seg;
8330
8331 rsmseglock_release(seg);
8332
8333 DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmmap_dup done\n"));
8334
8335 return (DDI_SUCCESS);
8336 }
8337
8338 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)8339 rsmmap_unmap(devmap_cookie_t dhp, void *pvtp, offset_t off, size_t len,
8340 devmap_cookie_t new_dhp1, void **pvtp1,
8341 devmap_cookie_t new_dhp2, void **pvtp2)
8342 {
8343 /*
8344 * Remove pvtp structure from segment list.
8345 */
8346 rsmseg_t *seg = (rsmseg_t *)pvtp;
8347 int freeflag;
8348
8349 DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_FUNC_ALL | RSM_DDI);
8350
8351 DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmmap_unmap enter\n"));
8352
8353 off = off; len = len;
8354 pvtp1 = pvtp1; pvtp2 = pvtp2;
8355
8356 rsmseglock_acquire(seg);
8357
8358 ASSERT(seg->s_hdr.rsmrc_type == RSM_RESOURCE_IMPORT_SEGMENT);
8359
8360 DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
8361 "rsmmap_unmap: dhp = %x\n", dhp));
8362 /*
8363 * We can go ahead and remove the dhps even if we are in
8364 * the MAPPING state because the dhps being removed here
8365 * belong to a different mmap and we are holding the segment
8366 * lock.
8367 */
8368 if (new_dhp1 == NULL && new_dhp2 == NULL) {
8369 /* find and remove dhp handle */
8370 rsmcookie_t *tmp, **back = &seg->s_ckl;
8371
8372 while (*back != NULL) {
8373 tmp = *back;
8374 if (tmp->c_dhp == dhp) {
8375 *back = tmp->c_next;
8376 kmem_free(tmp, sizeof (*tmp));
8377 break;
8378 }
8379 back = &tmp->c_next;
8380 }
8381 } else {
8382 DBG_PRINTF((category, RSM_DEBUG_LVL2,
8383 "rsmmap_unmap:parital unmap"
8384 "new_dhp1 %lx, new_dhp2 %lx\n",
8385 (size_t)new_dhp1, (size_t)new_dhp2));
8386 }
8387
8388 /*
8389 * rsmmap_unmap is called for each mapping cookie on the list.
8390 * When the list becomes empty and we are not in the MAPPING
8391 * state then unmap in the rsmpi driver.
8392 */
8393 if ((seg->s_ckl == NULL) && (seg->s_state != RSM_STATE_MAPPING))
8394 (void) rsm_unmap(seg);
8395
8396 if (seg->s_state == RSM_STATE_END && seg->s_ckl == NULL) {
8397 freeflag = 1;
8398 } else {
8399 freeflag = 0;
8400 }
8401
8402 rsmseglock_release(seg);
8403
8404 if (freeflag) {
8405 /* Free the segment structure */
8406 rsmseg_free(seg);
8407 }
8408 DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmmap_unmap done\n"));
8409
8410 }
8411
8412 static struct devmap_callback_ctl rsmmap_ops = {
8413 DEVMAP_OPS_REV, /* devmap_ops version number */
8414 rsmmap_map, /* devmap_ops map routine */
8415 rsmmap_access, /* devmap_ops access routine */
8416 rsmmap_dup, /* devmap_ops dup routine */
8417 rsmmap_unmap, /* devmap_ops unmap routine */
8418 };
8419
8420 static int
rsm_devmap(dev_t dev,devmap_cookie_t dhc,offset_t off,size_t len,size_t * maplen,uint_t model)8421 rsm_devmap(dev_t dev, devmap_cookie_t dhc, offset_t off, size_t len,
8422 size_t *maplen, uint_t model /*ARGSUSED*/)
8423 {
8424 struct devmap_callback_ctl *callbackops = &rsmmap_ops;
8425 int err;
8426 uint_t maxprot;
8427 minor_t rnum;
8428 rsmseg_t *seg;
8429 off_t dev_offset;
8430 size_t cur_len;
8431 DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_FUNC_ALL | RSM_DDI);
8432
8433 DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_devmap enter\n"));
8434
8435 DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
8436 "rsm_devmap: off = %lx, len = %lx\n", off, len));
8437 rnum = getminor(dev);
8438 seg = (rsmseg_t *)rsmresource_lookup(rnum, RSM_NOLOCK);
8439 ASSERT(seg != NULL);
8440
8441 if (seg->s_hdr.rsmrc_type == RSM_RESOURCE_BAR) {
8442 if ((off == barrier_offset) &&
8443 (len == barrier_size)) {
8444
8445 ASSERT(bar_va != NULL && bar_cookie != NULL);
8446
8447 /*
8448 * The offset argument in devmap_umem_setup represents
8449 * the offset within the kernel memory defined by the
8450 * cookie. We use this offset as barrier_offset.
8451 */
8452 err = devmap_umem_setup(dhc, rsm_dip, NULL, bar_cookie,
8453 barrier_offset, len, PROT_USER|PROT_READ,
8454 DEVMAP_DEFAULTS, 0);
8455
8456 if (err != 0) {
8457 DBG_PRINTF((category, RSM_ERR,
8458 "rsm_devmap done: %d\n", err));
8459 return (RSMERR_MAP_FAILED);
8460 }
8461 DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
8462 "rsm_devmap done: %d\n", err));
8463
8464 *maplen = barrier_size;
8465
8466 return (err);
8467 } else {
8468 DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
8469 "rsm_devmap done: %d\n", err));
8470 return (RSMERR_MAP_FAILED);
8471 }
8472 }
8473
8474 ASSERT(seg->s_hdr.rsmrc_type == RSM_RESOURCE_IMPORT_SEGMENT);
8475 ASSERT(seg->s_state == RSM_STATE_MAPPING);
8476
8477 /*
8478 * Make sure we still have permission for the map operation.
8479 */
8480 maxprot = PROT_USER;
8481 if (seg->s_mode & RSM_PERM_READ) {
8482 maxprot |= PROT_READ;
8483 }
8484
8485 if (seg->s_mode & RSM_PERM_WRITE) {
8486 maxprot |= PROT_WRITE;
8487 }
8488
8489 /*
8490 * For each devmap call, rsmmap_map is called. This maintains driver
8491 * private information for the mapping. Thus, if there are multiple
8492 * devmap calls there will be multiple rsmmap_map calls and for each
8493 * call, the mapping information will be stored.
8494 * In case of an error during the processing of the devmap call, error
8495 * will be returned. This error return causes the caller of rsm_devmap
8496 * to undo all the mappings by calling rsmmap_unmap for each one.
8497 * rsmmap_unmap will free up the private information for the requested
8498 * mapping.
8499 */
8500 if (seg->s_node != my_nodeid) {
8501 rsm_mapinfo_t *p;
8502
8503 p = rsm_get_mapinfo(seg, off, len, &dev_offset, &cur_len);
8504 if (p == NULL) {
8505 DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
8506 "rsm_devmap: incorrect mapping info\n"));
8507 return (RSMERR_MAP_FAILED);
8508 }
8509 err = devmap_devmem_setup(dhc, p->dip,
8510 callbackops, p->dev_register,
8511 dev_offset, cur_len, maxprot,
8512 DEVMAP_ALLOW_REMAP | DEVMAP_DEFAULTS, 0);
8513
8514 DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
8515 "rsm_devmap: dip=%lx,dreg=%lu,doff=%lx,"
8516 "off=%lx,len=%lx\n",
8517 p->dip, p->dev_register, dev_offset, off, cur_len));
8518
8519 if (err != 0) {
8520 DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
8521 "rsm_devmap: devmap_devmem_setup failed %d\n",
8522 err));
8523 return (RSMERR_MAP_FAILED);
8524 }
8525 /* cur_len is always an integral multiple pagesize */
8526 ASSERT((cur_len & (PAGESIZE-1)) == 0);
8527 *maplen = cur_len;
8528 return (err);
8529
8530 } else {
8531 err = devmap_umem_setup(dhc, rsm_dip, callbackops,
8532 seg->s_cookie, off, len, maxprot,
8533 DEVMAP_ALLOW_REMAP|DEVMAP_DEFAULTS, 0);
8534 if (err != 0) {
8535 DBG_PRINTF((category, RSM_DEBUG,
8536 "rsm_devmap: devmap_umem_setup failed %d\n",
8537 err));
8538 return (RSMERR_MAP_FAILED);
8539 }
8540 DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
8541 "rsm_devmap: loopback done\n"));
8542
8543 *maplen = ptob(btopr(len));
8544
8545 return (err);
8546 }
8547 }
8548
8549 /*
8550 * We can use the devmap framework for mapping device memory to user space by
8551 * specifying this routine in the rsm_cb_ops structure. The kernel mmap
8552 * processing calls this entry point and devmap_setup is called within this
8553 * function, which eventually calls rsm_devmap
8554 */
8555 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)8556 rsm_segmap(dev_t dev, off_t off, struct as *as, caddr_t *addrp, off_t len,
8557 uint_t prot, uint_t maxprot, uint_t flags, struct cred *cred)
8558 {
8559 int error = 0;
8560 int old_state;
8561 minor_t rnum;
8562 rsmseg_t *seg, *eseg;
8563 adapter_t *adapter;
8564 rsm_import_share_t *sharedp;
8565 DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_FUNC_ALL | RSM_DDI);
8566
8567 DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_segmap enter\n"));
8568
8569 /*
8570 * find segment
8571 */
8572 rnum = getminor(dev);
8573 seg = (rsmseg_t *)rsmresource_lookup(rnum, RSM_LOCK);
8574
8575 if (seg == NULL) {
8576 DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
8577 "rsm_segmap done: invalid segment\n"));
8578 return (EINVAL);
8579 }
8580
8581 /*
8582 * the user is trying to map a resource that has not been
8583 * defined yet. The library uses this to map in the
8584 * barrier page.
8585 */
8586 if (seg->s_hdr.rsmrc_type == RSM_RESOURCE_BAR) {
8587 rsmseglock_release(seg);
8588
8589 /*
8590 * The mapping for the barrier page is identified
8591 * by the special offset barrier_offset
8592 */
8593
8594 if (off == (off_t)barrier_offset ||
8595 len == (off_t)barrier_size) {
8596 if (bar_cookie == NULL || bar_va == NULL) {
8597 DBG_PRINTF((category, RSM_DEBUG,
8598 "rsm_segmap: bar cookie/va is NULL\n"));
8599 return (EINVAL);
8600 }
8601
8602 error = devmap_setup(dev, (offset_t)off, as, addrp,
8603 (size_t)len, prot, maxprot, flags, cred);
8604
8605 DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
8606 "rsm_segmap done: %d\n", error));
8607 return (error);
8608 } else {
8609 DBG_PRINTF((category, RSM_DEBUG,
8610 "rsm_segmap: bad offset/length\n"));
8611 return (EINVAL);
8612 }
8613 }
8614
8615 /* Make sure you can only map imported segments */
8616 if (seg->s_hdr.rsmrc_type != RSM_RESOURCE_IMPORT_SEGMENT) {
8617 rsmseglock_release(seg);
8618 DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
8619 "rsm_segmap done: not an import segment\n"));
8620 return (EINVAL);
8621 }
8622 /* check means library is broken */
8623 ASSERT(seg->s_hdr.rsmrc_num == rnum);
8624
8625 /* wait for the segment to become unquiesced */
8626 while (seg->s_state == RSM_STATE_CONN_QUIESCE) {
8627 if (cv_wait_sig(&seg->s_cv, &seg->s_lock) == 0) {
8628 rsmseglock_release(seg);
8629 DBG_PRINTF((category, RSM_DEBUG,
8630 "rsm_segmap done: cv_wait INTR"));
8631 return (ENODEV);
8632 }
8633 }
8634
8635 /* wait until segment leaves the mapping state */
8636 while (seg->s_state == RSM_STATE_MAPPING)
8637 cv_wait(&seg->s_cv, &seg->s_lock);
8638
8639 /*
8640 * we allow multiple maps of the same segment in the KA
8641 * and it works because we do an rsmpi map of the whole
8642 * segment during the first map and all the device mapping
8643 * information needed in rsm_devmap is in the mapinfo list.
8644 */
8645 if ((seg->s_state != RSM_STATE_CONNECT) &&
8646 (seg->s_state != RSM_STATE_ACTIVE)) {
8647 rsmseglock_release(seg);
8648 DBG_PRINTF((category, RSM_DEBUG,
8649 "rsm_segmap done: segment not connected\n"));
8650 return (ENODEV);
8651 }
8652
8653 /*
8654 * Make sure we are not mapping a larger segment than what's
8655 * exported
8656 */
8657 if ((size_t)off + ptob(btopr(len)) > seg->s_len) {
8658 rsmseglock_release(seg);
8659 DBG_PRINTF((category, RSM_DEBUG,
8660 "rsm_segmap done: off+len>seg size\n"));
8661 return (ENXIO);
8662 }
8663
8664 /*
8665 * Make sure we still have permission for the map operation.
8666 */
8667 maxprot = PROT_USER;
8668 if (seg->s_mode & RSM_PERM_READ) {
8669 maxprot |= PROT_READ;
8670 }
8671
8672 if (seg->s_mode & RSM_PERM_WRITE) {
8673 maxprot |= PROT_WRITE;
8674 }
8675
8676 if ((prot & maxprot) != prot) {
8677 /* No permission */
8678 rsmseglock_release(seg);
8679 DBG_PRINTF((category, RSM_DEBUG,
8680 "rsm_segmap done: no permission\n"));
8681 return (EACCES);
8682 }
8683
8684 old_state = seg->s_state;
8685
8686 ASSERT(seg->s_share != NULL);
8687
8688 rsmsharelock_acquire(seg);
8689
8690 sharedp = seg->s_share;
8691
8692 DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
8693 "rsm_segmap:RSMSI_STATE=%d\n", sharedp->rsmsi_state));
8694
8695 if ((sharedp->rsmsi_state != RSMSI_STATE_CONNECTED) &&
8696 (sharedp->rsmsi_state != RSMSI_STATE_MAPPED)) {
8697 rsmsharelock_release(seg);
8698 rsmseglock_release(seg);
8699 DBG_PRINTF((category, RSM_DEBUG,
8700 "rsm_segmap done:RSMSI_STATE %d invalid\n",
8701 sharedp->rsmsi_state));
8702 return (ENODEV);
8703 }
8704
8705 /*
8706 * Do the map - since we want importers to share mappings
8707 * we do the rsmpi map for the whole segment
8708 */
8709 if (seg->s_node != my_nodeid) {
8710 uint_t dev_register;
8711 off_t dev_offset;
8712 dev_info_t *dip;
8713 size_t tmp_len;
8714 size_t total_length_mapped = 0;
8715 size_t length_to_map = seg->s_len;
8716 off_t tmp_off = 0;
8717 rsm_mapinfo_t *p;
8718
8719 /*
8720 * length_to_map = seg->s_len is always an integral
8721 * multiple of PAGESIZE. Length mapped in each entry in mapinfo
8722 * list is a multiple of PAGESIZE - RSMPI map ensures this
8723 */
8724
8725 adapter = seg->s_adapter;
8726 ASSERT(sharedp->rsmsi_state == RSMSI_STATE_CONNECTED ||
8727 sharedp->rsmsi_state == RSMSI_STATE_MAPPED);
8728
8729 if (sharedp->rsmsi_state == RSMSI_STATE_CONNECTED) {
8730 error = 0;
8731 /* map the whole segment */
8732 while (total_length_mapped < seg->s_len) {
8733 tmp_len = 0;
8734
8735 error = adapter->rsmpi_ops->rsm_map(
8736 seg->s_handle.in, tmp_off,
8737 length_to_map, &tmp_len,
8738 &dip, &dev_register, &dev_offset,
8739 NULL, NULL);
8740
8741 if (error != 0)
8742 break;
8743
8744 /*
8745 * Store the mapping info obtained from rsm_map
8746 */
8747 p = kmem_alloc(sizeof (*p), KM_SLEEP);
8748 p->dev_register = dev_register;
8749 p->dev_offset = dev_offset;
8750 p->dip = dip;
8751 p->individual_len = tmp_len;
8752 p->start_offset = tmp_off;
8753 p->next = sharedp->rsmsi_mapinfo;
8754 sharedp->rsmsi_mapinfo = p;
8755
8756 total_length_mapped += tmp_len;
8757 length_to_map -= tmp_len;
8758 tmp_off += tmp_len;
8759 }
8760 seg->s_mapinfo = sharedp->rsmsi_mapinfo;
8761
8762 if (error != RSM_SUCCESS) {
8763 /* Check if this is the the first rsm_map */
8764 if (sharedp->rsmsi_mapinfo != NULL) {
8765 /*
8766 * A single rsm_unmap undoes
8767 * multiple rsm_maps.
8768 */
8769 (void) seg->s_adapter->rsmpi_ops->
8770 rsm_unmap(sharedp->rsmsi_handle);
8771 rsm_free_mapinfo(sharedp->
8772 rsmsi_mapinfo);
8773 }
8774 sharedp->rsmsi_mapinfo = NULL;
8775 sharedp->rsmsi_state = RSMSI_STATE_CONNECTED;
8776 rsmsharelock_release(seg);
8777 rsmseglock_release(seg);
8778 DBG_PRINTF((category, RSM_DEBUG,
8779 "rsm_segmap done: rsmpi map err %d\n",
8780 error));
8781 ASSERT(error != RSMERR_BAD_LENGTH &&
8782 error != RSMERR_BAD_MEM_ALIGNMENT &&
8783 error != RSMERR_BAD_SEG_HNDL);
8784 if (error == RSMERR_UNSUPPORTED_OPERATION)
8785 return (ENOTSUP);
8786 else if (error == RSMERR_INSUFFICIENT_RESOURCES)
8787 return (EAGAIN);
8788 else if (error == RSMERR_CONN_ABORTED)
8789 return (ENODEV);
8790 else
8791 return (error);
8792 } else {
8793 sharedp->rsmsi_state = RSMSI_STATE_MAPPED;
8794 }
8795 } else {
8796 seg->s_mapinfo = sharedp->rsmsi_mapinfo;
8797 }
8798
8799 sharedp->rsmsi_mapcnt++;
8800
8801 rsmsharelock_release(seg);
8802
8803 /* move to an intermediate mapping state */
8804 seg->s_state = RSM_STATE_MAPPING;
8805 rsmseglock_release(seg);
8806
8807 error = devmap_setup(dev, (offset_t)off, as, addrp,
8808 len, prot, maxprot, flags, cred);
8809
8810 rsmseglock_acquire(seg);
8811 ASSERT(seg->s_state == RSM_STATE_MAPPING);
8812
8813 if (error == DDI_SUCCESS) {
8814 seg->s_state = RSM_STATE_ACTIVE;
8815 } else {
8816 rsmsharelock_acquire(seg);
8817
8818 ASSERT(sharedp->rsmsi_state == RSMSI_STATE_MAPPED);
8819
8820 sharedp->rsmsi_mapcnt--;
8821 if (sharedp->rsmsi_mapcnt == 0) {
8822 /* unmap the shared RSMPI mapping */
8823 ASSERT(sharedp->rsmsi_handle != NULL);
8824 (void) adapter->rsmpi_ops->
8825 rsm_unmap(sharedp->rsmsi_handle);
8826 rsm_free_mapinfo(sharedp->rsmsi_mapinfo);
8827 sharedp->rsmsi_mapinfo = NULL;
8828 sharedp->rsmsi_state = RSMSI_STATE_CONNECTED;
8829 }
8830
8831 rsmsharelock_release(seg);
8832 seg->s_state = old_state;
8833 DBG_PRINTF((category, RSM_ERR,
8834 "rsm: devmap_setup failed %d\n", error));
8835 }
8836 cv_broadcast(&seg->s_cv);
8837 rsmseglock_release(seg);
8838 DBG_PRINTF((category, RSM_DEBUG_LVL2, "rsm_segmap done: %d\n",
8839 error));
8840 return (error);
8841 } else {
8842 /*
8843 * For loopback, the export segment mapping cookie (s_cookie)
8844 * is also used as the s_cookie value for its import segments
8845 * during mapping.
8846 * Note that reference counting for s_cookie of the export
8847 * segment is not required due to the following:
8848 * We never have a case of the export segment being destroyed,
8849 * leaving the import segments with a stale value for the
8850 * s_cookie field, since a force disconnect is done prior to a
8851 * destroy of an export segment. The force disconnect causes
8852 * the s_cookie value to be reset to NULL. Also for the
8853 * rsm_rebind operation, we change the s_cookie value of the
8854 * export segment as well as of all its local (loopback)
8855 * importers.
8856 */
8857 DBG_ADDCATEGORY(category, RSM_LOOPBACK);
8858
8859 rsmsharelock_release(seg);
8860 /*
8861 * In order to maintain the lock ordering between the export
8862 * and import segment locks, we need to acquire the export
8863 * segment lock first and only then acquire the import
8864 * segment lock.
8865 * The above is necessary to avoid any deadlock scenarios
8866 * with rsm_rebind which also acquires both the export
8867 * and import segment locks in the above mentioned order.
8868 * Based on code inspection, there seem to be no other
8869 * situations in which both the export and import segment
8870 * locks are acquired either in the same or opposite order
8871 * as mentioned above.
8872 * Thus in order to conform to the above lock order, we
8873 * need to change the state of the import segment to
8874 * RSM_STATE_MAPPING, release the lock. Once this is done we
8875 * can now safely acquire the export segment lock first
8876 * followed by the import segment lock which is as per
8877 * the lock order mentioned above.
8878 */
8879 /* move to an intermediate mapping state */
8880 seg->s_state = RSM_STATE_MAPPING;
8881 rsmseglock_release(seg);
8882
8883 eseg = rsmexport_lookup(seg->s_key);
8884
8885 if (eseg == NULL) {
8886 rsmseglock_acquire(seg);
8887 /*
8888 * Revert to old_state and signal any waiters
8889 * The shared state is not changed
8890 */
8891
8892 seg->s_state = old_state;
8893 cv_broadcast(&seg->s_cv);
8894 rsmseglock_release(seg);
8895 DBG_PRINTF((category, RSM_DEBUG,
8896 "rsm_segmap done: key %d not found\n", seg->s_key));
8897 return (ENODEV);
8898 }
8899
8900 rsmsharelock_acquire(seg);
8901 ASSERT(sharedp->rsmsi_state == RSMSI_STATE_CONNECTED ||
8902 sharedp->rsmsi_state == RSMSI_STATE_MAPPED);
8903
8904 sharedp->rsmsi_mapcnt++;
8905 sharedp->rsmsi_state = RSMSI_STATE_MAPPED;
8906 rsmsharelock_release(seg);
8907
8908 ASSERT(eseg->s_cookie != NULL);
8909
8910 /*
8911 * It is not required or necessary to acquire the import
8912 * segment lock here to change the value of s_cookie since
8913 * no one will touch the import segment as long as it is
8914 * in the RSM_STATE_MAPPING state.
8915 */
8916 seg->s_cookie = eseg->s_cookie;
8917
8918 rsmseglock_release(eseg);
8919
8920 error = devmap_setup(dev, (offset_t)off, as, addrp, (size_t)len,
8921 prot, maxprot, flags, cred);
8922
8923 rsmseglock_acquire(seg);
8924 ASSERT(seg->s_state == RSM_STATE_MAPPING);
8925 if (error == 0) {
8926 seg->s_state = RSM_STATE_ACTIVE;
8927 } else {
8928 rsmsharelock_acquire(seg);
8929
8930 ASSERT(sharedp->rsmsi_state == RSMSI_STATE_MAPPED);
8931
8932 sharedp->rsmsi_mapcnt--;
8933 if (sharedp->rsmsi_mapcnt == 0) {
8934 sharedp->rsmsi_mapinfo = NULL;
8935 sharedp->rsmsi_state = RSMSI_STATE_CONNECTED;
8936 }
8937 rsmsharelock_release(seg);
8938 seg->s_state = old_state;
8939 seg->s_cookie = NULL;
8940 }
8941 cv_broadcast(&seg->s_cv);
8942 rsmseglock_release(seg);
8943 DBG_PRINTF((category, RSM_DEBUG_LVL2,
8944 "rsm_segmap done: %d\n", error));
8945 return (error);
8946 }
8947 }
8948
8949 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)8950 rsmka_null_seg_create(
8951 rsm_controller_handle_t argcp,
8952 rsm_memseg_export_handle_t *handle,
8953 size_t size,
8954 uint_t flags,
8955 rsm_memory_local_t *memory,
8956 rsm_resource_callback_t callback,
8957 rsm_resource_callback_arg_t callback_arg /*ARGSUSED*/)
8958 {
8959 return (RSM_SUCCESS);
8960 }
8961
8962
8963 int
rsmka_null_seg_destroy(rsm_memseg_export_handle_t argmemseg)8964 rsmka_null_seg_destroy(
8965 rsm_memseg_export_handle_t argmemseg /*ARGSUSED*/)
8966 {
8967 return (RSM_SUCCESS);
8968 }
8969
8970
8971 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)8972 rsmka_null_bind(
8973 rsm_memseg_export_handle_t argmemseg,
8974 off_t offset,
8975 rsm_memory_local_t *argmemory,
8976 rsm_resource_callback_t callback,
8977 rsm_resource_callback_arg_t callback_arg /*ARGSUSED*/)
8978 {
8979 return (RSM_SUCCESS);
8980 }
8981
8982
8983 int
rsmka_null_unbind(rsm_memseg_export_handle_t argmemseg,off_t offset,size_t length)8984 rsmka_null_unbind(
8985 rsm_memseg_export_handle_t argmemseg,
8986 off_t offset,
8987 size_t length /*ARGSUSED*/)
8988 {
8989 return (DDI_SUCCESS);
8990 }
8991
8992 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)8993 rsmka_null_rebind(
8994 rsm_memseg_export_handle_t argmemseg,
8995 off_t offset,
8996 rsm_memory_local_t *memory,
8997 rsm_resource_callback_t callback,
8998 rsm_resource_callback_arg_t callback_arg /*ARGSUSED*/)
8999 {
9000 return (RSM_SUCCESS);
9001 }
9002
9003 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)9004 rsmka_null_publish(
9005 rsm_memseg_export_handle_t argmemseg,
9006 rsm_access_entry_t access_list[],
9007 uint_t access_list_length,
9008 rsm_memseg_id_t segment_id,
9009 rsm_resource_callback_t callback,
9010 rsm_resource_callback_arg_t callback_arg /*ARGSUSED*/)
9011 {
9012 return (RSM_SUCCESS);
9013 }
9014
9015
9016 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)9017 rsmka_null_republish(
9018 rsm_memseg_export_handle_t memseg,
9019 rsm_access_entry_t access_list[],
9020 uint_t access_list_length,
9021 rsm_resource_callback_t callback,
9022 rsm_resource_callback_arg_t callback_arg /*ARGSUSED*/)
9023 {
9024 return (RSM_SUCCESS);
9025 }
9026
9027 int
rsmka_null_unpublish(rsm_memseg_export_handle_t argmemseg)9028 rsmka_null_unpublish(
9029 rsm_memseg_export_handle_t argmemseg /*ARGSUSED*/)
9030 {
9031 return (RSM_SUCCESS);
9032 }
9033
9034
9035 void
rsmka_init_loopback()9036 rsmka_init_loopback()
9037 {
9038 rsm_ops_t *ops = &null_rsmpi_ops;
9039 DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_FUNC_ALL | RSM_LOOPBACK);
9040
9041 DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
9042 "rsmka_init_loopback enter\n"));
9043
9044 /* initialize null ops vector */
9045 ops->rsm_seg_create = rsmka_null_seg_create;
9046 ops->rsm_seg_destroy = rsmka_null_seg_destroy;
9047 ops->rsm_bind = rsmka_null_bind;
9048 ops->rsm_unbind = rsmka_null_unbind;
9049 ops->rsm_rebind = rsmka_null_rebind;
9050 ops->rsm_publish = rsmka_null_publish;
9051 ops->rsm_unpublish = rsmka_null_unpublish;
9052 ops->rsm_republish = rsmka_null_republish;
9053
9054 /* initialize attributes for loopback adapter */
9055 loopback_attr.attr_name = loopback_str;
9056 loopback_attr.attr_page_size = 0x8; /* 8K */
9057
9058 /* initialize loopback adapter */
9059 loopback_adapter.rsm_attr = loopback_attr;
9060 loopback_adapter.rsmpi_ops = &null_rsmpi_ops;
9061 DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
9062 "rsmka_init_loopback done\n"));
9063 }
9064
9065 /* ************** DR functions ********************************** */
9066 static void
rsm_quiesce_exp_seg(rsmresource_t * resp)9067 rsm_quiesce_exp_seg(rsmresource_t *resp)
9068 {
9069 int recheck_state;
9070 rsmseg_t *segp = (rsmseg_t *)resp;
9071 DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_FUNC_ALL);
9072 DBG_DEFINE_STR(function, "rsm_unquiesce_exp_seg");
9073
9074 DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
9075 "%s enter: key=%u\n", function, segp->s_key));
9076
9077 rsmseglock_acquire(segp);
9078 do {
9079 recheck_state = 0;
9080 if ((segp->s_state == RSM_STATE_NEW_QUIESCED) ||
9081 (segp->s_state == RSM_STATE_BIND_QUIESCED) ||
9082 (segp->s_state == RSM_STATE_EXPORT_QUIESCING) ||
9083 (segp->s_state == RSM_STATE_EXPORT_QUIESCED)) {
9084 rsmseglock_release(segp);
9085 DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
9086 "%s done:state =%d\n", function,
9087 segp->s_state));
9088 return;
9089 }
9090
9091 if (segp->s_state == RSM_STATE_NEW) {
9092 segp->s_state = RSM_STATE_NEW_QUIESCED;
9093 rsmseglock_release(segp);
9094 DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
9095 "%s done:state =%d\n", function,
9096 segp->s_state));
9097 return;
9098 }
9099
9100 if (segp->s_state == RSM_STATE_BIND) {
9101 /* unbind */
9102 (void) rsm_unbind_pages(segp);
9103 segp->s_state = RSM_STATE_BIND_QUIESCED;
9104 rsmseglock_release(segp);
9105 DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
9106 "%s done:state =%d\n", function,
9107 segp->s_state));
9108 return;
9109 }
9110
9111 if (segp->s_state == RSM_STATE_EXPORT) {
9112 /*
9113 * wait for putv/getv to complete if the segp is
9114 * a local memory handle
9115 */
9116 while ((segp->s_state == RSM_STATE_EXPORT) &&
9117 (segp->s_rdmacnt != 0)) {
9118 cv_wait(&segp->s_cv, &segp->s_lock);
9119 }
9120
9121 if (segp->s_state != RSM_STATE_EXPORT) {
9122 /*
9123 * state changed need to see what it
9124 * should be changed to.
9125 */
9126 recheck_state = 1;
9127 continue;
9128 }
9129
9130 segp->s_state = RSM_STATE_EXPORT_QUIESCING;
9131 rsmseglock_release(segp);
9132 /*
9133 * send SUSPEND messages - currently it will be
9134 * done at the end
9135 */
9136 DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
9137 "%s done:state =%d\n", function,
9138 segp->s_state));
9139 return;
9140 }
9141 } while (recheck_state);
9142
9143 rsmseglock_release(segp);
9144 }
9145
9146 static void
rsm_unquiesce_exp_seg(rsmresource_t * resp)9147 rsm_unquiesce_exp_seg(rsmresource_t *resp)
9148 {
9149 int ret;
9150 rsmseg_t *segp = (rsmseg_t *)resp;
9151 rsmapi_access_entry_t *acl;
9152 rsm_access_entry_t *rsmpi_acl;
9153 int acl_len;
9154 int create_flags = 0;
9155 struct buf *xbuf;
9156 rsm_memory_local_t mem;
9157 adapter_t *adapter;
9158 dev_t sdev = 0;
9159 rsm_resource_callback_t callback_flag;
9160 DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_FUNC_ALL);
9161 DBG_DEFINE_STR(function, "rsm_unquiesce_exp_seg");
9162
9163 rsmseglock_acquire(segp);
9164
9165 DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
9166 "%s enter: key=%u, state=%d\n", function, segp->s_key,
9167 segp->s_state));
9168
9169 if ((segp->s_state == RSM_STATE_NEW) ||
9170 (segp->s_state == RSM_STATE_BIND) ||
9171 (segp->s_state == RSM_STATE_EXPORT)) {
9172 rsmseglock_release(segp);
9173 DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "%s done:state=%d\n",
9174 function, segp->s_state));
9175 return;
9176 }
9177
9178 if (segp->s_state == RSM_STATE_NEW_QUIESCED) {
9179 segp->s_state = RSM_STATE_NEW;
9180 cv_broadcast(&segp->s_cv);
9181 rsmseglock_release(segp);
9182 DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "%s done:state=%d\n",
9183 function, segp->s_state));
9184 return;
9185 }
9186
9187 if (segp->s_state == RSM_STATE_BIND_QUIESCED) {
9188 /* bind the segment */
9189 ret = rsm_bind_pages(&segp->s_cookie, segp->s_region.r_vaddr,
9190 segp->s_len, segp->s_proc);
9191 if (ret == RSM_SUCCESS) { /* bind successful */
9192 segp->s_state = RSM_STATE_BIND;
9193 } else { /* bind failed - resource unavailable */
9194 segp->s_state = RSM_STATE_NEW;
9195 }
9196 cv_broadcast(&segp->s_cv);
9197 rsmseglock_release(segp);
9198 DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
9199 "%s done: bind_qscd bind = %d\n", function, ret));
9200 return;
9201 }
9202
9203 while (segp->s_state == RSM_STATE_EXPORT_QUIESCING) {
9204 /* wait for the segment to move to EXPORT_QUIESCED state */
9205 cv_wait(&segp->s_cv, &segp->s_lock);
9206 }
9207
9208 if (segp->s_state == RSM_STATE_EXPORT_QUIESCED) {
9209 /* bind the segment */
9210 ret = rsm_bind_pages(&segp->s_cookie, segp->s_region.r_vaddr,
9211 segp->s_len, segp->s_proc);
9212
9213 if (ret != RSM_SUCCESS) {
9214 /* bind failed - resource unavailable */
9215 acl_len = segp->s_acl_len;
9216 acl = segp->s_acl;
9217 rsmpi_acl = segp->s_acl_in;
9218 segp->s_acl_len = 0;
9219 segp->s_acl = NULL;
9220 segp->s_acl_in = NULL;
9221 rsmseglock_release(segp);
9222
9223 rsmexport_rm(segp);
9224 rsmacl_free(acl, acl_len);
9225 rsmpiacl_free(rsmpi_acl, acl_len);
9226
9227 rsmseglock_acquire(segp);
9228 segp->s_state = RSM_STATE_NEW;
9229 cv_broadcast(&segp->s_cv);
9230 rsmseglock_release(segp);
9231 DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
9232 "%s done: exp_qscd bind failed = %d\n",
9233 function, ret));
9234 return;
9235 }
9236 /*
9237 * publish the segment
9238 * if successful
9239 * segp->s_state = RSM_STATE_EXPORT;
9240 * else failed
9241 * segp->s_state = RSM_STATE_BIND;
9242 */
9243
9244 /* check whether it is a local_memory_handle */
9245 if (segp->s_acl != (rsmapi_access_entry_t *)NULL) {
9246 if ((segp->s_acl[0].ae_node == my_nodeid) &&
9247 (segp->s_acl[0].ae_permission == 0)) {
9248 segp->s_state = RSM_STATE_EXPORT;
9249 cv_broadcast(&segp->s_cv);
9250 rsmseglock_release(segp);
9251 DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
9252 "%s done:exp_qscd\n", function));
9253 return;
9254 }
9255 }
9256 xbuf = ddi_umem_iosetup(segp->s_cookie, 0, segp->s_len, B_WRITE,
9257 sdev, 0, NULL, DDI_UMEM_SLEEP);
9258 ASSERT(xbuf != NULL);
9259
9260 mem.ms_type = RSM_MEM_BUF;
9261 mem.ms_bp = xbuf;
9262
9263 adapter = segp->s_adapter;
9264
9265 if (segp->s_flags & RSMKA_ALLOW_UNBIND_REBIND) {
9266 create_flags = RSM_ALLOW_UNBIND_REBIND;
9267 }
9268
9269 if (segp->s_flags & RSMKA_SET_RESOURCE_DONTWAIT) {
9270 callback_flag = RSM_RESOURCE_DONTWAIT;
9271 } else {
9272 callback_flag = RSM_RESOURCE_SLEEP;
9273 }
9274
9275 ret = adapter->rsmpi_ops->rsm_seg_create(
9276 adapter->rsmpi_handle, &segp->s_handle.out,
9277 segp->s_len, create_flags, &mem,
9278 callback_flag, NULL);
9279
9280 if (ret != RSM_SUCCESS) {
9281 acl_len = segp->s_acl_len;
9282 acl = segp->s_acl;
9283 rsmpi_acl = segp->s_acl_in;
9284 segp->s_acl_len = 0;
9285 segp->s_acl = NULL;
9286 segp->s_acl_in = NULL;
9287 rsmseglock_release(segp);
9288
9289 rsmexport_rm(segp);
9290 rsmacl_free(acl, acl_len);
9291 rsmpiacl_free(rsmpi_acl, acl_len);
9292
9293 rsmseglock_acquire(segp);
9294 segp->s_state = RSM_STATE_BIND;
9295 cv_broadcast(&segp->s_cv);
9296 rsmseglock_release(segp);
9297 DBG_PRINTF((category, RSM_ERR,
9298 "%s done: exp_qscd create failed = %d\n",
9299 function, ret));
9300 return;
9301 }
9302
9303 ret = adapter->rsmpi_ops->rsm_publish(
9304 segp->s_handle.out, segp->s_acl_in, segp->s_acl_len,
9305 segp->s_segid, RSM_RESOURCE_DONTWAIT, NULL);
9306
9307 if (ret != RSM_SUCCESS) {
9308 acl_len = segp->s_acl_len;
9309 acl = segp->s_acl;
9310 rsmpi_acl = segp->s_acl_in;
9311 segp->s_acl_len = 0;
9312 segp->s_acl = NULL;
9313 segp->s_acl_in = NULL;
9314 adapter->rsmpi_ops->rsm_seg_destroy(segp->s_handle.out);
9315 rsmseglock_release(segp);
9316
9317 rsmexport_rm(segp);
9318 rsmacl_free(acl, acl_len);
9319 rsmpiacl_free(rsmpi_acl, acl_len);
9320
9321 rsmseglock_acquire(segp);
9322 segp->s_state = RSM_STATE_BIND;
9323 cv_broadcast(&segp->s_cv);
9324 rsmseglock_release(segp);
9325 DBG_PRINTF((category, RSM_ERR,
9326 "%s done: exp_qscd publish failed = %d\n",
9327 function, ret));
9328 return;
9329 }
9330
9331 segp->s_state = RSM_STATE_EXPORT;
9332 cv_broadcast(&segp->s_cv);
9333 rsmseglock_release(segp);
9334 DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "%s done: exp_qscd\n",
9335 function));
9336 return;
9337 }
9338
9339 rsmseglock_release(segp);
9340
9341 DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "%s done\n", function));
9342 }
9343
9344 static void
rsm_quiesce_imp_seg(rsmresource_t * resp)9345 rsm_quiesce_imp_seg(rsmresource_t *resp)
9346 {
9347 rsmseg_t *segp = (rsmseg_t *)resp;
9348 DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_FUNC_ALL);
9349 DBG_DEFINE_STR(function, "rsm_quiesce_imp_seg");
9350
9351 DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
9352 "%s enter: key=%u\n", function, segp->s_key));
9353
9354 rsmseglock_acquire(segp);
9355 segp->s_flags |= RSM_DR_INPROGRESS;
9356
9357 while (segp->s_rdmacnt != 0) {
9358 /* wait for the RDMA to complete */
9359 cv_wait(&segp->s_cv, &segp->s_lock);
9360 }
9361
9362 rsmseglock_release(segp);
9363
9364 DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "%s done\n", function));
9365
9366 }
9367
9368 static void
rsm_unquiesce_imp_seg(rsmresource_t * resp)9369 rsm_unquiesce_imp_seg(rsmresource_t *resp)
9370 {
9371 rsmseg_t *segp = (rsmseg_t *)resp;
9372 DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_FUNC_ALL);
9373 DBG_DEFINE_STR(function, "rsm_unquiesce_imp_seg");
9374
9375 DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
9376 "%s enter: key=%u\n", function, segp->s_key));
9377
9378 rsmseglock_acquire(segp);
9379
9380 segp->s_flags &= ~RSM_DR_INPROGRESS;
9381 /* wake up any waiting putv/getv ops */
9382 cv_broadcast(&segp->s_cv);
9383
9384 rsmseglock_release(segp);
9385
9386 DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "%s done\n", function));
9387
9388
9389 }
9390
9391 static void
rsm_process_exp_seg(rsmresource_t * resp,int event)9392 rsm_process_exp_seg(rsmresource_t *resp, int event)
9393 {
9394 if (event == RSM_DR_QUIESCE)
9395 rsm_quiesce_exp_seg(resp);
9396 else /* UNQUIESCE */
9397 rsm_unquiesce_exp_seg(resp);
9398 }
9399
9400 static void
rsm_process_imp_seg(rsmresource_t * resp,int event)9401 rsm_process_imp_seg(rsmresource_t *resp, int event)
9402 {
9403 if (event == RSM_DR_QUIESCE)
9404 rsm_quiesce_imp_seg(resp);
9405 else /* UNQUIESCE */
9406 rsm_unquiesce_imp_seg(resp);
9407 }
9408
9409 static void
rsm_dr_process_local_segments(int event)9410 rsm_dr_process_local_segments(int event)
9411 {
9412
9413 int i, j;
9414 rsmresource_blk_t *blk;
9415 rsmresource_t *p;
9416 DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_FUNC_ALL);
9417
9418 DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
9419 "rsm_dr_process_local_segments enter\n"));
9420
9421 /* iterate through the resource structure */
9422
9423 rw_enter(&rsm_resource.rsmrc_lock, RW_READER);
9424
9425 for (i = 0; i < rsm_resource.rsmrc_len; i++) {
9426 blk = rsm_resource.rsmrc_root[i];
9427 if (blk != NULL) {
9428 for (j = 0; j < RSMRC_BLKSZ; j++) {
9429 p = blk->rsmrcblk_blks[j];
9430 if ((p != NULL) && (p != RSMRC_RESERVED)) {
9431 /* valid resource */
9432 if (p->rsmrc_type ==
9433 RSM_RESOURCE_EXPORT_SEGMENT)
9434 rsm_process_exp_seg(p, event);
9435 else if (p->rsmrc_type ==
9436 RSM_RESOURCE_IMPORT_SEGMENT)
9437 rsm_process_imp_seg(p, event);
9438 }
9439 }
9440 }
9441 }
9442
9443 rw_exit(&rsm_resource.rsmrc_lock);
9444
9445 DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
9446 "rsm_dr_process_local_segments done\n"));
9447 }
9448
9449 /* *************** DR callback functions ************ */
9450 static void
rsm_dr_callback_post_add(void * arg,pgcnt_t delta)9451 rsm_dr_callback_post_add(void *arg, pgcnt_t delta /* ARGSUSED */)
9452 {
9453 DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_FUNC_ALL);
9454 DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
9455 "rsm_dr_callback_post_add is a no-op\n"));
9456 /* Noop */
9457 }
9458
9459 static int
rsm_dr_callback_pre_del(void * arg,pgcnt_t delta)9460 rsm_dr_callback_pre_del(void *arg, pgcnt_t delta /* ARGSUSED */)
9461 {
9462 int recheck_state = 0;
9463 DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_FUNC_ALL);
9464
9465 DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
9466 "rsm_dr_callback_pre_del enter\n"));
9467
9468 mutex_enter(&rsm_drv_data.drv_lock);
9469
9470 do {
9471 recheck_state = 0;
9472 DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
9473 "rsm_dr_callback_pre_del:state=%d\n",
9474 rsm_drv_data.drv_state));
9475
9476 switch (rsm_drv_data.drv_state) {
9477 case RSM_DRV_NEW:
9478 /*
9479 * The state should usually never be RSM_DRV_NEW
9480 * since in this state the callbacks have not yet
9481 * been registered. So, ASSERT.
9482 */
9483 ASSERT(0);
9484 return (0);
9485 case RSM_DRV_REG_PROCESSING:
9486 /*
9487 * The driver is in the process of registering
9488 * with the DR framework. So, wait till the
9489 * registration process is complete.
9490 */
9491 recheck_state = 1;
9492 cv_wait(&rsm_drv_data.drv_cv, &rsm_drv_data.drv_lock);
9493 break;
9494 case RSM_DRV_UNREG_PROCESSING:
9495 /*
9496 * If the state is RSM_DRV_UNREG_PROCESSING, the
9497 * module is in the process of detaching and
9498 * unregistering the callbacks from the DR
9499 * framework. So, simply return.
9500 */
9501 mutex_exit(&rsm_drv_data.drv_lock);
9502 DBG_PRINTF((category, RSM_DEBUG,
9503 "rsm_dr_callback_pre_del:"
9504 "pre-del on NEW/UNREG\n"));
9505 return (0);
9506 case RSM_DRV_OK:
9507 rsm_drv_data.drv_state = RSM_DRV_PREDEL_STARTED;
9508 break;
9509 case RSM_DRV_PREDEL_STARTED:
9510 /* FALLTHRU */
9511 case RSM_DRV_PREDEL_COMPLETED:
9512 /* FALLTHRU */
9513 case RSM_DRV_POSTDEL_IN_PROGRESS:
9514 recheck_state = 1;
9515 cv_wait(&rsm_drv_data.drv_cv, &rsm_drv_data.drv_lock);
9516 break;
9517 case RSM_DRV_DR_IN_PROGRESS:
9518 rsm_drv_data.drv_memdel_cnt++;
9519 mutex_exit(&rsm_drv_data.drv_lock);
9520 DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
9521 "rsm_dr_callback_pre_del done\n"));
9522 return (0);
9523 /* break; */
9524 default:
9525 ASSERT(0);
9526 break;
9527 }
9528
9529 } while (recheck_state);
9530
9531 rsm_drv_data.drv_memdel_cnt++;
9532
9533 mutex_exit(&rsm_drv_data.drv_lock);
9534
9535 /* Do all the quiescing stuff here */
9536 DBG_PRINTF((category, RSM_DEBUG,
9537 "rsm_dr_callback_pre_del: quiesce things now\n"));
9538
9539 rsm_dr_process_local_segments(RSM_DR_QUIESCE);
9540
9541 /*
9542 * now that all local segments have been quiesced lets inform
9543 * the importers
9544 */
9545 rsm_send_suspend();
9546
9547 /*
9548 * In response to the suspend message the remote node(s) will process
9549 * the segments and send a suspend_complete message. Till all
9550 * the nodes send the suspend_complete message we wait in the
9551 * RSM_DRV_PREDEL_STARTED state. In the exporter_quiesce
9552 * function we transition to the RSM_DRV_PREDEL_COMPLETED state.
9553 */
9554 mutex_enter(&rsm_drv_data.drv_lock);
9555
9556 while (rsm_drv_data.drv_state == RSM_DRV_PREDEL_STARTED) {
9557 cv_wait(&rsm_drv_data.drv_cv, &rsm_drv_data.drv_lock);
9558 }
9559
9560 ASSERT(rsm_drv_data.drv_state == RSM_DRV_PREDEL_COMPLETED);
9561
9562 rsm_drv_data.drv_state = RSM_DRV_DR_IN_PROGRESS;
9563 cv_broadcast(&rsm_drv_data.drv_cv);
9564
9565 mutex_exit(&rsm_drv_data.drv_lock);
9566
9567 DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
9568 "rsm_dr_callback_pre_del done\n"));
9569
9570 return (0);
9571 }
9572
9573 static void
rsm_dr_callback_post_del(void * arg,pgcnt_t delta,int cancelled)9574 rsm_dr_callback_post_del(void *arg, pgcnt_t delta, int cancelled /* ARGSUSED */)
9575 {
9576 int recheck_state = 0;
9577 DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_FUNC_ALL);
9578
9579 DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
9580 "rsm_dr_callback_post_del enter\n"));
9581
9582 mutex_enter(&rsm_drv_data.drv_lock);
9583
9584 do {
9585 recheck_state = 0;
9586 DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
9587 "rsm_dr_callback_post_del:state=%d\n",
9588 rsm_drv_data.drv_state));
9589
9590 switch (rsm_drv_data.drv_state) {
9591 case RSM_DRV_NEW:
9592 /*
9593 * The driver state cannot not be RSM_DRV_NEW
9594 * since in this state the callbacks have not
9595 * yet been registered.
9596 */
9597 ASSERT(0);
9598 return;
9599 case RSM_DRV_REG_PROCESSING:
9600 /*
9601 * The driver is in the process of registering with
9602 * the DR framework. Wait till the registration is
9603 * complete.
9604 */
9605 recheck_state = 1;
9606 cv_wait(&rsm_drv_data.drv_cv, &rsm_drv_data.drv_lock);
9607 break;
9608 case RSM_DRV_UNREG_PROCESSING:
9609 /*
9610 * RSM_DRV_UNREG_PROCESSING state means the module
9611 * is detaching and unregistering the callbacks
9612 * from the DR framework. So simply return.
9613 */
9614 /* FALLTHRU */
9615 case RSM_DRV_OK:
9616 /*
9617 * RSM_DRV_OK means we missed the pre-del
9618 * corresponding to this post-del coz we had not
9619 * registered yet, so simply return.
9620 */
9621 mutex_exit(&rsm_drv_data.drv_lock);
9622 DBG_PRINTF((category, RSM_DEBUG,
9623 "rsm_dr_callback_post_del:"
9624 "post-del on OK/UNREG\n"));
9625 return;
9626 /* break; */
9627 case RSM_DRV_PREDEL_STARTED:
9628 /* FALLTHRU */
9629 case RSM_DRV_PREDEL_COMPLETED:
9630 /* FALLTHRU */
9631 case RSM_DRV_POSTDEL_IN_PROGRESS:
9632 recheck_state = 1;
9633 cv_wait(&rsm_drv_data.drv_cv, &rsm_drv_data.drv_lock);
9634 break;
9635 case RSM_DRV_DR_IN_PROGRESS:
9636 rsm_drv_data.drv_memdel_cnt--;
9637 if (rsm_drv_data.drv_memdel_cnt > 0) {
9638 mutex_exit(&rsm_drv_data.drv_lock);
9639 DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
9640 "rsm_dr_callback_post_del done:\n"));
9641 return;
9642 }
9643 rsm_drv_data.drv_state = RSM_DRV_POSTDEL_IN_PROGRESS;
9644 break;
9645 default:
9646 ASSERT(0);
9647 return;
9648 /* break; */
9649 }
9650 } while (recheck_state);
9651
9652 mutex_exit(&rsm_drv_data.drv_lock);
9653
9654 /* Do all the unquiescing stuff here */
9655 DBG_PRINTF((category, RSM_DEBUG,
9656 "rsm_dr_callback_post_del: unquiesce things now\n"));
9657
9658 rsm_dr_process_local_segments(RSM_DR_UNQUIESCE);
9659
9660 /*
9661 * now that all local segments have been unquiesced lets inform
9662 * the importers
9663 */
9664 rsm_send_resume();
9665
9666 mutex_enter(&rsm_drv_data.drv_lock);
9667
9668 rsm_drv_data.drv_state = RSM_DRV_OK;
9669
9670 cv_broadcast(&rsm_drv_data.drv_cv);
9671
9672 mutex_exit(&rsm_drv_data.drv_lock);
9673
9674 DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
9675 "rsm_dr_callback_post_del done\n"));
9676
9677 return;
9678
9679 }
9680