rsmlib.c revision 004388ebfdfe2ed7dfd2d153a876dfcc22d2c006
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include "c_synonyms.h"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdarg.h>
#include <string.h>
#include <strings.h>
#include <ctype.h>
#include <sys/sysmacros.h>
#include <sys/resource.h>
#include <errno.h>
#include <assert.h>
#include <fcntl.h>
#include <dlfcn.h>
#include <sched.h>
#include <stropts.h>
#include <poll.h>
#include <rsmapi.h>
#include <rsmlib_in.h>
#ifdef __STDC__
#pragma weak rsm_memseg_import_destroy_barrier = \
#endif /* __STDC__ */
/* lint -w2 */
extern void __rsmloopback_init_ops(rsm_segops_t *);
extern void __rsmdefault_setops(rsm_segops_t *);
typedef void (*rsm_access_func_t)(void *, void *, rsm_access_size_t);
#ifdef DEBUG
#define RSMLOG_BUF_SIZE 256
static mutex_t rsmlog_lock;
int rsmlibdbg_category = RSM_LIBRARY;
int rsmlibdbg_level = RSM_ERR;
#endif /* DEBUG */
static rsm_segops_t loopback_ops;
#define MAX_STRLEN 80
#define RSM_IOTYPE_PUTGET 1
#define RSM_IOTYPE_SCATGATH 2
#define RSMFILE_BUFSIZE 256
#pragma init(_rsm_librsm_init)
static int _rsm_fd = -1;
static rsm_pollfd_table_t pollfd_table;
static int _rsm_get_nodeid(rsmapi_controller_handle_t,
rsm_addr_t, rsm_node_id_t *);
static int __rsm_import_implicit_map(rsmseg_handle_t *, int);
nfds_t, int, int *);
static rsm_lib_funcs_t lib_functions = {
};
/*
* service module function templates:
*/
/*
* The _rsm_librsm_init function is called the first time an application
* references the RSMAPI library
*/
int
{
int e, tmpfd;
int i;
char logname[MAXNAMELEN];
#ifdef DEBUG
return (errno);
}
#endif /* DEBUG */
"_rsm_librsm_init: enter\n"));
/* initialize the pollfd_table */
for (i = 0; i < RSM_MAX_BUCKETS; i++) {
}
if (_rsm_fd < 0) {
return (errno);
}
/*
* DUP the opened file descriptor to something greater than
* STDERR_FILENO so that we never use the STDIN_FILENO,
* STDOUT_FILENO or STDERR_FILENO.
*/
if (tmpfd < 0) {
"F_DUPFD failed\n"));
} else {
}
"_rsm_fd is %d\n", _rsm_fd));
"F_SETFD failed\n"));
}
/* get mapping generation number page info */
"RSM_IOCTL_BAR_INFO failed\n"));
return (errno);
}
/*
* bar_va is mapped to the mapping generation number page
* in order to support close barrier
*/
/* LINTED */
"unable to map barrier page\n"));
return (RSMERR_MAP_FAILED);
}
/* get local nodeid */
e = rsm_get_interconnect_topology(&tp);
if (e != RSM_SUCCESS) {
"unable to obtain topology data\n"));
return (e);
} else
"_rsm_librsm_init: exit\n"));
return (RSM_SUCCESS);
}
static int
{
rsm_controller_t *p;
"_rsm_loopbackload: enter\n"));
/*
* For now do this, but we should open some file and read the
* list of supported controllers and there numbers.
*/
if (!p) {
"not enough memory\n"));
return (RSMERR_INSUFFICIENT_MEM);
}
free((void *)p);
"RSM_IOCTL_ATTR failed\n"));
return (error);
}
p->cntr_segops = &loopback_ops;
/*
* Should add this entry into list
*/
p->cntr_refcnt = 1;
p->cntr_rqlist = NULL;
p->cntr_next = controller_list;
controller_list = p;
*chdl = p;
"_rsm_loopbackload: exit\n"));
return (RSM_SUCCESS);
}
static int
{
int error = RSM_SUCCESS;
char clib[MAX_STRLEN];
rsm_controller_t *p = NULL;
void *dlh;
"_rsm_modload: enter\n"));
/* found entry, try to load library */
"unable to find plugin library\n"));
goto skiplib;
}
/* allocate new lib structure */
/* get ops handler, attr and ops */
if (p != NULL) {
} else {
"not enough memory\n"));
}
} else {
"can't find symbol %s\n", clib));
}
if (p != NULL)
free((void *)p);
"_rsm_modload error %d\n", error));
return (error);
}
/* check the version number */
/* bad version number */
"wrong version; "
"found %d, expected %d\n",
free(p);
return (RSMERR_BAD_LIBRARY_VERSION);
} else {
/* pass the fuctions to NDI library */
&lib_functions) != RSM_SUCCESS)) {
"RSMNDI library not registering lib functions\n"));
}
/* get controller attributes */
free((void *)p);
"RSM_IOCTL_ATTR failed\n"));
return (error);
}
/* set controller access functions */
p->cntr_rqlist = NULL;
/* insert into list of controllers */
p->cntr_next = controller_list;
controller_list = p;
errno = RSM_SUCCESS;
}
"_rsm_modload: exit\n"));
return (error);
}
/*
* inserts a given segment handle into the pollfd table, this is called
* when rsm_memseg_get_pollfd() is called the first time on a segment handle.
* Returns RSM_SUCCESS if successful otherwise the error code is returned
*/
static int
{
int i;
int hash;
while (chunk) {
break;
}
if (!chunk) { /* couldn't find a free chunk - allocate a new one */
if (!chunk) {
return (RSMERR_INSUFFICIENT_MEM);
}
for (i = 1; i < RSM_POLLFD_PER_CHUNK; i++) {
}
/* insert this into the hash table */
"rsm_insert_pollfd: new chunk(%p) @ %d for %d:%d\n",
} else { /* a chunk with free slot was found */
for (i = 0; i < RSM_POLLFD_PER_CHUNK; i++) {
break;
}
}
"rsm_insert_pollfd: inserted @ %d for %d:%d chunk(%p)\n",
assert(i < RSM_POLLFD_PER_CHUNK);
}
return (RSM_SUCCESS);
}
/*
* Given a file descriptor returns the corresponding segment handles
* resource number, if the fd is not found returns 0. 0 is not a valid
* minor number for a rsmapi segment since it is used for the barrier
* resource.
*/
static minor_t
{
int i;
if (segfd < 0)
return (0);
while (chunk) {
for (i = 0; i < RSM_POLLFD_PER_CHUNK; i++) {
"rsm_lookup_pollfd: found(%d) rnum(%d)\n",
}
}
}
"rsm_lookup_pollfd: not found(%d)\n", segfd));
return (0);
}
/*
* Remove the entry corresponding to the given file descriptor from the
* pollfd table.
*/
static void
{
int i;
int hash;
if (segfd < 0)
return;
while (chunk) {
for (i = 0; i < RSM_POLLFD_PER_CHUNK; i++) {
"rsm_remove_pollfd: %d:%d\n",
/* chunk is empty free it */
if (prev_chunk == chunk) {
} else {
}
"rsm_remove_pollfd:free(%p)\n",
chunk));
return;
}
}
}
prev_chunk = chunk;
}
}
int
{
rsm_controller_t *p;
char *cntr_type;
int unit = 0;
int i, e;
"rsm_get_controller: enter\n"));
/*
* Lookup controller name and return ops vector and controller
* structure
*/
if (!chdl) {
"Invalid controller handle\n"));
return (RSMERR_BAD_CTLR_HNDL);
}
if (!name) {
/* use loopback if null */
} else {
/* scan from the end till a non-digit is found */
break;
}
i++;
"cntr_type=%s, instance=%d\n",
}
for (p = controller_list; p; p = p->cntr_next) {
p->cntr_refcnt++;
*chdl = (rsmapi_controller_handle_t)p;
"rsm_get_controller: exit\n"));
return (RSM_SUCCESS);
p->cntr_refcnt++;
*chdl = (rsmapi_controller_handle_t)p;
"rsm_get_controller: exit\n"));
return (RSM_SUCCESS);
}
}
(rsm_controller_t **)chdl);
} else {
}
" rsm_get_controller: exit\n"));
return (e);
}
int
{
int e = RSM_SUCCESS;
"rsm_release_controller: enter\n"));
if (chdl->cntr_refcnt == 0) {
"controller reference count is zero\n"));
return (RSMERR_BAD_CTLR_HNDL);
}
chdl->cntr_refcnt--;
if (chdl->cntr_refcnt > 0) {
"rsm_release_controller: exit\n"));
return (RSM_SUCCESS);
}
/*
* remove the controller in any case from the controller list
*/
} else {
}
break;
}
}
"rsm_release_controller: exit\n"));
return (e);
}
{
rsm_controller_t *p;
"rsm_get_controller_attr: enter\n"));
if (!chandle) {
"invalid controller handle\n"));
return (RSMERR_BAD_CTLR_HNDL);
}
if (!attr) {
"invalid attribute pointer\n"));
return (RSMERR_BAD_ADDR);
}
p = (rsm_controller_t *)chandle;
if (p->cntr_refcnt == 0) {
"cntr refcnt is 0\n"));
return (RSMERR_CTLR_NOT_PRESENT);
}
/* copy only the user part of the attr structure */
"rsm_get_controller_attr: exit\n"));
return (RSM_SUCCESS);
}
/*
* Create a segment handle for the virtual address range specified
* by vaddr and size
*/
int
void *vaddr,
{
rsmseg_handle_t *p;
int e;
#ifndef _LP64
int tmpfd;
#endif
"rsm_memseg_export_create: enter\n"));
if (!controller) {
"invalid controller handle\n"));
return (RSMERR_BAD_CTLR_HNDL);
}
if (!memseg) {
"invalid segment handle\n"));
return (RSMERR_BAD_SEG_HNDL);
}
*memseg = 0;
/*
* Check vaddr and size alignment, both must be mmu page size
* aligned
*/
if (!vaddr) {
"invalid arguments\n"));
return (RSMERR_BAD_ADDR);
}
if (!length) {
"invalid arguments\n"));
return (RSMERR_BAD_LENGTH);
}
"invalid mem alignment for vaddr or length\n"));
return (RSMERR_BAD_MEM_ALIGNMENT);
}
/*
* The following check does not apply for loopback controller
* since for the loopback adapter, the attr_max_export_segment_size
* is always 0.
*/
"length exceeds controller limits\n"));
"controller limits %d\n",
return (RSMERR_BAD_LENGTH);
}
}
p = (rsmseg_handle_t *)malloc(sizeof (*p));
if (p == NULL) {
"not enough memory\n"));
return (RSMERR_INSUFFICIENT_MEM);
}
if (p->rsmseg_fd < 0) {
free((void *)p);
return (RSMERR_INSUFFICIENT_RESOURCES);
}
#ifndef _LP64
/*
* libc can't handle fd's greater than 255, in order to
* fd > 255. Note: not needed for LP64
*/
e = errno;
if (tmpfd < 0) {
"F_DUPFD failed\n"));
} else {
}
#endif /* _LP64 */
"rsmseg_fd is %d\n", p->rsmseg_fd));
"F_SETFD failed\n"));
}
p->rsmseg_state = EXPORT_CREATE;
p->rsmseg_size = length;
/* increment controller handle */
p->rsmseg_controller = chdl;
/* try to bind user address range */
e = RSM_IOCTL_BIND;
/* Try to bind */
e = errno;
free((void *)p);
"RSM_IOCTL_BIND failed\n"));
return (e);
}
/* OK */
p->rsmseg_type = RSM_EXPORT_SEG;
p->rsmseg_vaddr = vaddr;
p->rsmseg_size = length;
p->rsmseg_state = EXPORT_BIND;
p->rsmseg_pollfd_refcnt = 0;
*memseg = (rsm_memseg_export_handle_t)p;
"rsm_memseg_export_create: exit\n"));
return (RSM_SUCCESS);
}
int
{
"rsm_memseg_export_destroy: enter\n"));
if (!memseg) {
"invalid segment handle\n"));
return (RSMERR_BAD_SEG_HNDL);
}
if (seg->rsmseg_pollfd_refcnt) {
"segment reference count not zero\n"));
return (RSMERR_POLLFD_IN_USE);
}
else
"rsm_memseg_export_destroy: exit\n"));
return (RSM_SUCCESS);
}
int
{
"rsm_memseg_export_rebind: enter\n"));
if (!seg) {
"invalid segment handle\n"));
return (RSMERR_BAD_SEG_HNDL);
}
if (!vaddr) {
"invalid vaddr\n"));
return (RSMERR_BAD_ADDR);
}
/*
* Same as bind except it's ok to have elimint in list.
* Call into driver to remove any existing mappings.
*/
"RSM_IOCTL_REBIND failed\n"));
return (errno);
}
"rsm_memseg_export_rebind: exit\n"));
return (RSM_SUCCESS);
}
int
{
"rsm_memseg_export_publish: enter\n"));
"invalid segment id\n"));
return (RSMERR_BAD_SEGID);
}
if (!seg) {
"invalid segment handle\n"));
return (RSMERR_BAD_SEG_HNDL);
}
if (access_list_length > 0 && !access_list) {
"invalid access control list\n"));
return (RSMERR_BAD_ACL);
}
"invalid segment state\n"));
return (RSMERR_SEG_ALREADY_PUBLISHED);
}
/*
* seg id < RSM_DLPI_END and in the RSM_USER_APP_ID range
* are reserved for internal use.
*/
if ((*seg_id > 0) &&
((*seg_id <= RSM_DLPI_ID_END) ||
"invalid segment id\n"));
return (RSMERR_RESERVED_SEGID);
}
"RSM_IOCTL_PUBLISH failed\n"));
return (errno);
}
if (*seg_id == 0)
"rsm_memseg_export_publish: exit\n"));
return (RSM_SUCCESS);
}
int
{
"rsm_memseg_export_unpublish: enter\n"));
if (!seg) {
"invalid arguments\n"));
return (RSMERR_BAD_SEG_HNDL);
}
"segment not published %d\n",
seg->rsmseg_keyid));
return (RSMERR_SEG_NOT_PUBLISHED);
}
"RSM_IOCTL_UNPUBLISH failed\n"));
return (errno);
}
"rsm_memseg_export_unpublish: exit\n"));
return (RSM_SUCCESS);
}
int
{
"rsm_memseg_export_republish: enter\n"));
if (!seg) {
"invalid segment or segment state\n"));
return (RSMERR_BAD_SEG_HNDL);
}
"segment not published\n"));
return (RSMERR_SEG_NOT_PUBLISHED);
}
if (access_list_length > 0 && !access_list) {
"invalid access control list\n"));
return (RSMERR_BAD_ACL);
}
"RSM_IOCTL_REPUBLISH failed\n"));
return (errno);
}
"rsm_memseg_export_republish: exit\n"));
return (RSM_SUCCESS);
}
/*
* import side memory segment operations:
*/
int
{
rsmseg_handle_t *p;
#ifndef _LP64 /* added for fd > 255 fix */
int tmpfd;
#endif
int e;
"rsm_memseg_import_connect: enter\n"));
if (!cntr) {
"invalid controller handle\n"));
return (RSMERR_BAD_CTLR_HNDL);
}
*im_memseg = 0;
p = (rsmseg_handle_t *)malloc(sizeof (*p));
if (!p) {
"not enough memory\n"));
return (RSMERR_INSUFFICIENT_MEM);
}
if (perm & ~RSM_PERM_RDWR) {
"invalid permissions\n"));
return (RSMERR_PERM_DENIED);
}
/*
* Get size, va from driver
*/
if (p->rsmseg_fd < 0) {
free((void *)p);
return (RSMERR_INSUFFICIENT_RESOURCES);
}
#ifndef _LP64
/*
* libc can't handle fd's greater than 255, in order to
* fd > 255. Note: not needed for LP64
*/
e = errno;
if (tmpfd < 0) {
"F_DUPFD failed\n"));
} else {
}
#endif /* _LP64 */
"rsmseg_fd is %d\n", p->rsmseg_fd));
"F_SETFD failed\n"));
}
e = errno;
free((void *)p);
"RSM_IOCTL_CONNECT failed\n"));
return (e);
}
/*
* We connected ok.
*/
p->rsmseg_type = RSM_IMPORT_SEG;
p->rsmseg_state = IMPORT_CONNECT;
p->rsmseg_keyid = segment_id;
p->rsmseg_nodeid = node_id;
p->rsmseg_perm = perm;
p->rsmseg_controller = cntr;
p->rsmseg_barrier = NULL;
p->rsmseg_pollfd_refcnt = 0;
p->rsmseg_maplen = 0; /* initialized, set in import_map */
p->rsmseg_mapoffset = 0;
p->rsmseg_flags = 0;
/*
* XXX: Based on permission and controller direct_access attribute
* we fix the segment ops vector
*/
p->rsmseg_vaddr = 0; /* defer mapping till using maps or trys to rw */
if (e != RSM_SUCCESS) {
mutex_destroy(&p->rsmseg_lock);
free((void *)p);
}
"rsm_memseg_import_connect: exit\n"));
return (e);
}
int
{
int e;
"rsm_memseg_import_disconnect: enter\n"));
if (!seg) {
"invalid segment handle\n"));
return (RSMERR_BAD_SEG_HNDL);
}
if (e != RSM_SUCCESS) {
"unmap failure\n"));
return (e);
}
} else {
"segment busy\n"));
return (RSMERR_SEG_STILL_MAPPED);
}
}
if (seg->rsmseg_pollfd_refcnt) {
"segment reference count not zero\n"));
return (RSMERR_POLLFD_IN_USE);
}
if (e == RSM_SUCCESS) {
}
"rsm_memseg_import_disconnect: exit\n"));
return (e);
}
/*
* import side memory segment operations (read access functions):
*/
static int
{
int error;
" __rsm_import_verify_access: enter\n"));
if (!seg) {
"invalid segment handle\n"));
return (RSMERR_BAD_SEG_HNDL);
}
if (!datap) {
"invalid data pointer\n"));
return (RSMERR_BAD_ADDR);
}
/*
* Check alignment of pointer
*/
"invalid alignment of data pointer\n"));
return (RSMERR_BAD_MEM_ALIGNMENT);
}
"invalid offset\n"));
return (RSMERR_BAD_MEM_ALIGNMENT);
}
/* make sure that the import seg is connected */
"incorrect segment state\n"));
return (RSMERR_BAD_SEG_HNDL);
}
/* do an implicit map if required */
if (error != RSM_SUCCESS) {
"implicit map failure\n"));
return (error);
}
}
"invalid permissions\n"));
return (RSMERR_PERM_DENIED);
}
seg->rsmseg_maplen)) {
"incorrect offset+length\n"));
return (RSMERR_BAD_OFFSET);
}
} else { /* IMPORT_CONNECT */
"incorrect offset+length\n"));
return (RSMERR_BAD_LENGTH);
}
}
"invalid barrier\n"));
return (RSMERR_BARRIER_UNINITIALIZED);
}
" __rsm_import_verify_access: exit\n"));
return (RSM_SUCCESS);
}
static int
{
int flag = MAP_SHARED;
int mapping_reqd = 0;
" __rsm_import_implicit_map: enter\n"));
if (iotype == RSM_IOTYPE_PUTGET)
else if (iotype == RSM_IOTYPE_SCATGATH)
if (mapping_reqd) {
if (va == MAP_FAILED) {
"implicit map failed\n"));
return (RSMERR_BAD_LENGTH);
return (RSMERR_CONN_ABORTED);
return (RSMERR_INSUFFICIENT_RESOURCES);
return (RSMERR_MAP_FAILED);
return (RSMERR_BAD_PERMS);
else
return (RSMERR_MAP_FAILED);
}
seg->rsmseg_mapoffset = 0;
}
" __rsm_import_implicit_map: exit\n"));
return (RSM_SUCCESS);
}
int
{
int e;
"rsm_memseg_import_get8: enter\n"));
RSM_DAS8);
if (e == RSM_SUCCESS) {
/* generation number snapshot */
}
rep_cnt, 0);
/* check the generation number for force disconnects */
return (RSMERR_CONN_ABORTED);
}
}
}
"rsm_memseg_import_get8: exit\n"));
return (e);
}
int
{
int e;
"rsm_memseg_import_get16: enter\n"));
if (e == RSM_SUCCESS) {
/* generation number snapshot */
}
rep_cnt, 0);
/* check the generation number for force disconnects */
return (RSMERR_CONN_ABORTED);
}
}
}
"rsm_memseg_import_get16: exit\n"));
return (e);
}
int
{
int e;
"rsm_memseg_import_get32: enter\n"));
if (e == RSM_SUCCESS) {
/* generation number snapshot */
}
rep_cnt, 0);
/* check the generation number for force disconnects */
return (RSMERR_CONN_ABORTED);
}
}
}
"rsm_memseg_import_get32: exit\n"));
return (e);
}
int
{
int e;
"rsm_memseg_import_get64: enter\n"));
if (e == RSM_SUCCESS) {
/* generation number snapshot */
}
rep_cnt, 0);
/* check the generation number for force disconnects */
return (RSMERR_CONN_ABORTED);
}
}
}
"rsm_memseg_import_get64: exit\n"));
return (e);
}
int
void *dst_addr,
{
int e;
"rsm_memseg_import_get: enter\n"));
RSM_DAS8);
if (e == RSM_SUCCESS) {
/* generation number snapshot */
}
length);
/* check the generation number for force disconnects */
return (RSMERR_CONN_ABORTED);
}
}
}
"rsm_memseg_import_get: exit\n"));
return (e);
}
int
{
int e;
"rsm_memseg_import_getv: enter\n"));
"invalid sg_io structure\n"));
return (RSMERR_BAD_SGIO);
}
"invalid remote segment handle in sg_io\n"));
return (RSMERR_BAD_SEG_HNDL);
}
"invalid controller handle\n"));
return (RSMERR_BAD_SEG_HNDL);
}
(sg_io->io_request_count == 0)) {
"io_request_count value incorrect\n"));
return (RSMERR_BAD_SGIO);
}
if (e != RSM_SUCCESS) {
"implicit map failure\n"));
return (e);
}
}
/*
* Copy the flags field of the sg_io structure in a local
* variable.
* This is required since the flags field can be
* changed by the plugin library routine to indicate that
* the signal post was done.
* This change in the flags field of the sg_io structure
* should not be reflected to the user. Hence once the flags
* field has been used for the purpose of determining whether
* the plugin executed a signal post, it must be restored to
* its original value which is stored in the local variable.
*/
/*
* At this point, if an implicit signal post was requested by
* the user, there could be two possibilities that arise:
* 1. the plugin routine has already executed the implicit
* signal post either successfully or unsuccessfully
* 2. the plugin does not have the capability of doing an
* implicit signal post and hence the signal post needs
* to be done here.
* The above two cases can be idenfied by the flags
* field within the sg_io structure as follows:
* In case 1, the RSM_IMPLICIT_SIGPOST bit is reset to 0 by the
* plugin, indicating that the signal post was done.
* In case 2, the bit remains set to a 1 as originally given
* by the user, and hence a signal post needs to be done here.
*/
e == RSM_SUCCESS) {
/* Do the implicit signal post */
/*
* The value of the second argument to this call
* depends on the value of the sg_io->flags field.
* If the RSM_SIGPOST_NO_ACCUMULATE flag has been
* ored into the sg_io->flags field, this indicates
* that the rsm_intr_signal_post is to be done with
* the flags argument set to RSM_SIGPOST_NO_ACCUMULATE
* Else, the flags argument is set to 0. These
* semantics can be achieved simply by masking off
* all other bits in the sg_io->flags field except the
* RSM_SIGPOST_NO_ACCUMULATE bit and using the result
* as the flags argument for the rsm_intr_signal_post.
*/
}
/* Restore the flags field within the users scatter gather structure */
"rsm_memseg_import_getv: exit\n"));
return (e);
}
/*
* import side memory segment operations (write access functions):
*/
int
{
int e;
"rsm_memseg_import_put8: enter\n"));
/* addr of data will always pass the alignment check, avoids */
/* need for a special case in verify_access for PUTs */
RSM_DAS8);
if (e == RSM_SUCCESS) {
/* generation number snapshot */
}
rep_cnt, 0);
/* check the generation number for force disconnects */
return (RSMERR_CONN_ABORTED);
}
}
}
"rsm_memseg_import_put8: exit\n"));
return (e);
}
int
{
int e;
"rsm_memseg_import_put16: enter\n"));
/* addr of data will always pass the alignment check, avoids */
/* need for a special case in verify_access for PUTs */
if (e == RSM_SUCCESS) {
/* generation number snapshot */
}
rep_cnt, 0);
/* check the generation number for force disconnects */
return (RSMERR_CONN_ABORTED);
}
}
}
"rsm_memseg_import_put16: exit\n"));
return (e);
}
int
{
int e;
"rsm_memseg_import_put32: enter\n"));
/* addr of data will always pass the alignment check, avoids */
/* need for a special case in verify_access for PUTs */
if (e == RSM_SUCCESS) {
/* generation number snapshot */
}
rep_cnt, 0);
/* check the generation number for force disconnects */
return (RSMERR_CONN_ABORTED);
}
}
}
"rsm_memseg_import_put32: exit\n"));
return (e);
}
int
{
int e;
"rsm_memseg_import_put64: enter\n"));
/* addr of data will always pass the alignment check, avoids */
/* need for a special case in verify_access for PUTs */
if (e == RSM_SUCCESS) {
/* generation number snapshot */
}
rep_cnt, 0);
/* check the generation number for force disconnects */
return (RSMERR_CONN_ABORTED);
}
}
}
"rsm_memseg_import_put64: exit\n"));
return (e);
}
int
void *src_addr,
{
int e;
"rsm_memseg_import_put: enter\n"));
RSM_DAS8);
if (e == RSM_SUCCESS) {
/* generation number snapshot */
}
length);
/* check the generation number for force disconnects */
return (RSMERR_CONN_ABORTED);
}
}
}
"rsm_memseg_import_put: exit\n"));
return (e);
}
int
{
int e;
"rsm_memseg_import_putv: enter\n"));
"invalid sg_io structure\n"));
return (RSMERR_BAD_SGIO);
}
"invalid remote segment handle in sg_io\n"));
return (RSMERR_BAD_SEG_HNDL);
}
"invalid controller handle\n"));
return (RSMERR_BAD_SEG_HNDL);
}
(sg_io->io_request_count == 0)) {
"io_request_count value incorrect\n"));
return (RSMERR_BAD_SGIO);
}
/* do an implicit map if required */
if (e != RSM_SUCCESS) {
"implicit map failed\n"));
return (e);
}
}
/*
* Copy the flags field of the sg_io structure in a local
* variable.
* This is required since the flags field can be
* changed by the plugin library routine to indicate that
* the signal post was done.
* This change in the flags field of the sg_io structure
* should not be reflected to the user. Hence once the flags
* field has been used for the purpose of determining whether
* the plugin executed a signal post, it must be restored to
* its original value which is stored in the local variable.
*/
/*
* At this point, if an implicit signal post was requested by
* the user, there could be two possibilities that arise:
* 1. the plugin routine has already executed the implicit
* signal post either successfully or unsuccessfully
* 2. the plugin does not have the capability of doing an
* implicit signal post and hence the signal post needs
* to be done here.
* The above two cases can be idenfied by the flags
* field within the sg_io structure as follows:
* In case 1, the RSM_IMPLICIT_SIGPOST bit is reset to 0 by the
* plugin, indicating that the signal post was done.
* In case 2, the bit remains set to a 1 as originally given
* by the user, and hence a signal post needs to be done here.
*/
e == RSM_SUCCESS) {
/* Do the implicit signal post */
/*
* The value of the second argument to this call
* depends on the value of the sg_io->flags field.
* If the RSM_SIGPOST_NO_ACCUMULATE flag has been
* ored into the sg_io->flags field, this indicates
* that the rsm_intr_signal_post is to be done with
* the flags argument set to RSM_SIGPOST_NO_ACCUMULATE
* Else, the flags argument is set to 0. These
* semantics can be achieved simply by masking off
* all other bits in the sg_io->flags field except the
* RSM_SIGPOST_NO_ACCUMULATE bit and using the result
* as the flags argument for the rsm_intr_signal_post.
*/
}
/* Restore the flags field within the users scatter gather structure */
"rsm_memseg_import_putv: exit\n"));
return (e);
}
/*
* import side memory segment operations (mapping):
*/
int
void **address,
{
int flag = MAP_SHARED;
int prot;
"rsm_memseg_import_map: enter\n"));
if (!seg) {
"invalid segment\n"));
return (RSMERR_BAD_SEG_HNDL);
}
if (!address) {
"invalid address\n"));
return (RSMERR_BAD_ADDR);
}
/*
* Only one map per segment handle!
* XXX need to take a lock here
*/
"segment already mapped\n"));
return (RSMERR_SEG_ALREADY_MAPPED);
}
/* Only import segments allowed to map */
return (RSMERR_BAD_SEG_HNDL);
}
/* check for permissions */
if (perm > RSM_PERM_RDWR) {
"bad permissions when mapping\n"));
return (RSMERR_BAD_PERMS);
}
if (length == 0) {
"mapping with length 0\n"));
return (RSMERR_BAD_LENGTH);
}
"map length + offset exceed segment size\n"));
return (RSMERR_BAD_LENGTH);
}
"bad mem alignment\n"));
return (RSMERR_BAD_MEM_ALIGNMENT);
}
if (attr & RSM_MAP_FIXED) {
"bad mem alignment\n"));
return (RSMERR_BAD_MEM_ALIGNMENT);
}
}
if (perm & RSM_PERM_READ)
if (perm & RSM_PERM_WRITE)
prot |= PROT_WRITE;
if (va == MAP_FAILED) {
int e = errno;
"error %d during map\n", e));
e == ENOMEM)
return (RSMERR_BAD_LENGTH);
else if (e == ENODEV)
return (RSMERR_CONN_ABORTED);
else if (e == EAGAIN)
return (RSMERR_INSUFFICIENT_RESOURCES);
else if (e == ENOTSUP)
return (RSMERR_MAP_FAILED);
else if (e == EACCES)
return (RSMERR_BAD_PERMS);
else
return (RSMERR_MAP_FAILED);
}
/*
* Fix segment ops vector to handle direct access.
*/
/*
* XXX: Set this only for full segment mapping. Keep a list
* of mappings to use for access functions
*/
"rsm_memseg_import_map: exit\n"));
return (RSM_SUCCESS);
}
int
{
/*
* Until we fix the rsm driver to catch unload, we unload
* the whole segment.
*/
"rsm_memseg_import_unmap: enter\n"));
if (!seg) {
"invalid segment or segment state\n"));
return (RSMERR_BAD_SEG_HNDL);
}
return (RSMERR_SEG_NOT_MAPPED);
}
"rsm_memseg_import_unmap: exit\n"));
return (RSM_SUCCESS);
}
/*
* import side memory segment operations (barriers):
*/
int
{
"rsm_memseg_import_init_barrier: enter\n"));
if (!seg) {
"invalid segment or barrier\n"));
return (RSMERR_BAD_SEG_HNDL);
}
if (!barrier) {
"invalid barrier pointer\n"));
return (RSMERR_BAD_BARRIER_PTR);
}
"rsm_memseg_import_init_barrier: exit\n"));
}
int
{
"rsm_memseg_import_open_barrier: enter\n"));
if (!bar) {
"invalid barrier\n"));
return (RSMERR_BAD_BARRIER_PTR);
}
if (!bar->rsmbar_seg) {
"uninitialized barrier\n"));
return (RSMERR_BARRIER_UNINITIALIZED);
}
/* generation number snapshot */
"rsm_memseg_import_open_barrier: exit\n"));
return (ops->rsm_memseg_import_open_barrier(
}
int
{
"rsm_memseg_import_order_barrier: enter\n"));
if (!bar) {
"invalid barrier\n"));
return (RSMERR_BAD_BARRIER_PTR);
}
if (!bar->rsmbar_seg) {
"uninitialized barrier\n"));
return (RSMERR_BARRIER_UNINITIALIZED);
}
"rsm_memseg_import_order_barrier: exit\n"));
return (ops->rsm_memseg_import_order_barrier(
}
int
{
"rsm_memseg_import_close_barrier: enter\n"));
if (!bar) {
"invalid barrier\n"));
return (RSMERR_BAD_BARRIER_PTR);
}
if (!bar->rsmbar_seg) {
"uninitialized barrier\n"));
return (RSMERR_BARRIER_UNINITIALIZED);
}
/* generation number snapshot */
return (RSMERR_CONN_ABORTED);
}
"rsm_memseg_import_close_barrier: exit\n"));
return (ops->rsm_memseg_import_close_barrier(
}
int
{
"rsm_memseg_import_destroy_barrier: enter\n"));
if (!bar) {
"invalid barrier\n"));
return (RSMERR_BAD_BARRIER_PTR);
}
if (!bar->rsmbar_seg) {
"uninitialized barrier\n"));
return (RSMERR_BARRIER_UNINITIALIZED);
}
"rsm_memseg_import_destroy_barrier: exit\n"));
return (ops->rsm_memseg_import_destroy_barrier
}
int
{
"rsm_memseg_import_get_mode: enter\n"));
if (seg) {
"rsm_memseg_import_get_mode: exit\n"));
mode));
}
"invalid arguments \n"));
return (RSMERR_BAD_SEG_HNDL);
}
int
{
"rsm_memseg_import_set_mode: enter\n"));
if (seg) {
if ((mode == RSM_BARRIER_MODE_IMPLICIT ||
mode == RSM_BARRIER_MODE_EXPLICIT)) {
"rsm_memseg_import_set_mode: exit\n"));
mode));
} else {
"bad barrier mode\n"));
return (RSMERR_BAD_MODE);
}
}
"invalid arguments\n"));
return (RSMERR_BAD_SEG_HNDL);
}
int
{
"rsm_intr_signal_post: enter\n"));
if (!seg) {
"invalid segment handle\n"));
return (RSMERR_BAD_SEG_HNDL);
}
"RSM_IOCTL_RING_BELL failed\n"));
return (errno);
}
"rsm_intr_signal_post: exit\n"));
return (RSM_SUCCESS);
}
int
{
"rsm_intr_signal_wait: enter\n"));
if (!seg) {
"invalid segment\n"));
return (RSMERR_BAD_SEG_HNDL);
}
}
int
int *numfdsp)
{
numfdsp));
}
/*
* This is the generic wait routine, it takes the following arguments
* - pollfd array
* - rnums array corresponding to the pollfd if known, if this is
* NULL then the fds are looked up from the pollfd_table.
* - number of fds in pollfd array,
* - timeout
* - pointer to a location where the number of fds with successful
* events is returned.
*/
static int
{
int i;
int numsegs = 0;
int numfd;
int fds_processed = 0;
if (numfdsp) {
*numfdsp = 0;
}
switch (numfd) {
case -1: /* poll returned error - map to RSMERR_... */
switch (errno) {
case EAGAIN:
return (RSMERR_INSUFFICIENT_RESOURCES);
case EFAULT:
return (RSMERR_BAD_ADDR);
case EINTR:
return (RSMERR_INTERRUPTED);
case EINVAL:
default:
return (RSMERR_BAD_ARGS_ERRORS);
}
case 0: /* timedout - return from here */
"signal wait timed out\n"));
return (RSMERR_TIMEOUT);
default:
break;
}
if (numfd <= RSM_MAX_POLLFDS) {
/* use the event array on the stack */
} else {
/*
* actual number of fds corresponding to rsmapi segments might
* be < numfd, don't want to scan the list to figure that out
* lets just allocate on the heap
*/
sizeof (rsm_poll_event_t)*numfd);
if (!event_list) {
/*
* return with error even if poll might have succeeded
* since the application can retry and the events will
* still be available.
*/
return (RSMERR_INSUFFICIENT_MEM);
}
events = event_list;
}
/*
* process the fds for events and if it corresponds to an rsmapi
* segment consume the event
*/
for (i = 0; i < nfds; i++) {
/*
* poll returned an event and if its POLLRDNORM, it
* might correspond to an rsmapi segment
*/
if (rnums) { /* resource num is passed in */
} else { /* lookup pollfd table to get resource num */
}
if (segrnum) {
numsegs++;
}
}
/*
* only "numfd" events have revents field set, once we
* process that many break out of the loop
*/
break;
}
}
if (numsegs == 0) { /* No events for rsmapi segs in the fdlist */
if (event_list) {
}
if (numfdsp) {
}
"wait_common exit: no rsmapi segs\n"));
return (RSM_SUCCESS);
}
if (event_list) {
}
"RSM_IOCTL_CONSUMEEVENT failed(%d)\n", error));
return (error);
}
/* count the number of segs for which consumeevent was successful */
for (i = 0; i < numsegs; i++) {
numfd++;
} else { /* failed to consume event so set revents to 0 */
}
}
if (event_list) {
}
if (numfd > 0) {
if (numfdsp) {
}
"wait_common exit\n"));
return (RSM_SUCCESS);
} else {
"wait_common exit\n"));
return (RSMERR_TIMEOUT);
}
}
/*
* This function provides the data (file descriptor and event) for
* the specified pollfd struct. The pollfd struct may then be
* subsequently used with the poll system call to wait for an event
* signalled by rsm_intr_signal_post. The memory segment must be
* currently published for a successful return with a valid pollfd.
* A reference count for the descriptor is incremented.
*/
int
_rsm_memseg_get_pollfd(void *memseg,
{
int i;
int err = RSM_SUCCESS;
"rsm_memseg_get_pollfd: enter\n"));
if (!seg) {
"invalid segment\n"));
return (RSMERR_BAD_SEG_HNDL);
}
/* insert the segment into the pollfd table */
seg->rsmseg_rnum);
}
"rsm_memseg_get_pollfd: exit(%d)\n", err));
return (err);
}
/*
* This function decrements the segment pollfd reference count.
* A segment unpublish or destroy operation will fail if the reference count is
* non zero.
*/
int
_rsm_memseg_release_pollfd(void * memseg)
{
int i;
"rsm_memseg_release_pollfd: enter\n"));
if (!seg) {
"invalid segment handle\n"));
return (RSMERR_BAD_SEG_HNDL);
}
if (seg->rsmseg_pollfd_refcnt) {
if (seg->rsmseg_pollfd_refcnt == 0) {
/* last reference removed - update the pollfd_table */
}
}
"rsm_memseg_release_pollfd: exit\n"));
return (RSM_SUCCESS);
}
/*
* The interconnect topology data is obtained from the Kernel Agent
* and stored in a memory buffer allocated by this function. A pointer
* to the buffer is stored in the location specified by the caller in
* the function argument. It is the callers responsibility to
* call rsm_free_interconnect_topolgy() to free the allocated memory.
*/
int
{
int error;
"rsm_get_interconnect_topology: enter\n"));
if (topology_data == NULL)
return (RSMERR_BAD_TOPOLOGY_PTR);
*topology_data = NULL;
/* obtain the size of the topology data */
"RSM_IOCTL_TOPOLOGY_SIZE failed\n"));
return (errno);
}
/* allocate double-word aligned memory to hold the topology data */
if (topology_ptr == NULL) {
"not enough memory\n"));
return (RSMERR_INSUFFICIENT_MEM);
}
/*
* Request the topology data.
* Pass in the size to be used as a check in case
* the data has grown since the size was obtained - if
* it has, the errno value will be E2BIG.
*/
free((void *)topology_ptr);
goto again;
else {
"RSM_IOCTL_TOPOLOGY_DATA failed\n"));
return (error);
}
} else
" rsm_get_interconnect_topology: exit\n"));
return (RSM_SUCCESS);
}
void
{
"rsm_free_interconnect_topology: enter\n"));
if (topology_ptr) {
free((void *)topology_ptr);
}
"rsm_free_interconnect_topology: exit\n"));
}
int
{
int e;
"rsm_create_localmemory_handle: enter\n"));
"invalid arguments\n"));
return (RSMERR_BAD_ADDR);
}
if (!cntrl_handle) {
"invalid controller handle\n"));
return (RSMERR_BAD_CTLR_HNDL);
}
if (!local_hndl_p) {
"invalid local memory handle pointer\n"));
return (RSMERR_BAD_LOCALMEM_HNDL);
}
if (len == 0) {
"invalid length\n"));
return (RSMERR_BAD_LENGTH);
}
len);
"rsm_create_localmemory_handle: exit\n"));
return (e);
}
int
{
int e;
"rsm_free_localmemory_handle: enter\n"));
if (!cntrl_handle) {
"invalid controller handle\n"));
return (RSMERR_BAD_CTLR_HNDL);
}
if (!local_handle) {
"invalid localmemory handle\n"));
return (RSMERR_BAD_LOCALMEM_HNDL);
}
"rsm_free_localmemory_handle: exit\n"));
return (e);
}
int
{
char buf[RSMFILE_BUFSIZE];
char *s;
char *fieldv[4];
int fieldc = 0;
int found = 0;
int err = RSMERR_BAD_APPID;
return (RSMERR_BAD_ADDR);
"cannot open <%s>\n", RSMSEGIDFILE));
return (RSMERR_BAD_CONF);
}
fieldc = 0;
while (isspace(*s)) /* skip the leading spaces */
s++;
if (*s == '#') { /* comment line - skip it */
continue;
}
/*
* parse the reserved segid file and
* set the pointers appropriately.
* fieldv[0] : keyword
* fieldv[1] : application identifier
* fieldv[2] : baseid
* fieldv[3] : length
*/
while (isspace(*s)) /* skip the leading spaces */
s++;
if (fieldc == 4) {
break;
}
while (*s && !isspace(*s))
++s; /* move to the next white space */
if (*s)
*s++ = '\0';
}
break;
}
errno = 0;
if (errno != 0) {
break;
}
errno = 0;
(char **)NULL, 10);
if (errno != 0) {
break;
}
found = 1;
} else { /* error in format */
}
break;
}
}
if (found)
return (RSM_SUCCESS);
return (err);
}
static int
{
rsm_ioctlmsg_t msg = {0};
"_rsm_get_hwaddr: enter\n"));
"invalid controller handle\n"));
return (RSMERR_BAD_CTLR_HNDL);
}
"RSM_IOCTL_MAP_TO_ADDR failed\n"));
return (error);
}
"_rsm_get_hwaddr: exit\n"));
return (RSM_SUCCESS);
}
static int
{
rsm_ioctlmsg_t msg = {0};
"_rsm_get_nodeid: enter\n"));
"invalid arguments\n"));
return (RSMERR_BAD_CTLR_HNDL);
}
"RSM_IOCTL_MAP_TO_NODEID failed\n"));
return (error);
}
"_rsm_get_nodeid: exit\n"));
return (RSM_SUCCESS);
}
#ifdef DEBUG
void
{
if ((msg_category & rsmlibdbg_category) &&
(msg_level <= rsmlibdbg_level)) {
"Thread %d ", thr_self());
}
}
#endif /* DEBUG */