wrsm_memseg_import.c revision 7c478bd95313f5f23a4c958a745db2134aa03244
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (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 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* This file implements the RSMPI import side memory segment functions
* for the Wildcat RSM driver.
*/
#include <vm/seg_kmem.h>
#include <sys/ddimapreq.h>
#include <vm/hat_sfmmu.h>
#include <sys/wrsm_common.h>
#include <sys/wrsm_session.h>
#include <sys/wrsm_memseg.h>
#include <sys/wrsm_memseg_impl.h>
#include <sys/wrsm_intr.h>
#include <sys/wrsm_plugin.h>
#ifdef DEBUG
#define DBG_IMPORT 0x004
#define DBG_IMPORT_EXTRA 0x040
#define DBG_WARN 0x100
#else /* DEBUG */
#define DPRINTF(a, b) { }
#endif /* DEBUG */
/*
* lock hierarchy:
* network->lock
* all_importsegs_lock
* node->memseg->lock
* importseg->rw_lock
* iseginfo->lock
* iseginfo->network->errorpage_lock
*
* Note: it is always safe to take all_importsegs_lock.
* It is also safe to take network->lock: the network must
* unregister (unregister_controller), which it can't do
* until clients all release the network (release_controller).
* If a client accesses these functions after doing a release
* controller, all bets are off.
*/
/*
* Find iseginfo in exporting node's hash using segid.
*/
static iseginfo_t *
{
int index;
while (iseginfo) {
return (iseginfo);
}
}
return (NULL);
}
/*
* Create a new iseginfo structure, add to hash, lock it.
*
* If in the middle of tearing down the session to this node, return
* a null iseginfo.
*/
static int
{
int index;
/* allocate memory from our wrsm_arena and zero it */
/* invalid node */
return (RSMERR_UNKNOWN_RSM_ADDR);
}
/*
* add to node's iseginfo_hash
*/
/*
* can't connect to a segment while the exporting
* node's session is in the process of being removed
*/
"node %d is removing_session; wait_for_unmap %d\n",
return (RSMERR_CONN_ABORTED);
}
if (oseginfo) {
node);
if (!oseginfo->unpublished) {
/*
* valid iseginfo already exists - return
* this segment locked
*/
return (WRSM_SUCCESS);
} else {
/*
* old iseginfo no longer valid -- can't connect to
* this segment id exported by this node until the
* old one has been cleaned up. (This could take a
* while if clients have mappings they aren't
* releasing.)
*/
return (RSMERR_CONN_ABORTED);
}
}
/*
* new iseginfo - add to node's hash
*/
return (WRSM_SUCCESS);
}
/*
* Remove iseginfo structure from exporting node's hash. Clean up no
* longer valid mapping information in iseginfo.
*/
static void
{
int index;
/*
* if session was terminated, other side no longer expects
* a disconnect message
*/
}
/*
* remove iseginfo from node's hash
*/
/* look for iseginfo in hash */
}
if (*isinfop) {
/* found iseginfo in hash; now remove it */
#ifdef DEBUG
} else {
/* didn't find iseginfo in hash - should never happen */
"iseginfo 0x%p (dev_t %d) not in hash table",
#endif
}
/*
* release resources used by iseginfo
*/
if (iseginfo->seg_tuples) {
}
}
static void
{
}
/*
* Find an iseginfo with specified segid in exporting node's iseginfo hash.
* Lock both the node and iseginfo (if iseginfo is found).
*/
static iseginfo_t *
{
if (iseginfo) {
if (iseginfo->unpublished) {
}
}
if (!iseginfo) {
}
return (iseginfo);
}
/*
* Find an unpublished iseginfo with specified segid in exporting node's
* iseginfo hash. Lock both the node and iseginfo (if iseginfo is found).
*/
static iseginfo_t *
{
"ctlr %d: lock_node_and_unpublished_iseginfo() "
if (iseginfo) {
if (!iseginfo->unpublished) {
}
}
if (!iseginfo) {
}
return (iseginfo);
}
/*
* Find an iseginfo with specified segid in exporting node's iseginfo hash
* and lock it.
*/
static iseginfo_t *
{
if (iseginfo) {
}
return (iseginfo);
}
/*
* Make sure this importseg is still in all_importsegs_hash and still valid
* (not being destroyed).
*/
int
{
int err = RSMERR_BAD_SEG_HNDL;
int index;
while (impsg) {
err = RSM_SUCCESS;
break;
}
}
/*
* make sure importseg is not currently being removed
*/
}
#ifdef DEBUG
if (err) {
"invalid memseg 0x%p\n", (void *)importseg));
}
#endif
return (err);
}
/*
* Remove kernel mapping to segment.
*/
static void
{
return;
}
}
/*
* Remove kernel mappings to barrier page and small put interrupt page.
*/
static void
{
int i;
return;
/*
* release mapping to barrier page
*/
MMU_PAGESIZE));
}
/*
* release mapping to small put interrupt page
*/
}
if (iseginfo->errorpages) {
for (i = 0; i < iseginfo->errorpages; i++) {
}
iseginfo->errorpages = 0;
} else {
}
}
/*
* Create kernel mapping to segment.
*/
int
{
int i;
int err;
return (WRSM_SUCCESS);
/*
* This is not DDI compatible, but there is no DDI compatible way
* of mapping in a segment contiguously in the kernel virtual
* address space if it is backed by multiple physically
* discontiguous regions of "regspec" memory.
*/
/*
* Allocate a large enough kernel virtual memory region for this
* segment
*/
/* allocate memory from our wrsm_arena */
/*
* not enough space in kernel virtual memory to map
* this segment
*/
return (RSMERR_INSUFFICIENT_RESOURCES);
}
/* LINTED: E_PRECEDENCE_CONFUSION */
} else {
}
for (i = 0; i < iseginfo->num_seg_tuples; i++) {
/*
* get the physical address for this ncslice
*/
if (err) {
return (RSMERR_INSUFFICIENT_RESOURCES);
}
/*
* set up mapping to segment
*/
/*
* Force 8k tte entries to be used, so that the error
* mapping (which also uses 8k pages) will work without
* trouble. (HAT_LOAD_REMAP doesn't handle switching
* from other page sizes to 8k pages.)
*/
"hat_devload(kas kaddr "
"0x%p size 0x%x paddr 0x%lx perms 0x%x flags 0x%x",
(void *)kaddr8k, MMU_PAGESIZE,
kaddr8k += MMU_PAGESIZE;
}
"len 0x%lx to paddr 0x%lx (ncslice 0x%x, offset 0x%lx)\n",
}
return (RSM_SUCCESS);
}
/*
* Create kernel mappings to barrier page and small put interrupt page.
*/
static int
{
int err;
int i;
int pages;
return (WRSM_SUCCESS);
/*
* Reserve mappings to this controller's error page (enough for the
* segment, barrier page and interrupt page). The kernel only
* supports a fixed number of locked mappings from one address
* space to the same physical address, so if can't reserve enough
* mappings, allocate additional error pages (cmmu entries) for
* this segment.
*/
if ((network->errorpage_mappings +
} else {
/*
* Can't set up error mappings using default error page.
* Allocate one or more private error pages for this
* segment.
*/
sizeof (wrsm_errorpage_t), KM_SLEEP);
for (i = 0; i < iseginfo->errorpages; i++) {
B_FALSE)) != WRSM_SUCCESS) {
int j;
for (j = 0; j < i; j++) {
}
sizeof (wrsm_errorpage_t));
iseginfo->errorpages = 0;
return (RSMERR_INSUFFICIENT_RESOURCES);
}
}
}
/*
* map in the barrier page
*/
if (err) {
return (RSMERR_INSUFFICIENT_RESOURCES);
}
"to paddr 0x%lx (ncslice 0x%x, offset 0x%lx)\n",
/*
* map in the interrupt page
*/
if (err) {
return (RSMERR_INSUFFICIENT_RESOURCES);
}
/*
* assign each new segment a different stride in which to do
* small puts. Just one stride is used per segment to simplify
* flushing outstanding smallput interrupts.
*/
"to paddr 0x%lx (ncslice 0x%x, offset 0x%lx)\n",
return (WRSM_SUCCESS);
}
/*
* Modify kernel mappings to segment, barrier page and small put interrupt
* page so that they all point to the local loopback error page.
*/
static void
{
int i, mappings;
return;
/* LINTED: E_PRECEDENCE_CONFUSION */
} else {
}
/*
* Change segment mapping (if there is one) to point to loopback
* error page. Mappings to this page were reserved in
* create_kernel_mappings().
*/
mappings = 0;
i = 0;
if (kaddr) {
offset = 0;
"hat_devload(kas kaddr 0x%p "
"size 0x%x paddr 0x%lx perms 0x%x flags 0x%x",
(void *)kaddr,
offset += MMU_PAGESIZE;
kaddr += MMU_PAGESIZE;
mappings++;
if (mappings == MAX_HBLK_LCKCNT) {
/*
* If there are more than MAX_HBLK_LCKCNT
* mappings, we must have allocated private
* error pages for it.
*/
i++;
mappings = 0;
}
}
}
/*
* change barrier page mapping to loopback error page
*/
"hat_devload(kas kaddr 0x%p "
"size 0x%x paddr 0x%lx perms 0x%x flags 0x%x",
}
mappings++;
if (mappings == MAX_HBLK_LCKCNT) {
/*
* If there are more than MAX_HBLK_LCKCNT
* mappings, we must have allocated private
* error pages for it.
*/
i++;
mappings = 0;
}
/*
* change small put interrupt page mapping to loopback error page
*/
"hat_devload(kas kaddr 0x%p "
"size 0x%x paddr 0x%lx perms 0x%x flags 0x%x",
}
}
/*
* Lost access to this iseginfo - tear down mappings and mark
* related importsegs as no longer valid.
*/
static void
{
/*
* This iseginfo is no longer backed by the remote node's segment,
* so remove it from the remote node's list. However don't free it
* until the last importseg has been freed.
*/
if (iseginfo->unpublished) {
/* already cleaned up after this segment */
return;
}
if (iseginfo->kernel_users) {
/* change kernel mappings to use loopback error page */
}
/*
* notify any clients that have done mappings that the
* mappings are no longer valid
*/
/*
* Callback client to notify them mappings
* are no longer valid.
*/
if (importseg->mapping_callback) {
(*(importseg->mapping_callback))(
}
}
}
if (iseginfo->wait_for_unmaps == 0) {
/*
* All mappings to segment cleaned up. Segment is no longer
* valid (except for access from remaining importsegs).
*/
}
}
/*
* Send message to specified node to collect information about segment.
*/
static int
{
int err = WRSM_SUCCESS;
/* LINTED */
!= WRSM_SUCCESS) {
/*
* This node is not responding (message not delivered or
* response not received). (Transport Layer tears down the
* session if there is a message delivery failure).
*/
return (RSMERR_RSM_ADDR_UNREACHABLE);
}
#ifdef DEBUG
if (wrsm_import_memseg_debug & DBG_IMPORT_EXTRA) {
}
#endif
return (RSMERR_RSM_ADDR_UNREACHABLE);
}
case ENOENT:
break;
case EACCES:
break;
default:
break;
}
return (err);
}
/*
* save information in iseginfo
*/
"got num_seg_tuples %d size 0x%lx perms 0x%x\n",
return (WRSM_SUCCESS);
}
/*
* Send message to specified node to collect small put page mapping
* information for segment.
*/
static int
{
int err = WRSM_SUCCESS;
/* LINTED */
!= WRSM_SUCCESS) {
/*
* This node is not responding (message not delivered or
* response not received). (Transport Layer tears down the
* session if there is a message delivery failure).
*/
return (RSMERR_RSM_ADDR_UNREACHABLE);
}
#ifdef DEBUG
#endif
return (RSMERR_RSM_ADDR_UNREACHABLE);
}
case ENOENT:
break;
case EACCES:
break;
default:
break;
}
return (err);
}
/*
* save information in iseginfo
*/
"got small put intr ncslice %d offset 0x%lx\n",
return (WRSM_SUCCESS);
}
/*
* Send message to specified node to collect barrier page mapping
* information for segment.
*/
static int
{
int err = WRSM_SUCCESS;
/* LINTED */
!= WRSM_SUCCESS) {
/*
* This node is not responding (message not delivered or
* response not received). (Transport Layer tears down the
* session if there is a message delivery failure).
*/
return (RSMERR_RSM_ADDR_UNREACHABLE);
}
#ifdef DEBUG
#endif
return (RSMERR_RSM_ADDR_UNREACHABLE);
}
case ENOENT:
break;
case EACCES:
break;
default:
break;
}
return (err);
}
/*
* save information in iseginfo
*/
"got barrier_page ncslice %d offset 0x%lx\n",
return (WRSM_SUCCESS);
}
/*
* Send message to specified node to collect segment mapping information
* for segment.
*/
static int
{
int err = WRSM_SUCCESS;
int tuple_index;
/* LINTED */
tuple_index = 0;
!= WRSM_SUCCESS) {
/*
* This node is not responding (message not
* delivered or response not received). (Transport
* Layer tears down the session if there is a
* message delivery failure).
*/
return (RSMERR_RSM_ADDR_UNREACHABLE);
}
#ifdef DEBUG
#endif
return (RSMERR_RSM_ADDR_UNREACHABLE);
}
case ENOENT:
break;
case EACCES:
/* tab oddly to make cstyle happy */
break;
default:
break;
}
return (err);
}
/*
* number of tuples in map response can't really
* fit in buffer (bad msg?) or doesn't match the
* number we were told to expect in connect response
*/
"received %d tuples > max (%d) per message or "
"> expected remaining (%d - %d)\n",
return (RSMERR_RSM_ADDR_UNREACHABLE);
}
/*
* save information in iseginfo
*/
}
return (WRSM_SUCCESS);
}
/*
* Notify exporting node that this segment is no longer being accessed.
*/
static void
{
/* LINTED */
}
/*
* Segment is no longer being published. Attempt clean up after all
* connections. If there are no mappings to segment, notify sender
* that there are no longer any connections.
*/
void
wrsm_unpublish_msg_evt(void *arg)
{
#ifdef DEBUG
#endif
/* non-existent node */
return;
}
/* session must not be valid */
return;
}
/*
* does segment exist?
*/
/*
* no iseginfo, or no connections to iseginfo
*/
if (iseginfo) {
/* no connections to iseginfo -- free it */
}
"sending WC_DISCONNECTED response\n"));
return;
}
/*
* We have some cleanup work to do. Let the other side
* know we got the message, but aren't finished cleaning up.
*/
/*
* Tear down mappings to this iseginfo. Notify remote node
* when all mappings have been torn down.
*/
/* We're done, deallocate our incoming args struct and the message */
}
/*
* Remember new permissions for segment.
*/
void
wrsm_access_msg_evt(void *arg)
{
#ifdef DEBUG
#endif
/* non-existent node */
return;
}
/* session must not be valid */
return;
}
/*
* Record new permissions
*/
if (iseginfo) {
}
/*
* send acknowledgement
*/
/* We're done, deallocate our incoming args struct and the message */
}
/*
* Collect information about segmenet from exporting node. Verify that
* it is valid.
*/
static int
{
int err;
int i, last_tuple;
/*
* collect segment info from exporter
*/
/* don't send disconnect message */
return (err);
}
/*
* no need to fetch mappings for a 0 length segment
*/
return (WRSM_SUCCESS);
}
/*
* collect mapping info for small put interrupt from exporter
*/
return (err);
}
"received bad small_put_tuple ncslice %d tuple %d\n",
return (RSMERR_RSM_ADDR_UNREACHABLE);
}
/*
* collect mapping info for barrier page from exporter
*/
return (err);
}
"received bad barrier_tuple ncslice %d tuple %d\n",
return (RSMERR_RSM_ADDR_UNREACHABLE);
}
/*
* collect mapping info for segment from exporter
*/
return (err);
}
offset = 0;
last_tuple = 0;
for (i = 0; i < iseginfo->num_seg_tuples; i++) {
/*
* verify that this ncslice is exported by the remote node
*/
last_tuple++) {
break;
}
}
if (last_tuple == WRSM_NODE_NCSLICES) {
/*
* Node is claiming it exports an ncslice it doesn't!
* Something must be wrong with connection.
*/
"segmap received bad ncslice %d tuple %d\n",
return (RSMERR_RSM_ADDR_UNREACHABLE);
}
/* part of segment doesn't have a mapping! */
"segmap received bad info in tuple %d\n", i));
return (RSMERR_RSM_ADDR_UNREACHABLE);
}
}
return (WRSM_SUCCESS);
}
/*
* The session to the specified node has been torn down. Clean up
* references to any segments imported from this node.
*/
{
int i;
/*
* it is presumed that at this point the node was removed from the
* cluster_members_bits registers in all wcis
*/
/*
* Clean up iseginfos imported from remote node. The node lock
* could be held for a long time, but seeing as the node is
* considered unreachable, this shouldn't really be a problem.
*/
for (i = 0; i < WRSM_SEGID_HASH_SIZE; i++) {
while (iseginfo) {
}
}
/*
* new session can be established once all mappings
* to node are torn down
*/
}
}
/*
* The controller is being removed -- all clients have called
* release_controller, so it should be ok to remove objects the client may
* not have bothered to clean up.
*/
void
{
int i;
network->rsm_ctlr_id));
for (i = 0; i < WRSM_MAX_CNODES; i++) {
if (node) {
/* assume mappings have been removed */
}
}
}
return;
}
for (i = 0; i < WRSM_SEGID_HASH_SIZE; i++) {
importsegp = &(all_importsegs_hash[i]);
while (*importsegp != NULL) {
importseg = *importsegp;
/*
* remove importseg from all_importsegs_hash
*/
/*
* remove importseg from iseginfo list
*/
}
if (importseg->kernel_user) {
iseginfo->kernel_users--;
if (iseginfo->kernel_users == 0)
iseginfo);
}
sizeof (iseginfo_t));
} else {
}
} else {
}
}
}
#ifdef DEBUG
"importseg count %d after exportseg cleanup\n",
}
#endif
}
/*
*
* RSM functions
*
*/
int
{
int index;
int err;
"invalid network 0x%p\n", (void *)network));
return (RSMERR_BAD_CTLR_HNDL);
}
if (addr >= WRSM_MAX_CNODES) {
/*
* wrsm hardware addresses must be cnodeids
*/
"%ld\n", addr));
return (RSMERR_UNKNOWN_RSM_ADDR);
}
/*
* create importseg structure for this connection
*/
/*
* get existing or create new iseginfo for this <node, segid>
* and return it locked
*/
WRSM_SUCCESS) {
return (err);
}
if (new) {
/*
* First import of this <node, segid>: collect mapping
* information from the node exporting it.
*/
if (err) {
/* had a problem collecting mapping info */
}
if (err == RSMERR_RSM_ADDR_UNREACHABLE) {
}
return (err);
}
/* set up mappings to interrupt and barrier pages */
if (err) {
/* had a problem setting up mappings */
}
return (err);
}
}
/*
* add importseg to list of importsegs for this iseginfo
*/
/*
* add to all_importsegs_hash
*/
return (RSM_SUCCESS);
}
/*
* destroy this importseg handle
*/
int
{
int err;
int index;
(void *)importseg));
RSM_SUCCESS) {
return (err);
}
if (importseg->have_mappings) {
return (RSMERR_SEG_IN_USE);
}
/*
* remove from iseginfo importseg list
*/
while (*importsegp != importseg) {
}
ASSERT(*importsegp);
if (importseg->kernel_user) {
iseginfo->kernel_users--;
if (iseginfo->kernel_users == 0)
}
/*
* Just removed the last importseg from a no longer valid
* iseginfo. There are now no references to iseginfo, so
* it is safe to free it.
*/
"freeing unpublished iseginfo\n"));
} else {
}
/*
* Remove from all_importsegs_hash.
* importseg->rw_lock can't be held prior to taking
* all_importsegs_lock.
*/
*importsegp != NULL;
if (*importsegp == importseg) {
break;
}
}
return (RSM_SUCCESS);
}
int
{
int num_seg_tuples, i;
int err;
(void *)importseg));
if (len <= 0) {
return (RSMERR_BAD_LENGTH);
}
RSM_SUCCESS) {
return (err);
}
/* segment size never changes, so check immediately */
return (RSMERR_BAD_LENGTH);
}
/*
* Release the importseg lock, take the exporting node's lock, then
* retake the importseg lock.
*/
return (RSMERR_CONN_ABORTED);
}
RSM_SUCCESS) {
return (err);
}
if (importseg->unpublished) {
/*
* new mappings not allowed on a segment that has
* been unpublished
*/
return (RSMERR_CONN_ABORTED);
}
/*
* remember that map has been called on this segment
*/
}
}
/*
* Calculate the ncslice and offset within the slice that maps to
* the requested segment offset. Also determine the size of the
* contiguous region starting at this offset that maps to the
* segment.
*/
for (i = 0; i < num_seg_tuples; i++) {
/*
* offset falls within this ncslice region
*/
}
break;
}
}
/* It is not possible that the desired offset does not have a mapping */
ASSERT(i < num_seg_tuples);
*dipp = wrsm_ncslice_dip;
/*
* record the mapping-no-longer-valid callback and arg for this
* importseg.
*/
return (RSM_SUCCESS);
}
/*
* one rsm_unmap() call cancels all previous rsm_map calls
*/
int
{
int err;
(void *)importseg));
RSM_SUCCESS) {
return (err);
}
/*
* Release the importseg lock, take the exporting node's lock, then
* retake the importseg lock. If this is the last mapping for the
* reflect this.
*/
return (RSMERR_CONN_ABORTED);
}
RSM_SUCCESS) {
return (err);
}
if (!iseginfo->wait_for_unmaps) {
/*
* segment not mapped, so do nothing
*/
return (RSM_SUCCESS);
}
if (iseginfo->wait_for_unmaps == 0) {
if (iseginfo->unpublished) {
}
/*
* Make sure session state reflects that
* there are no more references to this
* node.
*/
}
}
}
return (RSM_SUCCESS);
}
/* RSMAPI helper functions */
/*
* returns the locked iseginfo that corresponds to ctrl_num,
* remote_cnode, and segid.
* Returns RSM_SUCCESS upon successful completion.
* If an iseginfo is successfully returned, the CALLER must RELEASE
* the iseginfo->mutex.
*/
int
{
return (ENXIO);
}
/*
* we know that the network can't be removed because we are using
* either an ioctl or mmap to call this function. The driver will
* not allow the network to be removed while in use, hence, we do
* not need to grab and hold wrsm_networks_lock
*/
"_iseginfo node NULL"));
return (EBADF);
}
"wrsm_memseg_remote_node_to_iseginfo NO iseginfo found"));
return (EBADF);
}
return (RSM_SUCCESS);
}
/* ARGSUSED */
int
{
int error;
if (len != WRSM_PAGESIZE) {
return (EINVAL);
}
/* minor number is the controller number */
"for controller id %d export cnode %d ",
/*
* Get iseginfo for this controller, cnodeid, and segment_id.
* iseginfo is returned locked.
*/
if (error != RSM_SUCCESS) {
" segment for controller id %d export cnode %d\n",
return (error);
}
/*
* page_type field represents the type of page trying to be mapped.
* those types are Interrupt, Barrier, barrier registers (CESR and
* wci_cluster_error_count mapped in via page 0 of ncslice)
* and Reconfiguration counter.
*/
" Only read permission allowed with Reconfig"
" mapping cntrl %d, export_cnode %d, segment %d",
return (EACCES);
}
}
}
/* ARGSUSED */
int
{
int error;
/* Set up data access attribute structure */
struct ddi_device_acc_attr wrsm_acc_attr = {
};
if (len != WRSM_PAGESIZE) {
return (EINVAL);
}
/*
* Get iseginfo for this controller, cnodeid, and segment_id.
* iseginfo is returned locked.
*/
if (error != RSM_SUCCESS) {
" for controller id %d\n", rsm_ctrl_id);
return (error);
}
" page for controller id %d", rsm_ctrl_id));
return (ENXIO);
}
break;
case WRSM_MMAP_BARRIER_REGS:
/*
* From WCI-2 CESR, wci_cluster_error_count registers
* and write lockout registers are visible through page 0 of
* the remotes node's ncslice
*/
" for CRS's on controller id %d\n", rsm_ctrl_id));
offset = 0;
return (ENXIO);
}
break;
case WRSM_MMAP_RECONFIG:
"rerouting, and striping for controller id %d",
rsm_ctrl_id));
/*
* special case of wrsm_devmap. maps kernel memory
* rather than device memory for the network->route_counter
* and the network->routing and striping.
* The plugin needs these counters to implement
* barriers.
*/
offset = 0;
" defined for controller id %d", rsm_ctrl_id);
return (ENXIO);
}
/* Set up the kernel mapping */
if (error != 0)
return (EINVAL);
else
return (RSM_SUCCESS);
default:
/* this case should NOT occur */
" for controller id %d", rsm_ctrl_id);
return (ENXIO);
}
/* Set up the device mapping */
/* acknowledge the entire range */
if (error != 0)
return (EINVAL);
else
return (RSM_SUCCESS);
}