#include <sys/types.h>
#include <sys/param.h>
#include <sys/user.h>
#include <sys/buf.h>
#include <sys/systm.h>
#include <sys/cred.h>
#include <sys/vm.h>
#include <sys/uio.h>
#include <vm/seg.h>
#include <vm/page.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/errno.h>
#include <sys/file.h>
#include <sys/uio.h>
#include <sys/proc.h>
#include <sys/mman.h>
#include <sys/open.h>
#include <sys/atomic.h>
#include <sys/mem_config.h>
#include <sys/ddi.h>
#include <sys/devops.h>
#include <sys/ddidevmap.h>
#include <sys/sunddi.h>
#include <sys/esunddi.h>
#include <sys/ddi_impldefs.h>
#include <sys/kmem.h>
#include <sys/conf.h>
#include <sys/devops.h>
#include <sys/ddi_impldefs.h>
#include <sys/modctl.h>
#include <sys/policy.h>
#include <sys/types.h>
#include <sys/conf.h>
#include <sys/param.h>
#include <sys/taskq.h>
#include <sys/rsm/rsm_common.h>
#include <sys/rsm/rsmapi_common.h>
#include <sys/rsm/rsm.h>
#include <rsm_in.h>
#include <sys/rsm/rsmka_path_int.h>
#include <sys/rsm/rsmpi.h>
#include <sys/modctl.h>
#include <sys/debug.h>
#include <sys/tuneable.h>
#ifdef RSM_DRTEST
extern int rsm_kphysm_setup_func_register(kphysm_setup_vector_t *vec,
void *arg);
extern void rsm_kphysm_setup_func_unregister(kphysm_setup_vector_t *vec,
void *arg);
#endif
extern void dbg_printf(int category, int level, char *fmt, ...);
extern void rsmka_pathmanager_init();
extern void rsmka_pathmanager_cleanup();
extern void rele_sendq_token(sendq_token_t *);
extern rsm_addr_t get_remote_hwaddr(adapter_t *, rsm_node_id_t);
extern rsm_node_id_t get_remote_nodeid(adapter_t *, rsm_addr_t);
extern int rsmka_topology_ioctl(caddr_t, int, int);
extern pri_t maxclsyspri;
extern work_queue_t work_queue;
extern kmutex_t ipc_info_lock;
extern kmutex_t ipc_info_cvlock;
extern kcondvar_t ipc_info_cv;
extern kmutex_t path_hold_cvlock;
extern kcondvar_t path_hold_cv;
extern kmutex_t rsmka_buf_lock;
extern path_t *rsm_find_path(char *, int, rsm_addr_t);
extern adapter_t *rsmka_lookup_adapter(char *, int);
extern sendq_token_t *rsmka_get_sendq_token(rsm_node_id_t, sendq_token_t *);
extern boolean_t rsmka_do_path_active(path_t *, int);
extern boolean_t rsmka_check_node_alive(rsm_node_id_t);
extern void rsmka_release_adapter(adapter_t *);
extern void rsmka_enqueue_msgbuf(path_t *path, void *data);
extern void rsmka_dequeue_msgbuf(path_t *path);
extern msgbuf_elem_t *rsmka_gethead_msgbuf(path_t *path);
static int rsm_open(dev_t *, int, int, cred_t *);
static int rsm_close(dev_t, int, int, cred_t *);
static int rsm_ioctl(dev_t dev, int cmd, intptr_t arg, int mode,
cred_t *credp, int *rvalp);
static int rsm_devmap(dev_t, devmap_cookie_t, offset_t, size_t, size_t *,
uint_t);
static int rsm_segmap(dev_t, off_t, struct as *, caddr_t *, off_t, uint_t,
uint_t, uint_t, cred_t *);
static int rsm_chpoll(dev_t dev, short events, int anyyet, short *reventsp,
struct pollhead **phpp);
static int rsm_info(dev_info_t *, ddi_info_cmd_t, void *, void **);
static int rsm_attach(dev_info_t *, ddi_attach_cmd_t);
static int rsm_detach(dev_info_t *, ddi_detach_cmd_t);
static int rsmipc_send(rsm_node_id_t, rsmipc_request_t *, rsmipc_reply_t *);
static void rsm_force_unload(rsm_node_id_t, rsm_memseg_id_t, boolean_t);
static void rsm_send_importer_disconnects(rsm_memseg_id_t, rsm_node_id_t);
static void rsm_send_republish(rsm_memseg_id_t, rsmapi_access_entry_t *, int,
rsm_permission_t);
static void rsm_export_force_destroy(ddi_umem_cookie_t *);
static void rsmacl_free(rsmapi_access_entry_t *, int);
static void rsmpiacl_free(rsm_access_entry_t *, int);
static int rsm_inc_pgcnt(pgcnt_t);
static void rsm_dec_pgcnt(pgcnt_t);
static void rsm_free_mapinfo(rsm_mapinfo_t *mapinfop);
static rsm_mapinfo_t *rsm_get_mapinfo(rsmseg_t *, off_t, size_t, off_t *,
size_t *);
static void exporter_quiesce();
static void rsmseg_suspend(rsmseg_t *, int *);
static void rsmsegshare_suspend(rsmseg_t *);
static int rsmseg_resume(rsmseg_t *, void **);
static int rsmsegshare_resume(rsmseg_t *);
static struct cb_ops rsm_cb_ops = {
rsm_open,
rsm_close,
nodev,
nodev,
nodev,
nodev,
nodev,
rsm_ioctl,
rsm_devmap,
NULL,
rsm_segmap,
rsm_chpoll,
ddi_prop_op,
0,
D_NEW|D_MP|D_DEVMAP,
0,
0,
0
};
static struct dev_ops rsm_ops = {
DEVO_REV,
0,
rsm_info,
nulldev,
nulldev,
rsm_attach,
rsm_detach,
nodev,
&rsm_cb_ops,
(struct bus_ops *)0,
0,
ddi_quiesce_not_needed,
};
static struct modldrv modldrv = {
&mod_driverops,
"Remote Shared Memory Driver",
&rsm_ops,
};
static struct modlinkage modlinkage = {
MODREV_1,
(void *)&modldrv,
0,
0,
0
};
static void rsm_dr_callback_post_add(void *arg, pgcnt_t delta);
static int rsm_dr_callback_pre_del(void *arg, pgcnt_t delta);
static void rsm_dr_callback_post_del(void *arg, pgcnt_t delta, int cancelled);
static kphysm_setup_vector_t rsm_dr_callback_vec = {
KPHYSM_SETUP_VECTOR_VERSION,
rsm_dr_callback_post_add,
rsm_dr_callback_pre_del,
rsm_dr_callback_post_del
};
int rsmka_modunloadok = 1;
int no_reply_cnt = 0;
uint64_t rsm_ctrlmsg_errcnt = 0;
uint64_t rsm_ipcsend_errcnt = 0;
#define MAX_NODES 64
static struct rsm_driver_data rsm_drv_data;
static struct rsmresource_table rsm_resource;
static void rsmresource_insert(minor_t, rsmresource_t *, rsm_resource_type_t);
static void rsmresource_destroy(void);
static int rsmresource_alloc(minor_t *);
static rsmresource_t *rsmresource_free(minor_t rnum);
static int rsm_closeconnection(rsmseg_t *seg, void **cookie);
static int rsm_unpublish(rsmseg_t *seg, int mode);
static int rsm_unbind(rsmseg_t *seg);
static uint_t rsmhash(rsm_memseg_id_t key);
static void rsmhash_alloc(rsmhash_table_t *rhash, int size);
static void rsmhash_free(rsmhash_table_t *rhash, int size);
static void *rsmhash_getbkt(rsmhash_table_t *rhash, uint_t hashval);
static void **rsmhash_bktaddr(rsmhash_table_t *rhash, uint_t hashval);
static int rsm_send_notimporting(rsm_node_id_t dest, rsm_memseg_id_t segid,
void *cookie);
int rsm_disconnect(rsmseg_t *seg);
void rsmseg_unload(rsmseg_t *);
void rsm_suspend_complete(rsm_node_id_t src_node, int flag);
rsm_intr_hand_ret_t 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);
static void rsm_intr_callback(void *, rsm_addr_t, rsm_intr_hand_arg_t);
rsm_node_id_t my_nodeid;
static rsm_gnum_t *bar_va;
static ddi_umem_cookie_t bar_cookie;
static off_t barrier_offset;
static size_t barrier_size;
static int max_segs;
static ddi_umem_cookie_t remap_cookie;
static rsm_memseg_id_t rsm_nextavail_segmentid;
extern taskq_t *work_taskq;
extern char *taskq_name;
static dev_info_t *rsm_dip;
static rsmhash_table_t rsm_export_segs;
rsmhash_table_t rsm_import_segs;
static rsmhash_table_t rsm_event_queues;
static rsm_ipc_t rsm_ipc;
static list_head_t rsm_suspend_list;
static importers_table_t importer_list;
kmutex_t rsm_suspend_cvlock;
kcondvar_t rsm_suspend_cv;
static kmutex_t rsm_lock;
adapter_t loopback_adapter;
rsm_controller_attr_t loopback_attr;
int rsmipc_send_controlmsg(path_t *path, int msgtype);
void rsmka_init_loopback();
int rsmka_null_seg_create(
rsm_controller_handle_t,
rsm_memseg_export_handle_t *,
size_t,
uint_t,
rsm_memory_local_t *,
rsm_resource_callback_t,
rsm_resource_callback_arg_t);
int rsmka_null_seg_destroy(
rsm_memseg_export_handle_t);
int rsmka_null_bind(
rsm_memseg_export_handle_t,
off_t,
rsm_memory_local_t *,
rsm_resource_callback_t,
rsm_resource_callback_arg_t);
int rsmka_null_unbind(
rsm_memseg_export_handle_t,
off_t,
size_t);
int rsmka_null_rebind(
rsm_memseg_export_handle_t,
off_t,
rsm_memory_local_t *,
rsm_resource_callback_t,
rsm_resource_callback_arg_t);
int rsmka_null_publish(
rsm_memseg_export_handle_t,
rsm_access_entry_t [],
uint_t,
rsm_memseg_id_t,
rsm_resource_callback_t,
rsm_resource_callback_arg_t);
int rsmka_null_republish(
rsm_memseg_export_handle_t,
rsm_access_entry_t [],
uint_t,
rsm_resource_callback_t,
rsm_resource_callback_arg_t);
int rsmka_null_unpublish(
rsm_memseg_export_handle_t);
rsm_ops_t null_rsmpi_ops;
static pgcnt_t rsm_pgcnt;
static pgcnt_t rsm_pgcnt_max;
static kmutex_t rsm_pgcnt_lock;
static int rsm_enable_dr;
static char loopback_str[] = "loopback";
int rsm_hash_size;
int
_init(void)
{
int e;
e = mod_install(&modlinkage);
if (e != 0) {
return (e);
}
mutex_init(&rsm_lock, NULL, MUTEX_DRIVER, NULL);
mutex_init(&rsmka_buf_lock, NULL, MUTEX_DEFAULT, NULL);
rw_init(&rsm_resource.rsmrc_lock, NULL, RW_DRIVER, NULL);
rsm_hash_size = RSM_HASHSZ;
rw_init(&rsm_export_segs.rsmhash_rw, NULL, RW_DRIVER, NULL);
rw_init(&rsm_import_segs.rsmhash_rw, NULL, RW_DRIVER, NULL);
mutex_init(&importer_list.lock, NULL, MUTEX_DRIVER, NULL);
mutex_init(&rsm_ipc.lock, NULL, MUTEX_DRIVER, NULL);
cv_init(&rsm_ipc.cv, NULL, CV_DRIVER, 0);
mutex_init(&rsm_suspend_cvlock, NULL, MUTEX_DRIVER, NULL);
cv_init(&rsm_suspend_cv, NULL, CV_DRIVER, 0);
mutex_init(&rsm_drv_data.drv_lock, NULL, MUTEX_DRIVER, NULL);
cv_init(&rsm_drv_data.drv_cv, NULL, CV_DRIVER, 0);
rsm_ipc.count = RSMIPC_SZ;
rsm_ipc.wanted = 0;
rsm_ipc.sequence = 0;
(void) mutex_init(&rsm_pgcnt_lock, NULL, MUTEX_DRIVER, NULL);
for (e = 0; e < RSMIPC_SZ; e++) {
rsmipc_slot_t *slot = &rsm_ipc.slots[e];
RSMIPC_SET(slot, RSMIPC_FREE);
mutex_init(&slot->rsmipc_lock, NULL, MUTEX_DRIVER, NULL);
cv_init(&slot->rsmipc_cv, NULL, CV_DRIVER, 0);
}
rsm_suspend_list.list_head = NULL;
mutex_init(&rsm_suspend_list.list_lock, NULL, MUTEX_DRIVER, NULL);
rsmka_pathmanager_init();
DBG_PRINTF((RSM_KERNEL_AGENT, RSM_DEBUG_VERBOSE,
"rsm: _init done\n"));
return (DDI_SUCCESS);
}
int
_info(struct modinfo *modinfop)
{
return (mod_info(&modlinkage, modinfop));
}
int
_fini(void)
{
int e;
DBG_PRINTF((RSM_KERNEL_AGENT, RSM_DEBUG_VERBOSE,
"rsm: _fini enter\n"));
if (rsmka_modunloadok == 0)
return (EBUSY);
e = mod_remove(&modlinkage);
if (e) {
DBG_PRINTF((RSM_KERNEL_AGENT, RSM_ERR,
"Unable to fini RSM %x\n", e));
return (e);
}
rsmka_pathmanager_cleanup();
rw_destroy(&rsm_resource.rsmrc_lock);
rw_destroy(&rsm_export_segs.rsmhash_rw);
rw_destroy(&rsm_import_segs.rsmhash_rw);
rw_destroy(&rsm_event_queues.rsmhash_rw);
mutex_destroy(&importer_list.lock);
mutex_destroy(&rsm_ipc.lock);
cv_destroy(&rsm_ipc.cv);
(void) mutex_destroy(&rsm_suspend_list.list_lock);
(void) mutex_destroy(&rsm_pgcnt_lock);
DBG_PRINTF((RSM_KERNEL_AGENT, RSM_DEBUG_VERBOSE, "_fini done\n"));
return (DDI_SUCCESS);
}
static int
rsm_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
{
minor_t rnum;
int percent;
int ret;
DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_DDI);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_attach enter\n"));
switch (cmd) {
case DDI_ATTACH:
break;
case DDI_RESUME:
default:
DBG_PRINTF((category, RSM_ERR,
"rsm:rsm_attach - cmd not supported\n"));
return (DDI_FAILURE);
}
if (rsm_dip != NULL) {
DBG_PRINTF((category, RSM_ERR,
"rsm:rsm_attach - supports only "
"one instance\n"));
return (DDI_FAILURE);
}
rsm_enable_dr = ddi_prop_get_int(DDI_DEV_T_ANY, devi,
DDI_PROP_DONTPASS | DDI_PROP_NOTPROM,
"enable-dynamic-reconfiguration", 1);
mutex_enter(&rsm_drv_data.drv_lock);
rsm_drv_data.drv_state = RSM_DRV_REG_PROCESSING;
mutex_exit(&rsm_drv_data.drv_lock);
if (rsm_enable_dr) {
#ifdef RSM_DRTEST
ret = rsm_kphysm_setup_func_register(&rsm_dr_callback_vec,
(void *)NULL);
#else
ret = kphysm_setup_func_register(&rsm_dr_callback_vec,
(void *)NULL);
#endif
if (ret != 0) {
mutex_exit(&rsm_drv_data.drv_lock);
cmn_err(CE_CONT, "rsm:rsm_attach - Dynamic "
"reconfiguration setup failed\n");
return (DDI_FAILURE);
}
}
mutex_enter(&rsm_drv_data.drv_lock);
ASSERT(rsm_drv_data.drv_state == RSM_DRV_REG_PROCESSING);
rsm_drv_data.drv_state = RSM_DRV_OK;
cv_broadcast(&rsm_drv_data.drv_cv);
mutex_exit(&rsm_drv_data.drv_lock);
rsm_hash_size = ddi_prop_get_int(DDI_DEV_T_ANY, devi,
DDI_PROP_DONTPASS | DDI_PROP_NOTPROM,
"segment-hashtable-size", RSM_HASHSZ);
if (rsm_hash_size == 0) {
DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
"rsm: segment-hashtable-size in rsm.conf "
"must be greater than 0, defaulting to 128\n"));
rsm_hash_size = RSM_HASHSZ;
}
DBG_PRINTF((category, RSM_DEBUG, "rsm_attach rsm_hash_size: %d\n",
rsm_hash_size));
rsm_pgcnt = 0;
percent = ddi_prop_get_int(DDI_DEV_T_ANY, devi,
DDI_PROP_DONTPASS | DDI_PROP_NOTPROM,
"max-exported-memory", 0);
if (percent < 0) {
DBG_PRINTF((category, RSM_ERR,
"rsm:rsm_attach not enough memory available to "
"export, or max-exported-memory set incorrectly.\n"));
return (DDI_FAILURE);
}
rsm_pgcnt_max = (percent*maxmem)/100;
if (rsm_pgcnt_max > 0) {
DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
"rsm: Available physical memory = %lu pages, "
"Max exportable memory = %lu pages",
maxmem, rsm_pgcnt_max));
}
if (rsmresource_alloc(&rnum) != RSM_SUCCESS) {
DBG_PRINTF((category, RSM_ERR,
"rsm: rsm_attach - Unable to get "
"minor number\n"));
return (DDI_FAILURE);
}
ASSERT(rnum == RSM_DRIVER_MINOR);
if (ddi_create_minor_node(devi, DRIVER_NAME, S_IFCHR,
rnum, DDI_PSEUDO, 0) == DDI_FAILURE) {
DBG_PRINTF((category, RSM_ERR,
"rsm: rsm_attach - unable to allocate "
"minor #\n"));
return (DDI_FAILURE);
}
rsm_dip = devi;
rsmhash_alloc(&rsm_export_segs, rsm_hash_size);
rsmhash_alloc(&rsm_import_segs, rsm_hash_size);
importer_list.bucket = (importing_token_t **)
kmem_zalloc(rsm_hash_size * sizeof (importing_token_t *), KM_SLEEP);
{
rsmresource_t *p;
p = (rsmresource_t *)kmem_zalloc(sizeof (*p), KM_SLEEP);
mutex_init(&p->rsmrc_lock, NULL, MUTEX_DRIVER, (void *) NULL);
rsmresource_insert(rnum, p, RSM_RESOURCE_BAR);
}
max_segs = ddi_prop_get_int(DDI_DEV_T_ANY, devi,
DDI_PROP_DONTPASS | DDI_PROP_NOTPROM,
"max-segments", 0);
if (max_segs == 0) {
max_segs = RSM_MAX_NUM_SEG;
}
barrier_size = roundup((max_segs + 1) * sizeof (rsm_gnum_t),
PAGESIZE);
bar_va = (rsm_gnum_t *)ddi_umem_alloc(barrier_size,
DDI_UMEM_SLEEP, &bar_cookie);
barrier_offset = 0;
(void) ddi_umem_alloc((size_t)TRASHSIZE,
DDI_UMEM_TRASH, &remap_cookie);
rsm_nextavail_segmentid = (rsm_memseg_id_t)RSM_USER_APP_ID_BASE;
rsmka_init_loopback();
ddi_report_dev(devi);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_attach done\n"));
return (DDI_SUCCESS);
}
static int
rsm_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
{
DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_DDI);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_detach enter\n"));
switch (cmd) {
case DDI_DETACH:
break;
default:
DBG_PRINTF((category, RSM_ERR,
"rsm:rsm_detach - cmd %x not supported\n",
cmd));
return (DDI_FAILURE);
}
mutex_enter(&rsm_drv_data.drv_lock);
while (rsm_drv_data.drv_state != RSM_DRV_OK)
cv_wait(&rsm_drv_data.drv_cv, &rsm_drv_data.drv_lock);
rsm_drv_data.drv_state = RSM_DRV_UNREG_PROCESSING;
mutex_exit(&rsm_drv_data.drv_lock);
if (rsm_enable_dr) {
#ifdef RSM_DRTEST
rsm_kphysm_setup_func_unregister(&rsm_dr_callback_vec,
(void *)NULL);
#else
kphysm_setup_func_unregister(&rsm_dr_callback_vec,
(void *)NULL);
#endif
}
mutex_enter(&rsm_drv_data.drv_lock);
ASSERT(rsm_drv_data.drv_state == RSM_DRV_UNREG_PROCESSING);
rsm_drv_data.drv_state = RSM_DRV_NEW;
mutex_exit(&rsm_drv_data.drv_lock);
ASSERT(rsm_suspend_list.list_head == NULL);
ddi_remove_minor_node(dip, DRIVER_NAME);
rsm_dip = NULL;
{
rsmresource_t *p;
p = rsmresource_free(RSM_DRIVER_MINOR);
if (p) {
mutex_destroy(&p->rsmrc_lock);
kmem_free((void *)p, sizeof (*p));
}
}
rsmresource_destroy();
rsmhash_free(&rsm_export_segs, rsm_hash_size);
rsmhash_free(&rsm_import_segs, rsm_hash_size);
kmem_free((void *)importer_list.bucket,
rsm_hash_size * sizeof (importing_token_t *));
importer_list.bucket = NULL;
if (bar_cookie != NULL) {
ddi_umem_free(bar_cookie);
}
bar_va = NULL;
bar_cookie = NULL;
if (remap_cookie != NULL) {
ddi_umem_free(remap_cookie);
}
remap_cookie = NULL;
DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_detach done\n"));
return (DDI_SUCCESS);
}
static int
rsm_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
{
register int error;
DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_DDI);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_info enter\n"));
switch (infocmd) {
case DDI_INFO_DEVT2DEVINFO:
if (rsm_dip == NULL)
error = DDI_FAILURE;
else {
*result = (void *)rsm_dip;
error = DDI_SUCCESS;
}
break;
case DDI_INFO_DEVT2INSTANCE:
*result = (void *)0;
error = DDI_SUCCESS;
break;
default:
error = DDI_FAILURE;
}
DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_info done\n"));
return (error);
}
adapter_t *
rsm_getadapter(rsm_ioctlmsg_t *msg, int mode)
{
adapter_t *adapter;
char adapter_devname[MAXNAMELEN];
int instance;
DBG_DEFINE(category,
RSM_KERNEL_AGENT | RSM_IMPORT | RSM_EXPORT | RSM_IOCTL);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_getadapter enter\n"));
instance = msg->cnum;
if ((msg->cname_len <= 0) || (msg->cname_len > MAXNAMELEN)) {
return (NULL);
}
if (ddi_copyin(msg->cname, adapter_devname, msg->cname_len, mode))
return (NULL);
if (strcmp(adapter_devname, "loopback") == 0)
return (&loopback_adapter);
adapter = rsmka_lookup_adapter(adapter_devname, instance);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_getadapter done\n"));
return (adapter);
}
static int
rsmresource_alloc(minor_t *rnum)
{
int i, j, empty = -1;
rsmresource_blk_t *blk;
DBG_PRINTF((RSM_KERNEL_ALL, RSM_DEBUG_VERBOSE,
"rsmresource_alloc enter\n"));
rw_enter(&rsm_resource.rsmrc_lock, RW_WRITER);
for (i = 0; i < rsm_resource.rsmrc_len; i++) {
blk = rsm_resource.rsmrc_root[i];
if (blk != NULL && blk->rsmrcblk_avail > 0) {
for (j = 0; j < RSMRC_BLKSZ; j++) {
if (blk->rsmrcblk_blks[j] == NULL) {
*rnum = (minor_t)
(j + (i * RSMRC_BLKSZ));
if (*rnum >= max_segs + 1) {
if (empty < 0) {
rw_exit(&rsm_resource.
rsmrc_lock);
DBG_PRINTF((
RSM_KERNEL_ALL,
RSM_ERR,
"rsmresource"
"_alloc failed:"
"not enough res"
"%d\n", *rnum));
return (RSMERR_INSUFFICIENT_RESOURCES);
} else {
break;
}
}
blk->rsmrcblk_blks[j] = RSMRC_RESERVED;
blk->rsmrcblk_avail--;
rw_exit(&rsm_resource.rsmrc_lock);
DBG_PRINTF((RSM_KERNEL_ALL,
RSM_DEBUG_VERBOSE,
"rsmresource_alloc done\n"));
return (RSM_SUCCESS);
}
}
} else if (blk == NULL && empty < 0) {
empty = i;
}
}
if (empty < 0) {
if (rsm_resource.rsmrc_len == rsm_resource.rsmrc_sz) {
rsmresource_blk_t **p;
uint_t newsz = (uint_t)rsm_resource.rsmrc_sz +
RSMRC_BLKSZ;
if (rsm_resource.rsmrc_len*RSMRC_BLKSZ >=
max_segs + 1) {
rw_exit(&rsm_resource.rsmrc_lock);
return (RSMERR_INSUFFICIENT_RESOURCES);
}
p = (rsmresource_blk_t **)kmem_zalloc(
newsz * sizeof (*p),
KM_SLEEP);
if (rsm_resource.rsmrc_root) {
uint_t oldsz;
oldsz = (uint_t)(rsm_resource.rsmrc_sz *
(int)sizeof (*p));
bcopy(rsm_resource.rsmrc_root, p, oldsz);
kmem_free(rsm_resource.rsmrc_root, oldsz);
}
rsm_resource.rsmrc_root = p;
rsm_resource.rsmrc_sz = (int)newsz;
}
empty = rsm_resource.rsmrc_len;
rsm_resource.rsmrc_len++;
}
blk = (rsmresource_blk_t *)kmem_zalloc(sizeof (*blk), KM_SLEEP);
ASSERT(rsm_resource.rsmrc_root[empty] == NULL);
rsm_resource.rsmrc_root[empty] = blk;
blk->rsmrcblk_avail = RSMRC_BLKSZ - 1;
*rnum = (minor_t)(empty * RSMRC_BLKSZ);
if (*rnum >= max_segs + 1) {
rw_exit(&rsm_resource.rsmrc_lock);
DBG_PRINTF((RSM_KERNEL_ALL, RSM_ERR,
"rsmresource_alloc failed %d\n", *rnum));
return (RSMERR_INSUFFICIENT_RESOURCES);
}
blk->rsmrcblk_blks[0] = RSMRC_RESERVED;
rw_exit(&rsm_resource.rsmrc_lock);
DBG_PRINTF((RSM_KERNEL_ALL, RSM_DEBUG_VERBOSE,
"rsmresource_alloc done\n"));
return (RSM_SUCCESS);
}
static rsmresource_t *
rsmresource_free(minor_t rnum)
{
int i, j;
rsmresource_blk_t *blk;
rsmresource_t *p;
DBG_PRINTF((RSM_KERNEL_ALL, RSM_DEBUG_VERBOSE,
"rsmresource_free enter\n"));
i = (int)(rnum / RSMRC_BLKSZ);
j = (int)(rnum % RSMRC_BLKSZ);
if (i >= rsm_resource.rsmrc_len) {
DBG_PRINTF((RSM_KERNEL_ALL, RSM_DEBUG_VERBOSE,
"rsmresource_free done\n"));
return (NULL);
}
rw_enter(&rsm_resource.rsmrc_lock, RW_WRITER);
ASSERT(rsm_resource.rsmrc_root);
ASSERT(i < rsm_resource.rsmrc_len);
ASSERT(i < rsm_resource.rsmrc_sz);
blk = rsm_resource.rsmrc_root[i];
if (blk == NULL) {
rw_exit(&rsm_resource.rsmrc_lock);
DBG_PRINTF((RSM_KERNEL_ALL, RSM_DEBUG_VERBOSE,
"rsmresource_free done\n"));
return (NULL);
}
ASSERT(blk->rsmrcblk_blks[j]);
p = blk->rsmrcblk_blks[j];
if (p == RSMRC_RESERVED) {
p = NULL;
}
blk->rsmrcblk_blks[j] = NULL;
blk->rsmrcblk_avail++;
if (blk->rsmrcblk_avail == RSMRC_BLKSZ) {
kmem_free(blk, sizeof (*blk));
rsm_resource.rsmrc_root[i] = NULL;
}
rw_exit(&rsm_resource.rsmrc_lock);
DBG_PRINTF((RSM_KERNEL_ALL, RSM_DEBUG_VERBOSE,
"rsmresource_free done\n"));
return (p);
}
static rsmresource_t *
rsmresource_lookup(minor_t rnum, int lock)
{
int i, j;
rsmresource_blk_t *blk;
rsmresource_t *p;
DBG_PRINTF((RSM_KERNEL_ALL, RSM_DEBUG_VERBOSE,
"rsmresource_lookup enter\n"));
i = (int)(rnum / RSMRC_BLKSZ);
j = (int)(rnum % RSMRC_BLKSZ);
if (i >= rsm_resource.rsmrc_len) {
DBG_PRINTF((RSM_KERNEL_ALL, RSM_DEBUG_VERBOSE,
"rsmresource_lookup done\n"));
return (NULL);
}
rw_enter(&rsm_resource.rsmrc_lock, RW_READER);
blk = rsm_resource.rsmrc_root[i];
if (blk != NULL) {
ASSERT(i < rsm_resource.rsmrc_len);
ASSERT(i < rsm_resource.rsmrc_sz);
p = blk->rsmrcblk_blks[j];
if (lock == RSM_LOCK) {
if (p != RSMRC_RESERVED) {
mutex_enter(&p->rsmrc_lock);
} else {
p = NULL;
}
}
} else {
p = NULL;
}
rw_exit(&rsm_resource.rsmrc_lock);
DBG_PRINTF((RSM_KERNEL_ALL, RSM_DEBUG_VERBOSE,
"rsmresource_lookup done\n"));
return (p);
}
static void
rsmresource_insert(minor_t rnum, rsmresource_t *p, rsm_resource_type_t type)
{
int i, j;
rsmresource_blk_t *blk;
DBG_PRINTF((RSM_KERNEL_ALL, RSM_DEBUG_VERBOSE,
"rsmresource_insert enter\n"));
i = (int)(rnum / RSMRC_BLKSZ);
j = (int)(rnum % RSMRC_BLKSZ);
p->rsmrc_type = type;
p->rsmrc_num = rnum;
rw_enter(&rsm_resource.rsmrc_lock, RW_READER);
ASSERT(rsm_resource.rsmrc_root);
ASSERT(i < rsm_resource.rsmrc_len);
ASSERT(i < rsm_resource.rsmrc_sz);
blk = rsm_resource.rsmrc_root[i];
ASSERT(blk);
ASSERT(blk->rsmrcblk_blks[j] == RSMRC_RESERVED);
blk->rsmrcblk_blks[j] = p;
DBG_PRINTF((RSM_KERNEL_ALL, RSM_DEBUG_VERBOSE,
"rsmresource_insert done\n"));
rw_exit(&rsm_resource.rsmrc_lock);
}
static void
rsmresource_destroy()
{
int i, j;
DBG_PRINTF((RSM_KERNEL_ALL, RSM_DEBUG_VERBOSE,
"rsmresource_destroy enter\n"));
rw_enter(&rsm_resource.rsmrc_lock, RW_WRITER);
for (i = 0; i < rsm_resource.rsmrc_len; i++) {
rsmresource_blk_t *blk;
blk = rsm_resource.rsmrc_root[i];
if (blk == NULL) {
continue;
}
for (j = 0; j < RSMRC_BLKSZ; j++) {
if (blk->rsmrcblk_blks[j] != NULL) {
DBG_PRINTF((RSM_KERNEL_ALL, RSM_DEBUG_VERBOSE,
"Not null slot %d, %lx\n", j,
(size_t)blk->rsmrcblk_blks[j]));
}
}
kmem_free(blk, sizeof (*blk));
rsm_resource.rsmrc_root[i] = NULL;
}
if (rsm_resource.rsmrc_root) {
i = rsm_resource.rsmrc_sz * (int)sizeof (rsmresource_blk_t *);
kmem_free(rsm_resource.rsmrc_root, (uint_t)i);
rsm_resource.rsmrc_root = NULL;
rsm_resource.rsmrc_len = 0;
rsm_resource.rsmrc_sz = 0;
}
DBG_PRINTF((RSM_KERNEL_ALL, RSM_DEBUG_VERBOSE,
"rsmresource_destroy done\n"));
rw_exit(&rsm_resource.rsmrc_lock);
}
static rsmresource_t *
rsmhash_lookup(rsmhash_table_t *rhash, rsm_memseg_id_t key,
rsm_resource_state_t state)
{
rsmresource_t *p;
uint_t hashval;
DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_FUNC_ALL);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmhash_lookup enter\n"));
hashval = rsmhash(key);
DBG_PRINTF((category, RSM_DEBUG_LVL2, "rsmhash_lookup %u=%d\n",
key, hashval));
rw_enter(&rhash->rsmhash_rw, RW_READER);
p = (rsmresource_t *)rsmhash_getbkt(rhash, hashval);
for (; p; p = p->rsmrc_next) {
if (p->rsmrc_key == key) {
RSMRC_LOCK(p);
break;
}
}
rw_exit(&rhash->rsmhash_rw);
if (p != NULL && p->rsmrc_state != state) {
RSMRC_UNLOCK(p);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
"rsmhash_lookup done: state changed\n"));
return (NULL);
}
DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmhash_lookup done\n"));
return (p);
}
static void
rsmhash_rm(rsmhash_table_t *rhash, rsmresource_t *rcelm)
{
rsmresource_t *p, **back;
uint_t hashval;
DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_FUNC_ALL);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmhash_rm enter\n"));
hashval = rsmhash(rcelm->rsmrc_key);
DBG_PRINTF((category, RSM_DEBUG_LVL2, "rsmhash_rm %u=%d\n",
rcelm->rsmrc_key, hashval));
rw_enter(&rhash->rsmhash_rw, RW_WRITER);
back = (rsmresource_t **)rsmhash_bktaddr(rhash, hashval);
for (; (p = *back) != NULL; back = &p->rsmrc_next) {
if (p == rcelm) {
*back = rcelm->rsmrc_next;
break;
}
}
DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmhash_rm done\n"));
rw_exit(&rhash->rsmhash_rw);
}
static int
rsmhash_add(rsmhash_table_t *rhash, rsmresource_t *new, rsm_memseg_id_t key,
int dup_check, rsm_resource_state_t state)
{
rsmresource_t *p = NULL, **bktp;
uint_t hashval;
DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_FUNC_ALL);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmhash_add enter\n"));
rw_enter(&rhash->rsmhash_rw, RW_WRITER);
RSMRC_LOCK(new);
if (new->rsmrc_state != state) {
RSMRC_UNLOCK(new);
rw_exit(&rhash->rsmhash_rw);
return (RSMERR_BAD_SEG_HNDL);
}
hashval = rsmhash(key);
DBG_PRINTF((category, RSM_DEBUG_LVL2, "rsmhash_add %d\n", hashval));
if (dup_check) {
p = (rsmresource_t *)rsmhash_getbkt(rhash, hashval);
for (; p; p = p->rsmrc_next) {
if (p->rsmrc_key == key) {
RSMRC_UNLOCK(new);
break;
}
}
}
if (p == NULL) {
bktp = (rsmresource_t **)rsmhash_bktaddr(rhash, hashval);
new->rsmrc_key = key;
new->rsmrc_next = *bktp;
*bktp = new;
}
rw_exit(&rhash->rsmhash_rw);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmhash_add done\n"));
return (p == NULL ? RSM_SUCCESS : RSMERR_SEGID_IN_USE);
}
static uint_t
rsmhash(rsm_memseg_id_t key)
{
uint_t hash = key;
hash ^= (key >> 8);
hash ^= (key >> 16);
hash ^= (key >> 24);
return (hash % rsm_hash_size);
}
static void *
rsmhash_getbkt(rsmhash_table_t *rhash, uint_t hashval)
{
if (rhash->bucket == NULL)
return (NULL);
else
return ((void *)rhash->bucket[hashval]);
}
static void **
rsmhash_bktaddr(rsmhash_table_t *rhash, uint_t hashval)
{
if (rhash->bucket == NULL)
return (NULL);
else
return ((void **)&(rhash->bucket[hashval]));
}
static void
rsmhash_alloc(rsmhash_table_t *rhash, int size)
{
rhash->bucket = (rsmresource_t **)
kmem_zalloc(size * sizeof (rsmresource_t *), KM_SLEEP);
}
static void
rsmhash_free(rsmhash_table_t *rhash, int size)
{
kmem_free((void *)rhash->bucket, size * sizeof (caddr_t));
rhash->bucket = NULL;
}
#define rsmexport_add(new, key) \
rsmhash_add(&rsm_export_segs, (rsmresource_t *)new, key, 1, \
RSM_STATE_BIND)
#define rsmexport_rm(arg) \
rsmhash_rm(&rsm_export_segs, (rsmresource_t *)(arg))
#define rsmexport_lookup(key) \
(rsmseg_t *)rsmhash_lookup(&rsm_export_segs, key, RSM_STATE_EXPORT)
#define rsmimport_add(arg, key) \
rsmhash_add(&rsm_import_segs, (rsmresource_t *)(arg), (key), 0, \
RSM_STATE_NEW)
#define rsmimport_rm(arg) \
rsmhash_rm(&rsm_import_segs, (rsmresource_t *)(arg))
static rsm_import_share_t *
rsmshare_get(rsm_memseg_id_t key, rsm_node_id_t node, adapter_t *adapter,
rsmseg_t *segp)
{
uint_t hash;
rsmresource_t *p;
rsm_import_share_t *shdatap;
DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_FUNC_ALL);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmshare_get enter\n"));
hash = rsmhash(key);
rw_enter(&rsm_import_segs.rsmhash_rw, RW_WRITER);
DBG_PRINTF((category, RSM_DEBUG_LVL2, "rsmshare_get:key=%u, hash=%d\n",
key, hash));
p = (rsmresource_t *)rsmhash_getbkt(&rsm_import_segs, hash);
for (; p; p = p->rsmrc_next) {
if ((p->rsmrc_key == key) &&
(p->rsmrc_node == node) &&
(p->rsmrc_adapter == adapter) &&
(((rsmseg_t *)p)->s_share != NULL)) {
shdatap = ((rsmseg_t *)p)->s_share;
break;
}
}
if (p == NULL) {
shdatap = kmem_zalloc(sizeof (rsm_import_share_t), KM_SLEEP);
shdatap->rsmsi_state = RSMSI_STATE_NEW;
shdatap->rsmsi_segid = key;
shdatap->rsmsi_node = node;
mutex_init(&shdatap->rsmsi_lock, NULL, MUTEX_DRIVER, NULL);
cv_init(&shdatap->rsmsi_cv, NULL, CV_DRIVER, 0);
}
rsmseglock_acquire(segp);
mutex_enter(&shdatap->rsmsi_lock);
shdatap->rsmsi_refcnt++;
segp->s_share = shdatap;
rsmseglock_release(segp);
rw_exit(&rsm_import_segs.rsmhash_rw);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmshare_get done\n"));
return (shdatap);
}
void
rsmsharecv_signal(rsmseg_t *seg, int oldstate, int newstate)
{
ASSERT(rsmsharelock_held(seg));
if (seg->s_share->rsmsi_state == oldstate) {
seg->s_share->rsmsi_state = newstate;
cv_broadcast(&seg->s_share->rsmsi_cv);
}
}
static void
importer_list_add(rsm_node_id_t node, rsm_memseg_id_t key, rsm_addr_t hwaddr,
void *cookie)
{
importing_token_t *head;
importing_token_t *new_token;
int index;
DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_FUNC_ALL);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "importer_list_add enter\n"));
new_token = kmem_zalloc(sizeof (importing_token_t), KM_SLEEP);
new_token->importing_node = node;
new_token->key = key;
new_token->import_segment_cookie = cookie;
new_token->importing_adapter_hwaddr = hwaddr;
index = rsmhash(key);
mutex_enter(&importer_list.lock);
head = importer_list.bucket[index];
importer_list.bucket[index] = new_token;
new_token->next = head;
mutex_exit(&importer_list.lock);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "importer_list_add done\n"));
}
static void
importer_list_rm(rsm_node_id_t node, rsm_memseg_id_t key, void *cookie)
{
importing_token_t *prev, *token = NULL;
int index;
DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_FUNC_ALL);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "importer_list_rm enter\n"));
index = rsmhash(key);
mutex_enter(&importer_list.lock);
token = importer_list.bucket[index];
prev = token;
while (token != NULL) {
if (token->importing_node == node &&
token->import_segment_cookie == cookie) {
if (prev == token)
importer_list.bucket[index] = token->next;
else
prev->next = token->next;
kmem_free((void *)token, sizeof (*token));
break;
} else {
prev = token;
token = token->next;
}
}
mutex_exit(&importer_list.lock);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "importer_list_rm done\n"));
}
static void
rsmseg_free(rsmseg_t *seg)
{
DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_FUNC_ALL);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmseg_free enter\n"));
rsmseglock_acquire(seg);
if (seg->s_ckl != NULL) {
seg->s_state = RSM_STATE_END;
rsmseglock_release(seg);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
"rsmseg_free done\n"));
return;
}
rsmseglock_release(seg);
ASSERT(seg->s_state == RSM_STATE_END || seg->s_state == RSM_STATE_NEW);
if (seg->s_share != NULL) {
ASSERT(seg->s_type == RSM_RESOURCE_IMPORT_SEGMENT);
rsmsharelock_acquire(seg);
ASSERT(seg->s_share->rsmsi_refcnt > 0);
seg->s_share->rsmsi_refcnt--;
if (seg->s_share->rsmsi_refcnt == 0) {
rsmsharelock_release(seg);
mutex_destroy(&seg->s_share->rsmsi_lock);
cv_destroy(&seg->s_share->rsmsi_cv);
kmem_free((void *)(seg->s_share),
sizeof (rsm_import_share_t));
} else {
rsmsharelock_release(seg);
}
seg->s_share = NULL;
}
cv_destroy(&seg->s_cv);
mutex_destroy(&seg->s_lock);
rsmacl_free(seg->s_acl, seg->s_acl_len);
rsmpiacl_free(seg->s_acl_in, seg->s_acl_len);
if (seg->s_adapter)
rsmka_release_adapter(seg->s_adapter);
kmem_free((void *)seg, sizeof (*seg));
DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmseg_free done\n"));
}
static rsmseg_t *
rsmseg_alloc(minor_t num, struct cred *cred)
{
rsmseg_t *new;
DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_FUNC_ALL);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmseg_alloc enter\n"));
new = (rsmseg_t *)kmem_zalloc(sizeof (*new), KM_SLEEP);
new->s_state = RSM_STATE_NEW;
new->s_minor = num;
new->s_acl_len = 0;
new->s_cookie = NULL;
new->s_adapter = NULL;
new->s_mode = 0777 & ~PTOU((ttoproc(curthread)))->u_cmask;
new->s_uid = crgetuid(cred);
new->s_gid = crgetgid(cred);
mutex_init(&new->s_lock, NULL, MUTEX_DRIVER, (void *)NULL);
cv_init(&new->s_cv, NULL, CV_DRIVER, 0);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmseg_alloc done\n"));
return (new);
}
static int
rsm_open(dev_t *devp, int flag, int otyp, struct cred *cred)
{
minor_t rnum;
DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_FUNC_ALL| RSM_DDI);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_open enter\n"));
if (otyp != OTYP_CHR) {
DBG_PRINTF((category, RSM_ERR, "rsm_open: bad otyp\n"));
return (EINVAL);
}
if (getminor(*devp) != RSM_DRIVER_MINOR) {
DBG_PRINTF((category, RSM_ERR,
"rsm_open: bad minor %d\n", getminor(*devp)));
return (ENODEV);
}
if ((flag & FEXCL) != 0 && secpolicy_excl_open(cred) != 0) {
DBG_PRINTF((category, RSM_ERR, "rsm_open: bad perm\n"));
return (EPERM);
}
if (!(flag & FWRITE)) {
DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
"rsm_open RDONLY done\n"));
return (DDI_SUCCESS);
}
if (rsmresource_alloc(&rnum) == RSM_SUCCESS) {
*devp = makedevice(getmajor(*devp), rnum);
} else {
return (EAGAIN);
}
DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_open done\n"));
return (DDI_SUCCESS);
}
static void
rsmseg_close(rsmseg_t *seg, int force_flag)
{
int e = RSM_SUCCESS;
DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_FUNC_ALL| RSM_DDI);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmseg_close enter\n"));
rsmseglock_acquire(seg);
if (!force_flag && (seg->s_hdr.rsmrc_type ==
RSM_RESOURCE_EXPORT_SEGMENT)) {
while (seg->s_flags & RSM_FORCE_DESTROY_WAIT) {
cv_wait(&seg->s_cv, &seg->s_lock);
}
}
rsmseglock_release(seg);
switch (seg->s_state) {
case RSM_STATE_EXPORT:
case RSM_STATE_EXPORT_QUIESCING:
case RSM_STATE_EXPORT_QUIESCED:
e = rsm_unpublish(seg, 1);
case RSM_STATE_BIND_QUIESCED:
case RSM_STATE_BIND:
e = rsm_unbind(seg);
if (e != RSM_SUCCESS && force_flag == 1)
return;
ASSERT(seg->s_hdr.rsmrc_type == RSM_RESOURCE_EXPORT_SEGMENT);
case RSM_STATE_NEW_QUIESCED:
rsmseglock_acquire(seg);
seg->s_state = RSM_STATE_NEW;
cv_broadcast(&seg->s_cv);
rsmseglock_release(seg);
break;
case RSM_STATE_NEW:
break;
case RSM_STATE_ZOMBIE:
rsmseglock_acquire(seg);
seg->s_state = RSM_STATE_NEW;
rsmseglock_release(seg);
break;
case RSM_STATE_MAP_QUIESCE:
case RSM_STATE_ACTIVE:
case RSM_STATE_CONN_QUIESCE:
case RSM_STATE_CONNECT:
case RSM_STATE_DISCONNECT:
ASSERT(seg->s_hdr.rsmrc_type == RSM_RESOURCE_IMPORT_SEGMENT);
(void) rsm_disconnect(seg);
break;
case RSM_STATE_MAPPING:
case RSM_STATE_END:
DBG_PRINTF((category, RSM_ERR,
"Invalid segment state %d in rsm_close\n", seg->s_state));
break;
default:
DBG_PRINTF((category, RSM_ERR,
"Invalid segment state %d in rsm_close\n", seg->s_state));
break;
}
ASSERT(seg->s_state == RSM_STATE_NEW);
if (force_flag) {
rsmseglock_acquire(seg);
seg->s_state = RSM_STATE_ZOMBIE;
rsmseglock_release(seg);
} else {
rsmseg_free(seg);
}
DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmseg_close done\n"));
}
static int
rsm_close(dev_t dev, int flag, int otyp, cred_t *cred)
{
minor_t rnum = getminor(dev);
rsmresource_t *res;
DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_FUNC_ALL| RSM_DDI);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_close enter\n"));
flag = flag; cred = cred;
if (otyp != OTYP_CHR)
return (EINVAL);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rnum = %d\n", rnum));
if (rnum == RSM_DRIVER_MINOR ||
(res = rsmresource_free(rnum)) == NULL) {
DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_close done\n"));
return (DDI_SUCCESS);
}
switch (res->rsmrc_type) {
case RSM_RESOURCE_EXPORT_SEGMENT:
case RSM_RESOURCE_IMPORT_SEGMENT:
rsmseg_close((rsmseg_t *)res, 0);
break;
case RSM_RESOURCE_BAR:
DBG_PRINTF((category, RSM_ERR, "bad resource in rsm_close\n"));
break;
default:
break;
}
DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_close done\n"));
return (DDI_SUCCESS);
}
static int
rsm_inc_pgcnt(pgcnt_t pnum)
{
DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_EXPORT);
if (rsm_pgcnt_max == 0) {
return (RSM_SUCCESS);
}
mutex_enter(&rsm_pgcnt_lock);
if (rsm_pgcnt + pnum > rsm_pgcnt_max) {
mutex_exit(&rsm_pgcnt_lock);
return (RSMERR_INSUFFICIENT_MEM);
}
rsm_pgcnt += pnum;
DBG_PRINTF((category, RSM_DEBUG, "rsm_pgcnt incr to %d.\n",
rsm_pgcnt));
mutex_exit(&rsm_pgcnt_lock);
return (RSM_SUCCESS);
}
static void
rsm_dec_pgcnt(pgcnt_t pnum)
{
DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_EXPORT);
if (rsm_pgcnt_max == 0) {
return;
}
mutex_enter(&rsm_pgcnt_lock);
ASSERT(rsm_pgcnt >= pnum);
rsm_pgcnt -= pnum;
DBG_PRINTF((category, RSM_DEBUG, "rsm_pgcnt decr to %d.\n",
rsm_pgcnt));
mutex_exit(&rsm_pgcnt_lock);
}
static struct umem_callback_ops rsm_as_ops = {
UMEM_CALLBACK_VERSION,
rsm_export_force_destroy,
};
static int
rsm_bind_pages(ddi_umem_cookie_t *cookie, caddr_t vaddr, size_t len,
proc_t *procp)
{
int error = RSM_SUCCESS;
ulong_t pnum;
struct umem_callback_ops *callbackops = &rsm_as_ops;
DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_EXPORT);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_bind_pages enter\n"));
if ((uintptr_t)vaddr & (PAGESIZE - 1)) {
return (RSMERR_BAD_ADDR);
}
if (len & (PAGESIZE - 1)) {
return (RSMERR_BAD_LENGTH);
}
pnum = btopr(len);
error = rsm_inc_pgcnt(pnum);
if (error != RSM_SUCCESS) {
DBG_PRINTF((category, RSM_ERR,
"rsm_bind_pages:mem limit exceeded\n"));
return (RSMERR_INSUFFICIENT_MEM);
}
error = umem_lockmemory(vaddr, len,
DDI_UMEMLOCK_WRITE|DDI_UMEMLOCK_READ|DDI_UMEMLOCK_LONGTERM,
cookie,
callbackops, procp);
if (error) {
rsm_dec_pgcnt(pnum);
DBG_PRINTF((category, RSM_ERR,
"rsm_bind_pages:ddi_umem_lock failed\n"));
if (error == EFAULT)
return (RSMERR_BAD_ADDR);
else if (error == EACCES)
return (RSMERR_PERM_DENIED);
else
return (RSMERR_INSUFFICIENT_MEM);
}
DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_bind_pages done\n"));
return (error);
}
static int
rsm_unbind_pages(rsmseg_t *seg)
{
DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_EXPORT);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_unbind_pages enter\n"));
ASSERT(rsmseglock_held(seg));
if (seg->s_cookie != NULL) {
ddi_umem_unlock(seg->s_cookie);
rsm_dec_pgcnt(btopr(seg->s_len));
seg->s_cookie = NULL;
}
DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_unbind_pages done\n"));
return (RSM_SUCCESS);
}
static int
rsm_bind(rsmseg_t *seg, rsm_ioctlmsg_t *msg, intptr_t dataptr, int mode)
{
int e;
adapter_t *adapter;
DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_EXPORT);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_bind enter\n"));
adapter = rsm_getadapter(msg, mode);
if (adapter == NULL) {
DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
"rsm_bind done:no adapter\n"));
return (RSMERR_CTLR_NOT_PRESENT);
}
if (msg->vaddr == NULL) {
rsmka_release_adapter(adapter);
DBG_PRINTF((category, RSM_ERR,
"rsm: rsm_bind done: invalid vaddr\n"));
return (RSMERR_BAD_ADDR);
}
if (msg->len <= 0) {
rsmka_release_adapter(adapter);
DBG_PRINTF((category, RSM_ERR,
"rsm_bind: invalid length\n"));
return (RSMERR_BAD_LENGTH);
}
rsmseglock_acquire(seg);
while (seg->s_state == RSM_STATE_NEW_QUIESCED) {
if (cv_wait_sig(&seg->s_cv, &seg->s_lock) == 0) {
DBG_PRINTF((category, RSM_DEBUG,
"rsm_bind done: cv_wait INTERRUPTED"));
rsmka_release_adapter(adapter);
rsmseglock_release(seg);
return (RSMERR_INTERRUPTED);
}
}
ASSERT(seg->s_state == RSM_STATE_NEW);
ASSERT(seg->s_cookie == NULL);
e = rsm_bind_pages(&seg->s_cookie, msg->vaddr, msg->len, curproc);
if (e == RSM_SUCCESS) {
seg->s_flags |= RSM_USER_MEMORY;
if (msg->perm & RSM_ALLOW_REBIND) {
seg->s_flags |= RSMKA_ALLOW_UNBIND_REBIND;
}
if (msg->perm & RSM_CREATE_SEG_DONTWAIT) {
seg->s_flags |= RSMKA_SET_RESOURCE_DONTWAIT;
}
seg->s_region.r_vaddr = msg->vaddr;
seg->s_pid = ddi_get_pid();
seg->s_len = msg->len;
seg->s_state = RSM_STATE_BIND;
seg->s_adapter = adapter;
seg->s_proc = curproc;
} else {
rsmka_release_adapter(adapter);
DBG_PRINTF((category, RSM_WARNING,
"unable to lock down pages\n"));
}
msg->rnum = seg->s_minor;
rsmseglock_release(seg);
if (e == RSM_SUCCESS) {
#ifdef _MULTI_DATAMODEL
if ((mode & DATAMODEL_MASK) == DATAMODEL_ILP32) {
rsm_ioctlmsg32_t msg32;
msg32.rnum = msg->rnum;
if (ddi_copyout((caddr_t)&msg32.rnum,
(caddr_t)&((rsm_ioctlmsg32_t *)dataptr)->rnum,
sizeof (minor_t), mode)) {
rsmka_release_adapter(adapter);
e = RSMERR_BAD_ADDR;
}
}
#endif
if (ddi_copyout((caddr_t)&msg->rnum,
(caddr_t)&((rsm_ioctlmsg_t *)dataptr)->rnum,
sizeof (minor_t), mode)) {
rsmka_release_adapter(adapter);
e = RSMERR_BAD_ADDR;
}
}
DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_bind done\n"));
return (e);
}
static void
rsm_remap_local_importers(rsm_node_id_t src_nodeid,
rsm_memseg_id_t ex_segid, ddi_umem_cookie_t cookie)
{
rsmresource_t *p = NULL;
rsmhash_table_t *rhash = &rsm_import_segs;
uint_t index;
DBG_PRINTF((RSM_KERNEL_AGENT | RSM_FUNC_ALL, RSM_DEBUG_VERBOSE,
"rsm_remap_local_importers enter\n"));
index = rsmhash(ex_segid);
rw_enter(&rhash->rsmhash_rw, RW_READER);
p = rsmhash_getbkt(rhash, index);
for (; p; p = p->rsmrc_next) {
rsmseg_t *seg = (rsmseg_t *)p;
rsmseglock_acquire(seg);
if ((seg->s_segid == ex_segid) && (seg->s_node == src_nodeid) &&
(seg->s_state == RSM_STATE_ACTIVE)) {
seg->s_cookie = cookie;
}
rsmseglock_release(seg);
}
rw_exit(&rhash->rsmhash_rw);
DBG_PRINTF((RSM_KERNEL_AGENT | RSM_FUNC_ALL, RSM_DEBUG_VERBOSE,
"rsm_remap_local_importers done\n"));
}
static int
rsm_rebind(rsmseg_t *seg, rsm_ioctlmsg_t *msg)
{
int e;
adapter_t *adapter;
ddi_umem_cookie_t cookie;
DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_EXPORT);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_rebind enter\n"));
if (!(seg->s_flags & RSMKA_ALLOW_UNBIND_REBIND)) {
return (RSMERR_REBIND_NOT_ALLOWED);
}
if (seg->s_pid != ddi_get_pid() &&
ddi_get_pid() != 0) {
DBG_PRINTF((category, RSM_ERR, "rsm_rebind: Not owner\n"));
return (RSMERR_NOT_CREATOR);
}
if (msg->vaddr == NULL) {
DBG_PRINTF((category, RSM_ERR,
"rsm_rebind done: null msg->vaddr\n"));
return (RSMERR_BAD_ADDR);
}
if (msg->len != seg->s_len) {
DBG_PRINTF((category, RSM_ERR,
"rsm_rebind: invalid length\n"));
return (RSMERR_BAD_LENGTH);
}
rsmseglock_acquire(seg);
while ((seg->s_state == RSM_STATE_BIND_QUIESCED) ||
(seg->s_state == RSM_STATE_EXPORT_QUIESCING) ||
(seg->s_state == RSM_STATE_EXPORT_QUIESCED)) {
if (cv_wait_sig(&seg->s_cv, &seg->s_lock) == 0) {
rsmseglock_release(seg);
DBG_PRINTF((category, RSM_DEBUG,
"rsm_rebind done: cv_wait INTERRUPTED"));
return (RSMERR_INTERRUPTED);
}
}
if ((seg->s_state != RSM_STATE_BIND) &&
(seg->s_state != RSM_STATE_EXPORT)) {
rsmseglock_release(seg);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
"rsm_rebind done: invalid state\n"));
return (RSMERR_BAD_SEG_HNDL);
}
ASSERT(seg->s_cookie != NULL);
if (msg->vaddr == seg->s_region.r_vaddr) {
rsmseglock_release(seg);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_rebind done\n"));
return (RSM_SUCCESS);
}
e = rsm_bind_pages(&cookie, msg->vaddr, msg->len, curproc);
if (e == RSM_SUCCESS) {
struct buf *xbuf;
dev_t sdev = 0;
rsm_memory_local_t mem;
xbuf = ddi_umem_iosetup(cookie, 0, msg->len, B_WRITE,
sdev, 0, NULL, DDI_UMEM_SLEEP);
ASSERT(xbuf != NULL);
mem.ms_type = RSM_MEM_BUF;
mem.ms_bp = xbuf;
adapter = seg->s_adapter;
e = adapter->rsmpi_ops->rsm_rebind(
seg->s_handle.out, 0, &mem,
RSM_RESOURCE_DONTWAIT, NULL);
if (e == RSM_SUCCESS) {
(void) rsm_unbind_pages(seg);
seg->s_cookie = cookie;
seg->s_region.r_vaddr = msg->vaddr;
rsm_remap_local_importers(my_nodeid, seg->s_segid,
cookie);
} else {
ddi_umem_unlock(cookie);
rsm_dec_pgcnt(btopr(msg->len));
DBG_PRINTF((category, RSM_ERR,
"rsm_rebind failed with %d\n", e));
}
freerbuf(xbuf);
}
rsmseglock_release(seg);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_rebind done\n"));
return (e);
}
static int
rsm_unbind(rsmseg_t *seg)
{
DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_EXPORT);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_unbind enter\n"));
rsmseglock_acquire(seg);
if ((seg->s_state != RSM_STATE_BIND) &&
(seg->s_state != RSM_STATE_BIND_QUIESCED)) {
rsmseglock_release(seg);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
"rsm_unbind: invalid state\n"));
return (RSMERR_BAD_SEG_HNDL);
}
(void) rsm_unbind_pages(seg);
if (seg->s_state == RSM_STATE_BIND) {
seg->s_state = RSM_STATE_NEW;
} else if (seg->s_state == RSM_STATE_BIND_QUIESCED) {
seg->s_state = RSM_STATE_NEW_QUIESCED;
}
rsmseglock_release(seg);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_unbind done\n"));
return (RSM_SUCCESS);
}
static void
rsmacl_free(rsmapi_access_entry_t *acl, int acl_len)
{
int acl_sz;
DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_EXPORT);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmacl_free enter\n"));
if (acl != NULL && acl_len > 0) {
acl_sz = acl_len * sizeof (rsmapi_access_entry_t);
kmem_free((void *)acl, acl_sz);
}
DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmacl_free done\n"));
}
static void
rsmpiacl_free(rsm_access_entry_t *acl, int acl_len)
{
int acl_sz;
DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_EXPORT);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmpiacl_free enter\n"));
if (acl != NULL && acl_len > 0) {
acl_sz = acl_len * sizeof (rsm_access_entry_t);
kmem_free((void *)acl, acl_sz);
}
DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmpiacl_free done\n"));
}
static int
rsmacl_build(rsm_ioctlmsg_t *msg, int mode,
rsmapi_access_entry_t **list, int *len, int loopback)
{
rsmapi_access_entry_t *acl;
int acl_len;
int i;
DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_EXPORT);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmacl_build enter\n"));
*len = 0;
*list = NULL;
acl_len = msg->acl_len;
if ((loopback && acl_len > 1) || (acl_len < 0) ||
(acl_len > MAX_NODES)) {
DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
"rsmacl_build done: acl invalid\n"));
return (RSMERR_BAD_ACL);
}
if (acl_len > 0 && acl_len <= MAX_NODES) {
size_t acl_size = acl_len * sizeof (rsmapi_access_entry_t);
acl = kmem_alloc(acl_size, KM_SLEEP);
if (ddi_copyin((caddr_t)msg->acl, (caddr_t)acl,
acl_size, mode)) {
kmem_free((void *) acl, acl_size);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
"rsmacl_build done: BAD_ADDR\n"));
return (RSMERR_BAD_ADDR);
}
for (i = 0; i < acl_len; i++) {
if (acl[i].ae_node > MAX_NODES ||
(loopback && (acl[i].ae_node != my_nodeid)) ||
acl[i].ae_permission > RSM_ACCESS_TRUSTED) {
kmem_free((void *) acl, acl_size);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
"rsmacl_build done: EINVAL\n"));
return (RSMERR_BAD_ACL);
}
}
*len = acl_len;
*list = acl;
}
DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmacl_build done\n"));
return (DDI_SUCCESS);
}
static int
rsmpiacl_create(rsmapi_access_entry_t *src, rsm_access_entry_t **dest,
int acl_len, adapter_t *adapter)
{
rsm_access_entry_t *acl;
rsm_addr_t hwaddr;
int i;
DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_EXPORT);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmpiacl_create enter\n"));
if (src != NULL) {
size_t acl_size = acl_len * sizeof (rsm_access_entry_t);
acl = kmem_alloc(acl_size, KM_SLEEP);
for (i = 0; i < acl_len; i++) {
if (src[i].ae_node == my_nodeid) {
acl[i].ae_addr = adapter->hwaddr;
} else {
hwaddr = get_remote_hwaddr(adapter,
src[i].ae_node);
if ((int64_t)hwaddr < 0) {
kmem_free((void *) acl, acl_size);
DBG_PRINTF((category,
RSM_DEBUG_VERBOSE,
"rsmpiacl_create done:"
"EINVAL hwaddr\n"));
return (RSMERR_INTERNAL_ERROR);
}
acl[i].ae_addr = hwaddr;
}
acl[i].ae_permission =
src[i].ae_permission & RSM_PERM_RDWR;
}
*dest = acl;
} else {
*dest = NULL;
}
DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmpiacl_create done\n"));
return (RSM_SUCCESS);
}
static int
rsmsegacl_validate(rsmipc_request_t *req, rsm_node_id_t rnode,
rsmipc_reply_t *reply)
{
int i;
rsmseg_t *seg;
rsm_memseg_id_t key = req->rsmipc_key;
rsm_permission_t perm = req->rsmipc_perm;
DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_EXPORT);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
"rsmsegacl_validate enter\n"));
seg = rsmexport_lookup(key);
if (!seg) {
DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
"rsmsegacl_validate done: %u ENXIO\n", key));
return (RSMERR_SEG_NOT_PUBLISHED);
}
ASSERT(rsmseglock_held(seg));
ASSERT(seg->s_state == RSM_STATE_EXPORT);
if (seg->s_acl_len > 0) {
ASSERT(seg->s_acl != NULL);
for (i = 0; i < seg->s_acl_len; i++) {
if (seg->s_acl[i].ae_node == rnode) {
perm &= seg->s_acl[i].ae_permission;
goto found;
}
}
rsmseglock_release(seg);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
"rsmsegacl_validate done: EPERM\n"));
return (RSMERR_SEG_NOT_PUBLISHED_TO_NODE);
} else {
perm &= seg->s_mode;
}
found:
reply->rsmipc_mode = perm;
reply->rsmipc_uid = seg->s_uid;
reply->rsmipc_gid = seg->s_gid;
reply->rsmipc_segid = seg->s_segid;
reply->rsmipc_seglen = seg->s_len;
rsmseglock_release(seg);
importer_list_add(rnode, key, req->rsmipc_adapter_hwaddr,
req->rsmipc_segment_cookie);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmsegacl_validate done\n"));
return (RSM_SUCCESS);
}
static int
rsm_publish(rsmseg_t *seg, rsm_ioctlmsg_t *msg, intptr_t dataptr, int mode)
{
int e;
int acl_len;
rsmapi_access_entry_t *acl;
rsm_access_entry_t *rsmpi_acl;
rsm_memory_local_t mem;
struct buf *xbuf;
dev_t sdev = 0;
adapter_t *adapter;
rsm_memseg_id_t segment_id = 0;
int loopback_flag = 0;
int create_flags = 0;
rsm_resource_callback_t callback_flag;
DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_EXPORT);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_publish enter\n"));
if (seg->s_adapter == &loopback_adapter)
loopback_flag = 1;
if (seg->s_pid != ddi_get_pid() &&
ddi_get_pid() != 0) {
DBG_PRINTF((category, RSM_ERR,
"rsm_publish: Not creator\n"));
return (RSMERR_NOT_CREATOR);
}
e = rsmacl_build(msg, mode, &acl, &acl_len, loopback_flag);
if (e != DDI_SUCCESS) {
DBG_PRINTF((category, RSM_ERR,
"rsm_publish done: rsmacl_build failed\n"));
return (e);
}
if (msg->key == 0) {
mutex_enter(&rsm_lock);
segment_id = rsm_nextavail_segmentid;
if (segment_id != 0) {
rsm_nextavail_segmentid++;
mutex_exit(&rsm_lock);
} else {
mutex_exit(&rsm_lock);
DBG_PRINTF((category, RSM_ERR,
"rsm_publish done: no more keys avlbl\n"));
return (RSMERR_INSUFFICIENT_RESOURCES);
}
} else if BETWEEN(msg->key, RSM_RSMLIB_ID_BASE, RSM_RSMLIB_ID_END)
segment_id = msg->key;
else if (msg->key <= RSM_DLPI_ID_END)
return (RSMERR_RESERVED_SEGID);
else if (msg->key <= (uint_t)RSM_USER_APP_ID_BASE -1)
segment_id = msg->key;
else {
DBG_PRINTF((category, RSM_ERR,
"rsm_publish done: invalid key %u\n", msg->key));
return (RSMERR_RESERVED_SEGID);
}
e = rsmexport_add(seg, segment_id);
if (e) {
rsmacl_free(acl, acl_len);
DBG_PRINTF((category, RSM_ERR,
"rsm_publish done: export_add failed: %d\n", e));
return (e);
}
seg->s_segid = segment_id;
if ((seg->s_state != RSM_STATE_BIND) &&
(seg->s_state != RSM_STATE_BIND_QUIESCED)) {
rsmseglock_release(seg);
rsmexport_rm(seg);
rsmacl_free(acl, acl_len);
DBG_PRINTF((category, RSM_ERR,
"rsm_publish done: segment in wrong state: %d\n",
seg->s_state));
return (RSMERR_BAD_SEG_HNDL);
}
if (acl != (rsmapi_access_entry_t *)NULL) {
if (acl[0].ae_node == my_nodeid && acl[0].ae_permission == 0)
goto skipdriver;
}
xbuf = ddi_umem_iosetup(seg->s_cookie, 0, seg->s_len, B_WRITE,
sdev, 0, NULL, DDI_UMEM_SLEEP);
ASSERT(xbuf != NULL);
mem.ms_type = RSM_MEM_BUF;
mem.ms_bp = xbuf;
adapter = seg->s_adapter;
e = rsmpiacl_create(acl, &rsmpi_acl, acl_len, adapter);
if (e != RSM_SUCCESS) {
rsmseglock_release(seg);
rsmexport_rm(seg);
rsmacl_free(acl, acl_len);
freerbuf(xbuf);
DBG_PRINTF((category, RSM_ERR,
"rsm_publish done: rsmpiacl_create failed: %d\n", e));
return (e);
}
if (seg->s_state == RSM_STATE_BIND) {
if (seg->s_flags & RSMKA_ALLOW_UNBIND_REBIND) {
create_flags = RSM_ALLOW_UNBIND_REBIND;
}
if (seg->s_flags & RSMKA_SET_RESOURCE_DONTWAIT) {
callback_flag = RSM_RESOURCE_DONTWAIT;
} else {
callback_flag = RSM_RESOURCE_SLEEP;
}
e = adapter->rsmpi_ops->rsm_seg_create(
adapter->rsmpi_handle,
&seg->s_handle.out, seg->s_len,
create_flags, &mem,
callback_flag, NULL);
freerbuf(xbuf);
if (e != RSM_SUCCESS) {
rsmseglock_release(seg);
rsmexport_rm(seg);
rsmacl_free(acl, acl_len);
rsmpiacl_free(rsmpi_acl, acl_len);
DBG_PRINTF((category, RSM_ERR,
"rsm_publish done: export_create failed: %d\n", e));
ASSERT(e != RSMERR_BAD_MEM_ALIGNMENT &&
e != RSMERR_BAD_LENGTH);
if (e == RSMERR_NOT_MEM)
e = RSMERR_INSUFFICIENT_MEM;
return (e);
}
e = adapter->rsmpi_ops->rsm_publish(
seg->s_handle.out,
rsmpi_acl, acl_len,
seg->s_segid,
RSM_RESOURCE_DONTWAIT, NULL);
if (e != RSM_SUCCESS) {
adapter->rsmpi_ops->rsm_seg_destroy(seg->s_handle.out);
rsmseglock_release(seg);
rsmexport_rm(seg);
rsmacl_free(acl, acl_len);
rsmpiacl_free(rsmpi_acl, acl_len);
DBG_PRINTF((category, RSM_ERR,
"rsm_publish done: export_publish failed: %d\n",
e));
return (e);
}
}
seg->s_acl_in = rsmpi_acl;
skipdriver:
seg->s_acl_len = acl_len;
seg->s_acl = acl;
if (seg->s_state == RSM_STATE_BIND) {
seg->s_state = RSM_STATE_EXPORT;
} else if (seg->s_state == RSM_STATE_BIND_QUIESCED) {
seg->s_state = RSM_STATE_EXPORT_QUIESCED;
cv_broadcast(&seg->s_cv);
}
rsmseglock_release(seg);
if (msg->key == 0) {
msg->key = segment_id;
#ifdef _MULTI_DATAMODEL
if ((mode & DATAMODEL_MASK) == DATAMODEL_ILP32) {
rsm_ioctlmsg32_t msg32;
msg32.key = msg->key;
DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
"rsm_publish done\n"));
return (ddi_copyout((caddr_t)&msg32,
(caddr_t)dataptr, sizeof (msg32), mode));
}
#endif
DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
"rsm_publish done\n"));
return (ddi_copyout((caddr_t)msg,
(caddr_t)dataptr, sizeof (*msg), mode));
}
DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_publish done\n"));
return (DDI_SUCCESS);
}
static int
rsm_republish(rsmseg_t *seg, rsm_ioctlmsg_t *msg, int mode)
{
rsmapi_access_entry_t *new_acl, *old_acl, *tmp_acl;
rsm_access_entry_t *rsmpi_new_acl, *rsmpi_old_acl;
int new_acl_len, old_acl_len, tmp_acl_len;
int e, i;
adapter_t *adapter;
int loopback_flag = 0;
rsm_memseg_id_t key;
rsm_permission_t permission;
DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_EXPORT);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_republish enter\n"));
if ((seg->s_state != RSM_STATE_EXPORT) &&
(seg->s_state != RSM_STATE_EXPORT_QUIESCED) &&
(seg->s_state != RSM_STATE_EXPORT_QUIESCING))
return (RSMERR_SEG_NOT_PUBLISHED);
if (seg->s_pid != ddi_get_pid() &&
ddi_get_pid() != 0) {
DBG_PRINTF((category, RSM_ERR,
"rsm_republish: Not owner\n"));
return (RSMERR_NOT_CREATOR);
}
if (seg->s_adapter == &loopback_adapter)
loopback_flag = 1;
e = rsmacl_build(msg, mode, &new_acl, &new_acl_len, loopback_flag);
if (e) {
DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
"rsm_republish done: rsmacl_build failed %d", e));
return (e);
}
rsmseglock_acquire(seg);
while (((seg->s_state == RSM_STATE_EXPORT) &&
(seg->s_flags & RSM_REPUBLISH_WAIT)) ||
(seg->s_state == RSM_STATE_EXPORT_QUIESCED) ||
(seg->s_state == RSM_STATE_EXPORT_QUIESCING)) {
if (cv_wait_sig(&seg->s_cv, &seg->s_lock) == 0) {
DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
"rsm_republish done: cv_wait INTERRUPTED"));
rsmseglock_release(seg);
rsmacl_free(new_acl, new_acl_len);
return (RSMERR_INTERRUPTED);
}
}
if (seg->s_state != RSM_STATE_EXPORT) {
rsmseglock_release(seg);
rsmacl_free(new_acl, new_acl_len);
return (RSMERR_SEG_NOT_PUBLISHED);
}
key = seg->s_key;
old_acl = seg->s_acl;
old_acl_len = seg->s_acl_len;
seg->s_acl = new_acl;
seg->s_acl_len = new_acl_len;
adapter = seg->s_adapter;
e = rsmpiacl_create(new_acl, &rsmpi_new_acl, new_acl_len, adapter);
if (e != RSM_SUCCESS) {
seg->s_acl = old_acl;
seg->s_acl_len = old_acl_len;
rsmseglock_release(seg);
rsmacl_free(new_acl, new_acl_len);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
"rsm_republish done: rsmpiacl_create failed %d", e));
return (e);
}
rsmpi_old_acl = seg->s_acl_in;
seg->s_acl_in = rsmpi_new_acl;
e = adapter->rsmpi_ops->rsm_republish(seg->s_handle.out,
seg->s_acl_in, seg->s_acl_len,
RSM_RESOURCE_DONTWAIT, NULL);
if (e != RSM_SUCCESS) {
seg->s_acl = old_acl;
seg->s_acl_in = rsmpi_old_acl;
seg->s_acl_len = old_acl_len;
rsmseglock_release(seg);
rsmacl_free(new_acl, new_acl_len);
rsmpiacl_free(rsmpi_new_acl, new_acl_len);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
"rsm_republish done: rsmpi republish failed %d\n", e));
return (e);
}
tmp_acl_len = new_acl_len;
if (tmp_acl_len > 0) {
tmp_acl = kmem_zalloc(new_acl_len*sizeof (*tmp_acl), KM_SLEEP);
for (i = 0; i < tmp_acl_len; i++) {
tmp_acl[i].ae_node = new_acl[i].ae_node;
tmp_acl[i].ae_permission = new_acl[i].ae_permission;
}
permission = 0;
} else {
tmp_acl = NULL;
permission = seg->s_mode;
}
seg->s_flags |= RSM_REPUBLISH_WAIT;
rsmseglock_release(seg);
rsm_send_republish(key, tmp_acl, tmp_acl_len, permission);
rsmseglock_acquire(seg);
seg->s_flags &= ~RSM_REPUBLISH_WAIT;
cv_broadcast(&seg->s_cv);
rsmseglock_release(seg);
rsmacl_free(tmp_acl, tmp_acl_len);
rsmacl_free(old_acl, old_acl_len);
rsmpiacl_free(rsmpi_old_acl, old_acl_len);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_republish done\n"));
return (DDI_SUCCESS);
}
static int
rsm_unpublish(rsmseg_t *seg, int mode)
{
rsmapi_access_entry_t *acl;
rsm_access_entry_t *rsmpi_acl;
int acl_len;
int e;
adapter_t *adapter;
DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_EXPORT);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_unpublish enter\n"));
if (seg->s_pid != ddi_get_pid() &&
ddi_get_pid() != 0) {
DBG_PRINTF((category, RSM_ERR,
"rsm_unpublish: Not creator\n"));
return (RSMERR_NOT_CREATOR);
}
rsmseglock_acquire(seg);
while ((seg->s_state == RSM_STATE_EXPORT_QUIESCING) ||
((seg->s_state == RSM_STATE_EXPORT) && (seg->s_rdmacnt > 0))) {
if (cv_wait_sig(&seg->s_cv, &seg->s_lock) == 0) {
rsmseglock_release(seg);
DBG_PRINTF((category, RSM_ERR,
"rsm_unpublish done: cv_wait INTR qscing"
"getv/putv in progress"));
return (RSMERR_INTERRUPTED);
}
}
if ((seg->s_state != RSM_STATE_EXPORT) &&
(seg->s_state != RSM_STATE_EXPORT_QUIESCED)) {
rsmseglock_release(seg);
DBG_PRINTF((category, RSM_ERR,
"rsm_unpublish done: bad state %x\n", seg->s_state));
return (RSMERR_SEG_NOT_PUBLISHED);
}
rsmseglock_release(seg);
rsmexport_rm(seg);
rsm_send_importer_disconnects(seg->s_segid, my_nodeid);
rsmseglock_acquire(seg);
while ((seg->s_state == RSM_STATE_EXPORT) &&
(seg->s_flags & RSM_REPUBLISH_WAIT)) {
if (cv_wait_sig(&seg->s_cv, &seg->s_lock) == 0) {
DBG_PRINTF((category, RSM_ERR,
"rsm_unpublish done: cv_wait INTR repubing"));
rsmseglock_release(seg);
return (RSMERR_INTERRUPTED);
}
}
if ((seg->s_state != RSM_STATE_EXPORT) &&
(seg->s_state != RSM_STATE_EXPORT_QUIESCED)) {
DBG_PRINTF((category, RSM_ERR,
"rsm_unpublish done: invalid state"));
rsmseglock_release(seg);
return (RSMERR_SEG_NOT_PUBLISHED);
}
acl = seg->s_acl;
if (acl != (rsmapi_access_entry_t *)NULL) {
if (acl[0].ae_node == my_nodeid && acl[0].ae_permission == 0)
goto bypass;
}
if (seg->s_state == RSM_STATE_EXPORT_QUIESCED)
goto bypass;
adapter = seg->s_adapter;
for (;;) {
if (seg->s_state != RSM_STATE_EXPORT) {
rsmseglock_release(seg);
DBG_PRINTF((category, RSM_ERR,
"rsm_unpublish done: bad state %x\n",
seg->s_state));
return (RSMERR_SEG_NOT_PUBLISHED);
}
e = adapter->rsmpi_ops->rsm_unpublish(seg->s_handle.out);
if (e == RSM_SUCCESS) {
break;
}
if (e == RSMERR_SEG_IN_USE && mode == 1) {
seg->s_flags |= RSM_EXPORT_WAIT;
(void) cv_reltimedwait(&seg->s_cv, &seg->s_lock,
drv_usectohz(1000), TR_CLOCK_TICK);
DBG_PRINTF((category, RSM_ERR,
"rsm_unpublish: SEG_IN_USE\n"));
seg->s_flags &= ~RSM_EXPORT_WAIT;
} else {
if (mode == 1) {
DBG_PRINTF((category, RSM_ERR,
"rsm:rsmpi unpublish err %x\n", e));
seg->s_state = RSM_STATE_BIND;
}
rsmseglock_release(seg);
return (e);
}
}
e = adapter->rsmpi_ops->rsm_seg_destroy(seg->s_handle.out);
if (e != RSM_SUCCESS) {
DBG_PRINTF((category, RSM_ERR,
"rsm_unpublish: rsmpi destroy key=%x failed %x\n",
seg->s_key, e));
}
bypass:
acl = seg->s_acl;
rsmpi_acl = seg->s_acl_in;
acl_len = seg->s_acl_len;
seg->s_acl = NULL;
seg->s_acl_in = NULL;
seg->s_acl_len = 0;
if (seg->s_state == RSM_STATE_EXPORT) {
seg->s_state = RSM_STATE_BIND;
} else if (seg->s_state == RSM_STATE_EXPORT_QUIESCED) {
seg->s_state = RSM_STATE_BIND_QUIESCED;
cv_broadcast(&seg->s_cv);
}
rsmseglock_release(seg);
rsmacl_free(acl, acl_len);
rsmpiacl_free(rsmpi_acl, acl_len);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_unpublish done\n"));
return (DDI_SUCCESS);
}
static void
rsm_send_importer_disconnects(rsm_memseg_id_t ex_segid,
rsm_node_id_t ex_nodeid)
{
rsmipc_request_t request;
importing_token_t *prev_token, *token, *tmp_token, *tokp;
importing_token_t *force_disconnect_list = NULL;
int index;
DBG_PRINTF((RSM_KERNEL_AGENT | RSM_EXPORT, RSM_DEBUG_VERBOSE,
"rsm_send_importer_disconnects enter\n"));
index = rsmhash(ex_segid);
mutex_enter(&importer_list.lock);
prev_token = NULL;
token = importer_list.bucket[index];
while (token != NULL) {
if (token->key == ex_segid) {
if (prev_token == NULL)
importer_list.bucket[index] = token->next;
else
prev_token->next = token->next;
tmp_token = token;
token = token->next;
if (force_disconnect_list == NULL) {
force_disconnect_list = tmp_token;
tmp_token->next = NULL;
} else {
tokp = force_disconnect_list;
while (tokp != NULL) {
if (tokp->importing_node ==
tmp_token->importing_node) {
break;
}
tokp = tokp->next;
}
if (tokp == NULL) {
tmp_token->next =
force_disconnect_list;
force_disconnect_list = tmp_token;
} else {
kmem_free((void *)tmp_token,
sizeof (*token));
}
}
} else {
prev_token = token;
token = token->next;
}
}
mutex_exit(&importer_list.lock);
token = force_disconnect_list;
while (token != NULL) {
if (token->importing_node == my_nodeid) {
rsm_force_unload(ex_nodeid, ex_segid,
DISCONNECT);
} else {
request.rsmipc_hdr.rsmipc_type =
RSMIPC_MSG_DISCONNECT;
request.rsmipc_key = token->key;
for (;;) {
if (rsmipc_send(token->importing_node,
&request,
RSM_NO_REPLY) == RSM_SUCCESS) {
break;
} else {
delay(drv_usectohz(10000));
}
}
}
tmp_token = token;
token = token->next;
kmem_free((void *)tmp_token, sizeof (*token));
}
DBG_PRINTF((RSM_KERNEL_AGENT | RSM_EXPORT, RSM_DEBUG_VERBOSE,
"rsm_send_importer_disconnects done\n"));
}
static void
rsm_export_force_destroy(ddi_umem_cookie_t *ck)
{
rsmresource_blk_t *blk;
rsmresource_t *p;
rsmseg_t *eseg = NULL;
int i, j;
int found = 0;
DBG_PRINTF((RSM_KERNEL_AGENT | RSM_EXPORT, RSM_DEBUG_VERBOSE,
"rsm_export_force_destroy enter\n"));
rw_enter(&rsm_resource.rsmrc_lock, RW_READER);
for (i = 0; i < rsm_resource.rsmrc_len; i++) {
blk = rsm_resource.rsmrc_root[i];
if (blk == NULL) {
continue;
}
for (j = 0; j < RSMRC_BLKSZ; j++) {
p = blk->rsmrcblk_blks[j];
if ((p != NULL) && (p != RSMRC_RESERVED) &&
(p->rsmrc_type == RSM_RESOURCE_EXPORT_SEGMENT)) {
eseg = (rsmseg_t *)p;
if (eseg->s_cookie != ck)
continue;
rsmseglock_acquire(eseg);
eseg->s_flags |= RSM_FORCE_DESTROY_WAIT;
rsmseglock_release(eseg);
found = 1;
break;
}
}
if (found)
break;
}
rw_exit(&rsm_resource.rsmrc_lock);
if (found) {
ASSERT(eseg != NULL);
rsmseg_close(eseg, 1);
rsmseglock_acquire(eseg);
eseg->s_flags &= ~RSM_FORCE_DESTROY_WAIT;
cv_broadcast(&eseg->s_cv);
rsmseglock_release(eseg);
}
DBG_PRINTF((RSM_KERNEL_AGENT | RSM_EXPORT, RSM_DEBUG_VERBOSE,
"rsm_export_force_destroy done\n"));
}
static void
rsm_intr_segconnect(rsm_node_id_t src, rsmipc_request_t *req)
{
rsmipc_reply_t reply;
DBG_DEFINE(category,
RSM_KERNEL_AGENT | RSM_FUNC_ALL | RSM_INTR_CALLBACK);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
"rsm_intr_segconnect enter\n"));
reply.rsmipc_status = (short)rsmsegacl_validate(req, src, &reply);
reply.rsmipc_hdr.rsmipc_type = RSMIPC_MSG_REPLY;
reply.rsmipc_hdr.rsmipc_cookie = req->rsmipc_hdr.rsmipc_cookie;
(void) rsmipc_send(src, NULL, &reply);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
"rsm_intr_segconnect done\n"));
}
static void
rsm_force_unload(rsm_node_id_t src_nodeid, rsm_memseg_id_t ex_segid,
boolean_t disconnect_flag)
{
rsmresource_t *p = NULL;
rsmhash_table_t *rhash = &rsm_import_segs;
uint_t index;
DBG_DEFINE(category,
RSM_KERNEL_AGENT | RSM_FUNC_ALL | RSM_INTR_CALLBACK);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_force_unload enter\n"));
index = rsmhash(ex_segid);
rw_enter(&rhash->rsmhash_rw, RW_READER);
p = rsmhash_getbkt(rhash, index);
for (; p; p = p->rsmrc_next) {
rsmseg_t *seg = (rsmseg_t *)p;
if ((seg->s_segid == ex_segid) && (seg->s_node == src_nodeid)) {
rsmseglock_acquire(seg);
if (disconnect_flag)
seg->s_flags |= RSM_FORCE_DISCONNECT;
rsmseg_unload(seg);
}
}
rw_exit(&rhash->rsmhash_rw);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_force_unload done\n"));
}
static void
rsm_intr_reply(rsmipc_msghdr_t *msg)
{
rsmipc_slot_t *slot;
rsmipc_cookie_t *cookie;
void *data = (void *) msg;
size_t size = sizeof (rsmipc_reply_t);
DBG_DEFINE(category,
RSM_KERNEL_AGENT | RSM_FUNC_ALL | RSM_INTR_CALLBACK);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_intr_reply enter\n"));
cookie = &msg->rsmipc_cookie;
if (cookie->ic.index >= RSMIPC_SZ) {
DBG_PRINTF((category, RSM_ERR,
"rsm: rsm_intr_reply bad cookie %d\n", cookie->ic.index));
return;
}
ASSERT(cookie->ic.index < RSMIPC_SZ);
slot = &rsm_ipc.slots[cookie->ic.index];
mutex_enter(&slot->rsmipc_lock);
if (slot->rsmipc_cookie.value == cookie->value) {
if (RSMIPC_GET(slot, RSMIPC_PENDING)) {
bcopy(data, slot->rsmipc_data, size);
RSMIPC_CLEAR(slot, RSMIPC_PENDING);
cv_signal(&slot->rsmipc_cv);
}
} else {
DBG_PRINTF((category, RSM_DEBUG,
"rsm: rsm_intr_reply mismatched reply %d\n",
cookie->ic.index));
}
mutex_exit(&slot->rsmipc_lock);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_intr_reply done\n"));
}
static void
rsm_sqready_ack_deferred(void *arg)
{
path_t *path = (path_t *)arg;
DBG_DEFINE(category,
RSM_KERNEL_AGENT | RSM_FUNC_ALL | RSM_INTR_CALLBACK);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
"rsm_sqready_ack_deferred enter\n"));
mutex_enter(&path->mutex);
if (path->state != RSMKA_PATH_ACTIVE) {
PATH_RELE_NOLOCK(path);
mutex_exit(&path->mutex);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
"rsm_sqready_ack_deferred done:!ACTIVE\n"));
return;
}
(void) rsmipc_send_controlmsg(path, RSMIPC_MSG_SQREADY_ACK);
path->sendq_token.msgbuf_avail = RSMIPC_MAX_MESSAGES;
cv_broadcast(&path->sendq_token.sendq_cv);
PATH_RELE_NOLOCK(path);
mutex_exit(&path->mutex);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
"rsm_sqready_ack_deferred done\n"));
}
static void
rsm_proc_sqready(rsmipc_controlmsg_t *msg, rsm_addr_t src_hwaddr,
rsm_intr_hand_arg_t arg)
{
rsmipc_msghdr_t *msghdr = (rsmipc_msghdr_t *)msg;
srv_handler_arg_t *hdlr_argp = (srv_handler_arg_t *)arg;
path_t *path;
DBG_DEFINE(category,
RSM_KERNEL_AGENT | RSM_FUNC_ALL | RSM_INTR_CALLBACK);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_proc_sqready enter\n"));
path = rsm_find_path(hdlr_argp->adapter_name,
hdlr_argp->adapter_instance, src_hwaddr);
if (path == NULL) {
DBG_PRINTF((category, RSM_DEBUG,
"rsm_proc_sqready done: msg dropped no path\n"));
return;
}
mutex_exit(&path->mutex);
taskq_wait(path->recv_taskq);
mutex_enter(&path->mutex);
path->flags &= ~RSMKA_WAIT_FOR_SQACK;
if (path->state != RSMKA_PATH_ACTIVE) {
PATH_RELE_NOLOCK(path);
mutex_exit(&path->mutex);
DBG_PRINTF((category, RSM_DEBUG,
"rsm_proc_sqready done: msg dropped path !ACTIVE\n"));
return;
}
DBG_PRINTF((category, RSM_DEBUG, "rsm_proc_sqready:path=%lx "
" src=%lx:%llx\n", path, msghdr->rsmipc_src, src_hwaddr));
path->remote_incn = msg->rsmipc_local_incn;
path->sendq_token.msgbuf_avail = 0;
path->procmsg_cnt = 0;
(void) taskq_dispatch(path->recv_taskq,
rsm_sqready_ack_deferred, path, KM_NOSLEEP);
mutex_exit(&path->mutex);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_proc_sqready done\n"));
}
static void
rsm_proc_sqready_ack(rsmipc_controlmsg_t *msg, rsm_addr_t src_hwaddr,
rsm_intr_hand_arg_t arg)
{
rsmipc_msghdr_t *msghdr = (rsmipc_msghdr_t *)msg;
srv_handler_arg_t *hdlr_argp = (srv_handler_arg_t *)arg;
path_t *path;
DBG_DEFINE(category,
RSM_KERNEL_AGENT | RSM_FUNC_ALL | RSM_INTR_CALLBACK);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
"rsm_proc_sqready_ack enter\n"));
path = rsm_find_path(hdlr_argp->adapter_name,
hdlr_argp->adapter_instance, src_hwaddr);
if (path == NULL) {
DBG_PRINTF((category, RSM_DEBUG,
"rsm_proc_sqready_ack done: msg dropped no path\n"));
return;
}
if ((path->state != RSMKA_PATH_ACTIVE) ||
!(path->flags & RSMKA_WAIT_FOR_SQACK)) {
PATH_RELE_NOLOCK(path);
mutex_exit(&path->mutex);
DBG_PRINTF((category, RSM_DEBUG,
"rsm_proc_sqready_ack done: msg dropped\n"));
return;
}
if (path->local_incn != msghdr->rsmipc_incn) {
PATH_RELE_NOLOCK(path);
mutex_exit(&path->mutex);
DBG_PRINTF((category, RSM_DEBUG,
"rsm_proc_sqready_ack done: msg old incn %lld\n",
msghdr->rsmipc_incn));
return;
}
DBG_PRINTF((category, RSM_DEBUG, "rsm_proc_sqready_ack:path=%lx "
" src=%lx:%llx\n", path, msghdr->rsmipc_src, src_hwaddr));
path->flags &= ~RSMKA_WAIT_FOR_SQACK;
path->remote_incn = msg->rsmipc_local_incn;
path->sendq_token.msgbuf_avail = RSMIPC_MAX_MESSAGES;
cv_broadcast(&path->sendq_token.sendq_cv);
PATH_RELE_NOLOCK(path);
mutex_exit(&path->mutex);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
"rsm_proc_sqready_ack done\n"));
}
static void
rsm_add_credits(rsmipc_controlmsg_t *msg, rsm_addr_t src_hwaddr,
rsm_intr_hand_arg_t arg)
{
rsmipc_msghdr_t *msghdr = (rsmipc_msghdr_t *)msg;
srv_handler_arg_t *hdlr_argp = (srv_handler_arg_t *)arg;
path_t *path;
DBG_DEFINE(category,
RSM_KERNEL_AGENT | RSM_FUNC_ALL |
RSM_INTR_CALLBACK | RSM_FLOWCONTROL);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_add_credits enter\n"));
path = rsm_find_path(hdlr_argp->adapter_name,
hdlr_argp->adapter_instance, src_hwaddr);
if (path == NULL) {
DBG_PRINTF((category, RSM_DEBUG,
"rsm_add_credits enter: path not found\n"));
return;
}
if (path->state != RSMKA_PATH_ACTIVE) {
PATH_RELE_NOLOCK(path);
mutex_exit(&path->mutex);
DBG_PRINTF((category, RSM_DEBUG,
"rsm_add_credits enter:path=%lx !ACTIVE\n", path));
return;
}
if (path->local_incn != msghdr->rsmipc_incn) {
PATH_RELE_NOLOCK(path);
mutex_exit(&path->mutex);
DBG_PRINTF((category, RSM_DEBUG,
"rsm_add_credits enter: old incn %lld\n",
msghdr->rsmipc_incn));
return;
}
DBG_PRINTF((category, RSM_DEBUG,
"rsm_add_credits:path=%lx new-creds=%d "
"curr credits=%d src=%lx:%llx\n", path, msg->rsmipc_credits,
path->sendq_token.msgbuf_avail, msghdr->rsmipc_src,
src_hwaddr));
path->sendq_token.msgbuf_avail += msg->rsmipc_credits;
ASSERT(path->sendq_token.msgbuf_avail <= RSMIPC_MAX_MESSAGES);
cv_broadcast(&path->sendq_token.sendq_cv);
PATH_RELE_NOLOCK(path);
mutex_exit(&path->mutex);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_add_credits done\n"));
}
static void
rsm_intr_event(rsmipc_request_t *msg)
{
rsmseg_t *seg;
rsmresource_t *p;
rsm_node_id_t src_node;
DBG_DEFINE(category,
RSM_KERNEL_AGENT | RSM_FUNC_ALL | RSM_INTR_CALLBACK);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_intr_event enter\n"));
src_node = msg->rsmipc_hdr.rsmipc_src;
if ((seg = msg->rsmipc_segment_cookie) != NULL) {
uint_t hashval = rsmhash(msg->rsmipc_key);
rw_enter(&rsm_import_segs.rsmhash_rw, RW_READER);
p = (rsmresource_t *)rsmhash_getbkt(&rsm_import_segs, hashval);
for (; p; p = p->rsmrc_next) {
if ((p->rsmrc_key == msg->rsmipc_key) &&
(p->rsmrc_node == src_node)) {
seg = (rsmseg_t *)p;
rsmseglock_acquire(seg);
atomic_inc_32(&seg->s_pollevent);
if (seg->s_pollflag & RSM_SEGMENT_POLL)
pollwakeup(&seg->s_poll, POLLRDNORM);
rsmseglock_release(seg);
}
}
rw_exit(&rsm_import_segs.rsmhash_rw);
} else {
seg = rsmexport_lookup(msg->rsmipc_key);
if (!seg) {
DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
"rsm_intr_event done: exp seg not found\n"));
return;
}
ASSERT(rsmseglock_held(seg));
atomic_inc_32(&seg->s_pollevent);
if (seg->s_pollflag & RSM_SEGMENT_POLL)
pollwakeup(&seg->s_poll, POLLRDNORM);
rsmseglock_release(seg);
}
DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_intr_event done\n"));
}
static void
importer_update(rsm_node_id_t src_node, rsm_memseg_id_t key,
rsm_permission_t perm)
{
rsmresource_t *p;
rsmseg_t *seg;
uint_t hashval = rsmhash(key);
DBG_DEFINE(category,
RSM_KERNEL_AGENT | RSM_FUNC_ALL | RSM_INTR_CALLBACK);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "importer_update enter\n"));
rw_enter(&rsm_import_segs.rsmhash_rw, RW_READER);
p = (rsmresource_t *)rsmhash_getbkt(&rsm_import_segs, hashval);
for (; p; p = p->rsmrc_next) {
if ((p->rsmrc_key == key) && (p->rsmrc_node == src_node)) {
seg = (rsmseg_t *)p;
rsmseglock_acquire(seg);
rsmsharelock_acquire(seg);
seg->s_share->rsmsi_mode = perm;
rsmsharelock_release(seg);
rsmseglock_release(seg);
break;
}
}
rw_exit(&rsm_import_segs.rsmhash_rw);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "importer_update done\n"));
}
void
rsm_suspend_complete(rsm_node_id_t src_node, int flag)
{
int done = 1;
list_element_t *elem;
DBG_DEFINE(category,
RSM_KERNEL_AGENT | RSM_FUNC_ALL | RSM_INTR_CALLBACK);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
"rsm_suspend_complete enter\n"));
mutex_enter(&rsm_suspend_list.list_lock);
if (rsm_suspend_list.list_head == NULL) {
DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
"rsm_suspend_complete done: suspend_list is empty\n"));
mutex_exit(&rsm_suspend_list.list_lock);
return;
}
elem = rsm_suspend_list.list_head;
while (elem != NULL) {
if (elem->nodeid == src_node) {
elem->flags &= ~RSM_SUSPEND_ACKPENDING;
elem->flags |= flag;
}
if (done && (elem->flags & RSM_SUSPEND_ACKPENDING))
done = 0;
elem = elem->next;
}
mutex_exit(&rsm_suspend_list.list_lock);
if (!done) {
DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
"rsm_suspend_complete done: acks pending\n"));
return;
}
exporter_quiesce();
DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
"rsm_suspend_complete done\n"));
}
static void
exporter_quiesce()
{
int i, e;
rsmresource_t *current;
rsmseg_t *seg;
adapter_t *adapter;
DBG_DEFINE(category,
RSM_KERNEL_AGENT | RSM_FUNC_ALL | RSM_INTR_CALLBACK);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "exporter_quiesce enter\n"));
rw_enter(&rsm_export_segs.rsmhash_rw, RW_READER);
for (i = 0; i < rsm_hash_size; i++) {
current = rsm_export_segs.bucket[i];
while (current != NULL) {
seg = (rsmseg_t *)current;
rsmseglock_acquire(seg);
if (current->rsmrc_state ==
RSM_STATE_EXPORT_QUIESCING) {
adapter = seg->s_adapter;
if ((seg->s_acl == NULL) ||
(seg->s_acl[0].ae_node != my_nodeid) ||
(seg->s_acl[0].ae_permission != 0)) {
e = adapter->rsmpi_ops->rsm_unpublish(
seg->s_handle.out);
DBG_PRINTF((category, RSM_DEBUG,
"exporter_quiesce:unpub %d\n", e));
e = adapter->rsmpi_ops->rsm_seg_destroy(
seg->s_handle.out);
DBG_PRINTF((category, RSM_DEBUG,
"exporter_quiesce:destroy %d\n",
e));
}
(void) rsm_unbind_pages(seg);
seg->s_state = RSM_STATE_EXPORT_QUIESCED;
cv_broadcast(&seg->s_cv);
}
rsmseglock_release(seg);
current = current->rsmrc_next;
}
}
rw_exit(&rsm_export_segs.rsmhash_rw);
mutex_enter(&rsm_drv_data.drv_lock);
ASSERT(rsm_drv_data.drv_state == RSM_DRV_PREDEL_STARTED);
rsm_drv_data.drv_state = RSM_DRV_PREDEL_COMPLETED;
cv_broadcast(&rsm_drv_data.drv_cv);
mutex_exit(&rsm_drv_data.drv_lock);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "exporter_quiesce done\n"));
}
static void
importer_suspend(rsm_node_id_t src_node)
{
int i;
int susp_flg;
int num_importers;
rsmresource_t *p = NULL, *curp;
rsmhash_table_t *rhash = &rsm_import_segs;
rsmseg_t *seg;
rsmipc_request_t request;
DBG_DEFINE(category,
RSM_KERNEL_AGENT | RSM_FUNC_ALL | RSM_INTR_CALLBACK);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "importer_suspend enter\n"));
rw_enter(&rhash->rsmhash_rw, RW_READER);
for (i = 0; i < rsm_hash_size; i++) {
p = rhash->bucket[i];
for (; p; p = p->rsmrc_next) {
rsmseg_t *first = (rsmseg_t *)p;
if ((first->s_node != src_node) ||
(first->s_state == RSM_STATE_DISCONNECT))
continue;
num_importers = 0;
for (curp = p; curp; curp = curp->rsmrc_next) {
seg = (rsmseg_t *)curp;
rsmseglock_acquire(seg);
if ((seg->s_node != first->s_node) ||
(seg->s_key != first->s_key) ||
(seg->s_state == RSM_STATE_DISCONNECT)) {
rsmseglock_release(seg);
continue;
}
rsmseg_suspend(seg, &susp_flg);
if (susp_flg) {
rsmseglock_release(seg);
break;
}
num_importers++;
rsmsharelock_acquire(seg);
if (num_importers ==
seg->s_share->rsmsi_refcnt) {
rsmsharelock_release(seg);
rsmseglock_release(seg);
break;
}
rsmsharelock_release(seg);
rsmseglock_release(seg);
}
if (!susp_flg) {
rsmsegshare_suspend(seg);
}
}
}
rw_exit(&rhash->rsmhash_rw);
request.rsmipc_hdr.rsmipc_type = RSMIPC_MSG_SUSPEND_DONE;
(void) rsmipc_send(src_node, &request, RSM_NO_REPLY);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "importer_suspend done\n"));
}
static void
rsmseg_suspend(rsmseg_t *seg, int *susp_flg)
{
int recheck_state;
rsmcookie_t *hdl;
DBG_DEFINE(category,
RSM_KERNEL_AGENT | RSM_FUNC_ALL | RSM_INTR_CALLBACK);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
"rsmseg_suspend enter: key=%u\n", seg->s_key));
*susp_flg = 0;
ASSERT(rsmseglock_held(seg));
while (seg->s_rdmacnt > 0)
cv_wait(&seg->s_cv, &seg->s_lock);
do {
recheck_state = 0;
DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
"rsmseg_suspend:segment %x state=%d\n",
seg->s_key, seg->s_state));
switch (seg->s_state) {
case RSM_STATE_NEW:
break;
case RSM_STATE_CONNECTING:
seg->s_state = RSM_STATE_ABORT_CONNECT;
break;
case RSM_STATE_ABORT_CONNECT:
break;
case RSM_STATE_CONNECT:
seg->s_handle.in = NULL;
seg->s_state = RSM_STATE_CONN_QUIESCE;
break;
case RSM_STATE_MAPPING:
while (seg->s_state == RSM_STATE_MAPPING)
cv_wait(&seg->s_cv, &seg->s_lock);
recheck_state = 1;
break;
case RSM_STATE_ACTIVE:
if (seg->s_ckl != NULL) {
hdl = seg->s_ckl;
for (; hdl != NULL; hdl = hdl->c_next) {
(void) devmap_unload(hdl->c_dhp,
hdl->c_off, hdl->c_len);
}
}
seg->s_mapinfo = NULL;
seg->s_state = RSM_STATE_MAP_QUIESCE;
break;
case RSM_STATE_CONN_QUIESCE:
case RSM_STATE_MAP_QUIESCE:
*susp_flg = 1;
break;
case RSM_STATE_DISCONNECT:
break;
default:
ASSERT(0);
}
} while (recheck_state);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmseg_suspend done\n"));
}
static void
rsmsegshare_suspend(rsmseg_t *seg)
{
int e;
adapter_t *adapter;
rsm_import_share_t *sharedp;
DBG_DEFINE(category,
RSM_KERNEL_AGENT | RSM_FUNC_ALL | RSM_INTR_CALLBACK);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
"rsmsegshare_suspend enter\n"));
rsmseglock_acquire(seg);
rsmsharelock_acquire(seg);
sharedp = seg->s_share;
adapter = seg->s_adapter;
switch (sharedp->rsmsi_state) {
case RSMSI_STATE_NEW:
break;
case RSMSI_STATE_CONNECTING:
sharedp->rsmsi_state = RSMSI_STATE_ABORT_CONNECT;
break;
case RSMSI_STATE_ABORT_CONNECT:
break;
case RSMSI_STATE_CONNECTED:
if (sharedp->rsmsi_node != my_nodeid) {
e = adapter->rsmpi_ops->
rsm_disconnect(sharedp->rsmsi_handle);
DBG_PRINTF((category, RSM_DEBUG,
"rsm:rsmpi disconnect seg=%x:err=%d\n",
sharedp->rsmsi_segid, e));
}
sharedp->rsmsi_handle = NULL;
sharedp->rsmsi_state = RSMSI_STATE_CONN_QUIESCE;
break;
case RSMSI_STATE_CONN_QUIESCE:
break;
case RSMSI_STATE_MAPPED:
if (sharedp->rsmsi_node != my_nodeid) {
e = adapter->rsmpi_ops->rsm_unmap(seg->s_handle.in);
DBG_PRINTF((category, RSM_DEBUG,
"rsmshare_suspend: rsmpi unmap %d\n", e));
e = adapter->rsmpi_ops->
rsm_disconnect(sharedp->rsmsi_handle);
DBG_PRINTF((category, RSM_DEBUG,
"rsm:rsmpi disconnect seg=%x:err=%d\n",
sharedp->rsmsi_segid, e));
}
sharedp->rsmsi_handle = NULL;
sharedp->rsmsi_state = RSMSI_STATE_MAP_QUIESCE;
break;
case RSMSI_STATE_MAP_QUIESCE:
break;
case RSMSI_STATE_DISCONNECTED:
break;
default:
ASSERT(0);
}
rsmsharelock_release(seg);
rsmseglock_release(seg);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
"rsmsegshare_suspend done\n"));
}
static void
importer_resume(rsm_node_id_t src_node)
{
int i;
rsmresource_t *p = NULL;
rsmhash_table_t *rhash = &rsm_import_segs;
void *cookie;
DBG_DEFINE(category,
RSM_KERNEL_AGENT | RSM_FUNC_ALL | RSM_INTR_CALLBACK);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "importer_resume enter\n"));
rw_enter(&rhash->rsmhash_rw, RW_READER);
for (i = 0; i < rsm_hash_size; i++) {
p = rhash->bucket[i];
for (; p; p = p->rsmrc_next) {
rsmseg_t *seg = (rsmseg_t *)p;
rsmseglock_acquire(seg);
if (seg->s_node != src_node) {
rsmseglock_release(seg);
continue;
}
if (rsmseg_resume(seg, &cookie) != RSM_SUCCESS) {
rsmipc_request_t request;
request.rsmipc_hdr.rsmipc_type =
RSMIPC_MSG_NOTIMPORTING;
request.rsmipc_key = seg->s_segid;
request.rsmipc_segment_cookie = cookie;
rsmseglock_release(seg);
(void) rsmipc_send(seg->s_node, &request,
RSM_NO_REPLY);
} else {
rsmseglock_release(seg);
}
}
}
rw_exit(&rhash->rsmhash_rw);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "importer_resume done\n"));
}
static int
rsmseg_resume(rsmseg_t *seg, void **cookie)
{
int e;
int retc;
off_t dev_offset;
size_t maplen;
uint_t maxprot;
rsm_mapinfo_t *p;
rsmcookie_t *hdl;
rsm_import_share_t *sharedp;
DBG_DEFINE(category,
RSM_KERNEL_AGENT | RSM_FUNC_ALL | RSM_INTR_CALLBACK);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
"rsmseg_resume enter: key=%u\n", seg->s_key));
*cookie = NULL;
ASSERT(rsmseglock_held(seg));
if ((seg->s_state != RSM_STATE_CONN_QUIESCE) &&
(seg->s_state != RSM_STATE_MAP_QUIESCE)) {
return (RSM_SUCCESS);
}
sharedp = seg->s_share;
rsmsharelock_acquire(seg);
retc = rsmsegshare_resume(seg);
if (seg->s_state == RSM_STATE_CONN_QUIESCE) {
if ((sharedp->rsmsi_state == RSMSI_STATE_CONNECTED) ||
(sharedp->rsmsi_state == RSMSI_STATE_MAPPED)) {
ASSERT(retc == RSM_SUCCESS);
seg->s_handle.in = sharedp->rsmsi_handle;
rsmsharelock_release(seg);
seg->s_state = RSM_STATE_CONNECT;
} else {
seg->s_handle.in = NULL;
seg->s_state = RSM_STATE_DISCONNECT;
sharedp->rsmsi_refcnt--;
cookie = (void *)sharedp->rsmsi_cookie;
if (sharedp->rsmsi_refcnt == 0) {
ASSERT(sharedp->rsmsi_mapcnt == 0);
rsmsharelock_release(seg);
mutex_destroy(&sharedp->rsmsi_lock);
cv_destroy(&sharedp->rsmsi_cv);
kmem_free((void *)(sharedp),
sizeof (rsm_import_share_t));
} else {
rsmsharelock_release(seg);
}
seg->s_share = NULL;
}
cv_broadcast(&seg->s_cv);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
"rsmseg_resume done:state=%d\n", seg->s_state));
return (retc);
}
ASSERT(seg->s_state == RSM_STATE_MAP_QUIESCE);
maxprot = PROT_USER;
if (seg->s_mode & RSM_PERM_READ) {
maxprot |= PROT_READ;
}
if (seg->s_mode & RSM_PERM_WRITE) {
maxprot |= PROT_WRITE;
}
if (sharedp->rsmsi_state != RSMSI_STATE_MAPPED) {
ASSERT(seg->s_ckl != NULL);
for (hdl = seg->s_ckl; hdl != NULL; hdl = hdl->c_next) {
e = devmap_umem_remap(hdl->c_dhp, rsm_dip,
remap_cookie, hdl->c_off, hdl->c_len,
maxprot, 0, NULL);
DBG_PRINTF((category, RSM_ERR,
"rsmseg_resume:remap=%d\n", e));
}
seg->s_handle.in = NULL;
seg->s_state = RSM_STATE_DISCONNECT;
sharedp->rsmsi_refcnt--;
sharedp->rsmsi_mapcnt--;
seg->s_mapinfo = NULL;
if (sharedp->rsmsi_refcnt == 0) {
ASSERT(sharedp->rsmsi_mapcnt == 0);
rsmsharelock_release(seg);
mutex_destroy(&sharedp->rsmsi_lock);
cv_destroy(&sharedp->rsmsi_cv);
kmem_free((void *)(sharedp),
sizeof (rsm_import_share_t));
} else {
rsmsharelock_release(seg);
}
seg->s_share = NULL;
cv_broadcast(&seg->s_cv);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
"rsmseg_resume done:seg=%x,err=%d\n",
seg->s_key, retc));
return (retc);
}
seg->s_handle.in = sharedp->rsmsi_handle;
if (seg->s_node == my_nodeid) {
ASSERT(seg->s_mapinfo == NULL);
for (hdl = seg->s_ckl; hdl != NULL; hdl = hdl->c_next) {
e = devmap_umem_remap(hdl->c_dhp,
rsm_dip, seg->s_cookie,
hdl->c_off, hdl->c_len,
maxprot, 0, NULL);
DBG_PRINTF((category, RSM_ERR,
"rsmseg_resume:remap=%d\n", e));
}
} else {
seg->s_mapinfo = sharedp->rsmsi_mapinfo;
for (hdl = seg->s_ckl; hdl != NULL; hdl = hdl->c_next) {
p = rsm_get_mapinfo(seg, hdl->c_off, hdl->c_len,
&dev_offset, &maplen);
e = devmap_devmem_remap(hdl->c_dhp,
p->dip, p->dev_register, dev_offset,
maplen, maxprot, 0, NULL);
DBG_PRINTF((category, RSM_ERR,
"rsmseg_resume:remap=%d\n", e));
}
}
rsmsharelock_release(seg);
seg->s_state = RSM_STATE_ACTIVE;
cv_broadcast(&seg->s_cv);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmseg_resume done\n"));
return (retc);
}
static int
rsmsegshare_resume(rsmseg_t *seg)
{
int e = RSM_SUCCESS;
adapter_t *adapter;
rsm_import_share_t *sharedp;
DBG_DEFINE(category,
RSM_KERNEL_AGENT | RSM_FUNC_ALL | RSM_INTR_CALLBACK);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmsegshare_resume enter\n"));
ASSERT(rsmseglock_held(seg));
ASSERT(rsmsharelock_held(seg));
sharedp = seg->s_share;
if ((sharedp->rsmsi_state != RSMSI_STATE_CONN_QUIESCE) &&
(sharedp->rsmsi_state != RSMSI_STATE_MAP_QUIESCE)) {
return (RSM_SUCCESS);
}
adapter = seg->s_adapter;
if (sharedp->rsmsi_node != my_nodeid) {
rsm_addr_t hwaddr;
hwaddr = get_remote_hwaddr(adapter, sharedp->rsmsi_node);
e = adapter->rsmpi_ops->rsm_connect(
adapter->rsmpi_handle, hwaddr,
sharedp->rsmsi_segid, &sharedp->rsmsi_handle);
DBG_PRINTF((category, RSM_DEBUG,
"rsmsegshare_resume:rsmpi connect seg=%x:err=%d\n",
sharedp->rsmsi_segid, e));
if (e != RSM_SUCCESS) {
sharedp->rsmsi_handle = NULL;
sharedp->rsmsi_state = RSMSI_STATE_DISCONNECTED;
cv_broadcast(&sharedp->rsmsi_cv);
return (e);
}
}
if (sharedp->rsmsi_state == RSMSI_STATE_CONN_QUIESCE) {
sharedp->rsmsi_state = RSMSI_STATE_CONNECTED;
cv_broadcast(&sharedp->rsmsi_cv);
return (e);
}
ASSERT(sharedp->rsmsi_state == RSMSI_STATE_MAP_QUIESCE);
if (sharedp->rsmsi_node != my_nodeid) {
size_t mapped_len;
rsm_mapinfo_t *p;
p = sharedp->rsmsi_mapinfo;
while (p != NULL) {
mapped_len = 0;
e = adapter->rsmpi_ops->rsm_map(
sharedp->rsmsi_handle, p->start_offset,
p->individual_len, &mapped_len,
&p->dip, &p->dev_register, &p->dev_offset,
NULL, NULL);
if (e != 0) {
DBG_PRINTF((category, RSM_ERR,
"rsmsegshare_resume: rsmpi map err=%d\n",
e));
break;
}
if (mapped_len != p->individual_len) {
DBG_PRINTF((category, RSM_ERR,
"rsmsegshare_resume: rsmpi maplen"
"< reqlen=%lx\n", mapped_len));
e = RSMERR_BAD_LENGTH;
break;
}
p = p->next;
}
if (e != RSM_SUCCESS) {
int err;
if (p != sharedp->rsmsi_mapinfo) {
(void) seg->s_adapter->rsmpi_ops->
rsm_unmap(sharedp->rsmsi_handle);
}
rsm_free_mapinfo(sharedp->rsmsi_mapinfo);
sharedp->rsmsi_mapinfo = NULL;
err = adapter->rsmpi_ops->
rsm_disconnect(sharedp->rsmsi_handle);
DBG_PRINTF((category, RSM_DEBUG,
"rsmsegshare_resume:disconn seg=%x:err=%d\n",
sharedp->rsmsi_segid, err));
sharedp->rsmsi_handle = NULL;
sharedp->rsmsi_state = RSMSI_STATE_DISCONNECTED;
cv_broadcast(&sharedp->rsmsi_cv);
DBG_PRINTF((category, RSM_DEBUG,
"rsmsegshare_resume done: rsmpi map err\n"));
return (e);
}
}
sharedp->rsmsi_state = RSMSI_STATE_MAPPED;
cv_broadcast(&sharedp->rsmsi_cv);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmsegshare_resume done\n"));
return (e);
}
static void
rsm_intr_proc_deferred(void *arg)
{
path_t *path = (path_t *)arg;
rsmipc_request_t *msg;
rsmipc_msghdr_t *msghdr;
rsm_node_id_t src_node;
msgbuf_elem_t *head;
int e;
DBG_DEFINE(category,
RSM_KERNEL_AGENT | RSM_FUNC_ALL | RSM_INTR_CALLBACK);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
"rsm_intr_proc_deferred enter\n"));
mutex_enter(&path->mutex);
head = rsmka_gethead_msgbuf(path);
mutex_exit(&path->mutex);
msg = (rsmipc_request_t *)&(head->msg);
msghdr = (rsmipc_msghdr_t *)msg;
src_node = msghdr->rsmipc_src;
switch (msghdr->rsmipc_type) {
case RSMIPC_MSG_SEGCONNECT:
if (msghdr->rsmipc_version != RSM_VERSION) {
rsmipc_reply_t reply;
reply.rsmipc_status = RSMERR_BAD_DRIVER_VERSION;
reply.rsmipc_hdr.rsmipc_type = RSMIPC_MSG_REPLY;
reply.rsmipc_hdr.rsmipc_cookie = msghdr->rsmipc_cookie;
(void) rsmipc_send(msghdr->rsmipc_src, NULL, &reply);
} else {
rsm_intr_segconnect(src_node, msg);
}
break;
case RSMIPC_MSG_DISCONNECT:
rsm_force_unload(src_node, msg->rsmipc_key, DISCONNECT);
break;
case RSMIPC_MSG_SUSPEND:
importer_suspend(src_node);
break;
case RSMIPC_MSG_SUSPEND_DONE:
rsm_suspend_complete(src_node, 0);
break;
case RSMIPC_MSG_RESUME:
importer_resume(src_node);
break;
default:
ASSERT(0);
}
mutex_enter(&path->mutex);
rsmka_dequeue_msgbuf(path);
if (path->procmsg_cnt < RSMIPC_MAX_MESSAGES)
path->procmsg_cnt++;
ASSERT(path->procmsg_cnt <= RSMIPC_MAX_MESSAGES);
if ((path->state == RSMKA_PATH_ACTIVE) &&
(path->procmsg_cnt >= RSMIPC_LOTSFREE_MSGBUFS)) {
e = rsmipc_send_controlmsg(path, RSMIPC_MSG_CREDIT);
if (e == 0)
path->procmsg_cnt = 0;
else
DBG_PRINTF((category, RSM_ERR,
"rsm_intr_proc_deferred:send credits err=%d\n", e));
}
PATH_RELE_NOLOCK(path);
mutex_exit(&path->mutex);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
"rsm_intr_proc_deferred done\n"));
}
static void
rsm_intr_callback_dispatch(void *data, rsm_addr_t src_hwaddr,
rsm_intr_hand_arg_t arg)
{
srv_handler_arg_t *hdlr_argp = (srv_handler_arg_t *)arg;
path_t *path;
rsmipc_msghdr_t *msghdr = (rsmipc_msghdr_t *)data;
DBG_DEFINE(category,
RSM_KERNEL_AGENT | RSM_FUNC_ALL | RSM_INTR_CALLBACK);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
"rsm_intr_callback_dispatch enter\n"));
ASSERT(data && hdlr_argp);
path = rsm_find_path(hdlr_argp->adapter_name,
hdlr_argp->adapter_instance, src_hwaddr);
if (path == NULL) {
DBG_PRINTF((category, RSM_DEBUG,
"rsm_intr_callback_dispatch done: msg dropped\n"));
return;
}
if (path->state != RSMKA_PATH_ACTIVE) {
PATH_RELE_NOLOCK(path);
mutex_exit(&path->mutex);
DBG_PRINTF((category, RSM_DEBUG,
"rsm_intr_callback_dispatch done: msg dropped"
" path=%lx !ACTIVE\n", path));
return;
}
if (path->local_incn != msghdr->rsmipc_incn) {
PATH_RELE_NOLOCK(path);
mutex_exit(&path->mutex);
DBG_PRINTF((category, RSM_DEBUG,
"rsm_intr_callback_dispatch done: old incn %lld\n",
msghdr->rsmipc_incn));
return;
}
rsmka_enqueue_msgbuf(path, data);
(void) taskq_dispatch(path->recv_taskq,
rsm_intr_proc_deferred, path, KM_NOSLEEP);
mutex_exit(&path->mutex);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
"rsm_intr_callback_dispatch done\n"));
}
static void
rsm_sqcreateop_callback(rsm_addr_t src_hwaddr, rsm_intr_hand_arg_t arg)
{
srv_handler_arg_t *hdlr_argp = (srv_handler_arg_t *)arg;
path_t *path;
DBG_DEFINE(category,
RSM_KERNEL_AGENT | RSM_FUNC_ALL | RSM_INTR_CALLBACK);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
"rsm_sqcreateop_callback enter\n"));
path = rsm_find_path(hdlr_argp->adapter_name,
hdlr_argp->adapter_instance, src_hwaddr);
if (path == NULL) {
DBG_PRINTF((category, RSM_DEBUG,
"rsm_sqcreateop_callback done: no path\n"));
return;
}
if ((path->state == RSMKA_PATH_UP) &&
(path->flags & RSMKA_SQCREATE_PENDING)) {
(void) rsmka_do_path_active(path, RSMKA_NO_SLEEP);
} else {
PATH_RELE_NOLOCK(path);
}
mutex_exit(&path->mutex);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
"rsm_sqcreateop_callback done\n"));
}
static void
rsm_intr_callback(void *data, rsm_addr_t src_hwaddr, rsm_intr_hand_arg_t arg)
{
rsmipc_msghdr_t *msghdr = (rsmipc_msghdr_t *)data;
rsmipc_request_t *msg = (rsmipc_request_t *)data;
rsmipc_controlmsg_t *ctrlmsg = (rsmipc_controlmsg_t *)data;
rsm_node_id_t src_node;
DBG_DEFINE(category,
RSM_KERNEL_AGENT | RSM_FUNC_ALL | RSM_INTR_CALLBACK);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_intr_callback enter:"
"src=%d, type=%d\n", msghdr->rsmipc_src,
msghdr->rsmipc_type));
if (msghdr->rsmipc_version != RSM_VERSION) {
DBG_PRINTF((category, RSM_ERR, "wrong KA version\n"));
if (msghdr->rsmipc_type != RSMIPC_MSG_SEGCONNECT) {
return;
}
}
src_node = msghdr->rsmipc_src;
switch (msghdr->rsmipc_type) {
case RSMIPC_MSG_SEGCONNECT:
case RSMIPC_MSG_DISCONNECT:
case RSMIPC_MSG_SUSPEND:
case RSMIPC_MSG_SUSPEND_DONE:
case RSMIPC_MSG_RESUME:
rsm_intr_callback_dispatch(data, src_hwaddr, arg);
break;
case RSMIPC_MSG_NOTIMPORTING:
importer_list_rm(src_node, msg->rsmipc_key,
msg->rsmipc_segment_cookie);
break;
case RSMIPC_MSG_SQREADY:
rsm_proc_sqready(data, src_hwaddr, arg);
break;
case RSMIPC_MSG_SQREADY_ACK:
rsm_proc_sqready_ack(data, src_hwaddr, arg);
break;
case RSMIPC_MSG_CREDIT:
rsm_add_credits(ctrlmsg, src_hwaddr, arg);
break;
case RSMIPC_MSG_REPLY:
rsm_intr_reply(msghdr);
break;
case RSMIPC_MSG_BELL:
rsm_intr_event(msg);
break;
case RSMIPC_MSG_IMPORTING:
importer_list_add(src_node, msg->rsmipc_key,
msg->rsmipc_adapter_hwaddr,
msg->rsmipc_segment_cookie);
break;
case RSMIPC_MSG_REPUBLISH:
importer_update(src_node, msg->rsmipc_key, msg->rsmipc_perm);
break;
default:
DBG_PRINTF((category, RSM_DEBUG,
"rsm_intr_callback: bad msg %lx type %d data %lx\n",
(size_t)msg, (int)(msghdr->rsmipc_type), (size_t)data));
}
DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_intr_callback done\n"));
}
rsm_intr_hand_ret_t 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)
{
DBG_DEFINE(category,
RSM_KERNEL_AGENT | RSM_FUNC_ALL | RSM_INTR_CALLBACK);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_srv_func enter\n"));
switch (opcode) {
case RSM_INTR_Q_OP_CREATE:
DBG_PRINTF((category, RSM_DEBUG, "rsm_srv_func:OP_CREATE\n"));
rsm_sqcreateop_callback(src, arg);
break;
case RSM_INTR_Q_OP_DESTROY:
DBG_PRINTF((category, RSM_DEBUG, "rsm_srv_func:OP_DESTROY\n"));
break;
case RSM_INTR_Q_OP_RECEIVE:
rsm_intr_callback(data, src, arg);
break;
default:
DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
"rsm_srv_func: unknown opcode = %x\n", opcode));
}
chd = chd;
size = size;
DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_srv_func done\n"));
return (RSM_INTR_HAND_CLAIMED);
}
static rsmipc_slot_t *
rsmipc_alloc()
{
int i;
rsmipc_slot_t *slot;
DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_FUNC_ALL);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmipc_alloc enter\n"));
mutex_enter(&rsm_ipc.lock);
while (rsm_ipc.count == 0) {
rsm_ipc.wanted = 1;
cv_wait(&rsm_ipc.cv, &rsm_ipc.lock);
}
slot = &rsm_ipc.slots[0];
for (i = 0; i < RSMIPC_SZ; i++, slot++) {
if (RSMIPC_GET(slot, RSMIPC_FREE)) {
RSMIPC_CLEAR(slot, RSMIPC_FREE);
break;
}
}
ASSERT(i < RSMIPC_SZ);
rsm_ipc.count--;
rsm_ipc.sequence++;
slot->rsmipc_cookie.ic.sequence = (uint_t)rsm_ipc.sequence;
slot->rsmipc_cookie.ic.index = (uint_t)i;
mutex_exit(&rsm_ipc.lock);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmipc_alloc done\n"));
return (slot);
}
static void
rsmipc_free(rsmipc_slot_t *slot)
{
DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_FUNC_ALL);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmipc_free enter\n"));
ASSERT(MUTEX_HELD(&slot->rsmipc_lock));
ASSERT(&rsm_ipc.slots[slot->rsmipc_cookie.ic.index] == slot);
mutex_enter(&rsm_ipc.lock);
RSMIPC_SET(slot, RSMIPC_FREE);
slot->rsmipc_cookie.ic.sequence = 0;
mutex_exit(&slot->rsmipc_lock);
rsm_ipc.count++;
ASSERT(rsm_ipc.count <= RSMIPC_SZ);
if (rsm_ipc.wanted) {
rsm_ipc.wanted = 0;
cv_broadcast(&rsm_ipc.cv);
}
mutex_exit(&rsm_ipc.lock);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmipc_free done\n"));
}
static int
rsmipc_send(rsm_node_id_t dest, rsmipc_request_t *req, rsmipc_reply_t *reply)
{
int e = 0;
int credit_check = 0;
int retry_cnt = 0;
int min_retry_cnt = 10;
rsm_send_t is;
rsmipc_slot_t *rslot;
adapter_t *adapter;
path_t *path;
sendq_token_t *sendq_token;
sendq_token_t *used_sendq_token = NULL;
rsm_send_q_handle_t ipc_handle;
DBG_DEFINE(category,
RSM_KERNEL_AGENT | RSM_FUNC_ALL | RSM_INTR_CALLBACK);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmipc_send enter:dest=%d",
dest));
if (dest == my_nodeid) {
switch (req->rsmipc_hdr.rsmipc_type) {
case RSMIPC_MSG_SEGCONNECT:
reply->rsmipc_status = (short)rsmsegacl_validate(
req, dest, reply);
break;
case RSMIPC_MSG_BELL:
req->rsmipc_hdr.rsmipc_src = dest;
rsm_intr_event(req);
break;
case RSMIPC_MSG_IMPORTING:
importer_list_add(dest, req->rsmipc_key,
req->rsmipc_adapter_hwaddr,
req->rsmipc_segment_cookie);
break;
case RSMIPC_MSG_NOTIMPORTING:
importer_list_rm(dest, req->rsmipc_key,
req->rsmipc_segment_cookie);
break;
case RSMIPC_MSG_REPUBLISH:
importer_update(dest, req->rsmipc_key,
req->rsmipc_perm);
break;
case RSMIPC_MSG_SUSPEND:
importer_suspend(dest);
break;
case RSMIPC_MSG_SUSPEND_DONE:
rsm_suspend_complete(dest, 0);
break;
case RSMIPC_MSG_RESUME:
importer_resume(dest);
break;
default:
ASSERT(0);
}
DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
"rsmipc_send done\n"));
return (0);
}
if (dest >= MAX_NODES) {
DBG_PRINTF((category, RSM_ERR,
"rsm: rsmipc_send bad node number %x\n", dest));
return (RSMERR_REMOTE_NODE_UNREACHABLE);
}
if (req != NULL) {
DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
"rsmipc_send:request type=%d\n",
req->rsmipc_hdr.rsmipc_type));
switch (req->rsmipc_hdr.rsmipc_type) {
case RSMIPC_MSG_SEGCONNECT:
case RSMIPC_MSG_DISCONNECT:
case RSMIPC_MSG_IMPORTING:
case RSMIPC_MSG_SUSPEND:
case RSMIPC_MSG_SUSPEND_DONE:
case RSMIPC_MSG_RESUME:
credit_check = 1;
break;
default:
credit_check = 0;
}
}
again:
if (retry_cnt++ == min_retry_cnt) {
delay(drv_usectohz(10000));
retry_cnt = 0;
}
sendq_token = rsmka_get_sendq_token(dest, used_sendq_token);
if (sendq_token == NULL) {
DBG_PRINTF((category, RSM_ERR,
"rsm: rsmipc_send no device to reach node %d\n", dest));
return (RSMERR_REMOTE_NODE_UNREACHABLE);
}
if ((sendq_token == used_sendq_token) &&
((e == RSMERR_CONN_ABORTED) || (e == RSMERR_TIMEOUT) ||
(e == RSMERR_COMM_ERR_MAYBE_DELIVERED))) {
rele_sendq_token(sendq_token);
DBG_PRINTF((category, RSM_DEBUG, "rsmipc_send done=%d\n", e));
return (RSMERR_CONN_ABORTED);
} else
used_sendq_token = sendq_token;
path = SQ_TOKEN_TO_PATH(sendq_token);
adapter = path->local_adapter;
ipc_handle = sendq_token->rsmpi_sendq_handle;
DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
"rsmipc_send: path=%lx sendq_hdl=%lx\n", path, ipc_handle));
if (reply == NULL) {
req->rsmipc_hdr.rsmipc_version = RSM_VERSION;
req->rsmipc_hdr.rsmipc_src = my_nodeid;
req->rsmipc_hdr.rsmipc_incn = path->remote_incn;
is.is_data = (void *)req;
is.is_size = sizeof (*req);
is.is_flags = RSM_INTR_SEND_DELIVER | RSM_INTR_SEND_SLEEP;
is.is_wait = 0;
if (credit_check) {
mutex_enter(&path->mutex);
while ((sendq_token->msgbuf_avail == 0) &&
(path->state == RSMKA_PATH_ACTIVE)) {
e = cv_wait_sig(&sendq_token->sendq_cv,
&path->mutex);
if (e == 0) {
mutex_exit(&path->mutex);
no_reply_cnt++;
rele_sendq_token(sendq_token);
DBG_PRINTF((category, RSM_DEBUG,
"rsmipc_send done: "
"cv_wait INTERRUPTED"));
return (RSMERR_INTERRUPTED);
}
}
if (path->state != RSMKA_PATH_ACTIVE) {
mutex_exit(&path->mutex);
rele_sendq_token(sendq_token);
e = RSMERR_CONN_ABORTED;
DBG_PRINTF((category, RSM_ERR,
"rsm: rsmipc_send: path !ACTIVE"));
goto again;
}
ASSERT(sendq_token->msgbuf_avail > 0);
sendq_token->msgbuf_avail--;
mutex_exit(&path->mutex);
e = adapter->rsmpi_ops->rsm_send(ipc_handle, &is,
NULL);
if (e != RSM_SUCCESS) {
mutex_enter(&path->mutex);
sendq_token->msgbuf_avail++;
cv_broadcast(&sendq_token->sendq_cv);
mutex_exit(&path->mutex);
}
} else
e = adapter->rsmpi_ops->rsm_send(ipc_handle, &is,
NULL);
no_reply_cnt++;
rele_sendq_token(sendq_token);
if (e != RSM_SUCCESS) {
DBG_PRINTF((category, RSM_ERR,
"rsm: rsmipc_send no reply send"
" err = %d no reply count = %d\n",
e, no_reply_cnt));
ASSERT(e != RSMERR_QUEUE_FENCE_UP &&
e != RSMERR_BAD_BARRIER_HNDL);
atomic_inc_64(&rsm_ipcsend_errcnt);
goto again;
} else {
DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
"rsmipc_send done\n"));
return (e);
}
}
if (req == NULL) {
reply->rsmipc_hdr.rsmipc_version = RSM_VERSION;
reply->rsmipc_hdr.rsmipc_src = my_nodeid;
reply->rsmipc_hdr.rsmipc_incn = path->remote_incn;
is.is_data = (void *)reply;
is.is_size = sizeof (*reply);
is.is_flags = RSM_INTR_SEND_DELIVER | RSM_INTR_SEND_SLEEP;
is.is_wait = 0;
e = adapter->rsmpi_ops->rsm_send(ipc_handle, &is, NULL);
rele_sendq_token(sendq_token);
if (e != RSM_SUCCESS) {
DBG_PRINTF((category, RSM_ERR,
"rsm: rsmipc_send reply send"
" err = %d\n", e));
atomic_inc_64(&rsm_ipcsend_errcnt);
goto again;
} else {
DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
"rsmipc_send done\n"));
return (e);
}
}
rslot = rsmipc_alloc();
mutex_enter(&rslot->rsmipc_lock);
rslot->rsmipc_data = (void *)reply;
RSMIPC_SET(rslot, RSMIPC_PENDING);
while (RSMIPC_GET(rslot, RSMIPC_PENDING)) {
req->rsmipc_hdr.rsmipc_version = RSM_VERSION;
req->rsmipc_hdr.rsmipc_src = my_nodeid;
req->rsmipc_hdr.rsmipc_cookie = rslot->rsmipc_cookie;
req->rsmipc_hdr.rsmipc_incn = path->remote_incn;
is.is_data = (void *)req;
is.is_size = sizeof (*req);
is.is_flags = RSM_INTR_SEND_DELIVER | RSM_INTR_SEND_SLEEP;
is.is_wait = 0;
if (credit_check) {
mutex_enter(&path->mutex);
while ((sendq_token->msgbuf_avail == 0) &&
(path->state == RSMKA_PATH_ACTIVE)) {
e = cv_wait_sig(&sendq_token->sendq_cv,
&path->mutex);
if (e == 0) {
mutex_exit(&path->mutex);
RSMIPC_CLEAR(rslot, RSMIPC_PENDING);
rsmipc_free(rslot);
rele_sendq_token(sendq_token);
DBG_PRINTF((category, RSM_DEBUG,
"rsmipc_send done: "
"cv_wait INTERRUPTED"));
return (RSMERR_INTERRUPTED);
}
}
if (path->state != RSMKA_PATH_ACTIVE) {
mutex_exit(&path->mutex);
RSMIPC_CLEAR(rslot, RSMIPC_PENDING);
rsmipc_free(rslot);
rele_sendq_token(sendq_token);
e = RSMERR_CONN_ABORTED;
DBG_PRINTF((category, RSM_ERR,
"rsm: rsmipc_send: path !ACTIVE"));
goto again;
}
ASSERT(sendq_token->msgbuf_avail > 0);
sendq_token->msgbuf_avail--;
mutex_exit(&path->mutex);
e = adapter->rsmpi_ops->rsm_send(ipc_handle, &is,
NULL);
if (e != RSM_SUCCESS) {
mutex_enter(&path->mutex);
sendq_token->msgbuf_avail++;
cv_broadcast(&sendq_token->sendq_cv);
mutex_exit(&path->mutex);
}
} else
e = adapter->rsmpi_ops->rsm_send(ipc_handle, &is,
NULL);
if (e != RSM_SUCCESS) {
DBG_PRINTF((category, RSM_ERR,
"rsm: rsmipc_send rsmpi send err = %d\n", e));
RSMIPC_CLEAR(rslot, RSMIPC_PENDING);
rsmipc_free(rslot);
rele_sendq_token(sendq_token);
atomic_inc_64(&rsm_ipcsend_errcnt);
goto again;
}
e = cv_reltimedwait_sig(&rslot->rsmipc_cv, &rslot->rsmipc_lock,
drv_usectohz(5000000), TR_CLOCK_TICK);
if (e < 0) {
e = RSMERR_TIMEOUT;
} else if (e == 0) {
e = RSMERR_INTERRUPTED;
break;
} else {
e = RSM_SUCCESS;
}
}
RSMIPC_CLEAR(rslot, RSMIPC_PENDING);
rsmipc_free(rslot);
rele_sendq_token(sendq_token);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmipc_send done=%d\n", e));
return (e);
}
static int
rsm_send_notimporting(rsm_node_id_t dest, rsm_memseg_id_t segid, void *cookie)
{
rsmipc_request_t request;
request.rsmipc_hdr.rsmipc_type = RSMIPC_MSG_NOTIMPORTING;
request.rsmipc_key = segid;
request.rsmipc_segment_cookie = cookie;
return (rsmipc_send(dest, &request, RSM_NO_REPLY));
}
static void
rsm_send_republish(rsm_memseg_id_t segid, rsmapi_access_entry_t *acl,
int acl_len, rsm_permission_t default_permission)
{
int i;
importing_token_t *token;
rsmipc_request_t request;
republish_token_t *republish_list = NULL;
republish_token_t *rp;
rsm_permission_t permission;
int index;
index = rsmhash(segid);
mutex_enter(&importer_list.lock);
token = importer_list.bucket[index];
while (token != NULL) {
if (segid == token->key) {
permission = default_permission;
for (i = 0; i < acl_len; i++) {
if (token->importing_node == acl[i].ae_node) {
permission = acl[i].ae_permission;
break;
}
}
rp = kmem_zalloc(sizeof (republish_token_t), KM_SLEEP);
rp->key = segid;
rp->importing_node = token->importing_node;
rp->permission = permission;
rp->next = republish_list;
republish_list = rp;
}
token = token->next;
}
mutex_exit(&importer_list.lock);
request.rsmipc_hdr.rsmipc_type = RSMIPC_MSG_REPUBLISH;
request.rsmipc_key = segid;
while (republish_list != NULL) {
request.rsmipc_perm = republish_list->permission;
(void) rsmipc_send(republish_list->importing_node,
&request, RSM_NO_REPLY);
rp = republish_list;
republish_list = republish_list->next;
kmem_free(rp, sizeof (republish_token_t));
}
}
static void
rsm_send_suspend()
{
int i, e;
rsmipc_request_t request;
list_element_t *tokp;
list_element_t *head = NULL;
importing_token_t *token;
DBG_PRINTF((RSM_KERNEL_AGENT | RSM_EXPORT, RSM_DEBUG_VERBOSE,
"rsm_send_suspend enter\n"));
mutex_enter(&importer_list.lock);
for (i = 0; i < rsm_hash_size; i++) {
token = importer_list.bucket[i];
while (token != NULL) {
tokp = head;
while (tokp != NULL) {
if (tokp->nodeid == token->importing_node) {
break;
}
tokp = tokp->next;
}
if (tokp == NULL) {
tokp = kmem_zalloc(sizeof (list_element_t),
KM_SLEEP);
tokp->nodeid = token->importing_node;
tokp->next = head;
head = tokp;
}
token = token->next;
}
}
mutex_exit(&importer_list.lock);
if (head == NULL) {
exporter_quiesce();
return;
}
mutex_enter(&rsm_suspend_list.list_lock);
ASSERT(rsm_suspend_list.list_head == NULL);
rsm_suspend_list.list_head = head;
mutex_exit(&rsm_suspend_list.list_lock);
tokp = head;
while (tokp != NULL) {
request.rsmipc_hdr.rsmipc_type = RSMIPC_MSG_SUSPEND;
e = rsmipc_send(tokp->nodeid, &request, RSM_NO_REPLY);
if (e == RSM_SUCCESS) {
tokp->flags |= RSM_SUSPEND_ACKPENDING;
}
tokp = tokp->next;
}
DBG_PRINTF((RSM_KERNEL_AGENT | RSM_EXPORT, RSM_DEBUG_VERBOSE,
"rsm_send_suspend done\n"));
}
static void
rsm_send_resume()
{
rsmipc_request_t request;
list_element_t *elem, *head;
mutex_enter(&rsm_suspend_list.list_lock);
head = rsm_suspend_list.list_head;
rsm_suspend_list.list_head = NULL;
mutex_exit(&rsm_suspend_list.list_lock);
while (head != NULL) {
elem = head;
head = head->next;
request.rsmipc_hdr.rsmipc_type = RSMIPC_MSG_RESUME;
(void) rsmipc_send(elem->nodeid, &request, RSM_NO_REPLY);
kmem_free((void *)elem, sizeof (list_element_t));
}
}
int
rsmipc_send_controlmsg(path_t *path, int msgtype)
{
int e;
int retry_cnt = 0;
int min_retry_cnt = 10;
adapter_t *adapter;
rsm_send_t is;
rsm_send_q_handle_t ipc_handle;
rsmipc_controlmsg_t msg;
DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_FUNC_ALL | RSM_FLOWCONTROL);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
"rsmipc_send_controlmsg enter\n"));
ASSERT(MUTEX_HELD(&path->mutex));
adapter = path->local_adapter;
DBG_PRINTF((category, RSM_DEBUG, "rsmipc_send_controlmsg:path=%lx "
"msgtype=%d %lx:%llx->%lx:%llx procmsg=%d\n", path, msgtype,
my_nodeid, adapter->hwaddr, path->remote_node,
path->remote_hwaddr, path->procmsg_cnt));
if (path->state != RSMKA_PATH_ACTIVE) {
DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
"rsmipc_send_controlmsg done: ! RSMKA_PATH_ACTIVE"));
return (1);
}
ipc_handle = path->sendq_token.rsmpi_sendq_handle;
msg.rsmipc_hdr.rsmipc_version = RSM_VERSION;
msg.rsmipc_hdr.rsmipc_src = my_nodeid;
msg.rsmipc_hdr.rsmipc_type = msgtype;
msg.rsmipc_hdr.rsmipc_incn = path->remote_incn;
if (msgtype == RSMIPC_MSG_CREDIT)
msg.rsmipc_credits = path->procmsg_cnt;
msg.rsmipc_local_incn = path->local_incn;
msg.rsmipc_adapter_hwaddr = adapter->hwaddr;
PATH_HOLD_NOLOCK(path);
SENDQ_TOKEN_HOLD(path);
do {
mutex_exit(&path->mutex);
is.is_data = (void *)&msg;
is.is_size = sizeof (msg);
is.is_flags = RSM_INTR_SEND_DELIVER | RSM_INTR_SEND_SLEEP;
is.is_wait = 0;
e = adapter->rsmpi_ops->rsm_send(ipc_handle, &is, NULL);
ASSERT(e != RSMERR_QUEUE_FENCE_UP &&
e != RSMERR_BAD_BARRIER_HNDL);
mutex_enter(&path->mutex);
if (e == RSM_SUCCESS) {
break;
}
atomic_inc_64(&rsm_ctrlmsg_errcnt);
DBG_PRINTF((category, RSM_ERR,
"rsmipc_send_controlmsg:rsm_send error=%d", e));
if (++retry_cnt == min_retry_cnt) {
(void) cv_reltimedwait(&path->sendq_token.sendq_cv,
&path->mutex, drv_usectohz(10000), TR_CLOCK_TICK);
retry_cnt = 0;
}
} while (path->state == RSMKA_PATH_ACTIVE);
SENDQ_TOKEN_RELE(path);
PATH_RELE_NOLOCK(path);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
"rsmipc_send_controlmsg done=%d", e));
return (e);
}
void
rsmseg_unload(rsmseg_t *im_seg)
{
rsmcookie_t *hdl;
void *shared_cookie;
rsmipc_request_t request;
uint_t maxprot;
DBG_DEFINE(category,
RSM_KERNEL_AGENT | RSM_FUNC_ALL | RSM_INTR_CALLBACK);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmseg_unload enter\n"));
ASSERT(im_seg->s_hdr.rsmrc_type == RSM_RESOURCE_IMPORT_SEGMENT);
while (im_seg->s_state == RSM_STATE_MAPPING)
cv_wait(&im_seg->s_cv, &im_seg->s_lock);
if (im_seg->s_state == RSM_STATE_NEW) {
rsmseglock_release(im_seg);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
"rsmseg_unload done: RSM_STATE_NEW\n"));
return;
} else if (im_seg->s_state == RSM_STATE_CONNECTING) {
im_seg->s_state = RSM_STATE_ABORT_CONNECT;
rsmsharelock_acquire(im_seg);
im_seg->s_share->rsmsi_state = RSMSI_STATE_ABORT_CONNECT;
rsmsharelock_release(im_seg);
rsmseglock_release(im_seg);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
"rsmseg_unload done: RSM_STATE_CONNECTING\n"));
return;
}
if (im_seg->s_flags & RSM_FORCE_DISCONNECT) {
if (im_seg->s_ckl != NULL) {
int e;
maxprot = PROT_USER;
if (im_seg->s_mode & RSM_PERM_READ) {
maxprot |= PROT_READ;
}
if (im_seg->s_mode & RSM_PERM_WRITE) {
maxprot |= PROT_WRITE;
}
hdl = im_seg->s_ckl;
for (; hdl != NULL; hdl = hdl->c_next) {
e = devmap_umem_remap(hdl->c_dhp, rsm_dip,
remap_cookie,
hdl->c_off, hdl->c_len,
maxprot, 0, NULL);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
"remap returns %d\n", e));
}
}
(void) rsm_closeconnection(im_seg, &shared_cookie);
if (shared_cookie != NULL) {
request.rsmipc_hdr.rsmipc_type =
RSMIPC_MSG_NOTIMPORTING;
request.rsmipc_key = im_seg->s_segid;
request.rsmipc_segment_cookie = shared_cookie;
rsmseglock_release(im_seg);
(void) rsmipc_send(im_seg->s_node, &request,
RSM_NO_REPLY);
} else {
rsmseglock_release(im_seg);
}
}
else
rsmseglock_release(im_seg);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmseg_unload done\n"));
}
static int
rsm_access(uid_t owner, gid_t group, int perm, int mode, const struct cred *cr)
{
int shifts = 0;
if (crgetuid(cr) != owner) {
shifts += 3;
if (!groupmember(group, cr))
shifts += 3;
}
mode &= ~(perm << shifts);
if (mode == 0)
return (0);
return (secpolicy_rsm_access(cr, owner, mode));
}
static int
rsm_connect(rsmseg_t *seg, rsm_ioctlmsg_t *msg, cred_t *cred,
intptr_t dataptr, int mode)
{
int e;
int recheck_state = 0;
void *shared_cookie;
rsmipc_request_t request;
rsmipc_reply_t reply;
rsm_permission_t access;
adapter_t *adapter;
rsm_addr_t addr = 0;
rsm_import_share_t *sharedp;
DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_IMPORT);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_connect enter\n"));
adapter = rsm_getadapter(msg, mode);
if (adapter == NULL) {
DBG_PRINTF((category, RSM_ERR,
"rsm_connect done:ENODEV adapter=NULL\n"));
return (RSMERR_CTLR_NOT_PRESENT);
}
if ((adapter == &loopback_adapter) && (msg->nodeid != my_nodeid)) {
rsmka_release_adapter(adapter);
DBG_PRINTF((category, RSM_ERR,
"rsm_connect done:ENODEV loopback\n"));
return (RSMERR_CTLR_NOT_PRESENT);
}
ASSERT(seg->s_hdr.rsmrc_type == RSM_RESOURCE_IMPORT_SEGMENT);
ASSERT(seg->s_state == RSM_STATE_NEW);
if (msg->perm & ~RSM_PERM_RDWR) {
rsmka_release_adapter(adapter);
DBG_PRINTF((category, RSM_ERR,
"rsm_connect done:EINVAL invalid perms\n"));
return (RSMERR_BAD_PERMS);
}
access = 0;
if (msg->perm & RSM_PERM_READ)
access |= RSM_ACCESS_READ;
if (msg->perm & RSM_PERM_WRITE)
access |= RSM_ACCESS_WRITE;
seg->s_node = msg->nodeid;
e = rsmimport_add(seg, msg->key);
if (e) {
rsmka_release_adapter(adapter);
DBG_PRINTF((category, RSM_ERR,
"rsm_connect done:rsmimport_add failed %d\n", e));
return (e);
}
seg->s_state = RSM_STATE_CONNECTING;
seg->s_adapter = adapter;
rsmseglock_release(seg);
sharedp = rsmshare_get(msg->key, msg->nodeid, adapter, seg);
ASSERT(rsmsharelock_held(seg));
do {
recheck_state = 0;
DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
"rsm_connect:RSMSI_STATE=%d\n", sharedp->rsmsi_state));
switch (sharedp->rsmsi_state) {
case RSMSI_STATE_NEW:
sharedp->rsmsi_state = RSMSI_STATE_CONNECTING;
break;
case RSMSI_STATE_CONNECTING:
case RSMSI_STATE_CONN_QUIESCE:
case RSMSI_STATE_MAP_QUIESCE:
while ((sharedp->rsmsi_state ==
RSMSI_STATE_CONNECTING) ||
(sharedp->rsmsi_state ==
RSMSI_STATE_CONN_QUIESCE) ||
(sharedp->rsmsi_state ==
RSMSI_STATE_MAP_QUIESCE)) {
if (cv_wait_sig(&sharedp->rsmsi_cv,
&sharedp->rsmsi_lock) == 0) {
rsmsharelock_release(seg);
rsmimport_rm(seg);
seg->s_adapter = NULL;
rsmka_release_adapter(adapter);
seg->s_state = RSM_STATE_NEW;
DBG_PRINTF((category, RSM_ERR,
"rsm_connect done: INTERRUPTED\n"));
return (RSMERR_INTERRUPTED);
}
}
recheck_state = 1;
break;
case RSMSI_STATE_ABORT_CONNECT:
break;
case RSMSI_STATE_CONNECTED:
case RSMSI_STATE_MAPPED:
break;
case RSMSI_STATE_DISCONNECTED:
sharedp->rsmsi_state = RSMSI_STATE_CONNECTING;
break;
default:
ASSERT(0);
}
} while (recheck_state);
if (sharedp->rsmsi_state == RSMSI_STATE_CONNECTING) {
rsmsharelock_release(seg);
if (msg->nodeid != my_nodeid) {
addr = get_remote_hwaddr(adapter, msg->nodeid);
if ((int64_t)addr < 0) {
rsmsharelock_acquire(seg);
rsmsharecv_signal(seg, RSMSI_STATE_CONNECTING,
RSMSI_STATE_NEW);
rsmsharelock_release(seg);
rsmimport_rm(seg);
seg->s_adapter = NULL;
rsmka_release_adapter(adapter);
seg->s_state = RSM_STATE_NEW;
DBG_PRINTF((category, RSM_ERR,
"rsm_connect done: hwaddr<0\n"));
return (RSMERR_INTERNAL_ERROR);
}
} else {
addr = adapter->hwaddr;
}
request.rsmipc_key = msg->key;
request.rsmipc_perm = RSM_ACCESS_TRUSTED;
request.rsmipc_hdr.rsmipc_type = RSMIPC_MSG_SEGCONNECT;
request.rsmipc_adapter_hwaddr = addr;
request.rsmipc_segment_cookie = sharedp;
e = (int)rsmipc_send(msg->nodeid, &request, &reply);
if (e) {
rsmsharelock_acquire(seg);
rsmsharecv_signal(seg, RSMSI_STATE_CONNECTING,
RSMSI_STATE_NEW);
rsmsharelock_release(seg);
rsmimport_rm(seg);
seg->s_adapter = NULL;
rsmka_release_adapter(adapter);
seg->s_state = RSM_STATE_NEW;
DBG_PRINTF((category, RSM_ERR,
"rsm_connect done:rsmipc_send failed %d\n", e));
return (e);
}
if (reply.rsmipc_status != RSM_SUCCESS) {
rsmsharelock_acquire(seg);
rsmsharecv_signal(seg, RSMSI_STATE_CONNECTING,
RSMSI_STATE_NEW);
rsmsharelock_release(seg);
rsmimport_rm(seg);
seg->s_adapter = NULL;
rsmka_release_adapter(adapter);
seg->s_state = RSM_STATE_NEW;
DBG_PRINTF((category, RSM_ERR,
"rsm_connect done:rsmipc_send reply err %d\n",
reply.rsmipc_status));
return (reply.rsmipc_status);
}
rsmsharelock_acquire(seg);
sharedp->rsmsi_mode = reply.rsmipc_mode;
sharedp->rsmsi_uid = reply.rsmipc_uid;
sharedp->rsmsi_gid = reply.rsmipc_gid;
sharedp->rsmsi_seglen = reply.rsmipc_seglen;
sharedp->rsmsi_cookie = sharedp;
}
rsmsharelock_release(seg);
rsmseglock_acquire(seg);
rsmsharelock_acquire(seg);
ASSERT(seg->s_state == RSM_STATE_CONNECTING ||
seg->s_state == RSM_STATE_ABORT_CONNECT);
shared_cookie = sharedp->rsmsi_cookie;
if ((seg->s_state == RSM_STATE_ABORT_CONNECT) ||
(sharedp->rsmsi_state == RSMSI_STATE_ABORT_CONNECT)) {
seg->s_state = RSM_STATE_NEW;
seg->s_adapter = NULL;
rsmsharelock_release(seg);
rsmseglock_release(seg);
rsmimport_rm(seg);
rsmka_release_adapter(adapter);
rsmsharelock_acquire(seg);
if (!(sharedp->rsmsi_flags & RSMSI_FLAGS_ABORTDONE)) {
sharedp->rsmsi_flags |= RSMSI_FLAGS_ABORTDONE;
rsmsharelock_release(seg);
(void) rsm_send_notimporting(msg->nodeid,
msg->key, shared_cookie);
rsmsharelock_acquire(seg);
cv_broadcast(&sharedp->rsmsi_cv);
}
rsmsharelock_release(seg);
DBG_PRINTF((category, RSM_ERR,
"rsm_connect done: RSM_STATE_ABORT_CONNECT\n"));
return (RSMERR_INTERRUPTED);
}
e = rsm_access(sharedp->rsmsi_uid, sharedp->rsmsi_gid,
access & sharedp->rsmsi_mode,
(int)(msg->perm & RSM_PERM_RDWR), cred);
if (e) {
rsmsharelock_release(seg);
seg->s_state = RSM_STATE_NEW;
seg->s_adapter = NULL;
rsmseglock_release(seg);
rsmimport_rm(seg);
rsmka_release_adapter(adapter);
rsmsharelock_acquire(seg);
if (sharedp->rsmsi_state == RSMSI_STATE_CONNECTING) {
rsmsharelock_release(seg);
(void) rsm_send_notimporting(msg->nodeid, msg->key,
shared_cookie);
rsmsharelock_acquire(seg);
sharedp->rsmsi_state = RSMSI_STATE_NEW;
cv_broadcast(&sharedp->rsmsi_cv);
}
rsmsharelock_release(seg);
DBG_PRINTF((category, RSM_ERR,
"rsm_connect done: ipcaccess failed\n"));
return (RSMERR_PERM_DENIED);
}
seg->s_segid = sharedp->rsmsi_segid;
seg->s_len = sharedp->rsmsi_seglen;
seg->s_mode = access & sharedp->rsmsi_mode;
seg->s_pid = ddi_get_pid();
seg->s_mapinfo = NULL;
if (seg->s_node != my_nodeid) {
if (sharedp->rsmsi_state == RSMSI_STATE_CONNECTING) {
e = adapter->rsmpi_ops->rsm_connect(
adapter->rsmpi_handle,
addr, seg->s_segid, &sharedp->rsmsi_handle);
if (e != RSM_SUCCESS) {
seg->s_state = RSM_STATE_NEW;
seg->s_adapter = NULL;
rsmsharelock_release(seg);
rsmseglock_release(seg);
rsmimport_rm(seg);
rsmka_release_adapter(adapter);
(void) rsm_send_notimporting(msg->nodeid,
msg->key, shared_cookie);
rsmsharelock_acquire(seg);
sharedp->rsmsi_state = RSMSI_STATE_NEW;
cv_broadcast(&sharedp->rsmsi_cv);
rsmsharelock_release(seg);
DBG_PRINTF((category, RSM_ERR,
"rsm_connect error %d\n", e));
if (e == RSMERR_SEG_NOT_PUBLISHED_TO_RSM_ADDR)
return (
RSMERR_SEG_NOT_PUBLISHED_TO_NODE);
else if ((e == RSMERR_RSM_ADDR_UNREACHABLE) ||
(e == RSMERR_UNKNOWN_RSM_ADDR))
return (RSMERR_REMOTE_NODE_UNREACHABLE);
else
return (e);
}
}
seg->s_handle.in = sharedp->rsmsi_handle;
}
seg->s_state = RSM_STATE_CONNECT;
seg->s_flags &= ~RSM_IMPORT_DUMMY;
if (bar_va) {
atomic_inc_16(bar_va + seg->s_hdr.rsmrc_num);
msg->off = (int)seg->s_hdr.rsmrc_num;
msg->gnum = bar_va[msg->off];
} else {
msg->off = 0;
msg->gnum = 0;
}
msg->len = (int)sharedp->rsmsi_seglen;
msg->rnum = seg->s_minor;
rsmsharecv_signal(seg, RSMSI_STATE_CONNECTING, RSMSI_STATE_CONNECTED);
rsmsharelock_release(seg);
rsmseglock_release(seg);
#ifdef _MULTI_DATAMODEL
if ((mode & DATAMODEL_MASK) == DATAMODEL_ILP32) {
rsm_ioctlmsg32_t msg32;
if (msg->len > UINT_MAX)
msg32.len = RSM_MAXSZ_PAGE_ALIGNED;
else
msg32.len = msg->len;
msg32.off = msg->off;
msg32.perm = msg->perm;
msg32.gnum = msg->gnum;
msg32.rnum = msg->rnum;
DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
"rsm_connect done\n"));
if (ddi_copyout((caddr_t)&msg32, (caddr_t)dataptr,
sizeof (msg32), mode))
return (RSMERR_BAD_ADDR);
else
return (RSM_SUCCESS);
}
#endif
DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_connect done\n"));
if (ddi_copyout((caddr_t)msg, (caddr_t)dataptr, sizeof (*msg),
mode))
return (RSMERR_BAD_ADDR);
else
return (RSM_SUCCESS);
}
static int
rsm_unmap(rsmseg_t *seg)
{
int err;
adapter_t *adapter;
rsm_import_share_t *sharedp;
DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_IMPORT);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
"rsm_unmap enter %u\n", seg->s_segid));
ASSERT(seg->s_hdr.rsmrc_type == RSM_RESOURCE_IMPORT_SEGMENT);
ASSERT(rsmseglock_held(seg));
ASSERT(seg->s_state != RSM_STATE_MAPPING);
if ((seg->s_state != RSM_STATE_ACTIVE) &&
(seg->s_state != RSM_STATE_MAP_QUIESCE)) {
DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_unmap done\n"));
return (RSM_SUCCESS);
}
sharedp = seg->s_share;
rsmsharelock_acquire(seg);
ASSERT(sharedp->rsmsi_state == RSMSI_STATE_MAPPED ||
sharedp->rsmsi_state == RSMSI_STATE_MAP_QUIESCE);
ASSERT(sharedp->rsmsi_mapcnt > 0);
sharedp->rsmsi_mapcnt--;
if (sharedp->rsmsi_mapcnt == 0) {
if (sharedp->rsmsi_state == RSMSI_STATE_MAPPED) {
adapter = seg->s_adapter;
if (seg->s_node != my_nodeid) {
ASSERT(sharedp->rsmsi_handle != NULL);
err = adapter->rsmpi_ops->
rsm_unmap(sharedp->rsmsi_handle);
DBG_PRINTF((category, RSM_DEBUG,
"rsm_unmap: rsmpi unmap %d\n", err));
rsm_free_mapinfo(sharedp->rsmsi_mapinfo);
sharedp->rsmsi_mapinfo = NULL;
}
sharedp->rsmsi_state = RSMSI_STATE_CONNECTED;
} else {
sharedp->rsmsi_state = RSMSI_STATE_CONN_QUIESCE;
}
}
rsmsharelock_release(seg);
seg->s_cookie = NULL;
seg->s_mapinfo = NULL;
if (seg->s_state == RSM_STATE_ACTIVE)
seg->s_state = RSM_STATE_CONNECT;
else
seg->s_state = RSM_STATE_CONN_QUIESCE;
DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_unmap done\n"));
return (RSM_SUCCESS);
}
static int
rsm_closeconnection(rsmseg_t *seg, void **cookie)
{
int e;
adapter_t *adapter;
rsm_import_share_t *sharedp;
DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_IMPORT);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
"rsm_closeconnection enter\n"));
*cookie = (void *)NULL;
ASSERT(seg->s_hdr.rsmrc_type == RSM_RESOURCE_IMPORT_SEGMENT);
ASSERT(rsmseglock_held(seg));
if (seg->s_state == RSM_STATE_DISCONNECT) {
DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
"rsm_closeconnection done: already disconnected\n"));
return (RSM_SUCCESS);
}
while (seg->s_rdmacnt > 0) {
cv_wait(&seg->s_cv, &seg->s_lock);
}
(void) rsm_unmap(seg);
ASSERT(seg->s_state == RSM_STATE_CONNECT ||
seg->s_state == RSM_STATE_CONN_QUIESCE);
adapter = seg->s_adapter;
sharedp = seg->s_share;
ASSERT(sharedp != NULL);
rsmsharelock_acquire(seg);
if ((sharedp->rsmsi_state == RSMSI_STATE_CONNECTED) &&
(sharedp->rsmsi_node != my_nodeid)) {
if (sharedp->rsmsi_refcnt == 1) {
ASSERT(sharedp->rsmsi_mapcnt == 0);
e = adapter->rsmpi_ops->
rsm_disconnect(sharedp->rsmsi_handle);
if (e != RSM_SUCCESS) {
DBG_PRINTF((category, RSM_DEBUG,
"rsm:disconnect failed seg=%x:err=%d\n",
seg->s_key, e));
}
}
}
seg->s_handle.in = NULL;
sharedp->rsmsi_refcnt--;
if (sharedp->rsmsi_refcnt == 0) {
*cookie = (void *)sharedp->rsmsi_cookie;
sharedp->rsmsi_state = RSMSI_STATE_DISCONNECTED;
sharedp->rsmsi_handle = NULL;
rsmsharelock_release(seg);
mutex_destroy(&sharedp->rsmsi_lock);
cv_destroy(&sharedp->rsmsi_cv);
kmem_free((void *)(sharedp), sizeof (rsm_import_share_t));
} else {
rsmsharelock_release(seg);
}
if (bar_va) {
atomic_inc_16(bar_va + seg->s_hdr.rsmrc_num);
}
seg->s_share = NULL;
seg->s_state = RSM_STATE_DISCONNECT;
cv_broadcast(&seg->s_cv);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
"rsm_closeconnection done\n"));
return (RSM_SUCCESS);
}
int
rsm_disconnect(rsmseg_t *seg)
{
rsmipc_request_t request;
void *shared_cookie;
DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_IMPORT);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_disconnect enter\n"));
ASSERT(seg->s_hdr.rsmrc_type == RSM_RESOURCE_IMPORT_SEGMENT);
ASSERT(!rsmseglock_held(seg));
rsmimport_rm(seg);
rsmseglock_acquire(seg);
while (seg->s_state == RSM_STATE_MAPPING)
cv_wait(&seg->s_cv, &seg->s_lock);
if (seg->s_state == RSM_STATE_DISCONNECT) {
seg->s_state = RSM_STATE_NEW;
rsmseglock_release(seg);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
"rsm_disconnect done: already disconnected\n"));
return (RSM_SUCCESS);
}
(void) rsm_closeconnection(seg, &shared_cookie);
seg->s_state = RSM_STATE_NEW;
if (shared_cookie != NULL) {
request.rsmipc_hdr.rsmipc_type = RSMIPC_MSG_NOTIMPORTING;
request.rsmipc_key = seg->s_segid;
request.rsmipc_segment_cookie = shared_cookie;
rsmseglock_release(seg);
(void) rsmipc_send(seg->s_node, &request, RSM_NO_REPLY);
} else {
rsmseglock_release(seg);
}
DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_disconnect done\n"));
return (DDI_SUCCESS);
}
static int
rsm_chpoll(dev_t dev, short events, int anyyet, short *reventsp,
struct pollhead **phpp)
{
minor_t rnum;
rsmresource_t *res;
rsmseg_t *seg;
DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_FUNC_ALL | RSM_DDI);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_chpoll enter\n"));
rnum = getminor(dev);
res = rsmresource_lookup(rnum, RSM_NOLOCK);
if ((res == NULL) || (res == RSMRC_RESERVED) ||
(res->rsmrc_type == RSM_RESOURCE_BAR)) {
return (ENXIO);
}
seg = (rsmseg_t *)res;
if (seg->s_pollevent) {
*reventsp = POLLRDNORM;
} else {
*reventsp = 0;
}
if ((*reventsp == 0 && !anyyet) || (events & POLLET)) {
*phpp = &seg->s_poll;
seg->s_pollflag |= RSM_SEGMENT_POLL;
}
DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_chpoll done\n"));
return (0);
}
static rsmseg_t *
rsmresource_seg(rsmresource_t *res, minor_t rnum, cred_t *credp,
rsm_resource_type_t type)
{
rsmseg_t *seg;
DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_FUNC_ALL | RSM_IOCTL);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmresource_seg enter\n"));
if (res != RSMRC_RESERVED) {
seg = (rsmseg_t *)res;
} else {
seg = rsmseg_alloc(rnum, credp);
if (type == RSM_RESOURCE_EXPORT_SEGMENT) {
mutex_enter(&rsm_drv_data.drv_lock);
if ((rsm_drv_data.drv_state ==
RSM_DRV_PREDEL_STARTED) ||
(rsm_drv_data.drv_state ==
RSM_DRV_PREDEL_COMPLETED) ||
(rsm_drv_data.drv_state ==
RSM_DRV_DR_IN_PROGRESS)) {
seg->s_state = RSM_STATE_NEW_QUIESCED;
}
mutex_exit(&rsm_drv_data.drv_lock);
}
rsmresource_insert(rnum, (rsmresource_t *)seg, type);
}
DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmresource_seg done\n"));
return (seg);
}
static int
rsmexport_ioctl(rsmseg_t *seg, rsm_ioctlmsg_t *msg, int cmd, intptr_t arg,
int mode, cred_t *credp)
{
int error;
DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_EXPORT | RSM_IOCTL);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmexport_ioctl enter\n"));
arg = arg;
credp = credp;
ASSERT(seg != NULL);
switch (cmd) {
case RSM_IOCTL_BIND:
error = rsm_bind(seg, msg, arg, mode);
break;
case RSM_IOCTL_REBIND:
error = rsm_rebind(seg, msg);
break;
case RSM_IOCTL_UNBIND:
error = ENOTSUP;
break;
case RSM_IOCTL_PUBLISH:
error = rsm_publish(seg, msg, arg, mode);
break;
case RSM_IOCTL_REPUBLISH:
error = rsm_republish(seg, msg, mode);
break;
case RSM_IOCTL_UNPUBLISH:
error = rsm_unpublish(seg, 1);
break;
default:
error = EINVAL;
break;
}
DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmexport_ioctl done: %d\n",
error));
return (error);
}
static int
rsmimport_ioctl(rsmseg_t *seg, rsm_ioctlmsg_t *msg, int cmd, intptr_t arg,
int mode, cred_t *credp)
{
int error;
DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_IMPORT | RSM_IOCTL);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmimport_ioctl enter\n"));
ASSERT(seg);
switch (cmd) {
case RSM_IOCTL_CONNECT:
error = rsm_connect(seg, msg, credp, arg, mode);
break;
default:
error = EINVAL;
break;
}
DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmimport_ioctl done: %d\n",
error));
return (error);
}
static int
rsmbar_ioctl(rsmseg_t *seg, rsm_ioctlmsg_t *msg, int cmd, intptr_t arg,
int mode)
{
int e;
adapter_t *adapter;
DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_IMPORT | RSM_IOCTL);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmbar_ioctl enter\n"));
if ((seg->s_flags & RSM_IMPORT_DUMMY) != 0) {
DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
"rsmbar_ioctl done: RSM_IMPORT_DUMMY\n"));
return (RSMERR_CONN_ABORTED);
} else if (seg->s_node == my_nodeid) {
DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
"rsmbar_ioctl done: loopback\n"));
return (RSM_SUCCESS);
}
adapter = seg->s_adapter;
switch (cmd) {
case RSM_IOCTL_BAR_CHECK:
DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
"rsmbar_ioctl done: RSM_BAR_CHECK %d\n", bar_va));
return (bar_va ? RSM_SUCCESS : EINVAL);
case RSM_IOCTL_BAR_OPEN:
e = adapter->rsmpi_ops->
rsm_open_barrier_ctrl(adapter->rsmpi_handle, &msg->bar);
break;
case RSM_IOCTL_BAR_ORDER:
e = adapter->rsmpi_ops->rsm_order_barrier(&msg->bar);
break;
case RSM_IOCTL_BAR_CLOSE:
e = adapter->rsmpi_ops->rsm_close_barrier(&msg->bar);
break;
default:
e = EINVAL;
break;
}
if (e == RSM_SUCCESS) {
#ifdef _MULTI_DATAMODEL
if ((mode & DATAMODEL_MASK) == DATAMODEL_ILP32) {
rsm_ioctlmsg32_t msg32;
int i;
for (i = 0; i < 4; i++) {
msg32.bar.comp[i].u64 = msg->bar.comp[i].u64;
}
DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
"rsmbar_ioctl done\n"));
if (ddi_copyout((caddr_t)&msg32, (caddr_t)arg,
sizeof (msg32), mode))
return (RSMERR_BAD_ADDR);
else
return (RSM_SUCCESS);
}
#endif
DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
"rsmbar_ioctl done\n"));
if (ddi_copyout((caddr_t)&msg->bar, (caddr_t)arg,
sizeof (*msg), mode))
return (RSMERR_BAD_ADDR);
else
return (RSM_SUCCESS);
}
DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
"rsmbar_ioctl done: error=%d\n", e));
return (e);
}
static int
exportbell_ioctl(rsmseg_t *seg, int cmd )
{
int e = 0;
rsmipc_request_t request;
DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_IMPORT | RSM_IOCTL);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "exportbell_ioctl enter\n"));
request.rsmipc_key = seg->s_segid;
request.rsmipc_hdr.rsmipc_type = RSMIPC_MSG_BELL;
request.rsmipc_segment_cookie = NULL;
e = rsmipc_send(seg->s_node, &request, RSM_NO_REPLY);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
"exportbell_ioctl done: %d\n", e));
return (e);
}
static int
importbell_ioctl(rsmseg_t *seg, int cmd )
{
importing_token_t *token = NULL;
rsmipc_request_t request;
int index;
DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_EXPORT | RSM_IOCTL);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "importbell_ioctl enter\n"));
ASSERT(seg->s_state != RSM_STATE_NEW &&
seg->s_state != RSM_STATE_NEW_QUIESCED);
request.rsmipc_key = seg->s_segid;
request.rsmipc_hdr.rsmipc_type = RSMIPC_MSG_BELL;
index = rsmhash(seg->s_segid);
token = importer_list.bucket[index];
while (token != NULL) {
if (seg->s_key == token->key) {
request.rsmipc_segment_cookie =
token->import_segment_cookie;
(void) rsmipc_send(token->importing_node,
&request, RSM_NO_REPLY);
}
token = token->next;
}
DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
"importbell_ioctl done\n"));
return (RSM_SUCCESS);
}
static int
rsm_consumeevent_copyin(caddr_t arg, rsm_consume_event_msg_t *msgp,
rsm_poll_event_t **eventspp, int mode)
{
rsm_poll_event_t *evlist = NULL;
size_t evlistsz;
DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_IOCTL);
#ifdef _MULTI_DATAMODEL
if ((mode & DATAMODEL_MASK) == DATAMODEL_ILP32) {
int i;
rsm_consume_event_msg32_t cemsg32 = {0};
rsm_poll_event32_t event32[RSM_MAX_POLLFDS];
rsm_poll_event32_t *evlist32;
size_t evlistsz32;
if (ddi_copyin(arg, (caddr_t)&cemsg32,
sizeof (rsm_consume_event_msg32_t), mode)) {
DBG_PRINTF((category, RSM_ERR,
"consumeevent_copyin msgp: RSMERR_BAD_ADDR\n"));
return (RSMERR_BAD_ADDR);
}
msgp->seglist = (caddr_t)(uintptr_t)cemsg32.seglist;
msgp->numents = (int)cemsg32.numents;
evlistsz32 = sizeof (rsm_poll_event32_t) * msgp->numents;
if (msgp->numents > RSM_MAX_POLLFDS) {
if (msgp->numents > max_segs) {
DBG_PRINTF((category, RSM_ERR,
"consumeevent_copyin: "
"RSMERR_BAD_ARGS_ERRORS\n"));
return (RSMERR_BAD_ARGS_ERRORS);
}
evlist32 = kmem_zalloc(evlistsz32, KM_SLEEP);
} else {
evlist32 = event32;
}
if (ddi_copyin((caddr_t)msgp->seglist, (caddr_t)evlist32,
evlistsz32, mode)) {
if ((msgp->numents > RSM_MAX_POLLFDS) && evlist32) {
kmem_free(evlist32, evlistsz32);
}
DBG_PRINTF((category, RSM_ERR,
"consumeevent_copyin evlist: RSMERR_BAD_ADDR\n"));
return (RSMERR_BAD_ADDR);
}
evlistsz = sizeof (rsm_poll_event_t)* msgp->numents;
if (msgp->numents > RSM_MAX_POLLFDS) {
evlist = kmem_zalloc(evlistsz, KM_SLEEP);
*eventspp = evlist;
} else {
evlist = *eventspp;
}
for (i = 0; i < msgp->numents; i++) {
evlist[i].rnum = evlist32[i].rnum;
evlist[i].fdsidx = evlist32[i].fdsidx;
evlist[i].revent = evlist32[i].revent;
}
if ((msgp->numents > RSM_MAX_POLLFDS) && evlist32) {
kmem_free(evlist32, evlistsz32);
}
return (RSM_SUCCESS);
}
#endif
if (ddi_copyin(arg, (caddr_t)msgp, sizeof (rsm_consume_event_msg_t),
mode)) {
DBG_PRINTF((category, RSM_ERR,
"consumeevent_copyin msgp: RSMERR_BAD_ADDR\n"));
return (RSMERR_BAD_ADDR);
}
if (msgp->numents > RSM_MAX_POLLFDS) {
if (msgp->numents > max_segs) {
DBG_PRINTF((category, RSM_ERR,
"consumeevent_copyin: RSMERR_BAD_ARGS_ERRORS\n"));
return (RSMERR_BAD_ARGS_ERRORS);
}
evlistsz = sizeof (rsm_poll_event_t)*msgp->numents;
evlist = kmem_zalloc(evlistsz, KM_SLEEP);
*eventspp = evlist;
}
if (ddi_copyin((caddr_t)msgp->seglist, (caddr_t)(*eventspp),
sizeof (rsm_poll_event_t)*msgp->numents, mode)) {
if (evlist) {
kmem_free(evlist, evlistsz);
*eventspp = NULL;
}
DBG_PRINTF((category, RSM_ERR,
"consumeevent_copyin evlist: RSMERR_BAD_ADDR\n"));
return (RSMERR_BAD_ADDR);
}
DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
"consumeevent_copyin done\n"));
return (RSM_SUCCESS);
}
static int
rsm_consumeevent_copyout(rsm_consume_event_msg_t *msgp,
rsm_poll_event_t *eventsp, int mode)
{
size_t evlistsz;
int err = RSM_SUCCESS;
DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_IOCTL);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
"consumeevent_copyout enter: numents(%d) eventsp(%p)\n",
msgp->numents, eventsp));
#ifdef _MULTI_DATAMODEL
if ((mode & DATAMODEL_MASK) == DATAMODEL_ILP32) {
int i;
rsm_poll_event32_t event32[RSM_MAX_POLLFDS];
rsm_poll_event32_t *evlist32;
size_t evlistsz32;
evlistsz32 = sizeof (rsm_poll_event32_t)*msgp->numents;
if (msgp->numents > RSM_MAX_POLLFDS) {
evlist32 = kmem_zalloc(evlistsz32, KM_SLEEP);
} else {
evlist32 = event32;
}
for (i = 0; i < msgp->numents; i++) {
evlist32[i].rnum = eventsp[i].rnum;
evlist32[i].fdsidx = eventsp[i].fdsidx;
evlist32[i].revent = eventsp[i].revent;
}
if (ddi_copyout((caddr_t)evlist32, (caddr_t)msgp->seglist,
evlistsz32, mode)) {
err = RSMERR_BAD_ADDR;
}
if (msgp->numents > RSM_MAX_POLLFDS) {
if (evlist32) {
kmem_free(evlist32, evlistsz32);
}
evlistsz = sizeof (rsm_poll_event_t)*msgp->numents;
if (eventsp) {
kmem_free(eventsp, evlistsz);
}
}
DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
"consumeevent_copyout done: err=%d\n", err));
return (err);
}
#endif
evlistsz = sizeof (rsm_poll_event_t)*msgp->numents;
if (ddi_copyout((caddr_t)eventsp, (caddr_t)msgp->seglist, evlistsz,
mode)) {
err = RSMERR_BAD_ADDR;
}
if ((msgp->numents > RSM_MAX_POLLFDS) && eventsp) {
kmem_free(eventsp, evlistsz);
}
DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
"consumeevent_copyout done: err=%d\n", err));
return (err);
}
static int
rsm_consumeevent_ioctl(caddr_t arg, int mode)
{
int rc;
int i;
minor_t rnum;
rsm_consume_event_msg_t msg = {0};
rsmseg_t *seg;
rsm_poll_event_t *event_list;
rsm_poll_event_t events[RSM_MAX_POLLFDS];
DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_IOCTL);
event_list = events;
if ((rc = rsm_consumeevent_copyin(arg, &msg, &event_list, mode)) !=
RSM_SUCCESS) {
return (rc);
}
for (i = 0; i < msg.numents; i++) {
rnum = event_list[i].rnum;
event_list[i].revent = 0;
seg = (rsmseg_t *)rsmresource_lookup(rnum, RSM_LOCK);
if (seg) {
DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
"consumeevent_ioctl: rnum(%d) seg(%p)\n", rnum,
seg));
if (seg->s_pollevent) {
atomic_dec_32(&seg->s_pollevent);
event_list[i].revent = POLLRDNORM;
}
rsmseglock_release(seg);
}
}
if ((rc = rsm_consumeevent_copyout(&msg, event_list, mode)) !=
RSM_SUCCESS) {
return (rc);
}
return (RSM_SUCCESS);
}
static int
iovec_copyin(caddr_t user_vec, rsmka_iovec_t *iovec, int count, int mode)
{
int size;
DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_IMPORT | RSM_IOCTL);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "iovec_copyin enter\n"));
#ifdef _MULTI_DATAMODEL
if ((mode & DATAMODEL_MASK) == DATAMODEL_ILP32) {
rsmka_iovec32_t *iovec32, *iovec32_base;
int i;
size = count * sizeof (rsmka_iovec32_t);
iovec32_base = iovec32 = kmem_zalloc(size, KM_SLEEP);
if (ddi_copyin((caddr_t)user_vec,
(caddr_t)iovec32, size, mode)) {
kmem_free(iovec32, size);
DBG_PRINTF((category, RSM_DEBUG,
"iovec_copyin: returning RSMERR_BAD_ADDR\n"));
return (RSMERR_BAD_ADDR);
}
for (i = 0; i < count; i++, iovec++, iovec32++) {
iovec->io_type = (int)iovec32->io_type;
if (iovec->io_type == RSM_HANDLE_TYPE)
iovec->local.segid = (rsm_memseg_id_t)
iovec32->local;
else
iovec->local.vaddr =
(caddr_t)(uintptr_t)iovec32->local;
iovec->local_offset = (size_t)iovec32->local_offset;
iovec->remote_offset = (size_t)iovec32->remote_offset;
iovec->transfer_len = (size_t)iovec32->transfer_len;
}
kmem_free(iovec32_base, size);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
"iovec_copyin done\n"));
return (DDI_SUCCESS);
}
#endif
size = count * sizeof (rsmka_iovec_t);
if (ddi_copyin((caddr_t)user_vec, (caddr_t)iovec, size, mode)) {
DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
"iovec_copyin done: RSMERR_BAD_ADDR\n"));
return (RSMERR_BAD_ADDR);
}
DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "iovec_copyin done\n"));
return (DDI_SUCCESS);
}
static int
sgio_copyin(caddr_t arg, rsmka_scat_gath_t *sg_io, int mode)
{
DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_IMPORT | RSM_IOCTL);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "sgio_copyin enter\n"));
#ifdef _MULTI_DATAMODEL
if ((mode & DATAMODEL_MASK) == DATAMODEL_ILP32) {
rsmka_scat_gath32_t sg_io32;
if (ddi_copyin(arg, (caddr_t)&sg_io32, sizeof (sg_io32),
mode)) {
DBG_PRINTF((category, RSM_DEBUG,
"sgio_copyin done: returning EFAULT\n"));
return (RSMERR_BAD_ADDR);
}
sg_io->local_nodeid = (rsm_node_id_t)sg_io32.local_nodeid;
sg_io->io_request_count = (size_t)sg_io32.io_request_count;
sg_io->io_residual_count = (size_t)sg_io32.io_residual_count;
sg_io->flags = (size_t)sg_io32.flags;
sg_io->remote_handle = (rsm_memseg_import_handle_t)
(uintptr_t)sg_io32.remote_handle;
sg_io->iovec = (rsmka_iovec_t *)(uintptr_t)sg_io32.iovec;
DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
"sgio_copyin done\n"));
return (DDI_SUCCESS);
}
#endif
if (ddi_copyin(arg, (caddr_t)sg_io, sizeof (rsmka_scat_gath_t),
mode)) {
DBG_PRINTF((category, RSM_DEBUG,
"sgio_copyin done: returning EFAULT\n"));
return (RSMERR_BAD_ADDR);
}
DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "sgio_copyin done\n"));
return (DDI_SUCCESS);
}
static int
sgio_resid_copyout(caddr_t arg, rsmka_scat_gath_t *sg_io, int mode)
{
DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_IMPORT | RSM_IOCTL);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
"sgio_resid_copyout enter\n"));
#ifdef _MULTI_DATAMODEL
if ((mode & DATAMODEL_MASK) == DATAMODEL_ILP32) {
rsmka_scat_gath32_t sg_io32;
sg_io32.io_residual_count = sg_io->io_residual_count;
sg_io32.flags = sg_io->flags;
if (ddi_copyout((caddr_t)&sg_io32.io_residual_count,
(caddr_t)&((rsmka_scat_gath32_t *)arg)->io_residual_count,
sizeof (uint32_t), mode)) {
DBG_PRINTF((category, RSM_ERR,
"sgio_resid_copyout error: rescnt\n"));
return (RSMERR_BAD_ADDR);
}
if (ddi_copyout((caddr_t)&sg_io32.flags,
(caddr_t)&((rsmka_scat_gath32_t *)arg)->flags,
sizeof (uint32_t), mode)) {
DBG_PRINTF((category, RSM_ERR,
"sgio_resid_copyout error: flags\n"));
return (RSMERR_BAD_ADDR);
}
DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
"sgio_resid_copyout done\n"));
return (DDI_SUCCESS);
}
#endif
if (ddi_copyout((caddr_t)&sg_io->io_residual_count,
(caddr_t)&((rsmka_scat_gath_t *)arg)->io_residual_count,
sizeof (ulong_t), mode)) {
DBG_PRINTF((category, RSM_ERR,
"sgio_resid_copyout error:rescnt\n"));
return (RSMERR_BAD_ADDR);
}
if (ddi_copyout((caddr_t)&sg_io->flags,
(caddr_t)&((rsmka_scat_gath_t *)arg)->flags,
sizeof (uint_t), mode)) {
DBG_PRINTF((category, RSM_ERR,
"sgio_resid_copyout error:flags\n"));
return (RSMERR_BAD_ADDR);
}
DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "sgio_resid_copyout done\n"));
return (DDI_SUCCESS);
}
static int
rsm_iovec_ioctl(dev_t dev, caddr_t arg, int cmd, int mode, cred_t *credp)
{
rsmka_scat_gath_t sg_io;
rsmka_iovec_t ka_iovec_arr[RSM_MAX_IOVLEN];
rsmka_iovec_t *ka_iovec;
rsmka_iovec_t *ka_iovec_start;
rsmpi_scat_gath_t rsmpi_sg_io;
rsmpi_iovec_t iovec_arr[RSM_MAX_IOVLEN];
rsmpi_iovec_t *iovec;
rsmpi_iovec_t *iovec_start = NULL;
rsmapi_access_entry_t *acl;
rsmresource_t *res;
minor_t rnum;
rsmseg_t *im_seg, *ex_seg;
int e;
int error = 0;
uint_t i;
uint_t iov_proc = 0;
size_t size = 0;
size_t ka_size;
DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_IMPORT | RSM_IOCTL);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_iovec_ioctl enter\n"));
credp = credp;
e = sgio_copyin(arg, &sg_io, mode);
if (e != DDI_SUCCESS) {
DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
"rsm_iovec_ioctl done: sgio_copyin %d\n", e));
return (e);
}
if (sg_io.io_request_count > RSM_MAX_SGIOREQS) {
DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
"rsm_iovec_ioctl done: request_count(%d) too large\n",
sg_io.io_request_count));
return (RSMERR_BAD_SGIO);
}
rsmpi_sg_io.io_request_count = sg_io.io_request_count;
rsmpi_sg_io.io_residual_count = sg_io.io_request_count;
rsmpi_sg_io.io_segflg = 0;
if (sg_io.io_request_count > RSM_MAX_IOVLEN) {
ka_size = sg_io.io_request_count * sizeof (rsmka_iovec_t);
ka_iovec_start = ka_iovec = kmem_zalloc(ka_size, KM_SLEEP);
} else {
ka_iovec_start = ka_iovec = ka_iovec_arr;
}
e = iovec_copyin((caddr_t)sg_io.iovec, ka_iovec,
sg_io.io_request_count, mode);
if (e != DDI_SUCCESS) {
if (sg_io.io_request_count > RSM_MAX_IOVLEN)
kmem_free(ka_iovec, ka_size);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
"rsm_iovec_ioctl done: iovec_copyin %d\n", e));
return (e);
}
rnum = getminor(dev);
res = rsmresource_lookup(rnum, RSM_LOCK);
im_seg = (rsmseg_t *)res;
if (im_seg == NULL) {
if (sg_io.io_request_count > RSM_MAX_IOVLEN)
kmem_free(ka_iovec, ka_size);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
"rsm_iovec_ioctl done: rsmresource_lookup failed\n"));
return (EINVAL);
}
if (im_seg->s_type != RSM_RESOURCE_IMPORT_SEGMENT) {
rsmseglock_release(im_seg);
if (sg_io.io_request_count > RSM_MAX_IOVLEN)
kmem_free(ka_iovec, ka_size);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
"rsm_iovec_ioctl done: not an import segment\n"));
return (EINVAL);
}
while ((im_seg->s_state == RSM_STATE_CONN_QUIESCE) ||
(im_seg->s_state == RSM_STATE_MAP_QUIESCE) ||
(im_seg->s_flags & RSM_DR_INPROGRESS)) {
if (cv_wait_sig(&im_seg->s_cv, &im_seg->s_lock) == 0) {
DBG_PRINTF((category, RSM_DEBUG,
"rsm_iovec_ioctl done: cv_wait INTR"));
rsmseglock_release(im_seg);
return (RSMERR_INTERRUPTED);
}
}
if ((im_seg->s_state != RSM_STATE_CONNECT) &&
(im_seg->s_state != RSM_STATE_ACTIVE)) {
ASSERT(im_seg->s_state == RSM_STATE_DISCONNECT ||
im_seg->s_state == RSM_STATE_NEW);
DBG_PRINTF((category, RSM_DEBUG,
"rsm_iovec_ioctl done: im_seg not conn/map"));
rsmseglock_release(im_seg);
e = RSMERR_BAD_SGIO;
goto out;
}
im_seg->s_rdmacnt++;
rsmseglock_release(im_seg);
if (sg_io.io_request_count > RSM_MAX_IOVLEN) {
size = sg_io.io_request_count * sizeof (rsmpi_iovec_t);
iovec_start = iovec = kmem_zalloc(size, KM_SLEEP);
} else {
iovec_start = iovec = iovec_arr;
}
rsmpi_sg_io.iovec = iovec;
for (iov_proc = 0; iov_proc < sg_io.io_request_count; iov_proc++) {
if (ka_iovec->io_type == RSM_HANDLE_TYPE) {
ex_seg = rsmexport_lookup(ka_iovec->local.segid);
if (ex_seg == NULL) {
e = RSMERR_BAD_SGIO;
break;
}
ASSERT(ex_seg->s_state == RSM_STATE_EXPORT);
acl = ex_seg->s_acl;
if (acl[0].ae_permission == 0) {
struct buf *xbuf;
dev_t sdev = 0;
xbuf = ddi_umem_iosetup(ex_seg->s_cookie,
0, ex_seg->s_len, B_WRITE,
sdev, 0, NULL, DDI_UMEM_SLEEP);
ASSERT(xbuf != NULL);
iovec->local_mem.ms_type = RSM_MEM_BUF;
iovec->local_mem.ms_memory.bp = xbuf;
} else {
iovec->local_mem.ms_type = RSM_MEM_HANDLE;
iovec->local_mem.ms_memory.handle =
ex_seg->s_handle.out;
}
ex_seg->s_rdmacnt++;
rsmseglock_release(ex_seg);
} else {
iovec->local_mem.ms_type = RSM_MEM_VADDR;
iovec->local_mem.ms_memory.vr.vaddr =
ka_iovec->local.vaddr;
}
iovec->local_offset = ka_iovec->local_offset;
iovec->remote_handle = im_seg->s_handle.in;
iovec->remote_offset = ka_iovec->remote_offset;
iovec->transfer_length = ka_iovec->transfer_len;
iovec++;
ka_iovec++;
}
if (iov_proc < sg_io.io_request_count) {
rsmseglock_acquire(im_seg);
im_seg->s_rdmacnt--;
if (im_seg->s_rdmacnt == 0) {
cv_broadcast(&im_seg->s_cv);
}
rsmseglock_release(im_seg);
goto out;
}
if (cmd == RSM_IOCTL_PUTV)
e = im_seg->s_adapter->rsmpi_ops->rsm_memseg_import_putv(
im_seg->s_adapter->rsmpi_handle,
&rsmpi_sg_io);
else if (cmd == RSM_IOCTL_GETV)
e = im_seg->s_adapter->rsmpi_ops->rsm_memseg_import_getv(
im_seg->s_adapter->rsmpi_handle,
&rsmpi_sg_io);
else {
e = EINVAL;
DBG_PRINTF((category, RSM_DEBUG,
"iovec_ioctl: bad command = %x\n", cmd));
}
DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
"rsm_iovec_ioctl RSMPI oper done %d\n", e));
sg_io.io_residual_count = rsmpi_sg_io.io_residual_count;
if (sg_io.flags & RSM_IMPLICIT_SIGPOST &&
e == RSM_SUCCESS) {
rsmipc_request_t request;
request.rsmipc_key = im_seg->s_segid;
request.rsmipc_hdr.rsmipc_type = RSMIPC_MSG_BELL;
request.rsmipc_segment_cookie = NULL;
e = rsmipc_send(im_seg->s_node, &request, RSM_NO_REPLY);
sg_io.flags &= ~RSM_IMPLICIT_SIGPOST;
}
rsmseglock_acquire(im_seg);
im_seg->s_rdmacnt--;
if (im_seg->s_rdmacnt == 0) {
cv_broadcast(&im_seg->s_cv);
}
rsmseglock_release(im_seg);
error = sgio_resid_copyout(arg, &sg_io, mode);
out:
iovec = iovec_start;
ka_iovec = ka_iovec_start;
for (i = 0; i < iov_proc; i++) {
if (ka_iovec->io_type == RSM_HANDLE_TYPE) {
ex_seg = rsmexport_lookup(ka_iovec->local.segid);
ASSERT(ex_seg != NULL);
ASSERT(ex_seg->s_state == RSM_STATE_EXPORT);
ex_seg->s_rdmacnt--;
if (ex_seg->s_rdmacnt == 0) {
cv_broadcast(&ex_seg->s_cv);
}
rsmseglock_release(ex_seg);
}
ASSERT(iovec != NULL);
if (iovec->local_mem.ms_type == RSM_MEM_BUF) {
freerbuf(iovec->local_mem.ms_memory.bp);
}
iovec++;
ka_iovec++;
}
if (sg_io.io_request_count > RSM_MAX_IOVLEN) {
if (iovec_start)
kmem_free(iovec_start, size);
kmem_free(ka_iovec_start, ka_size);
}
DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
"rsm_iovec_ioctl done %d\n", e));
return ((e != RSM_SUCCESS) ? e : error);
}
static int
rsmaddr_ioctl(int cmd, rsm_ioctlmsg_t *msg, int mode)
{
adapter_t *adapter;
rsm_addr_t addr;
rsm_node_id_t node;
int rval = DDI_SUCCESS;
DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_FUNC_ALL | RSM_IOCTL);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmaddr_ioctl enter\n"));
adapter = rsm_getadapter(msg, mode);
if (adapter == NULL) {
DBG_PRINTF((category, RSM_DEBUG,
"rsmaddr_ioctl done: adapter not found\n"));
return (RSMERR_CTLR_NOT_PRESENT);
}
switch (cmd) {
case RSM_IOCTL_MAP_TO_ADDR:
if (msg->nodeid == my_nodeid) {
msg->hwaddr = adapter->hwaddr;
} else {
addr = get_remote_hwaddr(adapter, msg->nodeid);
if ((int64_t)addr < 0) {
rval = RSMERR_INTERNAL_ERROR;
} else {
msg->hwaddr = addr;
}
}
break;
case RSM_IOCTL_MAP_TO_NODEID:
if (msg->hwaddr == adapter->hwaddr) {
msg->nodeid = my_nodeid;
} else {
node = get_remote_nodeid(adapter, msg->hwaddr);
if ((int)node < 0) {
rval = RSMERR_INTERNAL_ERROR;
} else {
msg->nodeid = (rsm_node_id_t)node;
}
}
break;
default:
rval = EINVAL;
break;
}
rsmka_release_adapter(adapter);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
"rsmaddr_ioctl done: %d\n", rval));
return (rval);
}
static int
rsm_ddi_copyin(caddr_t arg, rsm_ioctlmsg_t *msg, int mode)
{
DBG_DEFINE(category,
RSM_KERNEL_AGENT | RSM_FUNC_ALL | RSM_IOCTL | RSM_DDI);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_ddi_copyin enter\n"));
#ifdef _MULTI_DATAMODEL
if ((mode & DATAMODEL_MASK) == DATAMODEL_ILP32) {
rsm_ioctlmsg32_t msg32;
int i;
if (ddi_copyin(arg, (caddr_t)&msg32, sizeof (msg32), mode)) {
DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
"rsm_ddi_copyin done: EFAULT\n"));
return (RSMERR_BAD_ADDR);
}
msg->len = msg32.len;
msg->vaddr = (caddr_t)(uintptr_t)msg32.vaddr;
msg->arg = (caddr_t)(uintptr_t)msg32.arg;
msg->key = msg32.key;
msg->acl_len = msg32.acl_len;
msg->acl = (rsmapi_access_entry_t *)(uintptr_t)msg32.acl;
msg->cnum = msg32.cnum;
msg->cname = (caddr_t)(uintptr_t)msg32.cname;
msg->cname_len = msg32.cname_len;
msg->nodeid = msg32.nodeid;
msg->hwaddr = msg32.hwaddr;
msg->perm = msg32.perm;
for (i = 0; i < 4; i++) {
msg->bar.comp[i].u64 = msg32.bar.comp[i].u64;
}
DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
"rsm_ddi_copyin done\n"));
return (RSM_SUCCESS);
}
#endif
DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_ddi_copyin done\n"));
if (ddi_copyin(arg, (caddr_t)msg, sizeof (*msg), mode))
return (RSMERR_BAD_ADDR);
else
return (RSM_SUCCESS);
}
static int
rsmattr_ddi_copyout(adapter_t *adapter, caddr_t arg, int mode)
{
rsmka_int_controller_attr_t rsm_cattr;
DBG_DEFINE(category,
RSM_KERNEL_AGENT | RSM_FUNC_ALL | RSM_IOCTL | RSM_DDI);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
"rsmattr_ddi_copyout enter\n"));
#ifdef _MULTI_DATAMODEL
if ((mode & DATAMODEL_MASK) == DATAMODEL_ILP32) {
rsmka_int_controller_attr32_t rsm_cattr32;
rsm_cattr32.attr_direct_access_sizes =
adapter->rsm_attr.attr_direct_access_sizes;
rsm_cattr32.attr_atomic_sizes =
adapter->rsm_attr.attr_atomic_sizes;
rsm_cattr32.attr_page_size =
adapter->rsm_attr.attr_page_size;
if (adapter->rsm_attr.attr_max_export_segment_size >
UINT_MAX)
rsm_cattr32.attr_max_export_segment_size =
RSM_MAXSZ_PAGE_ALIGNED;
else
rsm_cattr32.attr_max_export_segment_size =
adapter->rsm_attr.attr_max_export_segment_size;
if (adapter->rsm_attr.attr_tot_export_segment_size >
UINT_MAX)
rsm_cattr32.attr_tot_export_segment_size =
RSM_MAXSZ_PAGE_ALIGNED;
else
rsm_cattr32.attr_tot_export_segment_size =
adapter->rsm_attr.attr_tot_export_segment_size;
if (adapter->rsm_attr.attr_max_export_segments >
UINT_MAX)
rsm_cattr32.attr_max_export_segments =
UINT_MAX;
else
rsm_cattr32.attr_max_export_segments =
adapter->rsm_attr.attr_max_export_segments;
if (adapter->rsm_attr.attr_max_import_map_size >
UINT_MAX)
rsm_cattr32.attr_max_import_map_size =
RSM_MAXSZ_PAGE_ALIGNED;
else
rsm_cattr32.attr_max_import_map_size =
adapter->rsm_attr.attr_max_import_map_size;
if (adapter->rsm_attr.attr_tot_import_map_size >
UINT_MAX)
rsm_cattr32.attr_tot_import_map_size =
RSM_MAXSZ_PAGE_ALIGNED;
else
rsm_cattr32.attr_tot_import_map_size =
adapter->rsm_attr.attr_tot_import_map_size;
if (adapter->rsm_attr.attr_max_import_segments >
UINT_MAX)
rsm_cattr32.attr_max_import_segments =
UINT_MAX;
else
rsm_cattr32.attr_max_import_segments =
adapter->rsm_attr.attr_max_import_segments;
rsm_cattr32.attr_controller_addr =
adapter->rsm_attr.attr_controller_addr;
DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
"rsmattr_ddi_copyout done\n"));
if (ddi_copyout((caddr_t)&rsm_cattr32, arg,
sizeof (rsmka_int_controller_attr32_t), mode)) {
return (RSMERR_BAD_ADDR);
}
else
return (RSM_SUCCESS);
}
#endif
rsm_cattr.attr_direct_access_sizes =
adapter->rsm_attr.attr_direct_access_sizes;
rsm_cattr.attr_atomic_sizes =
adapter->rsm_attr.attr_atomic_sizes;
rsm_cattr.attr_page_size =
adapter->rsm_attr.attr_page_size;
rsm_cattr.attr_max_export_segment_size =
adapter->rsm_attr.attr_max_export_segment_size;
rsm_cattr.attr_tot_export_segment_size =
adapter->rsm_attr.attr_tot_export_segment_size;
rsm_cattr.attr_max_export_segments =
adapter->rsm_attr.attr_max_export_segments;
rsm_cattr.attr_max_import_map_size =
adapter->rsm_attr.attr_max_import_map_size;
rsm_cattr.attr_tot_import_map_size =
adapter->rsm_attr.attr_tot_import_map_size;
rsm_cattr.attr_max_import_segments =
adapter->rsm_attr.attr_max_import_segments;
rsm_cattr.attr_controller_addr =
adapter->rsm_attr.attr_controller_addr;
DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
"rsmattr_ddi_copyout done\n"));
if (ddi_copyout((caddr_t)&rsm_cattr, arg,
sizeof (rsmka_int_controller_attr_t), mode)) {
return (RSMERR_BAD_ADDR);
}
else
return (RSM_SUCCESS);
}
static int
rsm_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp,
int *rvalp)
{
rsmseg_t *seg;
rsmresource_t *res;
minor_t rnum;
rsm_ioctlmsg_t msg = {0};
int error;
adapter_t *adapter;
DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_FUNC_ALL | RSM_IOCTL);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_ioctl enter\n"));
if (cmd == RSM_IOCTL_CONSUMEEVENT) {
error = rsm_consumeevent_ioctl((caddr_t)arg, mode);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
"rsm_ioctl RSM_IOCTL_CONSUMEEVENT done: %d\n", error));
return (error);
}
if (RSM_IOCTL_CMDGRP(cmd) == RSM_IOCTL_TOPOLOGY) {
error = rsmka_topology_ioctl((caddr_t)arg, cmd, mode);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
"rsm_ioctl done: %d\n", error));
return (error);
}
if (RSM_IOCTL_CMDGRP(cmd) == RSM_IOCTL_IOVEC) {
error = rsm_iovec_ioctl(dev, (caddr_t)arg, cmd, mode, credp);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
"rsm_ioctl done: %d\n", error));
return (error);
}
if (cmd != RSM_IOCTL_RING_BELL &&
rsm_ddi_copyin((caddr_t)arg, &msg, mode)) {
DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
"rsm_ioctl done: EFAULT\n"));
return (RSMERR_BAD_ADDR);
}
if (cmd == RSM_IOCTL_ATTR) {
adapter = rsm_getadapter(&msg, mode);
if (adapter == NULL) {
DBG_PRINTF((category, RSM_DEBUG,
"rsm_ioctl done: ENODEV\n"));
return (RSMERR_CTLR_NOT_PRESENT);
}
error = rsmattr_ddi_copyout(adapter, msg.arg, mode);
rsmka_release_adapter(adapter);
DBG_PRINTF((category, RSM_DEBUG,
"rsm_ioctl:after copyout %d\n", error));
return (error);
}
if (cmd == RSM_IOCTL_BAR_INFO) {
msg.off = barrier_offset;
msg.len = (int)barrier_size;
#ifdef _MULTI_DATAMODEL
if ((mode & DATAMODEL_MASK) == DATAMODEL_ILP32) {
rsm_ioctlmsg32_t msg32;
if (msg.len > UINT_MAX)
msg.len = RSM_MAXSZ_PAGE_ALIGNED;
else
msg32.len = (int32_t)msg.len;
msg32.off = (int32_t)msg.off;
DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
"rsm_ioctl done\n"));
if (ddi_copyout((caddr_t)&msg32, (caddr_t)arg,
sizeof (msg32), mode))
return (RSMERR_BAD_ADDR);
else
return (RSM_SUCCESS);
}
#endif
DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
"rsm_ioctl done\n"));
if (ddi_copyout((caddr_t)&msg, (caddr_t)arg,
sizeof (msg), mode))
return (RSMERR_BAD_ADDR);
else
return (RSM_SUCCESS);
}
if (RSM_IOCTL_CMDGRP(cmd) == RSM_IOCTL_MAP_ADDR) {
error = rsmaddr_ioctl(cmd, &msg, mode);
if (error == RSM_SUCCESS) {
#ifdef _MULTI_DATAMODEL
if ((mode & DATAMODEL_MASK) == DATAMODEL_ILP32) {
rsm_ioctlmsg32_t msg32;
msg32.hwaddr = (uint64_t)msg.hwaddr;
msg32.nodeid = (uint32_t)msg.nodeid;
DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
"rsm_ioctl done\n"));
if (ddi_copyout((caddr_t)&msg32, (caddr_t)arg,
sizeof (msg32), mode))
return (RSMERR_BAD_ADDR);
else
return (RSM_SUCCESS);
}
#endif
DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
"rsm_ioctl done\n"));
if (ddi_copyout((caddr_t)&msg, (caddr_t)arg,
sizeof (msg), mode))
return (RSMERR_BAD_ADDR);
else
return (RSM_SUCCESS);
}
DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
"rsm_ioctl done: %d\n", error));
return (error);
}
rnum = getminor(dev);
res = rsmresource_lookup(rnum, RSM_NOLOCK);
ASSERT(res != NULL);
switch (RSM_IOCTL_CMDGRP(cmd)) {
case RSM_IOCTL_EXPORT_SEG:
seg = rsmresource_seg(res, rnum, credp,
RSM_RESOURCE_EXPORT_SEGMENT);
if (seg->s_type == RSM_RESOURCE_EXPORT_SEGMENT) {
error = rsmexport_ioctl(seg, &msg, cmd, arg, mode,
credp);
} else {
error = RSMERR_BAD_SEG_HNDL;
}
break;
case RSM_IOCTL_IMPORT_SEG:
seg = rsmresource_seg(res, rnum, credp,
RSM_RESOURCE_IMPORT_SEGMENT);
if (seg->s_type == RSM_RESOURCE_IMPORT_SEGMENT) {
error = rsmimport_ioctl(seg, &msg, cmd, arg, mode,
credp);
} else {
error = RSMERR_BAD_SEG_HNDL;
}
break;
case RSM_IOCTL_BAR:
if (res != RSMRC_RESERVED &&
res->rsmrc_type == RSM_RESOURCE_IMPORT_SEGMENT) {
error = rsmbar_ioctl((rsmseg_t *)res, &msg, cmd, arg,
mode);
} else {
error = RSMERR_BAD_SEG_HNDL;
}
break;
case RSM_IOCTL_BELL:
if (res != RSMRC_RESERVED) {
if (res->rsmrc_type == RSM_RESOURCE_IMPORT_SEGMENT)
error = exportbell_ioctl((rsmseg_t *)res, cmd);
else if (res->rsmrc_type == RSM_RESOURCE_EXPORT_SEGMENT)
error = importbell_ioctl((rsmseg_t *)res, cmd);
else
error = RSMERR_BAD_SEG_HNDL;
} else {
error = RSMERR_BAD_SEG_HNDL;
}
break;
default:
error = EINVAL;
}
DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_ioctl done: %d\n",
error));
return (error);
}
static rsm_mapinfo_t *
rsm_get_mapinfo(rsmseg_t *seg, off_t off, size_t len, off_t *dev_offset,
size_t *map_len)
{
rsm_mapinfo_t *p;
p = seg->s_mapinfo;
for (; p; p = p->next) {
if (p->start_offset <= off) {
*dev_offset = p->dev_offset + off - p->start_offset;
*map_len = (len > p->individual_len) ?
p->individual_len : ptob(btopr(len));
return (p);
}
p = p->next;
}
return (NULL);
}
static void
rsm_free_mapinfo(rsm_mapinfo_t *mapinfo)
{
rsm_mapinfo_t *p;
while (mapinfo != NULL) {
p = mapinfo;
mapinfo = mapinfo->next;
kmem_free(p, sizeof (*p));
}
}
static int
rsmmap_map(devmap_cookie_t dhp, dev_t dev, uint_t flags, offset_t off,
size_t len, void **pvtp)
{
rsmcookie_t *p;
rsmresource_t *res;
rsmseg_t *seg;
minor_t rnum;
DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_FUNC_ALL | RSM_DDI);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmmap_map enter\n"));
DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
"rsmmap_map: dhp = %x\n", dhp));
flags = flags;
rnum = getminor(dev);
res = (rsmresource_t *)rsmresource_lookup(rnum, RSM_NOLOCK);
ASSERT(res != NULL);
seg = (rsmseg_t *)res;
rsmseglock_acquire(seg);
ASSERT(seg->s_hdr.rsmrc_type == RSM_RESOURCE_IMPORT_SEGMENT);
p = kmem_alloc(sizeof (*p), KM_SLEEP);
p->c_dhp = dhp;
p->c_off = off;
p->c_len = len;
p->c_next = seg->s_ckl;
seg->s_ckl = p;
*pvtp = (void *)seg;
rsmseglock_release(seg);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmmap_map done\n"));
return (DDI_SUCCESS);
}
static int
rsmmap_access(devmap_cookie_t dhp, void *pvt, offset_t offset, size_t len,
uint_t type, uint_t rw)
{
int e;
rsmseg_t *seg = (rsmseg_t *)pvt;
DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_FUNC_ALL | RSM_DDI);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmmap_access enter\n"));
rsmseglock_acquire(seg);
ASSERT(seg->s_hdr.rsmrc_type == RSM_RESOURCE_IMPORT_SEGMENT);
while (seg->s_state == RSM_STATE_MAP_QUIESCE) {
if (cv_wait_sig(&seg->s_cv, &seg->s_lock) == 0) {
DBG_PRINTF((category, RSM_DEBUG,
"rsmmap_access done: cv_wait INTR"));
rsmseglock_release(seg);
return (RSMERR_INTERRUPTED);
}
}
ASSERT(seg->s_state == RSM_STATE_DISCONNECT ||
seg->s_state == RSM_STATE_ACTIVE);
if (seg->s_state == RSM_STATE_DISCONNECT)
seg->s_flags |= RSM_IMPORT_DUMMY;
DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
"rsmmap_access: dhp = %x\n", dhp));
rsmseglock_release(seg);
if (e = devmap_load(dhp, offset, len, type, rw)) {
DBG_PRINTF((category, RSM_ERR, "devmap_load failed\n"));
}
DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmmap_access done\n"));
return (e);
}
static int
rsmmap_dup(devmap_cookie_t dhp, void *oldpvt, devmap_cookie_t new_dhp,
void **newpvt)
{
rsmseg_t *seg = (rsmseg_t *)oldpvt;
rsmcookie_t *p, *old;
DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_FUNC_ALL | RSM_DDI);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmmap_dup enter\n"));
rsmseglock_acquire(seg);
ASSERT(seg->s_hdr.rsmrc_type == RSM_RESOURCE_IMPORT_SEGMENT);
for (old = seg->s_ckl; old != NULL; old = old->c_next) {
if (old->c_dhp == dhp) {
break;
}
}
if (old == NULL) {
DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
"rsmmap_dup done: EINVAL\n"));
rsmseglock_release(seg);
return (EINVAL);
}
p = kmem_alloc(sizeof (*p), KM_SLEEP);
p->c_dhp = new_dhp;
p->c_off = old->c_off;
p->c_len = old->c_len;
p->c_next = seg->s_ckl;
seg->s_ckl = p;
*newpvt = (void *)seg;
rsmseglock_release(seg);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmmap_dup done\n"));
return (DDI_SUCCESS);
}
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)
{
rsmseg_t *seg = (rsmseg_t *)pvtp;
int freeflag;
DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_FUNC_ALL | RSM_DDI);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmmap_unmap enter\n"));
off = off; len = len;
pvtp1 = pvtp1; pvtp2 = pvtp2;
rsmseglock_acquire(seg);
ASSERT(seg->s_hdr.rsmrc_type == RSM_RESOURCE_IMPORT_SEGMENT);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
"rsmmap_unmap: dhp = %x\n", dhp));
if (new_dhp1 == NULL && new_dhp2 == NULL) {
rsmcookie_t *tmp, **back = &seg->s_ckl;
while (*back != NULL) {
tmp = *back;
if (tmp->c_dhp == dhp) {
*back = tmp->c_next;
kmem_free(tmp, sizeof (*tmp));
break;
}
back = &tmp->c_next;
}
} else {
DBG_PRINTF((category, RSM_DEBUG_LVL2,
"rsmmap_unmap:parital unmap"
"new_dhp1 %lx, new_dhp2 %lx\n",
(size_t)new_dhp1, (size_t)new_dhp2));
}
if ((seg->s_ckl == NULL) && (seg->s_state != RSM_STATE_MAPPING))
(void) rsm_unmap(seg);
if (seg->s_state == RSM_STATE_END && seg->s_ckl == NULL) {
freeflag = 1;
} else {
freeflag = 0;
}
rsmseglock_release(seg);
if (freeflag) {
rsmseg_free(seg);
}
DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsmmap_unmap done\n"));
}
static struct devmap_callback_ctl rsmmap_ops = {
DEVMAP_OPS_REV,
rsmmap_map,
rsmmap_access,
rsmmap_dup,
rsmmap_unmap,
};
static int
rsm_devmap(dev_t dev, devmap_cookie_t dhc, offset_t off, size_t len,
size_t *maplen, uint_t model )
{
struct devmap_callback_ctl *callbackops = &rsmmap_ops;
int err;
uint_t maxprot;
minor_t rnum;
rsmseg_t *seg;
off_t dev_offset;
size_t cur_len;
DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_FUNC_ALL | RSM_DDI);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_devmap enter\n"));
DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
"rsm_devmap: off = %lx, len = %lx\n", off, len));
rnum = getminor(dev);
seg = (rsmseg_t *)rsmresource_lookup(rnum, RSM_NOLOCK);
ASSERT(seg != NULL);
if (seg->s_hdr.rsmrc_type == RSM_RESOURCE_BAR) {
if ((off == barrier_offset) &&
(len == barrier_size)) {
ASSERT(bar_va != NULL && bar_cookie != NULL);
err = devmap_umem_setup(dhc, rsm_dip, NULL, bar_cookie,
barrier_offset, len, PROT_USER|PROT_READ,
DEVMAP_DEFAULTS, 0);
if (err != 0) {
DBG_PRINTF((category, RSM_ERR,
"rsm_devmap done: %d\n", err));
return (RSMERR_MAP_FAILED);
}
DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
"rsm_devmap done: %d\n", err));
*maplen = barrier_size;
return (err);
} else {
DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
"rsm_devmap done: %d\n", err));
return (RSMERR_MAP_FAILED);
}
}
ASSERT(seg->s_hdr.rsmrc_type == RSM_RESOURCE_IMPORT_SEGMENT);
ASSERT(seg->s_state == RSM_STATE_MAPPING);
maxprot = PROT_USER;
if (seg->s_mode & RSM_PERM_READ) {
maxprot |= PROT_READ;
}
if (seg->s_mode & RSM_PERM_WRITE) {
maxprot |= PROT_WRITE;
}
if (seg->s_node != my_nodeid) {
rsm_mapinfo_t *p;
p = rsm_get_mapinfo(seg, off, len, &dev_offset, &cur_len);
if (p == NULL) {
DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
"rsm_devmap: incorrect mapping info\n"));
return (RSMERR_MAP_FAILED);
}
err = devmap_devmem_setup(dhc, p->dip,
callbackops, p->dev_register,
dev_offset, cur_len, maxprot,
DEVMAP_ALLOW_REMAP | DEVMAP_DEFAULTS, 0);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
"rsm_devmap: dip=%lx,dreg=%lu,doff=%lx,"
"off=%lx,len=%lx\n",
p->dip, p->dev_register, dev_offset, off, cur_len));
if (err != 0) {
DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
"rsm_devmap: devmap_devmem_setup failed %d\n",
err));
return (RSMERR_MAP_FAILED);
}
ASSERT((cur_len & (PAGESIZE-1)) == 0);
*maplen = cur_len;
return (err);
} else {
err = devmap_umem_setup(dhc, rsm_dip, callbackops,
seg->s_cookie, off, len, maxprot,
DEVMAP_ALLOW_REMAP|DEVMAP_DEFAULTS, 0);
if (err != 0) {
DBG_PRINTF((category, RSM_DEBUG,
"rsm_devmap: devmap_umem_setup failed %d\n",
err));
return (RSMERR_MAP_FAILED);
}
DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
"rsm_devmap: loopback done\n"));
*maplen = ptob(btopr(len));
return (err);
}
}
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)
{
int error = 0;
int old_state;
minor_t rnum;
rsmseg_t *seg, *eseg;
adapter_t *adapter;
rsm_import_share_t *sharedp;
DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_FUNC_ALL | RSM_DDI);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_segmap enter\n"));
rnum = getminor(dev);
seg = (rsmseg_t *)rsmresource_lookup(rnum, RSM_LOCK);
if (seg == NULL) {
DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
"rsm_segmap done: invalid segment\n"));
return (EINVAL);
}
if (seg->s_hdr.rsmrc_type == RSM_RESOURCE_BAR) {
rsmseglock_release(seg);
if (off == (off_t)barrier_offset ||
len == (off_t)barrier_size) {
if (bar_cookie == NULL || bar_va == NULL) {
DBG_PRINTF((category, RSM_DEBUG,
"rsm_segmap: bar cookie/va is NULL\n"));
return (EINVAL);
}
error = devmap_setup(dev, (offset_t)off, as, addrp,
(size_t)len, prot, maxprot, flags, cred);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
"rsm_segmap done: %d\n", error));
return (error);
} else {
DBG_PRINTF((category, RSM_DEBUG,
"rsm_segmap: bad offset/length\n"));
return (EINVAL);
}
}
if (seg->s_hdr.rsmrc_type != RSM_RESOURCE_IMPORT_SEGMENT) {
rsmseglock_release(seg);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
"rsm_segmap done: not an import segment\n"));
return (EINVAL);
}
ASSERT(seg->s_hdr.rsmrc_num == rnum);
while (seg->s_state == RSM_STATE_CONN_QUIESCE) {
if (cv_wait_sig(&seg->s_cv, &seg->s_lock) == 0) {
rsmseglock_release(seg);
DBG_PRINTF((category, RSM_DEBUG,
"rsm_segmap done: cv_wait INTR"));
return (ENODEV);
}
}
while (seg->s_state == RSM_STATE_MAPPING)
cv_wait(&seg->s_cv, &seg->s_lock);
if ((seg->s_state != RSM_STATE_CONNECT) &&
(seg->s_state != RSM_STATE_ACTIVE)) {
rsmseglock_release(seg);
DBG_PRINTF((category, RSM_DEBUG,
"rsm_segmap done: segment not connected\n"));
return (ENODEV);
}
if ((size_t)off + ptob(btopr(len)) > seg->s_len) {
rsmseglock_release(seg);
DBG_PRINTF((category, RSM_DEBUG,
"rsm_segmap done: off+len>seg size\n"));
return (ENXIO);
}
maxprot = PROT_USER;
if (seg->s_mode & RSM_PERM_READ) {
maxprot |= PROT_READ;
}
if (seg->s_mode & RSM_PERM_WRITE) {
maxprot |= PROT_WRITE;
}
if ((prot & maxprot) != prot) {
rsmseglock_release(seg);
DBG_PRINTF((category, RSM_DEBUG,
"rsm_segmap done: no permission\n"));
return (EACCES);
}
old_state = seg->s_state;
ASSERT(seg->s_share != NULL);
rsmsharelock_acquire(seg);
sharedp = seg->s_share;
DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
"rsm_segmap:RSMSI_STATE=%d\n", sharedp->rsmsi_state));
if ((sharedp->rsmsi_state != RSMSI_STATE_CONNECTED) &&
(sharedp->rsmsi_state != RSMSI_STATE_MAPPED)) {
rsmsharelock_release(seg);
rsmseglock_release(seg);
DBG_PRINTF((category, RSM_DEBUG,
"rsm_segmap done:RSMSI_STATE %d invalid\n",
sharedp->rsmsi_state));
return (ENODEV);
}
if (seg->s_node != my_nodeid) {
uint_t dev_register;
off_t dev_offset;
dev_info_t *dip;
size_t tmp_len;
size_t total_length_mapped = 0;
size_t length_to_map = seg->s_len;
off_t tmp_off = 0;
rsm_mapinfo_t *p;
adapter = seg->s_adapter;
ASSERT(sharedp->rsmsi_state == RSMSI_STATE_CONNECTED ||
sharedp->rsmsi_state == RSMSI_STATE_MAPPED);
if (sharedp->rsmsi_state == RSMSI_STATE_CONNECTED) {
error = 0;
while (total_length_mapped < seg->s_len) {
tmp_len = 0;
error = adapter->rsmpi_ops->rsm_map(
seg->s_handle.in, tmp_off,
length_to_map, &tmp_len,
&dip, &dev_register, &dev_offset,
NULL, NULL);
if (error != 0)
break;
p = kmem_alloc(sizeof (*p), KM_SLEEP);
p->dev_register = dev_register;
p->dev_offset = dev_offset;
p->dip = dip;
p->individual_len = tmp_len;
p->start_offset = tmp_off;
p->next = sharedp->rsmsi_mapinfo;
sharedp->rsmsi_mapinfo = p;
total_length_mapped += tmp_len;
length_to_map -= tmp_len;
tmp_off += tmp_len;
}
seg->s_mapinfo = sharedp->rsmsi_mapinfo;
if (error != RSM_SUCCESS) {
if (sharedp->rsmsi_mapinfo != NULL) {
(void) seg->s_adapter->rsmpi_ops->
rsm_unmap(sharedp->rsmsi_handle);
rsm_free_mapinfo(sharedp->
rsmsi_mapinfo);
}
sharedp->rsmsi_mapinfo = NULL;
sharedp->rsmsi_state = RSMSI_STATE_CONNECTED;
rsmsharelock_release(seg);
rsmseglock_release(seg);
DBG_PRINTF((category, RSM_DEBUG,
"rsm_segmap done: rsmpi map err %d\n",
error));
ASSERT(error != RSMERR_BAD_LENGTH &&
error != RSMERR_BAD_MEM_ALIGNMENT &&
error != RSMERR_BAD_SEG_HNDL);
if (error == RSMERR_UNSUPPORTED_OPERATION)
return (ENOTSUP);
else if (error == RSMERR_INSUFFICIENT_RESOURCES)
return (EAGAIN);
else if (error == RSMERR_CONN_ABORTED)
return (ENODEV);
else
return (error);
} else {
sharedp->rsmsi_state = RSMSI_STATE_MAPPED;
}
} else {
seg->s_mapinfo = sharedp->rsmsi_mapinfo;
}
sharedp->rsmsi_mapcnt++;
rsmsharelock_release(seg);
seg->s_state = RSM_STATE_MAPPING;
rsmseglock_release(seg);
error = devmap_setup(dev, (offset_t)off, as, addrp,
len, prot, maxprot, flags, cred);
rsmseglock_acquire(seg);
ASSERT(seg->s_state == RSM_STATE_MAPPING);
if (error == DDI_SUCCESS) {
seg->s_state = RSM_STATE_ACTIVE;
} else {
rsmsharelock_acquire(seg);
ASSERT(sharedp->rsmsi_state == RSMSI_STATE_MAPPED);
sharedp->rsmsi_mapcnt--;
if (sharedp->rsmsi_mapcnt == 0) {
ASSERT(sharedp->rsmsi_handle != NULL);
(void) adapter->rsmpi_ops->
rsm_unmap(sharedp->rsmsi_handle);
rsm_free_mapinfo(sharedp->rsmsi_mapinfo);
sharedp->rsmsi_mapinfo = NULL;
sharedp->rsmsi_state = RSMSI_STATE_CONNECTED;
}
rsmsharelock_release(seg);
seg->s_state = old_state;
DBG_PRINTF((category, RSM_ERR,
"rsm: devmap_setup failed %d\n", error));
}
cv_broadcast(&seg->s_cv);
rsmseglock_release(seg);
DBG_PRINTF((category, RSM_DEBUG_LVL2, "rsm_segmap done: %d\n",
error));
return (error);
} else {
DBG_ADDCATEGORY(category, RSM_LOOPBACK);
rsmsharelock_release(seg);
seg->s_state = RSM_STATE_MAPPING;
rsmseglock_release(seg);
eseg = rsmexport_lookup(seg->s_key);
if (eseg == NULL) {
rsmseglock_acquire(seg);
seg->s_state = old_state;
cv_broadcast(&seg->s_cv);
rsmseglock_release(seg);
DBG_PRINTF((category, RSM_DEBUG,
"rsm_segmap done: key %d not found\n", seg->s_key));
return (ENODEV);
}
rsmsharelock_acquire(seg);
ASSERT(sharedp->rsmsi_state == RSMSI_STATE_CONNECTED ||
sharedp->rsmsi_state == RSMSI_STATE_MAPPED);
sharedp->rsmsi_mapcnt++;
sharedp->rsmsi_state = RSMSI_STATE_MAPPED;
rsmsharelock_release(seg);
ASSERT(eseg->s_cookie != NULL);
seg->s_cookie = eseg->s_cookie;
rsmseglock_release(eseg);
error = devmap_setup(dev, (offset_t)off, as, addrp, (size_t)len,
prot, maxprot, flags, cred);
rsmseglock_acquire(seg);
ASSERT(seg->s_state == RSM_STATE_MAPPING);
if (error == 0) {
seg->s_state = RSM_STATE_ACTIVE;
} else {
rsmsharelock_acquire(seg);
ASSERT(sharedp->rsmsi_state == RSMSI_STATE_MAPPED);
sharedp->rsmsi_mapcnt--;
if (sharedp->rsmsi_mapcnt == 0) {
sharedp->rsmsi_mapinfo = NULL;
sharedp->rsmsi_state = RSMSI_STATE_CONNECTED;
}
rsmsharelock_release(seg);
seg->s_state = old_state;
seg->s_cookie = NULL;
}
cv_broadcast(&seg->s_cv);
rsmseglock_release(seg);
DBG_PRINTF((category, RSM_DEBUG_LVL2,
"rsm_segmap done: %d\n", error));
return (error);
}
}
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 )
{
return (RSM_SUCCESS);
}
int
rsmka_null_seg_destroy(
rsm_memseg_export_handle_t argmemseg )
{
return (RSM_SUCCESS);
}
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 )
{
return (RSM_SUCCESS);
}
int
rsmka_null_unbind(
rsm_memseg_export_handle_t argmemseg,
off_t offset,
size_t length )
{
return (DDI_SUCCESS);
}
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 )
{
return (RSM_SUCCESS);
}
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 )
{
return (RSM_SUCCESS);
}
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 )
{
return (RSM_SUCCESS);
}
int
rsmka_null_unpublish(
rsm_memseg_export_handle_t argmemseg )
{
return (RSM_SUCCESS);
}
void
rsmka_init_loopback()
{
rsm_ops_t *ops = &null_rsmpi_ops;
DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_FUNC_ALL | RSM_LOOPBACK);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
"rsmka_init_loopback enter\n"));
ops->rsm_seg_create = rsmka_null_seg_create;
ops->rsm_seg_destroy = rsmka_null_seg_destroy;
ops->rsm_bind = rsmka_null_bind;
ops->rsm_unbind = rsmka_null_unbind;
ops->rsm_rebind = rsmka_null_rebind;
ops->rsm_publish = rsmka_null_publish;
ops->rsm_unpublish = rsmka_null_unpublish;
ops->rsm_republish = rsmka_null_republish;
loopback_attr.attr_name = loopback_str;
loopback_attr.attr_page_size = 0x8;
loopback_adapter.rsm_attr = loopback_attr;
loopback_adapter.rsmpi_ops = &null_rsmpi_ops;
DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
"rsmka_init_loopback done\n"));
}
static void
rsm_quiesce_exp_seg(rsmresource_t *resp)
{
int recheck_state;
rsmseg_t *segp = (rsmseg_t *)resp;
DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_FUNC_ALL);
DBG_DEFINE_STR(function, "rsm_unquiesce_exp_seg");
DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
"%s enter: key=%u\n", function, segp->s_key));
rsmseglock_acquire(segp);
do {
recheck_state = 0;
if ((segp->s_state == RSM_STATE_NEW_QUIESCED) ||
(segp->s_state == RSM_STATE_BIND_QUIESCED) ||
(segp->s_state == RSM_STATE_EXPORT_QUIESCING) ||
(segp->s_state == RSM_STATE_EXPORT_QUIESCED)) {
rsmseglock_release(segp);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
"%s done:state =%d\n", function,
segp->s_state));
return;
}
if (segp->s_state == RSM_STATE_NEW) {
segp->s_state = RSM_STATE_NEW_QUIESCED;
rsmseglock_release(segp);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
"%s done:state =%d\n", function,
segp->s_state));
return;
}
if (segp->s_state == RSM_STATE_BIND) {
(void) rsm_unbind_pages(segp);
segp->s_state = RSM_STATE_BIND_QUIESCED;
rsmseglock_release(segp);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
"%s done:state =%d\n", function,
segp->s_state));
return;
}
if (segp->s_state == RSM_STATE_EXPORT) {
while ((segp->s_state == RSM_STATE_EXPORT) &&
(segp->s_rdmacnt != 0)) {
cv_wait(&segp->s_cv, &segp->s_lock);
}
if (segp->s_state != RSM_STATE_EXPORT) {
recheck_state = 1;
continue;
}
segp->s_state = RSM_STATE_EXPORT_QUIESCING;
rsmseglock_release(segp);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
"%s done:state =%d\n", function,
segp->s_state));
return;
}
} while (recheck_state);
rsmseglock_release(segp);
}
static void
rsm_unquiesce_exp_seg(rsmresource_t *resp)
{
int ret;
rsmseg_t *segp = (rsmseg_t *)resp;
rsmapi_access_entry_t *acl;
rsm_access_entry_t *rsmpi_acl;
int acl_len;
int create_flags = 0;
struct buf *xbuf;
rsm_memory_local_t mem;
adapter_t *adapter;
dev_t sdev = 0;
rsm_resource_callback_t callback_flag;
DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_FUNC_ALL);
DBG_DEFINE_STR(function, "rsm_unquiesce_exp_seg");
rsmseglock_acquire(segp);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
"%s enter: key=%u, state=%d\n", function, segp->s_key,
segp->s_state));
if ((segp->s_state == RSM_STATE_NEW) ||
(segp->s_state == RSM_STATE_BIND) ||
(segp->s_state == RSM_STATE_EXPORT)) {
rsmseglock_release(segp);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "%s done:state=%d\n",
function, segp->s_state));
return;
}
if (segp->s_state == RSM_STATE_NEW_QUIESCED) {
segp->s_state = RSM_STATE_NEW;
cv_broadcast(&segp->s_cv);
rsmseglock_release(segp);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "%s done:state=%d\n",
function, segp->s_state));
return;
}
if (segp->s_state == RSM_STATE_BIND_QUIESCED) {
ret = rsm_bind_pages(&segp->s_cookie, segp->s_region.r_vaddr,
segp->s_len, segp->s_proc);
if (ret == RSM_SUCCESS) {
segp->s_state = RSM_STATE_BIND;
} else {
segp->s_state = RSM_STATE_NEW;
}
cv_broadcast(&segp->s_cv);
rsmseglock_release(segp);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
"%s done: bind_qscd bind = %d\n", function, ret));
return;
}
while (segp->s_state == RSM_STATE_EXPORT_QUIESCING) {
cv_wait(&segp->s_cv, &segp->s_lock);
}
if (segp->s_state == RSM_STATE_EXPORT_QUIESCED) {
ret = rsm_bind_pages(&segp->s_cookie, segp->s_region.r_vaddr,
segp->s_len, segp->s_proc);
if (ret != RSM_SUCCESS) {
acl_len = segp->s_acl_len;
acl = segp->s_acl;
rsmpi_acl = segp->s_acl_in;
segp->s_acl_len = 0;
segp->s_acl = NULL;
segp->s_acl_in = NULL;
rsmseglock_release(segp);
rsmexport_rm(segp);
rsmacl_free(acl, acl_len);
rsmpiacl_free(rsmpi_acl, acl_len);
rsmseglock_acquire(segp);
segp->s_state = RSM_STATE_NEW;
cv_broadcast(&segp->s_cv);
rsmseglock_release(segp);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
"%s done: exp_qscd bind failed = %d\n",
function, ret));
return;
}
if (segp->s_acl != (rsmapi_access_entry_t *)NULL) {
if ((segp->s_acl[0].ae_node == my_nodeid) &&
(segp->s_acl[0].ae_permission == 0)) {
segp->s_state = RSM_STATE_EXPORT;
cv_broadcast(&segp->s_cv);
rsmseglock_release(segp);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
"%s done:exp_qscd\n", function));
return;
}
}
xbuf = ddi_umem_iosetup(segp->s_cookie, 0, segp->s_len, B_WRITE,
sdev, 0, NULL, DDI_UMEM_SLEEP);
ASSERT(xbuf != NULL);
mem.ms_type = RSM_MEM_BUF;
mem.ms_bp = xbuf;
adapter = segp->s_adapter;
if (segp->s_flags & RSMKA_ALLOW_UNBIND_REBIND) {
create_flags = RSM_ALLOW_UNBIND_REBIND;
}
if (segp->s_flags & RSMKA_SET_RESOURCE_DONTWAIT) {
callback_flag = RSM_RESOURCE_DONTWAIT;
} else {
callback_flag = RSM_RESOURCE_SLEEP;
}
ret = adapter->rsmpi_ops->rsm_seg_create(
adapter->rsmpi_handle, &segp->s_handle.out,
segp->s_len, create_flags, &mem,
callback_flag, NULL);
if (ret != RSM_SUCCESS) {
acl_len = segp->s_acl_len;
acl = segp->s_acl;
rsmpi_acl = segp->s_acl_in;
segp->s_acl_len = 0;
segp->s_acl = NULL;
segp->s_acl_in = NULL;
rsmseglock_release(segp);
rsmexport_rm(segp);
rsmacl_free(acl, acl_len);
rsmpiacl_free(rsmpi_acl, acl_len);
rsmseglock_acquire(segp);
segp->s_state = RSM_STATE_BIND;
cv_broadcast(&segp->s_cv);
rsmseglock_release(segp);
DBG_PRINTF((category, RSM_ERR,
"%s done: exp_qscd create failed = %d\n",
function, ret));
return;
}
ret = adapter->rsmpi_ops->rsm_publish(
segp->s_handle.out, segp->s_acl_in, segp->s_acl_len,
segp->s_segid, RSM_RESOURCE_DONTWAIT, NULL);
if (ret != RSM_SUCCESS) {
acl_len = segp->s_acl_len;
acl = segp->s_acl;
rsmpi_acl = segp->s_acl_in;
segp->s_acl_len = 0;
segp->s_acl = NULL;
segp->s_acl_in = NULL;
adapter->rsmpi_ops->rsm_seg_destroy(segp->s_handle.out);
rsmseglock_release(segp);
rsmexport_rm(segp);
rsmacl_free(acl, acl_len);
rsmpiacl_free(rsmpi_acl, acl_len);
rsmseglock_acquire(segp);
segp->s_state = RSM_STATE_BIND;
cv_broadcast(&segp->s_cv);
rsmseglock_release(segp);
DBG_PRINTF((category, RSM_ERR,
"%s done: exp_qscd publish failed = %d\n",
function, ret));
return;
}
segp->s_state = RSM_STATE_EXPORT;
cv_broadcast(&segp->s_cv);
rsmseglock_release(segp);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "%s done: exp_qscd\n",
function));
return;
}
rsmseglock_release(segp);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "%s done\n", function));
}
static void
rsm_quiesce_imp_seg(rsmresource_t *resp)
{
rsmseg_t *segp = (rsmseg_t *)resp;
DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_FUNC_ALL);
DBG_DEFINE_STR(function, "rsm_quiesce_imp_seg");
DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
"%s enter: key=%u\n", function, segp->s_key));
rsmseglock_acquire(segp);
segp->s_flags |= RSM_DR_INPROGRESS;
while (segp->s_rdmacnt != 0) {
cv_wait(&segp->s_cv, &segp->s_lock);
}
rsmseglock_release(segp);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "%s done\n", function));
}
static void
rsm_unquiesce_imp_seg(rsmresource_t *resp)
{
rsmseg_t *segp = (rsmseg_t *)resp;
DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_FUNC_ALL);
DBG_DEFINE_STR(function, "rsm_unquiesce_imp_seg");
DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
"%s enter: key=%u\n", function, segp->s_key));
rsmseglock_acquire(segp);
segp->s_flags &= ~RSM_DR_INPROGRESS;
cv_broadcast(&segp->s_cv);
rsmseglock_release(segp);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "%s done\n", function));
}
static void
rsm_process_exp_seg(rsmresource_t *resp, int event)
{
if (event == RSM_DR_QUIESCE)
rsm_quiesce_exp_seg(resp);
else
rsm_unquiesce_exp_seg(resp);
}
static void
rsm_process_imp_seg(rsmresource_t *resp, int event)
{
if (event == RSM_DR_QUIESCE)
rsm_quiesce_imp_seg(resp);
else
rsm_unquiesce_imp_seg(resp);
}
static void
rsm_dr_process_local_segments(int event)
{
int i, j;
rsmresource_blk_t *blk;
rsmresource_t *p;
DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_FUNC_ALL);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
"rsm_dr_process_local_segments enter\n"));
rw_enter(&rsm_resource.rsmrc_lock, RW_READER);
for (i = 0; i < rsm_resource.rsmrc_len; i++) {
blk = rsm_resource.rsmrc_root[i];
if (blk != NULL) {
for (j = 0; j < RSMRC_BLKSZ; j++) {
p = blk->rsmrcblk_blks[j];
if ((p != NULL) && (p != RSMRC_RESERVED)) {
if (p->rsmrc_type ==
RSM_RESOURCE_EXPORT_SEGMENT)
rsm_process_exp_seg(p, event);
else if (p->rsmrc_type ==
RSM_RESOURCE_IMPORT_SEGMENT)
rsm_process_imp_seg(p, event);
}
}
}
}
rw_exit(&rsm_resource.rsmrc_lock);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
"rsm_dr_process_local_segments done\n"));
}
static void
rsm_dr_callback_post_add(void *arg, pgcnt_t delta )
{
DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_FUNC_ALL);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
"rsm_dr_callback_post_add is a no-op\n"));
}
static int
rsm_dr_callback_pre_del(void *arg, pgcnt_t delta )
{
int recheck_state = 0;
DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_FUNC_ALL);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
"rsm_dr_callback_pre_del enter\n"));
mutex_enter(&rsm_drv_data.drv_lock);
do {
recheck_state = 0;
DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
"rsm_dr_callback_pre_del:state=%d\n",
rsm_drv_data.drv_state));
switch (rsm_drv_data.drv_state) {
case RSM_DRV_NEW:
ASSERT(0);
return (0);
case RSM_DRV_REG_PROCESSING:
recheck_state = 1;
cv_wait(&rsm_drv_data.drv_cv, &rsm_drv_data.drv_lock);
break;
case RSM_DRV_UNREG_PROCESSING:
mutex_exit(&rsm_drv_data.drv_lock);
DBG_PRINTF((category, RSM_DEBUG,
"rsm_dr_callback_pre_del:"
"pre-del on NEW/UNREG\n"));
return (0);
case RSM_DRV_OK:
rsm_drv_data.drv_state = RSM_DRV_PREDEL_STARTED;
break;
case RSM_DRV_PREDEL_STARTED:
case RSM_DRV_PREDEL_COMPLETED:
case RSM_DRV_POSTDEL_IN_PROGRESS:
recheck_state = 1;
cv_wait(&rsm_drv_data.drv_cv, &rsm_drv_data.drv_lock);
break;
case RSM_DRV_DR_IN_PROGRESS:
rsm_drv_data.drv_memdel_cnt++;
mutex_exit(&rsm_drv_data.drv_lock);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
"rsm_dr_callback_pre_del done\n"));
return (0);
default:
ASSERT(0);
break;
}
} while (recheck_state);
rsm_drv_data.drv_memdel_cnt++;
mutex_exit(&rsm_drv_data.drv_lock);
DBG_PRINTF((category, RSM_DEBUG,
"rsm_dr_callback_pre_del: quiesce things now\n"));
rsm_dr_process_local_segments(RSM_DR_QUIESCE);
rsm_send_suspend();
mutex_enter(&rsm_drv_data.drv_lock);
while (rsm_drv_data.drv_state == RSM_DRV_PREDEL_STARTED) {
cv_wait(&rsm_drv_data.drv_cv, &rsm_drv_data.drv_lock);
}
ASSERT(rsm_drv_data.drv_state == RSM_DRV_PREDEL_COMPLETED);
rsm_drv_data.drv_state = RSM_DRV_DR_IN_PROGRESS;
cv_broadcast(&rsm_drv_data.drv_cv);
mutex_exit(&rsm_drv_data.drv_lock);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
"rsm_dr_callback_pre_del done\n"));
return (0);
}
static void
rsm_dr_callback_post_del(void *arg, pgcnt_t delta, int cancelled )
{
int recheck_state = 0;
DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_FUNC_ALL);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
"rsm_dr_callback_post_del enter\n"));
mutex_enter(&rsm_drv_data.drv_lock);
do {
recheck_state = 0;
DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
"rsm_dr_callback_post_del:state=%d\n",
rsm_drv_data.drv_state));
switch (rsm_drv_data.drv_state) {
case RSM_DRV_NEW:
ASSERT(0);
return;
case RSM_DRV_REG_PROCESSING:
recheck_state = 1;
cv_wait(&rsm_drv_data.drv_cv, &rsm_drv_data.drv_lock);
break;
case RSM_DRV_UNREG_PROCESSING:
case RSM_DRV_OK:
mutex_exit(&rsm_drv_data.drv_lock);
DBG_PRINTF((category, RSM_DEBUG,
"rsm_dr_callback_post_del:"
"post-del on OK/UNREG\n"));
return;
case RSM_DRV_PREDEL_STARTED:
case RSM_DRV_PREDEL_COMPLETED:
case RSM_DRV_POSTDEL_IN_PROGRESS:
recheck_state = 1;
cv_wait(&rsm_drv_data.drv_cv, &rsm_drv_data.drv_lock);
break;
case RSM_DRV_DR_IN_PROGRESS:
rsm_drv_data.drv_memdel_cnt--;
if (rsm_drv_data.drv_memdel_cnt > 0) {
mutex_exit(&rsm_drv_data.drv_lock);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
"rsm_dr_callback_post_del done:\n"));
return;
}
rsm_drv_data.drv_state = RSM_DRV_POSTDEL_IN_PROGRESS;
break;
default:
ASSERT(0);
return;
}
} while (recheck_state);
mutex_exit(&rsm_drv_data.drv_lock);
DBG_PRINTF((category, RSM_DEBUG,
"rsm_dr_callback_post_del: unquiesce things now\n"));
rsm_dr_process_local_segments(RSM_DR_UNQUIESCE);
rsm_send_resume();
mutex_enter(&rsm_drv_data.drv_lock);
rsm_drv_data.drv_state = RSM_DRV_OK;
cv_broadcast(&rsm_drv_data.drv_cv);
mutex_exit(&rsm_drv_data.drv_lock);
DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
"rsm_dr_callback_post_del done\n"));
return;
}