idn_proto.c revision bf30efa4af94cd71664f6c1be0e6e950b1d7a0f4
/*
* 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"
/*
* Inter-Domain Network
*
*/
#include <sys/machparam.h>
#include <sys/sema_impl.h>
#include <sys/vm_machparam.h>
#define IDNBUG_CPUPERBOARD
extern pri_t maxclsyspri;
extern u_longlong_t gettick();
static int idn_connect(int domid);
static void idn_deconfig(int domid);
static void idn_retry_execute(void *arg);
uchar_t **data_rptrp);
static int idn_recv_config_done(int domid);
int new_cpuid);
static int idn_program_hardware(int domid);
static int idn_deprogram_hardware(int domid);
static void idn_mainmbox_activate(int domid);
static void idn_mainmbox_chan_register(int domid,
static int idn_deactivate_channel_services(int channel,
static int idn_activate_channel_services(int channel);
#if 0
#endif /* 0 */
int wait);
static void idn_submit_chanactivate_job(int channel);
static void idn_exec_chanactivate(void *chn);
static void idn_link_established(void *arg);
static void idn_prealloc_slab(int nslabs);
int serrno);
int nslabs);
int serrno);
static void idn_retry_nodename_req(void *arg);
static void idn_send_nodename_req(int domid);
int serrno);
static void idn_protocol_server(int *id);
static void idn_protocol_server_killall();
static domainset_t
static void idn_sync_register_awol(int domid);
static int idn_verify_config_mbox(int domid);
static int valid_slabsize(int slabsize);
static int valid_nwrsize(int nwrsize);
static int idn_master_init();
static void idn_master_deinit();
static void idn_final_nego(int domid);
static void idn_final_con(int domid);
static void idn_final_fin(int domid);
/*
* We keep a small cache of protojob structures just
* in case allocation within idn_handler comes back
* with nothing from the land of kmem.
*/
/*
* - receive message.
* - call check-function for current state.
* - if (check-function == ok) then
* call action-function for current state.
* else
* call error-function for current state.
* - transition state based on check results.
* - if (next state == final state) then
* call final-function.
*/
static idn_xphase_t xphase_nego = {
{
NULL,
NULL },
},
};
static idn_xphase_t xphase_con = {
{
NULL,
NULL },
},
};
static idn_xphase_t xphase_fin = {
{
NULL,
NULL },
},
};
{ /* IDNXS_PEND */
},
{ /* IDNXS_SENT */
},
{ /* IDNXS_RCVD */
},
{ /* IDNXS_FINAL */
}
};
/*
* NONE Respective domain does not have a master.
* OTHER Respective domain has a master different
* than either local or remote.
* LOCAL Respective domain has chosen local as master.
* REMOTE Respective domain has chosen remote as master.
*
* Actions:
* VOTE Compare votes and select one.
* VOTE_RCFG Compare votes and Reconfigure
* if necessary, i.e. remote won.
* CONNECT Connect to remote's OTHER if different
* than our local master.
* LOCAL Local domain is winner.
* REMOTE Remote domain is winner.
* WAIT Wait for remote to connect to our
* master if his is different.
* ERROR An impossible condition.
*
* Index:
* 0 = Local
* 1 = Remote
*/
{ /* local remote */
MASTER_SELECT_VOTE, /* NONE NONE */
MASTER_SELECT_CONNECT, /* NONE OTHER */
MASTER_SELECT_LOCAL, /* NONE LOCAL */
MASTER_SELECT_REMOTE /* NONE REMOTE */
},
{
MASTER_SELECT_WAIT, /* OTHER NONE */
MASTER_SELECT_CONNECT, /* OTHER OTHER */
MASTER_SELECT_WAIT, /* OTHER LOCAL */
MASTER_SELECT_WAIT /* OTHER REMOTE */
},
{
MASTER_SELECT_LOCAL, /* LOCAL NONE */
MASTER_SELECT_CONNECT, /* LOCAL OTHER */
MASTER_SELECT_LOCAL, /* LOCAL LOCAL */
MASTER_SELECT_VOTE_RCFG /* LOCAL REMOTE */
},
{
MASTER_SELECT_REMOTE, /* REMOTE NONE */
MASTER_SELECT_CONNECT, /* REMOTE OTHER */
MASTER_SELECT_ERROR, /* REMOTE LOCAL */
MASTER_SELECT_REMOTE /* REMOTE REMOTE */
}
};
void
idn_assign_cookie(int domid)
{
return;
;
}
void
{
if (pri >= IDNVOTE_MINPRI) {
PR_PROTO("%s:%d: SETTING PRIORITY to req(%d) "
"(localpri = 0x%x)\n",
} else {
PR_PROTO("%s:%d: PRIORITIES UNCHANGED (pri = 0x%x)\n",
}
}
/*
* Initiate a link between the local domain and the remote domain
* containing the given cpuid.
*/
int
{
int rv;
void *opcookie;
"IDN: 201: (LINK) invalid CPU ID (%d)", cpuid);
return (EINVAL);
}
if (waittime < 0) {
"IDN: 202: (LINK) invalid time-out value (%d)",
waittime);
return (EINVAL);
}
if (!VALID_DOMAINID(domid)) {
"IDN: 203: (LINK) invalid domain ID (%d)",
domid);
return (EINVAL);
}
return (0);
case IDNDS_CLOSED:
break;
case IDNDS_CONNECTED:
#ifdef DEBUG
"!IDN: domain %d (CPU ID %d) already connected",
#endif /* DEBUG */
return (0);
default:
"IDN: 204: domain %d state (%s) inappropriate",
return (EINVAL);
}
if (rv != 0) {
"IDN: 205: (%s) failed to open-domain(%d,%d)",
return (EIO);
}
if (waittime > 0)
if (waittime > 0) {
boardset_t domset = 0;
/*
* Well we've successfully allocated a domain id,
* but the link may not be fully established yet.
* Need to wait since it happens asynchronously.
*/
PR_PROTO("%s:%d: WAITING for op(%s) for (domset 0%x)...\n",
}
#ifdef DEBUG
if (rv == 0) {
if (waittime > 0) {
PR_PROTO("%s:%d: connect SUCCEEDED (cpu %d)\n",
} else {
PR_PROTO("%s:%d: connect KICKED OFF (cpu %d)\n",
}
} else {
PR_PROTO("%s:%d: connect FAILED (cpu %d)\n",
}
#endif /* DEBUG */
return (rv);
}
/*
* Unlink the given domain from any domain cluster of
* which it might be a member. Force indicates that domain
* should not go AWOL and if it's currently AWOL to close
* and remove it.
* IMPORTANT: If the (hard) force flag is set, the caller is
* assumed to GUARANTEE that the given domain will
* not attempt to communicate with the local domain
* in any manner.
*/
int
{
int rv = 0;
void *opcookie;
if (waittime < 0) {
"IDN: 202: (UNLINK) invalid time-out value (%d)",
waittime);
return (EINVAL);
}
if (!VALID_DOMAINID(domid)) {
"IDN: 203: (UNLINK) invalid domain ID (%d)",
domid);
return (EINVAL);
}
#ifdef DEBUG
"!IDN: %s: local domain not connected to an IDNnet",
proc);
#endif /* DEBUG */
return (0);
}
/*
* Lock ordering protocols requires that we grab the
* global lock _before_ the local domain's lock.
* However, non-local domains must have their lock
* grabbed _before_ the global lock.
*/
#ifdef DEBUG
"!IDN: %s: local domain not connected to an IDNnet",
proc);
#endif /* DEBUG */
IDN_GUNLOCK();
return (0);
}
} else {
}
IDN_GUNLOCK();
if (waittime > 0)
if (waittime > 0) {
/*
* Well the unlink has successfully kicked off.
* Since process is asynchronous we need to wait
* for it to complete.
*/
PR_PROTO("%s:%d: WAITING for op(%s) for (domset 0%x)...\n",
domset);
}
if (rv == 0) {
if (waittime > 0) {
PR_PROTO("%s:%d: disconnect SUCCEEDED\n",
} else {
PR_PROTO("%s:%d: disconnect KICKED OFF\n",
}
} else {
}
return (rv);
}
static void
{
int d;
/*
* Determine subset for which we have
* no active connections.
*/
/*
* Determine subset that are really candidates.
* Note that we include those already down the path
* since it's possible a request came in to upgrade
* their fintype (e.g. NORMAL->FORCE_SOFT).
*/
if (offset)
/*
* Don't add domains already transitioning off.
* If they caught on an earlier Reconfig wave then
* they'll already be in ds_relink anyway. Otherwise,
* once a domain is transition off we can't upgrade
* him to a RELINK.
*/
#ifdef DEBUG
PR_HITLIST("%s: domset=%x, hitlist=%x, trans_off=%x "
"-> relink = %x -> %x\n",
}
#endif /* DEBUG */
} else {
}
/*
* Update the ds_trans_on/off so we don't waste
* time talking to these folks.
*/
if (domset == 0) {
PR_HITLIST("%s:%x: HITLIST %x -> 0\n",
}
IDN_GUNLOCK();
return;
}
IDN_GUNLOCK();
for (d = 0; d < MAX_DOMAINS; d++) {
if (!DOMAIN_IN_SET(domset, d))
continue;
dp = &idn_domain[d];
IDN_DLOCK_EXCL(d);
/*
* If domain is not in the IDNSET passed
* down then we need to upgrade this to
* hard-force in order to prevent possible
* system failures (arbstop). This is simply
* extra protection beyond that checked by
* the SSP. IDNSET contains the set of boards
* that have a "link" to the local domain,
* including the SMD regs.
*/
PR_PROTO("%s:%d: boardset 0x%x "
"NOT in IDNSET 0x%x\n",
idnset);
if (ftype != IDNFIN_FORCE_HARD)
"!IDN: 222: no IDN linkage "
"found (b=0x%x, i=0x%x) "
"upgrading unlink %s to %s",
} else {
PR_PROTO("%s:%d: boardset 0x%x "
"FOUND in IDNSET 0x%x\n",
idnset);
}
}
IDN_DUNLOCK(d);
}
}
/*
*/
static int
idn_connect(int domid)
{
PR_PROTO("%s:%d: already connected or "
} else {
PR_PROTO("%s:%d: current state (%s) != "
}
return (-1);
}
return (0);
}
/*
*/
static int
{
return (-1);
}
/*
* Terminate any outstanding commands that were
* targeted towards this domain.
*/
/*
* Terminate any and all retries that may have
* outstanding for this domain.
*/
(void) idn_retry_terminate(token);
/*
* Stop all outstanding message timers for
* this guy.
*/
IDN_MSGTIMER_STOP(domid, 0, 0);
/*
* You can only upgrade a fin type.
* We don't allow it to be downgraded
* as it's too dangerous since some
* state may have been blown away while
* we were fin'ing at a higher level.
*/
}
PR_PROTO("%s:%d: disconnect synchronously = %s\n",
} else {
PR_HITLIST("%s:%d: HITLIST %x -> %x\n",
}
IDN_GUNLOCK();
if (new_masterid != IDN_NIL_DOMID)
return (0);
}
static int
{
int index;
if (!msg)
index = 0;
else if ((msg & IDNP_MSGTYPE_MASK) == 0)
else
if (index == -1) {
return (IDNXS_NIL);
}
if (err == -1) {
int n_xstate;
/*
* Caller is just interested in querying is this
* is a valid message to receive in the current
* xstate. A return value of IDNXS_NIL indicates
* that it's not. A return value of non-IDNXS_NIL
* indicates it's cool. An invalid message is
* determined by both err & !err states being IDNXS_NIL.
*/
return (n_xstate);
else
} else {
}
}
static int
{
int d, best_id = IDN_NIL_DOMID;
if (master_set == 0) {
return (IDN_NIL_DOMID);
}
for (d = 0; d < MAX_DOMAINS; d++) {
idn_vote_t v;
if (!DOMAIN_IN_SET(master_set, d))
continue;
dp = &idn_domain[d];
continue;
vote = IDNVOTE_ELECT(v);
best_id = d;
}
}
return (best_id);
}
/*
* If a non-zero value is returned then GLOCK will have been dropped.
* Otherwise, routine returns with all incoming locks still held.
*/
static int
{
char *sel;
int do_reconfig = 0;
PR_PROTO("%s:%d: lmasterid = %d, rmasterid = %d, rcpuid = %d\n",
/*
* Clear master bits since mastership is derived from
* other information (local/remote idn.masterid/idn.new_masterid)
* and we don't want the vote master bit to confuse matters.
*/
/*
* Each case is responsible for dropping DLOCK(localid)
* and GLOCK if it doesn't select a master, unless a
* reconfig is necessary.
*/
switch (select) {
case MASTER_SELECT_VOTE_RCFG:
sel = "VOTE_RECONFIG";
/*
* If the local domain is the winner then remote
* domain will have to Reconfig. We'll continue
* through the connection process anyway. The
* remote domains will tell us to back-off while
* Reconfigs, but that's okay as we'll keep retrying.
*/
do_reconfig = 1;
/*
* GLOCK will get dropped once reconfig
* is kicked off.
*/
} else {
"IDN: 206: cannot link domains "
"with equal votes (L(%d),R(%d),0x%x)",
IDN_GUNLOCK();
}
break;
case MASTER_SELECT_VOTE:
sel = "VOTE";
} else {
"IDN: 206: cannot link domains "
"with equal votes (L(%d),R(%d),0x%x)",
}
if (masterid != IDN_NIL_DOMID) {
} else {
IDN_GUNLOCK();
}
break;
case MASTER_SELECT_REMOTE:
sel = "REMOTE";
if (IDN_GET_MASTERID() == IDN_NIL_DOMID) {
}
break;
case MASTER_SELECT_LOCAL:
sel = "LOCAL";
if (IDN_GET_MASTERID() == IDN_NIL_DOMID) {
}
break;
case MASTER_SELECT_CONNECT:
sel = "CONNECT";
/*
* Local and remote have same master,
* let him come onboard.
*/
} else {
int rv;
IDN_GUNLOCK();
"master %d\n",
if (rv == 0) {
} else if (rv < 0) {
"IDN: 205: (%s) failed to "
"open-domain(%d,%d)",
} else {
/*
* Must already have a connection going.
*/
PR_PROTO("%s:%d: failed "
"idn_open_domain(%d,%d,0) "
"(rv = %d)\n",
}
}
break;
case MASTER_SELECT_WAIT:
sel = "WAIT";
/*
* If the remote domain has the same master as the local
* domain then there's no need to wait.
*/
} else {
IDN_GUNLOCK();
}
break;
case MASTER_SELECT_ERROR:
sel = "ERROR";
/*
* Hit impossible condition.
*/
"(%d.lmasterid = %d, %d.rmasterid = %d)",
IDN_GUNLOCK();
break;
default:
"IDN: 208: %s: unknown case (%d)",
IDN_GUNLOCK();
ASSERT(0);
break;
}
if (masterid == IDN_NIL_DOMID) {
PR_PROTO("%s:%d: NO MASTER SELECTED (rmstr=%d) sel=%s\n",
} else {
PR_PROTO("%s:%d: MASTER SELECTED = %d (%s)\n",
}
if (do_reconfig) {
/*
* Local domain already has a master.
* Need to dismantle all connections
* and reestablish one with new master.
*/
PR_PROTO("%s:%d: RECONFIG new masterid = %d\n",
IDN_GUNLOCK();
}
}
/*ARGSUSED1*/
static void
{
switch (rtype) {
case IDNRETRY_CONQ:
break;
case IDNRETRY_FINQ:
break;
default:
return;
}
if (query_set == 0) {
return;
}
for (d = 0; d < MAX_DOMAINS; d++) {
if (!DOMAIN_IN_SET(query_set, d))
continue;
dp = &idn_domain[d];
if (d != domid)
IDN_DLOCK_EXCL(d);
(!dp->dcookie_send &&
(rtype == IDNRETRY_CONQ))) {
if (d != domid)
IDN_DUNLOCK(d);
continue;
}
if (rtype == IDNRETRY_CONQ)
else
if (d != domid)
IDN_DUNLOCK(d);
}
}
static int
{
int d, masterid;
if (mtp) {
} else {
acknack = 0;
}
/*
* We only send the new-master "hint" to
* "other" domains. If the new-master is
* ourself or we're talking to the new-master
* then we need to be accurate about our
* real master so that the correct master
* is selected.
*/
}
}
/*
* Exclude domains from conset that are on
* remote domain's hitlist. He's not interested
* in hearing about them. SSP is probably requesting
* such domains be unlinked - will eventually get to
* local domain.
*/
if ((masterid != IDN_NIL_DOMID) &&
PR_PROTO("%s:%d: masterid(%d) on hitlist(0x%x) -> -1\n",
/*
* Yikes, our chosen master is on the hitlist!
*/
}
dmask = IDNNEG_DSET_MYMASK();
for (d = 0; d < MAX_DOMAINS; d++) {
int cpuid;
if (!DOMAIN_IN_SET(conset, d))
continue;
continue;
}
}
IDN_GUNLOCK();
/*
* We just want to send basic vote components without an
* indication of mastership (master bit) since that's primarily
* for local domain's usage. There is more correct master
* indications in the DSET. Recall that if we were in a
* Reconfig we would have transmitted the "new_masterid"
* which might conflict with the local domain's vote.v.master
* bit if he was originally the master prior to the Reconfig.
*/
PR_PROTO("%s:%d: sending nego%sto (cpu %d) "
"[v=0x%x, cs=0x%x, mstr=%d]\n",
return (0);
}
static int
{
#ifdef DEBUG
PR_HITLIST("%s:%d: dcpu=%d, dstate=%s, msg=%x, "
"hitlist=%x\n",
}
#endif /* DEBUG */
int cpuid;
/*
* Brandnew link. Need to open a new domain entry.
*/
PR_PROTO("%s:%d: FAILED to open doamin "
"(ticket = 0x%x)\n",
return (-1);
}
}
PR_PROTO("%s:%d: assigned SEND cookie 0x%x\n",
}
if (msg & IDNP_MSGTYPE_MASK) {
/*
* If we already have a connection to somebody
* trying to initiate a connection to us, then
* possibly we've awaken from a coma or he did.
* In any case, dismantle current connection
* and attempt to establish a new one.
*/
} else {
domid)) {
} else {
int new_masterid;
int new_cpuid = IDN_NIL_DCPU;
if (new_masterid == IDN_NIL_DOMID)
if (new_masterid != IDN_NIL_DOMID) {
}
IDN_GUNLOCK();
}
}
}
return (0);
}
return (0);
}
/*ARGSUSED1*/
static void
{
int new_masterid;
#ifdef DEBUG
}
#endif /* DEBUG */
PR_PROTO("%s:%d: dxp(%s) != NEGO...bailing...\n",
return;
}
PR_PROTO("%s:%d: xstate(%s) != %s...bailing\n",
return;
}
/*
* Have to try again later after
* reconfig has completed.
*/
PR_PROTO("%s:%d: reconfig in-progress...try later\n",
IDN_GUNLOCK();
return;
}
(new_masterid != IDN_NIL_DOMID) &&
(domid != new_masterid) &&
/*
* We have a new master pending and this
* guy isn't it. Wait until the local domain
* has a chance to connect with the new
* master before going forward with this
* guy.
*/
PR_PROTO("%s:%d: waiting for connect to new master %d\n",
IDN_GUNLOCK();
return;
}
IDN_GUNLOCK();
}
static int
{
int d, new_masterid, masterid;
PR_HITLIST("%s:%d(%s): (msg=%x) EXIT received, "
"adding to hitlist %x -> %x\n",
return (-1);
} else {
return (0);
}
}
PR_HITLIST("%s:%d(%s): (msg=%x) domain in hitlist (%x) - "
"exiting phase\n",
return (-1);
}
(msg & IDNP_MSGTYPE_MASK) &&
return (1);
PR_PROTO("%s:%d: DISCONNECT in-progress >>> EXIT\n",
IDN_GUNLOCK();
return (-1);
}
}
case IDNGS_RECONFIG:
PR_PROTO("%s:%d: RECONFIG in-progress >>> RETRY\n",
IDN_GUNLOCK();
return (1);
case IDNGS_CONNECT:
if ((new_masterid != IDN_NIL_DOMID) &&
(domid != new_masterid) &&
PR_PROTO("%s:%d: waiting for connect to "
"new master %d\n",
IDN_GUNLOCK();
return (1);
}
break;
default:
break;
}
con_set = 0;
if (msg) {
/*
* Sender should note have set master bit,
* but just in case clear it so local domain
* doesn't get confused.
*/
/*LINTED*/
if (new_masterid == IDNNEG_NO_MASTER) {
} else {
/*
* Remote domain has a master. Find
* his cpuid in the dset. We may need
* it to initiate a connection.
*/
if (new_masterid == domid) {
} else {
dmask);
if (m_cpuid == -1) {
/*
* Something is bogus if remote domain
* is reporting a valid masterid, but
* doesn't have the cpuid for it.
*/
"IDN: 209: remote domain (ID "
"%d, CPU %d) reporting master "
"(ID %d) without CPU ID",
domid);
IDN_GUNLOCK();
return (-1);
}
}
}
for (d = 0; d < MAX_DOMAINS; d++) {
continue;
if (cpuid != -1) {
DOMAINSET_ADD(con_set, d);
}
}
#ifdef DEBUG
PR_HITLIST("%s:%d: con_set %x -> %x (hitlist = %x)\n",
}
#endif /* DEBUG */
if ((new_masterid != IDN_NIL_DOMID) &&
new_masterid)) {
PR_HITLIST("%s:%d: new_mstr %d -> -1 (hitlist = %x)\n",
IDN_GUNLOCK();
return (1);
}
/*
*/
return (1);
}
masterid = IDN_GET_MASTERID();
/*
* This is the initial connection for
* the local domain.
*/
if (idn_master_init() < 0) {
"IDN: 210: failed to init "
"MASTER context");
IDN_GUNLOCK();
return (-1);
}
} else {
/*
* Either the remote domain is the
* master or its a new slave trying
* to connect to us. We can't allow
* further progress until we've
* sync'd up with the master.
*/
IDN_GUNLOCK();
return (1);
}
}
/*
* We've sync'd up with the new master.
*/
}
/*
* We can't progress any further with
* other domains until we've exchanged all
* the necessary CFG info with the master,
* i.e. until we have a mailbox area from
* which we can allocate mailboxes to
* other domains.
*/
PR_PROTO("%s:%d: still exchanging CFG "
IDN_GUNLOCK();
return (1);
}
}
}
IDN_GUNLOCK();
(void *)IDNP_CON);
}
/*
* Get this domain registered as an expected domain on
* the remaining domains in the CONNECT synchronization.
*/
/*
* Note that if (msg == 0), i.e. then there will be
* no dset and also pending_set will be 0.
* So, the following loop will never attempt to
* look at the dset unless (msg != 0), implying
* that we've been through the initial code above
* and have initialized dmask.
*/
for (d = 0; d < MAX_DOMAINS; d++) {
int rv;
if (!DOMAIN_IN_SET(pending_set, d))
continue;
dp = &idn_domain[d];
if (cpuid == -1) {
PR_PROTO("%s:%d: failed to get cpuid from dset "
"for domain %d (pset = 0x%x)\n",
continue;
}
IDN_DLOCK_EXCL(d);
PR_PROTO("%s:%d: failed "
"idn_open_domain(%d,%d,0) (rv = %d)\n",
if (rv < 0) {
"IDN: 205: (%s) failed to "
"open-domain(%d,%d)",
/*
* We've requested to connect to a domain
* from which we're disconnecting. We
* better mark this guy for relinking.
*/
}
IDN_DUNLOCK(d);
continue;
}
idn_connect(d);
IDN_DUNLOCK(d);
}
return (0);
}
/*ARGSUSED*/
static void
{
if (!msg) {
} else {
}
}
/*ARGSUSED*/
static void
{
int new_masterid, new_cpuid;
int retry = 1;
switch (nack) {
case IDNNACK_RETRY:
break;
case IDNNACK_EXIT:
retry = 0;
/*FALLTHROUGH*/
default:
break;
}
}
if (msg & IDNP_MSGTYPE_MASK) {
if (new_masterid == IDN_NIL_DOMID)
if (new_masterid != IDN_NIL_DOMID)
else
IDN_GUNLOCK();
}
if (retry) {
idn_msg_retrytime[(int)IDNRETRY_NEGO]);
} else {
}
}
/*ARGSUSED*/
static void
{
if ((msg & IDNP_ACKNACK_MASK) == 0) {
/*
* nego
*/
} else if (msg & IDNP_MSGTYPE_MASK) {
int d;
dmask = IDNNEG_DSET_MYMASK();
for (d = 0; d < MAX_DOMAINS; d++) {
int cpuid;
if (!DOMAIN_IN_SET(conset, d))
continue;
continue;
}
1);
/*
* nego+ack
*/
} else {
int new_masterid, new_cpuid;
int retry = 1;
/*
* nack - retry
*
* It's possible if we've made it this far that
* we may have already chosen a master and this
* dude might be it! If it is we need to clean up.
*/
switch (nack) {
case IDNNACK_RETRY:
break;
case IDNNACK_EXIT:
retry = 0;
/*FALLTHROUGH*/
default:
break;
}
if (retry) {
idn_msg_retrytime[(int)IDNRETRY_NEGO]);
} else {
}
}
}
/*ARGSUSED*/
static void
{
int new_masterid, new_cpuid;
int retry = 1;
/*
* nack - retry.
*
* At this stage of receiving a nack we need to
* check whether we need to start over again with
* selecting a new master.
*/
switch (nack) {
case IDNNACK_RETRY:
break;
case IDNNACK_EXIT:
retry = 0;
/*FALLTHROUGH*/
default:
break;
}
if (retry) {
idn_msg_retrytime[(int)IDNRETRY_NEGO]);
} else {
}
}
}
static void
idn_final_nego(int domid)
{
}
/*
*/
/*ARGSUSED1*/
static void
{
} else {
}
IDN_GUNLOCK();
/*
* Reset send cookie to 0 so that receiver does not validate
* cookie. This is necessary since at this early stage it's
* possible we may not have exchanged appropriate cookies.
*/
}
static void
{
int masterid;
int retry_domid = IDN_NIL_DOMID;
int rv;
if (trans_on == 0) {
int d;
/*
* This was the only guy we were trying
* to connect with.
*/
IDN_GUNLOCK();
/*
* If there's a new master available then
* just try and relink with him unless
* it's ourself.
*/
if ((new_masterid != IDN_NIL_DOMID) &&
(new_masterid != domid)) {
new_cpuid, 0);
if (rv < 0) {
"IDN: 205: (%s) failed to "
"open-domain(%d,%d)",
IDN_GUNLOCK();
} else {
}
}
if (relink)
for (d = 0; d < MAX_DOMAINS; d++) {
if (!DOMAIN_IN_SET(relink, d))
continue;
retry_domid = d;
break;
}
/*
* There are other domains we were trying
* to connect to. As long as the chosen
* master was somebody other then this
* domain that nack'd us, life is cool, but
* if it was this remote domain we'll need
* to start over.
*/
IDN_GUNLOCK();
} else if ((new_masterid != IDN_NIL_DOMID) &&
(new_masterid != domid) &&
new_masterid)) {
IDN_GUNLOCK();
new_cpuid, 0);
if (rv < 0) {
"IDN: 205: (%s) failed to "
"open-domain(%d,%d)",
} else {
}
IDN_GUNLOCK();
} else {
IDN_GUNLOCK();
}
} else {
IDN_GUNLOCK();
}
if (retry_domid != IDN_NIL_DOMID) {
idn_msg_retrytime[(int)IDNRETRY_NEGO]);
}
} else {
IDN_GUNLOCK();
}
}
static int
{
if (mtp) {
} else {
acknack = 0;
/*
* For simple CON queries we want a unique
* timer assigned. For others, they
* effectively share one.
*/
if (contype == IDNCON_QUERY)
else
}
PR_PROTO("%s:%d: sending con%sto (cpu %d) [ct=%s, cs=0x%x]\n",
return (0);
}
/*
*/
static int
{
if (msg & IDNP_MSGTYPE_MASK) {
}
if (query_set) {
idn_msg_retrytime[(int)IDNRETRY_CONQ]);
}
return (0);
}
/*
* Must have received an inappropriate error
* message as we should already be registered
* by the time we reach here.
*/
PR_PROTO("%s:%d: ERROR: NOT YET REGISTERED (%s/%s)\n",
if (msg & IDNP_MSGTYPE_MASK) {
}
return (-1);
}
return (0);
}
/*ARGSUSED1*/
static void
{
#ifdef DEBUG
}
#endif /* DEBUG */
PR_PROTO("%s:%d: dxp(%s) != CON...bailing...\n",
return;
}
"expected (%s/%s)\n",
return;
}
}
static int
{
int ready;
return (0);
(msg & IDNP_MSGTYPE_MASK) &&
return (1);
if (msg == 0) {
} else {
}
/*
* No need to query this domain as he's already
* in the CON sequence.
*/
if (ready) {
}
if (query_set) {
int d;
for (d = 0; d < MAX_DOMAINS; d++) {
if (!DOMAIN_IN_SET(query_set, d))
continue;
dp = &idn_domain[d];
IDN_DLOCK_EXCL(d);
!dp->dcookie_send) {
IDN_DUNLOCK(d);
continue;
}
IDN_DUNLOCK(d);
}
}
}
/*ARGSUSED2*/
static void
{
if (msg & IDNP_MSGTYPE_MASK) {
}
idn_msg_retrytime[(int)IDNRETRY_CON]);
}
/*ARGSUSED*/
static void
{
if (!msg) {
} else {
}
}
static void
{
if ((msg & IDNP_ACKNACK_MASK) == 0) {
/*
* con
*/
} else if (msg & IDNP_MSGTYPE_MASK) {
/*
* con+ack
*/
} else {
/*
* nack - retry
*/
idn_msg_retrytime[(int)IDNRETRY_CON]);
}
}
/*ARGSUSED*/
static void
{
/*
* nack - retry
*/
idn_msg_retrytime[(int)IDNRETRY_CON]);
}
}
static void
idn_final_con(int domid)
{
(void) idn_retry_terminate(token);
PR_HITLIST("%s:%d: HITLIST %x -> 0\n",
}
PR_PROTO("%s:%d: ALL CONNECTED ************ "
} else {
PR_PROTO("%s:%d: >>> ds_trans_on = 0x%x, ds_ready_on = 0x%x\n",
}
if (idn_verify_config_mbox(domid)) {
/*
* Mailbox is not cool. Need to disconnect.
*/
/*
* We cannot disconnect from an individual domain
* unless all domains are attempting to disconnect
* from him also, especially now since we touched
* the SMR and now we have a potential cache conflicts
* with the other domains with respect to this
* domain. Disconnect attempt will effectively
* shutdown connection with respective domain
* which is the effect we really want anyway.
*/
return;
}
/*
* This is our first connection. Need to
* kick some stuff into gear.
*/
targ = 0xf0;
} else {
targ = 0;
}
/*
* Need to kick off initial commands in background.
* We do not want to do them within the context of
* a protocol server because they may sleep and thus
* cause the protocol server to incur a soft-deadlock,
* i.e. he's sleeping waiting in the slab-waiting area
* for a response that will arrive on his protojob
* queue, but which he obviously can't process since
* he's not waiting on his protojob queue.
*/
"!IDN: 200: link (domain %d, CPU %d) connected",
}
static void
{
} else {
}
IDN_GUNLOCK();
}
static int
{
int need_timer = 1;
uint_t fintypearg = 0;
if (mtp) {
} else {
acknack = 0;
/*
* For simple FIN queries we want a unique
* timer assigned. For others, they
* effectively share one.
*/
if (fintype == IDNFIN_QUERY)
else
}
PR_PROTO("%s:%d: sending fin%sto (cpu %d) "
"[ft=%s, fa=%s, fs=0x%x, fo=%s, fm=(%d,%d)]\n",
if (need_timer) {
}
return (0);
}
/*
*/
static int
{
PR_PROTO("%s:%d: received NACK (type = %s)\n",
} else {
PR_PROTO("%s:%d: fintype = %s, finopt = %s, "
"finarg = %s, ready_set = 0x%x\n",
}
if (msg & IDNP_MSGTYPE_MASK) {
}
if (query_set) {
idn_msg_retrytime[(int)IDNRETRY_FINQ]);
}
return (0);
}
if (IDNDS_IS_CLOSED(dp)) {
PR_PROTO("%s:%d: domain already closed (%s)\n",
if (msg & IDNP_MSGTYPE_MASK) {
/*
* fin or fin+ack.
*/
}
return (0);
}
/*
* Need to do some clean-up ala idn_disconnect().
*
* Terminate any outstanding commands that were
* targeted towards this domain.
*/
/*
* Terminate any and all retries that may have
* outstanding for this domain.
*/
(void) idn_retry_terminate(token);
/*
* Stop all outstanding message timers for
* this guy.
*/
IDN_MSGTIMER_STOP(domid, 0, 0);
}
if (nack == IDNNACK_NOCONN) {
/*
* We're trying to FIN with somebody we're
* already disconnected from. Need to
* speed this guy through.
*/
/*
* Need to transform message to allow us to
* pass this guy right through and not waste time
* talking to him.
*/
case IDNDS_FIN_PEND:
break;
case IDNDS_FIN_SENT:
break;
case IDNDS_FIN_RCVD:
break;
default:
#ifdef DEBUG
"%s:%d: UNEXPECTED state = %s",
#endif /* DEBUG */
break;
}
}
}
return (0);
}
/*ARGSUSED1*/
static void
{
PR_PROTO("%s:%d: dxp(0x%p) != xstate_fin(0x%p)...bailing\n",
return;
}
PR_PROTO("%s:%d: xstate(%s) != %s...bailing\n",
return;
}
/*LINTED*/
IDN_GUNLOCK();
if (new_masterid != IDN_NIL_DOMID)
}
static int
{
int ready;
int finmasterid;
int fincpuid;
return (0);
(msg & IDNP_MSGTYPE_MASK) &&
return (1);
query_set = 0;
/*
* Can't remove domain from ds_connected yet,
* since he's still officially connected until
* we get an ACK from him.
*/
}
/*
* If we're disconnecting, reconfiguring,
* unlinking from the master, or unlinking
* the last of our connections, then we need
* to shutdown all the channels.
*/
} else {
}
IDN_GUNLOCK();
/*
* Remap the SMR back to our local space if the remote
* domain going down is the master. We do this now before
* flushing caches. This will help guarantee that any
* accidental accesses to the SMR after the cache flush
* will only go to local memory.
*/
PR_PROTO("%s:%d: deconfiging CURRENT MASTER - SMR remap\n",
/*
* We're going to remap the SMR,
* so gotta blow away our local
* pointer to the mbox table.
*/
}
IDN_GUNLOCK();
}
/*
* If for some reason remote domain
* sent us an invalid FIN type,
* override it to a NORMAL fin.
*/
PR_PROTO("%s:%d: WARNING invalid fintype (%d) -> %s(%d)\n",
}
if (!VALID_FINOPT(finopt)) {
PR_PROTO("%s:%d: WARNING invalid finopt (%d) -> %s(%d)\n",
(int)IDNFIN_OPT_UNLINK);
}
if ((finarg != IDNFIN_ARG_NONE) &&
if (IDNFIN_ARG_IS_FATAL(finarg)) {
}
/*
* The primary domain we were trying to
* connect to fin'd us with a fatal argument.
* Something isn't cool in our IDN environment,
* e.g. corrupted SMR or non-compatible CONFIG
* parameters. In any case we need to dismantle
* ourselves completely.
*/
IDN_GUNLOCK();
&idnerr);
PR_HITLIST("%s:%d: unlink_domainset(%x) "
"due to CFG error (relink=%x, "
}
PR_HITLIST("%s:%d: CFG error, (conn=%x, relink=%x, "
"hitlist=%x)\n",
}
}
if ((finmasterid != IDN_NIL_DOMID) &&
(!VALID_DOMAINID(finmasterid) ||
PR_HITLIST("%s:%d: finmasterid = %d -> -1, relink=%x, "
"hitlist=%x\n",
PR_PROTO("%s:%d: WARNING invalid finmasterid (%d) -> -1\n",
}
} else {
}
if ((domid == IDN_GET_NEW_MASTERID()) &&
}
(domid == IDN_GET_MASTERID())) {
IDN_GUNLOCK();
if ((finmasterid != IDN_NIL_DOMID) &&
if (finmasterid != domid)
"IDN: 205: (%s) failed to "
"open-domain(%d,%d)",
if (finmasterid != domid)
}
if (finmasterid != domid)
}
if (finmasterid == IDN_NIL_DOMID) {
int m;
/*
* Local domain gets to participate also.
*/
} else {
}
IDN_GUNLOCK();
} else {
IDN_GUNLOCK();
}
/*
* My local ready-set are those domains from which I
* have confirmed no datapaths exist.
*/
case IDNFIN_NORMAL:
case IDNFIN_FORCE_SOFT:
case IDNFIN_FORCE_HARD:
/*
* Remote domain has requested a
* FIN of lower priority than what
* we're currently running. Just
* leave the priority where it is.
*/
break;
}
/*FALLTHROUGH*/
default:
break;
}
if (msg == 0) {
/*
* Local domain is initiating a FIN sequence
* to remote domid. Note that remote domain
* remains in ds_connected even though he's
* in thet ready-set from the local domain's
* perspective. We can't remove him from
* ds_connected until we get a confirmed message
* from him indicating he has ceased communication.
*/
} else {
/*
* Remote domain initiated a FIN sequence
* to local domain. This implies that he
* has shutdown his datapath to us. Since
* we shutdown our datapath to him, we're
* effectively now in his ready-set.
*/
/*
* Since we know both sides of the connection
* have ceased, this remote domain is effectively
* considered disconnected.
*/
}
/*
* If we're doing a hard disconnect
* of this domain then we want to
* blow straight through and not
* waste time trying to talk to the
* remote domain nor to domains we
* believe are AWOL. Although we will
* try and do it cleanly with
* everybody else.
*/
/*
* If we're not fin'ing this domain
* synchronously then the only
* expected domain set is himself.
*/
}
(void *)IDNP_FIN);
}
/*
* No need to query this domain as he's already
* in the FIN sequence.
*/
if (ready) {
}
if (query_set) {
int d;
for (d = 0; d < MAX_DOMAINS; d++) {
if (!DOMAIN_IN_SET(query_set, d))
continue;
dp = &idn_domain[d];
IDN_DLOCK_EXCL(d);
IDN_DUNLOCK(d);
continue;
}
IDN_DUNLOCK(d);
}
}
}
/*ARGSUSED*/
static void
{
/*
* Don't communicate with domains that
* we're forcing a hard disconnect.
*/
(msg & IDNP_MSGTYPE_MASK)) {
}
idn_msg_retrytime[(int)IDNRETRY_FIN]);
}
static void
{
IDN_GUNLOCK();
if (new_masterid != IDN_NIL_DOMID)
if (!msg) {
} else {
}
} else if (!msg) {
} else if ((msg & IDNP_ACKNACK_MASK) == 0) {
/*
* fin
*/
} else {
/*
* nack - retry
*/
idn_msg_retrytime[(int)IDNRETRY_FIN]);
}
}
static int
{
int ready;
return (0);
/*
* If for some reason remote domain
* sent us an invalid FIN type,
* override it to a NORMAL fin.
*/
}
if (!VALID_FINOPT(finopt)) {
}
} else {
}
IDN_GUNLOCK();
case IDNFIN_NORMAL:
case IDNFIN_FORCE_SOFT:
case IDNFIN_FORCE_HARD:
/*
* Remote domain has requested a
* FIN of lower priority than what
* we're current running. Just
* leave the priority where it is.
*/
break;
}
/*FALLTHROUGH*/
default:
break;
}
/*
* If we're doing a hard disconnect
* of this domain then we want to
* blow straight through and not
* waste time trying to talk to the
* remote domain. By registering him
* as ready with respect to all
* possible domains he'll transition
* immediately. Note that we'll still
* try and do it coherently with
* other domains to which we're connected.
*/
} else {
}
/*
* No need to query this domain as he's already
* in the FIN sequence.
*/
if (ready) {
}
if (query_set) {
int d;
for (d = 0; d < MAX_DOMAINS; d++) {
if (!DOMAIN_IN_SET(query_set, d))
continue;
dp = &idn_domain[d];
IDN_DLOCK_EXCL(d);
IDN_DUNLOCK(d);
continue;
}
IDN_DUNLOCK(d);
}
}
return ((ready > 0) ? 0 : 1);
}
/*ARGSUSED*/
static void
{
/*
* Don't communicate with domains that
* we're forcing a hard disconnect.
*/
(msg & IDNP_MSGTYPE_MASK)) {
}
idn_msg_retrytime[(int)IDNRETRY_FIN]);
}
static void
{
IDN_GUNLOCK();
if (new_masterid != IDN_NIL_DOMID)
if ((msg & IDNP_ACKNACK_MASK) == 0) {
/*
* fin
*/
} else {
}
} else if (msg & IDNP_MSGTYPE_MASK) {
/*
* fin+ack
*/
}
} else {
/*
* nack - retry
*/
idn_msg_retrytime[(int)IDNRETRY_FIN]);
}
}
/*ARGSUSED*/
static void
{
/*
* nack - retry.
*/
idn_msg_retrytime[(int)IDNRETRY_FIN]);
}
}
static void
idn_final_fin(int domid)
{
int do_relink;
(void) idn_retry_terminate(token);
/*
* idn_deconfig will idn_close_domain.
*/
/*
* It's important that this update-op occur within
* the context of holding the glock(EXCL). There is
* still some additional state stuff to cleanup which
* will be completed once the glock is dropped in
* this flow. Which means anybody that's doing a
* SSI_INFO and waiting on glock will not actually
* run until the clean-up is completed, which is what
* we want. Recall that a separate thread processes
* (i.e. are awakened) they will immediately SSI_INFO
* and we don't want them to prematurely pick up stale
* information.
*/
if (domid == IDN_GET_MASTERID()) {
}
}
PR_HITLIST("%s:%d: HITLIST %x -> 0\n",
}
PR_PROTO("%s:%d: ds_connected = 0x%x, ds_trans_off = 0x%x\n",
IDN_GUNLOCK();
goto fin_done;
}
case IDNGS_CONNECT:
}
/*FALLTHROUGH*/
case IDNGS_ONLINE:
break;
case IDNGS_RECONFIG:
}
/*
* Need to do HWINIT since we won't
* be transitioning through OFFLINE
* which would normally be caught in
* idn_check_nego() when we
* initially go to CONNECT.
*/
break;
case IDNGS_DISCONNECT:
case IDNGS_OFFLINE:
"IDN: 211: disconnect domain %d, "
"unexpected Gstate (%s)",
IDN_GUNLOCK();
goto fin_done;
default:
/*
* XXX
* Go into FATAL state?
*/
"IDN: 212: disconnect domain %d, "
"bad Gstate (%d)",
/* not reached */
break;
}
} else {
}
}
}
/*
* If we reach here we've effectively disconnected all
* existing links, however new ones may be pending.
*/
IDN_GUNLOCK();
/*
* If we have no new masterid and yet there are relinkers
* out there, then force us to attempt to link with one
* of them.
*/
if (new_masterid != IDN_NIL_DOMID) {
/*
* If the local domain is the selected
* master then we'll want to initiate
* a link with one of the other candidates.
* If not, then we want to initiate a link
* with the master only.
*/
for (d = 0; d < MAX_DOMAINS; d++) {
int lock_held;
if (!DOMAIN_IN_SET(relinkset, d))
continue;
if (d == domid) {
do_relink = 0;
lock_held = 0;
} else {
IDN_DLOCK_EXCL(d);
lock_held = 1;
}
if (rv == 0) {
rv = idn_connect(d);
if (lock_held)
IDN_DUNLOCK(d);
/*
* If we're able to kick off at
* least one connect then that's
* good enough for now. The others
* will fall into place normally.
*/
if (rv == 0)
break;
} else if (rv < 0) {
if (lock_held)
IDN_DUNLOCK(d);
"IDN: 205: (%s.1) failed to "
"open-domain(%d,%d)",
} else {
if (lock_held)
IDN_DUNLOCK(d);
PR_PROTO("%s:%d: failed to "
"re-open domain %d "
"(cpu %d) [rv = %d]\n",
rv);
}
}
}
if (do_relink) {
if (rv == 0) {
(void) idn_connect(domid);
} else if (rv < 0) {
"IDN: 205: (%s.2) failed to "
"open-domain(%d,%d)",
}
}
}
static void
{
(void) idn_retry_terminate(token);
idn_msg_retrytime[(int)IDNRETRY_FIN]);
}
/*
*/
static int
{
void (*ffunc)(int);
int err = 0;
PR_PROTO("%s:%d: WARNING: domain xsp is NULL (msg = %s, "
"msgarg = %s) <<<<<<<<<<<<\n",
return (-1);
}
PR_PROTO("%s:%d: unwanted acknack received (o_xstate = %s, "
"msg = %s/%s - dropping message\n",
return (0);
}
/*
* Validate that message received is following
* the expected protocol for the current state.
*/
PR_PROTO("%s:%d: WARNING: o_xstate = %s, msg = %s -> NIL "
"<<<<<<<<<\n",
if (xfunc)
return (-1);
}
/*
* Verify that message type is correct for
* the given xstate.
*/
PR_PROTO("%s:%d: WARNING: msg expected %s(0x%x), "
"actual %s(0x%x) [msg=%s(0x%x), "
"msgarg=%s(0x%x)]\n",
if (xfunc)
return (-1);
}
}
if (o_xstate != IDNXS_PEND) {
}
if (xfunc)
return (-1);
}
PR_PROTO("%s:%d: WARNING: n_xstate = %s, msg = %s -> NIL "
"<<<<<<<<<\n",
if (xfunc)
return (-1);
}
}
if (err) {
}
return (0);
}
/*
*/
static int
{
switch (msg) {
case IDNP_CON:
break;
case IDNP_FIN:
break;
default:
PR_PROTO("%s:%d: ERROR: unknown msg (0x%x) <<<<<<<<\n",
return (0);
}
idn_msg_retrytime[(int)IDNRETRY_CON]);
else
idn_msg_retrytime[(int)IDNRETRY_FIN]);
return (1);
}
/*
*/
static void
{
int z;
z = IDN_SYNC_GETZONE(cmd);
ASSERT(z >= 0);
PR_SYNC("%s:%d: cmd=%s(%d), z=%d, xs=0x%x, rx=0x%x, cnt=%d\n",
}
/*
*/
void
{
PR_SYNC("%s:%d: cmd=%s(%d) (z=%d, zone=%d)\n",
#ifdef DEBUG
if (z != -1) {
tot_queries = tot_domains = 0;
for (d = 0; d < MAX_DOMAINS; d++) {
int qv;
tot_queries += qv;
tot_domains++;
PR_SYNC("%s:%d: query_count = %d\n",
}
}
PR_SYNC("%s:%d: tot_queries = %d, tot_domaines = %d\n",
}
#endif /* DEBUG */
if (zp) {
idn_syncop_t **spp;
break;
}
}
}
for (z = 0; z < IDN_SYNC_NUMZONE; z++) {
continue;
continue;
sp->s_transfunc) {
int delok;
PR_SYNC("%s:%d invoking transfunc "
"for domain %d\n",
sp->s_transarg);
if (delok) {
}
}
}
}
}
/*
*/
static domainset_t
{
int z;
PR_SYNC("%s:%d: ERROR: unexpected sync cmd(%d)\n",
return (0);
}
/*
* Find out what domains are in transition with respect
* to given command. There will be no need to query
* these folks.
*/
PR_SYNC("%s:%d: cmd=%s(%d), z=%d, rset=0x%x, "
"regtype=%s(%d), sc_op=%s\n",
if (regtype == IDNSYNC_REG_NEW) {
PR_SYNC("%s:%d: adding new to %d (exp=0x%x)\n",
} else if (regtype == IDNSYNC_REG_QUERY) {
continue;
}
continue;
/*
* Given domid doesn't have a desired
* domain in his ready-set. We'll need
* to query him again.
*/
continue;
}
/*
* If we reach here, then an expected domain
* has marked its respective datapath to
* sp->s_domid as down (i.e. in his ready_set).
*/
PR_SYNC("%s:%d: mark READY for domain %d "
"(r=0x%x, x=0x%x)\n",
#ifdef DEBUG
PR_SYNC("%s:%d: >>>>>>>>>>> DOMAIN %d "
"ALL CHECKED IN (0x%x)\n",
}
#endif /* DEBUG */
int delok;
PR_SYNC("%s:%d invoking transfunc "
"for domain %d\n",
sp->s_transarg);
if (delok) {
}
}
}
}
PR_SYNC("%s:%d: trans_set = 0x%x, query_set = 0x%x -> 0x%x\n",
return (query_set);
}
static void
{
int z;
PR_SYNC("%s:%d: ERROR: unexpected sync cmd(%d)\n",
return;
}
PR_SYNC("%s:%d: cmd=%s(%d), z=%d (domain %d = AWOL)\n",
PR_SYNC("%s:%d: adding new to %d (rdy=0x%x)\n",
}
}
}
static void
idn_link_established(void *arg)
{
int first_link;
masterid = IDN_GET_MASTERID();
if ((masterid == IDN_NIL_DOMID) ||
/*
* No point in doing this unless we're connected
* to the master.
*/
if ((masterid != IDN_NIL_DOMID) &&
/*
* As long as we're still online keep
* trying.
*/
}
IDN_GUNLOCK();
return;
}
IDN_GUNLOCK();
if (first_link && IDN_SLAB_PREALLOC)
/*
* No guarantee, but it might save a little
* time.
*/
/*
* Get the remote domain's dname.
*/
}
/*
* May have had some streams backed up waiting for
* this connection. Prod them.
*/
}
/*
* Send the following chunk of data received from above onto
* the IDN wire. This is raw data as far as the IDN driver
* is concerned.
* Returns:
* IDNXMIT_LOOP - Msg handled in loopback and thus
* still active (i.e. don't free).
* IDNXMIT_OKAY - Data handled (freemsg).
* IDNXMIT_DROP - Packet should be dropped.
* IDNXMIT_RETRY - Packet should be requeued and retried.
* IDNXMIT_REQUEUE - Packet should be requeued, but not
* immediatetly retried.
*/
int
{
int pktcnt = 0;
int msglen;
int rv = IDNXMIT_OKAY;
int xfersize = 0;
int cpuindex;
int serrno;
int channel;
int retry_reclaim;
struct ether_header *ehp;
#ifdef DEBUG
#endif /* DEBUG */
PR_DATA("%s:%d: (netaddr 0x%x) msgsize=%ld, msgdsize=%d\n",
if (msglen < 0) {
/*
* No data to send. That was easy!
*/
PR_DATA("%s:%d: BAD msg length (%d) (netaddr 0x%x)\n",
return (IDNXMIT_DROP);
}
if (dst_domid == IDN_NIL_DOMID) {
"IDN: 213: no destination specified "
"(d=%d, c=%d, n=0x%x)",
rv = IDNXMIT_DROP;
goto nocando;
}
#ifdef DEBUG
{
}
#endif /* DEBUG */
/*
* Get reader lock. We hold for the duration
* of the transfer so that our state doesn't
* change during this activity. Note that since
* we grab the reader lock, we can still permit
* simultaneous tranfers from different threads
* to the same domain.
* Before we waste a bunch of time gathering locks, etc.
* do a an unprotected check to make sure things are
* semi-copesetic. If these values are in flux,
* that's okay.
*/
} else {
rv = IDNXMIT_DROP;
}
goto nocando;
}
/*
* Gotta bail, somethin' s'up.
*/
goto nocando;
}
/*
* We're doing a broadcast. Need to set
* up IDN netaddr's one at a time.
* We set the ethernet destination to the same
* instance as the sending address. The instance
* numbers effectively represent subnets.
*/
&ehp->ether_dhost);
/*
* If this is a broadcast and going to
* the local domain, then we need to make
* a private copy of the message since
* the current one will be reused when
* transmitting to other domains.
*/
PR_DATA("%s:%d: dup broadcast msg for local domain\n",
/*
* Couldn't get a duplicate copy.
*/
rv = IDNXMIT_DROP;
goto nocando;
}
}
}
PR_DATA("%s:%d: dest netid (0x%x) != expected (0x%x)\n",
rv = IDNXMIT_DROP;
goto nocando;
}
int lbrv;
/*
* Sending to our local domain! Loopback.
* Note that idn_send_data_loop returning 0
* does not mean the message can now be freed.
* We need to return (-1) so that caller doesn't
* try to free mblk.
*/
if (lbrv == 0) {
return (IDNXMIT_LOOP);
} else {
return (IDNXMIT_DROP);
}
}
/*
* Can't send data unless a link has already been
* established with the target domain. Normally,
* a user cannot set the remote netaddr unless a
* link has already been established, however it
* is possible the connection may have become
* disconnected since that time.
*/
rv = IDNXMIT_DROP;
goto nocando;
}
/*
* Need to make sure the channel is active and that the
* domain to which we're sending is allowed to receive stuff.
*/
if (!IDN_CHANNEL_IS_SEND_ACTIVE(csp)) {
int not_active;
/*
* See if we can activate channel.
*/
if (!not_active) {
/*
* Only grab the lock for a recheck if we were
* able to activate the channel.
*/
}
/*
* Verify channel still active now that we have the lock.
*/
if (!not_active) {
/*
* Only need to drop the lock if it was
* acquired while we thought we had
* activated the channel.
*/
}
/*
* Damn! Must have went inactive during the window
* before we regrabbed the send lock. Oh well, can't
* spend all day doing this, bail out. Set csp to
* NULL to prevent inprogress update at bottom.
*/
/*
* Channel is not active, should not be used.
*/
PR_DATA("%s:%d: dest channel %d NOT ACTIVE\n",
goto nocando;
}
}
/*
* If we made it here then the channel is active
* Make sure the target domain is registered to receive stuff,
* i.e. we're still linked.
*/
/*
* If domain is not even registered with this channel
* then we have no business being here. Doesn't matter
* whether it's active or not.
*/
PR_DATA("%s:%d: domain not registered with channel %d\n",
/*
* Set csp to NULL to prevent in-progress update below.
*/
rv = IDNXMIT_DROP;
goto nocando;
}
/*
* Find a target cpu to send interrupt to if
* it becomes necessary (i.e. remote channel
* server is idle).
*/
/*
* dcpuindex is atomically incremented, but other than
* that is not well protected and that's okay. The
* intention is to simply spread around the interrupts
* at the destination domain, however we don't have to
* anal about it. If we hit the same cpu multiple times
* in a row that's okay, it will only be for a very short
* period anyway before the cpuindex is incremented
* to the next cpu.
*/
}
#ifdef XXX_DLPI_UNFRIENDLY
{
/*
* XXX
* This is not DLPI friendly, but we need some way
* of distributing our XDC interrupts to the cpus
* on the remote domain in a relatively random fashion
* while trying to remain constant for an individual
* network connection. Don't want the target network
* appl pinging around cpus thrashing the caches.
* So, we'll pick target cpus based on the destination
* this is to simply send all messages destined for
* particular domain to the same cpu (dcpu), but
* will lower our bandwidth and introduce a lot of
* contention on that target cpu.
*/
int hdr_length;
sizeof (struct ether_header);
/*
* Only the ethernet header was contained
* in the first block. Check for the
* next packet.
*/
}
/*
* If we still haven't found the IP header packet
* then don't bother. Can't search forever.
*/
if (nmp &&
switch (ipha->ipha_protocol) {
case IPPROTO_UDP:
case IPPROTO_TCP:
/*
* 0 15,16 31
* -----------------------
* | src port | dst port |
* -----------------------
*/
dstporta += 2;
break;
default:
break;
}
}
}
PR_DATA("%s:%d: (dstport %d) assigned %d\n",
}
#endif /* XXX_DLPI_UNFRIENDLY */
retry_reclaim = 1;
int reclaim_req;
/*
* Reclaim however many outstanding buffers
* there are up to IDN_RECLAIM_MAX if it's set.
*/
}
/*
* We have exceeded the minimum window for
* outstanding I/O buffers to this domain.
* Need to start the MSG timer to check for
* possible response from remote domain.
* The remote domain may be hung. Send a
* wakeup! Specify all channels for given
* domain since we don't know precisely which
* is backed up (dio is global).
*/
}
/*
* Yikes! We have exceeded the maximum window
* which means no more packets going to remote
* domain until he frees some up.
*/
rv = IDNXMIT_DROP;
goto nocando;
}
/*
* Allocate a SMR I/O buffer and send it.
*/
if (msglen == 0) {
/*
* A zero length messages is effectively a signal
* to just send an interrupt to the remote domain.
*/
}
int xrv;
#ifdef DEBUG
int n_xfersize;
#endif /* DEBUG */
if (serrno) {
PR_DATA("%s:%d: failed to alloc SMR I/O buffer "
"(serrno = %d)\n",
/*
* Failure is either due to a timeout waiting
* for the master to give us a slab, OR the
* local domain exhausted its slab quota!
* In either case we'll have to bail from
* here and let higher layers decide what
* to do.
* We also could have had locking problems.
* A negative serrno indicates we lost the lock
* on dst_domid, so no need in dropping lock.
*/
/*
* We were the first to acquire the
* lock indicating that it wasn't
* set on entry to idn_send_data.
* So, let's go back and see if we
* can't reclaim some buffers and
* try again.
* It's very likely diowanted will be
* enough to prevent us from looping
* on retrying here, however to protect
* against the small window where a
* race condition might exist, we use
* the retry_reclaim flag so that we
* don't retry more than once.
*/
retry_reclaim = 0;
goto retry;
}
switch (rv) {
case ENOMEM:
case EBUSY:
case ENOLCK:
case ETIMEDOUT:
case EDQUOT:
/*
* These are all transient conditions
* which should be recoverable over
* time.
*/
break;
default:
rv = IDNXMIT_DROP;
break;
}
goto nocando;
}
/*
* If the alignment of bufoffset took us pass the
* length of a smr_pkthdr_t then we need to possibly
* lower xfersize since it was calulated based on
* a perfect alignment. However, if we're in DLPI
* mode then shouldn't be necessary since the length
* of the incoming packet (mblk) should have already
* taken into consideration this possible adjustment.
*/
#ifdef DEBUG
if (bufoffset != sizeof (smr_pkthdr_t))
PR_DATA("%s:%d: offset ALIGNMENT (%lu -> %u) "
"(data_rptr = %p)\n",
if (xfersize != n_xfersize) {
PR_DATA("%s:%d: xfersize ADJUST (%d -> %d)\n",
"bufsize(%d)-bufoffset(%d) = %d)",
}
#endif /* DEBUG */
if (xrv) {
/*
* Reclaim packet.
* Return error on this packet so it can be retried
* (putbq). Note that it should be safe to assume
* that this for-loop is only executed once when in
* DLPI mode and so no need to worry about fractured
* mblk packet.
*/
PR_DATA("%s:%d: DATA XFER to chan %d FAILED "
"(ret=%d)\n",
PR_DATA("%s:%d: (line %d) dec(dio) -> %d\n",
rv = IDNXMIT_DROP;
goto nocando;
} else {
pktcnt++;
/*
* Packet will get freed on a subsequent send
* when we reclaim buffers that the receivers
* has finished consuming.
*/
}
}
#ifdef DEBUG
if (pktcnt > 1)
"%s: ERROR: sent multi-pkts (%d), len = %ld",
#endif /* DEBUG */
PR_DATA("%s:%d: SENT %d packets (%d @ 0x%x)\n",
return (IDNXMIT_OKAY);
if (csp) {
}
if (rv == IDNXMIT_REQUEUE) {
/*
* Better kick off monitor to check when
* it's ready to reenable the queues for
* this channel.
*/
}
return (rv);
}
/*
* Function to support local loopback testing of IDN driver.
* Primarily geared towards measuring stream-head and IDN driver
* overhead with respect to data messages. Setting idn_strhead_only
* allows routine to focus on stream-head overhead by simply putting
* the message straight to the 'next' queue of the destination
* read-queue. Current implementation puts the message directly to
* the read-queue thus sending the message right back to the IDN driver
* as though the data came in off the wire. No need to worry about
* any IDN layers attempting to ack data as that's normally handled
* by idnh_recv_data.
*
* dst_netaddr = destination port-n-addr on local domain.
* wq = write queue from whence message came.
* mp = the (data-only) message.
*
* Returns 0 Indicates data handled.
* errno EAGAIN indicates data can be retried.
* Other errno's indicate failure to handle.
*/
static int
{
int rv = 0;
PR_DATA("%s: dst_netaddr.net.netid 0x%x != local 0x%x\n",
rv = EADDRNOTAVAIL;
goto done;
}
rv = EDESTADDRREQ;
goto done;
}
rv = 0;
done:
return (rv);
}
/*
* Fill bufp with as much data as possible from the message pointed
* to by mp up to size bytes.
* Save our current read pointer in the variable parameter (data_rptrp)
* so we know where to start on the next go around. Don't want to
* bump the actual b_rptr in the mblk because the mblk may need to
* be reused, e.g. broadcast.
* Return the mblk pointer to the position we had to stop.
*/
static mblk_t *
{
int copysize;
return (NULL);
if (copysize > 0) {
/*
* If there's data to copy, do it.
*/
(*data_rptrp) += copysize;
}
/*
* If we emptied the mblk, then
* move on to the next one.
*/
;
if (mp)
}
}
return (mp);
}
/*
* Messages received here do NOT arrive on a stream, but are
* instead handled via the idn_protocol_servers. This routine
* is effectively the job processor for the protocol servers.
*/
static void
{
int sync_lock = 0;
/*
* Fault injection to simulate non-responsive domain.
*/
return;
}
/*
* msgtype = Is the type of message we received,
* e.g. nego, ack, nego+ack, etc.
*
* acktype = If we received a pure ack or nack
* then this variable is set to the
*/
/*
*/
}
if (!VALID_MSGTYPE(mtype)) {
PR_PROTO("%s:%d: ERROR: invalid message type (0x%x)\n",
return;
}
if (!VALID_CPUID(cpuid)) {
PR_PROTO("%s:%d: ERROR: invalid cpuid (%d)\n",
return;
}
/*
* No pure data packets should reach this level.
* Data+ack messages will reach here, but only
* for the purpose of stopping the timer which
* happens by default when this routine is called.
*/
/*
* We should never receive a request from ourself,
* except for commands in the case of broadcasts!
*/
char str[15];
"IDN: 214: received message (%s[0x%x]) from self "
"(domid %d)",
return;
}
/*
* Set a flag indicating whether we really need
* SYNC-LOCK. We'll drop it in a little bit if
* we really don't need it.
*/
switch (mtype) {
case IDNP_CON:
case IDNP_FIN:
case IDNP_NEGO:
sync_lock = 1;
break;
default:
break;
}
/*
* The only messages we do _not_ check the cookie are:
* nego
* nego+ack
* fin - if received cookie is 0.
* fin+ack - if received cookie is 0.
*/
dp->dcookie_errcnt++;
if (dp->dcookie_err == 0) {
/*
* Set cookie error to prevent a
* possible flood of bogus cookies
* and thus error messages.
*/
"IDN: 215: invalid cookie (0x%x) "
"for message (0x%x) from domain %d",
PR_PROTO("%s:%d: received cookie (0x%x), "
"expected (0x%x) [errcnt = %d]\n",
}
return;
}
}
dp->dcookie_err = 0;
IDN_GUNLOCK();
if (!sync_lock) /* really don't need SYNC-LOCK past here */
/*
* Stop any timers that may have been outstanding for
* this domain, for this particular message type.
* Note that CFG timers are directly managed by
*/
}
/*
* Keep track of the last cpu to send us a message.
* If the domain has not yet been assigned, we'll need
* this cpuid in order to send back a respond.
*/
switch (mtype) {
case IDNP_NEGO:
break;
case IDNP_CFG:
break;
case IDNP_CON:
break;
case IDNP_FIN:
break;
case IDNP_CMD:
break;
case IDNP_DATA:
/*
* When doing the fast track we simply process
* possible nack error conditions. The actual
* processing of the SMR data buffer is taken
* care of in idnh_recv_dataack. When NOT doing
* the fast track, we do all the processing here
* in the protocol server.
*/
break;
default:
/*
* Should be receiving 0 inum and 0 acknack.
*/
#ifdef DEBUG
#else /* DEBUG */
#endif /* DEBUG */
"IDN: 216: (0x%x)msgtype/(0x%x)acktype rcvd from "
break;
}
/*
* All receiving routines are responsible for dropping drwlock.
*/
if (sync_lock)
}
/*
* Once the CONFIG state is hit we immediately blast out all
* of our config info. This guarantees that the CONFIG state
* effectively signifies that the sender has sent _all_ of
* their config info.
*/
static void
{
int rv;
if (phase == 1) {
/*
* Reset stuff in dtmp to 0:
* dcfgphase
* dcksum
* dncfgitems
* dmaxnets
* dmboxpernet
*/
}
if (dp->dcfgsnddone) {
if (!dp->dcfgrcvdone) {
cfg_waittime, NULL);
}
return;
}
PR_PROTO("%s:%d: sending %s config (phase %d)\n",
phase);
else
if (rv >= 0) {
if (rv == 1) {
if (!dp->dcfgrcvdone) {
cfg_waittime, NULL);
}
} else {
cfg_waittime, NULL);
}
}
}
/*
* Clear out the mailbox table.
* NOTE: This routine touches the SMR.
*/
static void
{
int qi;
qi = 0;
do {
} while (qi);
}
static int
{
/*
* Get SMR offset of receive mailbox assigned
* to respective domain. If I'm a slave then
* my dmbox.m_tbl will not have been assigned yet.
* Instead of sending the actual offset I send
* the master his assigned index. Since the
* master knows what offset it will assign to
* me he can determine his assigned (recv) mailbox
* based on the offset and given index. The local
* domain can also use this information once the
* dmbox.m_tbl is received to properly assign the
* correct mbox offset to the master.
*/
/*
* Local domain has not yet been assigned a
* (recv) mailbox table. This must be the
* initial connection of this domain.
*/
} else {
/*
* Need to calculate mailbox table to
* assign to the given domain. Since
* I'm the master his mailbox is in
* the (all-domains) mailbox table.
*/
}
}
return (0);
}
/*
* RETURNS:
* 1 Unexpected/unnecessary phase.
* 0 Successfully handled, timer needed.
*/
static int
{
int rv = 0;
int nmcadr;
register int b, p, m;
m = 0;
cfg_subtype.val = 0;
switch (phase) {
case 1:
&mbox_domain);
/*
* ----------------------------------------------------
* Send: SLABSIZE, DATAMBOX.DOMAIN, DATAMBOX.TABLE
* ----------------------------------------------------
*/
PR_PROTO("%s:%d:%d: sending SLABSIZE (%d), "
"DATAMBOX.DOMAIN (0x%x), DATAMBOX.TABLE (0x%x)\n",
break;
case 2:
/*
* ----------------------------------------------------
* Send: NETID, BARLAR
* ----------------------------------------------------
*/
PR_PROTO("%s:%d:%d: sending NETID (%d), "
break;
case 3:
/*
* ----------------------------------------------------
* Send: CPUSET, NMCADR
* ----------------------------------------------------
*/
PR_PROTO("%s:%d:%d: sending CPUSET (0x%x.%x), NMCADR (%d)\n",
break;
case 4:
/*
* ----------------------------------------------------
* Send: BOARDSET, MTU, BUFSIZE
* ----------------------------------------------------
*/
PR_PROTO("%s:%d:%d: sending BOARDSET (0x%x), MTU (0x%lx), "
break;
case 5:
/*
* ----------------------------------------------------
* Send: MAXNETS, MBOXPERNET, CKSUM
* ----------------------------------------------------
*/
PR_PROTO("%s:%d:%d: sending MAXNETS (%d), "
"MBOXPERNET (%d), CKSUM (%d)\n",
break;
case 6:
/*
* ----------------------------------------------------
* Send: NWRSIZE (piggyback on MCADRs)
* ----------------------------------------------------
*/
mcadr[0] = IDN_NWR_SIZE;
m = 1;
/*FALLTHROUGH*/
default: /* case 7 and above */
/*
* ----------------------------------------------------
* Send: MCADR's
* ----------------------------------------------------
* First need to figure how many we've already sent
* based on what phase of CONFIG we're in.
* ----------------------------------------------------
*/
if (phase > 6) {
for (b = 0; (b < MAX_BOARDS) && (p > 0); b++)
p--;
} else {
b = 0;
}
for (; (b < MAX_BOARDS) && (m < 3); b++) {
continue;
m++;
}
if (m > 0) {
if (phase == 6) {
PR_PROTO("%s:%d:%d: sending NWRSIZE (%d), "
"MCADRs (0x%x, 0x%x)\n",
} else {
PR_PROTO("%s:%d:%d: sending MCADRs "
"(0x%x, 0x%x, 0x%x)\n",
}
} else {
rv = 1;
}
break;
}
return (rv);
}
/*
* RETURNS:
* 1 Unexpected/unnecessary phase.
* 0 Successfully handled.
*/
static int
{
int rv = 0;
int mbox_index;
switch (phase) {
case 1:
/*
* ----------------------------------------------------
* Send: DATAMBOX.DOMAIN or DATAMBOX.INDEX,
* DATASVR.MAXNETS, DATASVR.MBXPERNET
* ----------------------------------------------------
*/
cfg_subtype.val = 0;
if (mbox_index == IDN_NIL_DOMID) {
} else {
/*
* Should only be sending Index to
* the master and not another slave.
*/
}
PR_PROTO("%s:%d:%d: sending DATAMBOX.%s (0x%x), "
"MAXNETS (%d), MBXPERNET (%d)\n",
? "INDEX" : "DOMAIN",
(mbox_index == IDN_NIL_DOMID)
? mbox_domain : mbox_index,
((mbox_index == IDN_NIL_DOMID)
? mbox_domain : mbox_index),
break;
case 2:
/*
* ----------------------------------------------------
* Send: NETID, CPUSET
* ----------------------------------------------------
*/
cfg_subtype.val = 0;
PR_PROTO("%s:%d:%d: sending NETID (%d), "
break;
case 3:
/*
* ----------------------------------------------------
* Send: BOARDSET, MTU, BUFSIZE
* ----------------------------------------------------
*/
cfg_subtype.val = 0;
PR_PROTO("%s:%d:%d: sending BOARDSET (0x%x), MTU (0x%lx), "
"BUFSIZE (0x%x)\n",
break;
case 4:
/*
* ----------------------------------------------------
* Send: SLABSIZE, OPTIONS.CHECKSUM, NWR_SIZE
* ----------------------------------------------------
*/
cfg_subtype.val = 0;
PR_PROTO("%s:%d:%d: sending SLABSIZE (%d), CKSUM (%d), "
"NWRSIZE (%d)\n",
break;
default:
rv = 1;
break;
}
return (rv);
}
#define CFG_ERR_MTU 0x0002
#define CFG_ERR_BUF 0x0004
#define CFG_ERR_SLAB 0x0008
#define CFG_ERR_NWR 0x0010
#define CFG_ERR_NETS 0x0020
#define CFG_ERR_MBOX 0x0040
#define CFG_ERR_NMCADR 0x0080
#define CFG_ERR_MCADR 0x0100
#define CFG_ERR_CKSUM 0x0200
#define CFG_ERR_SMR 0x0400
#define CFG_MAX_ERRORS 16
#define CFGERR2IDNKERR(ce) \
#define CFGERR2FINARG(ce) \
/*
* Called when some CFG messages arrive. We use dncfgitems to count the
* total number of items received so far since we'll receive multiple CFG
* messages during the CONFIG phase. Note that dncfgitems is initialized
* in idn_send_config.
*/
static void
{
int pnum;
int phase;
register int p;
register int c;
int index;
&cfg_arg[2]);
cfg_arg[3] = 0;
/*
* Not ready to receive config info.
* Drop whatever he sent us. Let the
* timer continue and timeout if needed.
*/
PR_PROTO("%s:%d: WARNING state(%s) != CONFIG\n",
return;
}
}
if (msg & IDNP_ACKNACK_MASK) {
/*
*/
PR_PROTO("%s:%d: received ACK for CFG phase %d\n",
/*
* Phase is not what we were
* expecting. Something got lost
* in the shuffle. Restart the
* timer and let it timeout if necessary
* and reestablish the connection.
*/
} else {
xargs);
}
}
}
return;
}
for (p = 0; p < pnum; p++) {
int board;
#ifdef DEBUG
char *str;
val = 0;
#else
#define RCVCFG(s, v) {}
#endif /* DEBUG */
switch (subtype) {
case IDNCFG_BARLAR:
switch (subtype_arg) {
case IDNCFGARG_BARLAR_BAR:
dp->dncfgitems++;
}
break;
case IDNCFGARG_BARLAR_LAR:
dp->dncfgitems++;
}
break;
default:
"IDN 217: unknown CFGARG type (%d) "
"from domain %d",
subtype_arg, domid);
break;
}
IDN_GUNLOCK();
break;
case IDNCFG_MCADR:
board = subtype_arg;
dp->dncfgitems++;
}
break;
case IDNCFG_NMCADR:
dp->dncfgitems++;
}
break;
case IDNCFG_CPUSET:
switch (subtype_arg) {
case IDNCFGARG_CPUSET_UPPER:
{
dp->dncfgitems++;
break;
}
case IDNCFGARG_CPUSET_LOWER:
{
dp->dncfgitems++;
break;
}
default:
ASSERT(0);
break;
}
break;
case IDNCFG_NETID:
dp->dncfgitems++;
}
break;
case IDNCFG_BOARDSET:
/*
* Boardset better include what we
* already know about.
*/
dp->dncfgitems++;
}
break;
case IDNCFG_SIZE:
switch (subtype_arg) {
case IDNCFGARG_SIZE_MTU:
dp->dncfgitems++;
}
break;
case IDNCFGARG_SIZE_BUF:
dp->dncfgitems++;
}
break;
case IDNCFGARG_SIZE_SLAB:
dp->dncfgitems++;
}
break;
case IDNCFGARG_SIZE_NWR:
dp->dncfgitems++;
}
break;
default:
ASSERT(0);
break;
}
break;
case IDNCFG_DATAMBOX:
switch (subtype_arg) {
case IDNCFGARG_DATAMBOX_TABLE:
/*
* Only a master should be
* sending us a datambox table.
*/
break;
}
IDN_OFFSET2ADDR(cfg_arg[p]);
dp->dncfgitems++;
break;
break;
mbtp = (idn_mboxtbl_t *)
IDN_OFFSET2ADDR(cfg_arg[p]);
for (c = 0; c < IDN_MAX_NETS; c++) {
}
if (c <= 0)
break;
dp->dncfgitems++;
break;
case IDNCFGARG_DATAMBOX_INDEX:
/*
* If I'm not the master then
* I can't handle processing a
* mailbox index.
* OR, if I already have the send
* mailbox, I'm done with this
* config item.
*/
break;
}
/*
* The given index is the local domain's
* index into the remote domain's mailbox
* table that contains the mailbox that
* remote domain wants the local domain to
* use as the send mailbox for messages
* destined for the remote domain.
* I.e. from the remote domain's
* perspective, this is his receive
* mailbox.
*/
for (c = 0; c < IDN_MAX_NETS; c++) {
}
if (c <= 0)
break;
dp->dncfgitems++;
break;
default:
ASSERT(0);
break;
}
break;
case IDNCFG_DATASVR:
switch (subtype_arg) {
break;
dp->dncfgitems++;
break;
if (dp->dmboxpernet)
break;
dp->dncfgitems++;
break;
default:
ASSERT(0);
break;
}
break;
case IDNCFG_OPTIONS:
switch (subtype_arg) {
case IDNCFGARG_CHECKSUM:
break;
if ((cfg_arg[p] & 0xff) == 0)
else
dp->dncfgitems++;
break;
default:
ASSERT(0);
break;
}
default:
break;
}
#ifdef DEBUG
PR_PROTO("%s:%d: received %s (0x%x)\n",
#endif /* DEBUG */
}
rv_expected = rv_actual = 0;
/*
* Remote domain is a slave, check if we've received
* all that we were expecting, and if so transition to
* the next state.
*/
} else {
/*
* Remote domain is a master, check if this slave has
* received all that it was expecting, and if so
* transition to the next state.
*/
}
switch (rv) {
case CFG_DONE:
/*
* All config info received that was expected, wrap up.
*/
}
break;
case CFG_CONTINUE:
/*
* If we're not done sending our own config, then
* there's no need to set a timer since one will
* automatically be set when we send a config
* message waiting for an acknowledgement.
*/
if (dp->dcfgsnddone) {
/*
* We haven't yet received all the config
* information we were expecting. Need to
* restart CFG timer if we've sent everything..
*/
}
break;
case CFG_FATAL:
/*
* Fatal error occurred during config exchange.
* We need to shutdown connection in this
* case, so initiate a (non-relink) FIN.
* so let's get the show on the road.
*/
/*
* If the state has changed from CONFIG
* then somebody else has taken over
* control of this domain so we can just
* bail out.
*/
/*
* Keep this guy around so we can try again.
*/
}
break;
default: /* parameter conflict */
/*
* Hmmm...changed in the short period
* we had dropped the lock, oh well.
*/
break;
}
c = 0;
for (p = 0; p < CFG_MAX_ERRORS; p++)
if (rv & (1 << p))
c++;
if (c > 1) {
SET_IDNKERR_PARAM1(&idnerr, c);
} else {
}
/*
* Any parameter conflicts are grounds for dismissal.
*/
/*
* We have no other connections yet.
* We must blow out of here completely
* unless we have relinkers left from
* a RECONFIG.
*/
}
IDN_GUNLOCK();
PR_HITLIST("%s:%d: unlink_domainset(%x) due to "
"CFG error (relink=%x, hitlist=%x)\n",
} else {
PR_HITLIST("%s:%d: idn_disconnect(%d) due to CFG "
"error (conn=%x, relink=%x, hitlist=%x)\n",
/*
* If we have other connections then
* we're only going to blow away this
* single connection.
*/
}
break;
}
}
/*
* Called by master or slave which expects exactly the following
* with respect to config info received from a SLAVE:
* IDNCFG_CPUSET
* IDNCFG_NETID
* IDNCFG_BOARDSET
* IDNCFG_SIZE (MTU, BUF, SLAB, NWR)
* IDNCFG_DATAMBOX (DOMAIN or INDEX if caller is master)
* IDNCFG_DATASVR (MAXNETS, MBXPERNET)
* IDNCFG_OPTIONS (CHECKSUM)
*/
static uint_t
{
PR_PROTO("%s:%d: number received %d, number expected %d\n",
return (CFG_CONTINUE);
(dp->dmboxpernet == 0) ||
/*
* We received our IDN_SLAVE_NCFGITEMS config items,
* but not all what we were expecting! Gotta nack and
* close connection.
*/
"IDN: 218: missing some required config items from "
"domain %d", domid);
goto done;
}
"IDN: 219: remote domain %d MTU (%d) invalid "
rv |= CFG_ERR_MTU;
}
"IDN: 220: remote domain %d BUFSIZE (%d) invalid "
rv |= CFG_ERR_BUF;
}
"IDN: 221: remote domain %d SLABSIZE (%d) invalid "
"(local.slabsize = %d)",
rv |= CFG_ERR_SLAB;
}
"IDN: 223: remote domain %d NWRSIZE (%d) invalid "
"(local.nwrsize = %d)",
rv |= CFG_ERR_NWR;
}
"IDN: 224: remote domain %d MAX_NETS (%d) invalid "
"(local.maxnets = %d)",
rv |= CFG_ERR_NETS;
}
"IDN: 225: remote domain %d MBOX_PER_NET (%d) "
"invalid (local.mboxpernet = %d)",
rv |= CFG_ERR_MBOX;
}
"IDN: 226: remote domain %d CHECKSUM flag (%d) "
"mismatches local domain's (%d)",
rv |= CFG_ERR_CKSUM;
}
done:
}
/*
* Called by slave ONLY which expects exactly the following
* config info from the MASTER:
* IDNCFG_BARLAR
* IDNCFG_MCADR
* IDNCFG_NMCADR
* IDNCFG_CPUSET
* IDNCFG_NETID
* IDNCFG_BOARDSET
* IDNCFG_SIZE (MTU, BUF, SLAB, NWR)
* IDNCFG_DATAMBOX (TABLE, DOMAIN)
* IDNCFG_DATASVR (MAXNETS, MBXPERNET)
* IDNCFG_OPTIONS (CHECKSUM)
*/
static uint_t
{
int nmcadr;
int total_expitems;
int p, m, err;
PR_PROTO("%s:%d: number received %d, minimum number expected %d\n",
return (CFG_CONTINUE);
/*
* We have at least IDN_MASTER_NCFGITEMS items which
* means we have at least one MCADR. Need to make sure
* we have all that we're expecting, NMCADR.
*/
/*
* We have not yet received all the MCADRs
* we're expecting.
*/
PR_PROTO("%s:%d: haven't received all MCADRs yet.\n",
return (CFG_CONTINUE);
}
nmcadr = 0;
for (p = 0; p < MAX_BOARDS; p++)
nmcadr++;
(dp->dmboxpernet == 0) ||
IDN_GUNLOCK();
/*
* We received all of our config items, but not
* all what we were expecting! Gotta reset and
* close connection.
*/
"IDN: 227: missing some required config items from "
"domain %d", domid);
goto done;
}
/*
* The master's SMR region is larger than
* mine! This means that this domain may
* receive I/O buffers which are out of the
* range of this local domain's SMR virtual
* address space. The master SMR has to be
* no larger than the local SMR in order to
* guarantee enough local virtual addresses
* to see all of the SMR space.
* XXX - Possibly add negotiating SMR size.
* Try to create a new virtual mapping.
* Could let domains negotiate SMR size.
* Winning size would have to be smallest
* in DC. If so, how to handle incoming
* domains with even smaller SMRs?
* - Could either disallow connection
* - Could reconfigure to use smaller SMR.
*/
"IDN: 228: master's SMR (%ld) larger than "
"local's SMR (%ld)",
rv |= CFG_ERR_SMR;
}
IDN_GUNLOCK();
"IDN: 219: remote domain %d MTU (%d) invalid "
rv |= CFG_ERR_MTU;
}
"IDN: 220: remote domain %d BUFSIZE (%d) invalid "
rv |= CFG_ERR_BUF;
}
"IDN: 223: remote domain %d NWRSIZE (%d) invalid "
"(local.nwrsize = %d)",
rv |= CFG_ERR_NWR;
}
"IDN: 224: remote domain %d MAX_NETS (%d) invalid "
"(local.maxnets = %d)",
rv |= CFG_ERR_NETS;
}
"IDN: 225: remote domain %d MBOX_PER_NET (%d) "
"invalid (local.mboxpernet = %d)",
rv |= CFG_ERR_MBOX;
}
"IDN: 226: remote domain %d CHECKSUM flag (%d) "
"mismatches local domain's (%d)",
rv |= CFG_ERR_CKSUM;
}
nmcadr = 0;
err = 0;
for (m = 0; m < MAX_BOARDS; m++) {
"IDN: 229: remote domain %d boardset (0x%x) "
"conflicts with MCADR(board %d) [0x%x]",
err++;
}
nmcadr++;
}
if (err) {
*exp = 0;
rv |= CFG_ERR_MCADR;
"IDN: 230: remote domain %d reported number of "
"MCADRs (%d) mismatches received (%d)",
rv |= CFG_ERR_NMCADR;
}
done:
}
static int
{
register int p, i;
register idn_domain_t *dp;
/*
* Well, we received all that we were expecting
* so stop any CFG timers we had going.
*/
for (p = 0; p < NCPU; p++)
for (p = 0; p < MAX_BOARDS; p++)
/*
* Verify dcpuset and dhw.dh_boardset don't
* conflict with any existing DC member.
*/
if (b_conflicts) {
"IDN: 231: domain %d boardset "
"(0x%x) conflicts with existing "
"IDN boardset (0x%x)",
}
if (!CPUSET_ISNULL(p_conflicts)) {
"IDN: 232: domain %d cpuset "
"(0x%x.%0x) conflicts with existing "
"IDN cpuset (0x%x.%0x)", domid,
}
IDN_GUNLOCK();
/*
* Need to disconnect and not retry with this guy.
*/
return (-1);
}
#ifdef IDNBUG_CPUPERBOARD
/*
* We only allow connections to domains whose (mem) boards
* all have at least one cpu. This is necessary so that
* we can program the CICs of that respective board. This
* is primarily only a requirement if the remote domain
* is the master _and_ has the SMR in that particular board.
* To simplify the checking we simply restrict connections to
* domains that have at least one cpu on all boards that
* contain memory.
*/
"IDN: 233: domain %d missing CPU per "
"memory boardset (0x%x), CPU boardset (0x%x)",
IDN_GUNLOCK();
/*
* Need to disconnect and not retry with this guy.
*/
return (-1);
}
#endif /* IDNBUG_CPUPERBOARD */
IDN_GUNLOCK();
/*
* Set up the portmap for this domain.
*/
i = -1;
for (p = 0; p < NCPU; p++) {
}
/*
* Got everything we need from the remote
* domain, now we can program hardware as needed.
*/
if (idn_program_hardware(domid) != 0) {
/*
* Yikes! Failed to program hardware.
* Gotta bail.
*/
"IDN: 234: failed to program hardware for domain %d "
"(boardset = 0x%x)",
/*
* If we're having problems programming our
* hardware we better unlink completely from
* the IDN before things get really bad.
*/
IDN_GUNLOCK();
return (-1);
}
/*
* Now that hardware has been programmed we can
* remap the SMR into our local space, if necessary.
*/
if (domid == IDN_GET_MASTERID()) {
/*
* No need to worry about disabling the data
* server since at this stage there is only
* one and he doesn't go active until his
* mailbox (dmbox.m_recv->mm_smr_mboxp) is set up.
*/
}
IDN_GUNLOCK();
/*
* There is no need to ACK the CFG messages since remote
* domain would not progress to the next state (CON_SENT)
* unless he has received everything.
*/
if (dp->dcfgsnddone) {
/*
* Well, we've received all that we were expecting,
* but we don't know if the remote domain has
* received all that it was expecting from us,
* although we know we transferred everything
* so let's get the show on the road.
*/
/*
* If the state has changed from CONFIG
* then somebody else has taken over
* control of this domain so we can just
* bail out.
*/
}
}
return (0);
}
static int
{
int c, rv = 0;
/*
* The master will have assigned us the dmbox.m_tbl
* from which we assign our receive mailboxes.
* The first (0) entry contains the cookie used
* for verification.
*/
/*
* Now that we have an assigned mboxtbl from the
* master, we can determine which receive mailbox
* we indirectly assigned to him at the time we
* sent him his MBOX_INDEX. Prep it, however note
* that the master will have not been able to
* validate it because of the chicken 'n egg
* problem between a master and slave. Thus we
* need to reset the cookie after the prep.
*/
for (c = 0; c < IDN_MAX_NETS; c++) {
"IDN: 235: [recv] mailbox (domain %d, "
"channel %d) SMR CORRUPTED - RELINK",
domid, c);
"IDN: 235: [recv] expected (cookie 0x%x, "
"cksum 0x%x) actual (cookie 0x%x, "
"cksum 0x%x)\n",
IDN_MAKE_MBOXHDR_COOKIE(0, 0, c),
(int)mbox_csum);
rv = -1;
break;
}
/*
* Verify pointers are valid.
*/
"IDN: 235: [recv] mailbox (domain %d, "
"channel %d) SMR CORRUPTED - RELINK",
domid, c);
"IDN: 235: [recv] activeptr (0x%x), "
"readyptr (0x%x)\n",
rv = -1;
break;
}
mmp[c].mm_smr_activep =
mmp[c].mm_smr_readyp =
}
if (rv)
return (rv);
/*
* Now we need to translate SMR offsets for send mailboxes
* to actual virtual addresses.
*/
for (c = 0; c < IDN_MAX_NETS; mmp++, c++) {
rv = -1;
break;
}
"IDN: 235: [send] mailbox (domain %d, "
"channel %d) SMR CORRUPTED - RELINK",
domid, c);
"IDN: 235: [send] expected (cookie 0x%x, "
"cksum 0x%x) actual (cookie 0x%x, "
"cksum 0x%x)\n",
IDN_MAKE_MBOXHDR_COOKIE(0, 0, c),
(int)mbox_csum);
rv = -1;
break;
}
/*
* Paranoid check.
*/
"IDN: 235: [send] mailbox (domain %d, "
"channel %d) SMR CORRUPTED - RELINK",
domid, c);
"IDN: 235: [send] activeptr (0x%x), "
"readyptr (0x%x)\n",
rv = -1;
break;
}
}
return (rv);
}
/*
* The BUFSIZEs between domains have to be equal so that slave buffers
* and the master's slabpool are consistent.
* The MTUs between domains have to be equal so they can transfer
* packets consistently without possible data truncation.
*
* ZZZ - Perhaps these could be negotiated?
*/
static int
{
}
static int
{
}
static int
valid_slabsize(int slabsize)
{
}
static int
valid_nwrsize(int nwrsize)
{
}
static int
{
IDN_GUNLOCK();
return (0);
}
if (domid != IDN_GET_MASTERID()) {
/*
* If the remote domain is a slave, then
* all we have to program is the CIC sm_mask.
*/
is_master = 0;
/*
* This is our first HW link and I'm the
* master, which means we need to program
*/
} else {
/*
* Otherwise, just a slave linking to
* necessary.
*/
}
} else {
/*
* If the remote domain is a master, then
* and PC's.
*/
is_master = 1;
}
PR_PROTO("%s:%d: ADD bset (0x%x)\n",
if (rv == 0) {
} else {
}
IDN_GUNLOCK();
return (rv);
}
static int
{
/*
* Need to take into consideration what boards remote
* domain was connected to. If we don't have a connection to
* them ourself, then we better remove them now , otherwise
* they'll never be removed (unless we link to them at some point).
*/
#if 0
DEBUG_USECDELAY(500000);
#endif /* 0 */
IDN_GUNLOCK();
return (0);
}
/*
* It's possible to come through this flow for domains that
* have not been programmed, i.e. not in idn.hwlinked_domset,
* so don't bother asserting that they might be in there.
* sequence. If this occurs we won't know whether the remote
* domain has programmed its hardware or not. If it has then
* it will have to go through the DMAP sequence and thus we
* have to go through it also. So, if we reach at least the
* CONFIG state, we need to go through the DMAP handshake.
*/
PR_PROTO("%s:%d: SUB bset (0x%x)\n",
is_master = 1;
} else {
is_master = 0;
}
if (rv == 0)
IDN_GUNLOCK();
return (rv);
}
/*
* Remember can't send slabs back to master at this point.
* Entered with write-drwlock held.
* Returns with drwlock dropped.
*/
static void
idn_deconfig(int domid)
{
smr_slab_t *sp;
int c, masterid;
PR_PROTO("%s:%d: (dio=%d, dioerr=%d, dnslabs=%d)\n",
masterid = IDN_GET_MASTERID();
for (c = 0; c < NCPU; c++) {
}
}
IDN_GUNLOCK();
(void) smr_buf_free_all(domid);
/*
* Since I'm the master there may
* have been slabs in this domain's
* idn_domain[] entry.
*/
PR_PROTO("%s:%d: freeing up %d dead slabs\n",
}
/*
* We're shutting down the master!
* We need to blow away our local slab
* data structures.
* Since I'm not the master, there should
* be no slab structures in the given
* domain's idn_domain[] entry. They should
* only exist in the local domain's entry.
*/
#ifdef DEBUG
{
int nbusy = 0;
if (!smr_slab_busy(sp))
continue;
nbusy++;
}
if (nbusy)
PR_PROTO("%s:%d: found %d busy slabs "
"(dommask = 0x%x)\n",
}
#endif /* DEBUG */
PR_PROTO("%s:%d: freeing up %d local slab "
}
}
PR_PROTO("%s:%d: reset dio (%d) to 0\n",
}
PR_PROTO("%s:%d: reset diocheck (%x) to 0\n",
/*
* Should have already flush our memory before
* reaching this stage. The issue is that by the
* time we reach here the remote domains may have
* already reprogrammed their hardware and so flushing
* if we have data that needs to go back to one
* of the remote domains that has already reprogrammed
* its hardware.
*/
(void) idn_deprogram_hardware(domid);
/*
* XXX - what to do if we
* fail to program hardware
* probably should panic since
* demise of system may be near?
* Sufficient to just shutdown network?
*/
}
/*
* If we're sending a Reset we better make sure we don't have any
* references or traffic headed in the direction of this guy, since
* when he receives the reset, he'll start shutting down which means
* we effectively have to shutdown _before_ sending the reset.
* DO NOT HOLD ANY DOMAIN RWLOCKS ON ENTRY. Could result in deadlock
* due to channel server looping back through STREAMs and attempting
* to acquire domain lock, i.e. channel server will never "stop".
*/
static void
{
int do_allchan;
register int d;
if (do_allchan) {
/*
* Need to stop all outgoing and
* incoming SMR references.
*/
}
/*
* If force is set then we don't want to reference
* the SMR at all, so deactivate the domains from
* channels first. This will result in the mainmbox-flush
* routines to just clean up without referencing the
* SMR space.
*/
if (force)
/*
* Flush out mailboxes (clear smr reference).
*/
for (d = 0; d < MAX_DOMAINS; d++) {
if (!DOMAIN_IN_SET(domset, d))
continue;
dp = &idn_domain[d];
continue;
IDN_MBOX_LOCK(d);
IDN_MBOX_UNLOCK(d);
}
/*
* Deactivate all domain references also.
* Only necessary if it wasn't already done above.
*/
if (!force)
}
void
{
PR_PROTO("%s:%d: sending command %s\n",
}
void
{
/*
* It's possible local domain received a command
* from itself. However, we cannot send a normal
* "ack" response (XDC) to ourself.
*/
return;
}
}
static void
{
return;
}
void
{
PR_PROTO("%s: broadcasting command (%s) to domainset 0x%x\n",
domset);
IDN_GUNLOCK();
/*
* This is a broadcast which means local domain needs
* to process it also. Since we can't XDC to ourselves
* we simply call a local function.
*/
}
/*
* Since xargs[0] contains the cmdtype, only xargs[1], xargs[2], xargs[3]
* are valid possible response arguments.
*/
static void
{
register idn_domain_t *dp;
int islocal;
PR_PROTO("%s:%d: (local=%d) acknack=0x%x, cmdtype=%s(%d), "
"a1=0x%x, a2=0x%x, a3=0x%x\n",
unsup_cmd_sent = unsup_cmd_recvd = 0;
if ((IDN_GET_MASTERID() == IDN_NIL_DOMID) ||
/*
* Commands cannot be handled without a valid
* master. If this is a request then nack him.
*/
PR_PROTO("%s:%d: cannot process CMD w/o master (%d, %s)\n",
IDN_GUNLOCK();
return;
}
IDN_GUNLOCK();
if (acknack & IDNP_ACKNACK_MASK) {
/*
* Receiving a cmd+ack or cmd+nack in response to some
* earlier command we must have issued.
* If the response is a nack, there are two possibilites:
*
* 1. Remote domain failed to allocate due
* to limited resources.
*
* 2. Remote domain does not support this
* particular command.
*
* In the case of #2, the argument immediately after
* the cmdtype (xargs[1]) will be (-1).
*/
if (islocal) {
/*
*/
}
switch (cmdtype) {
case IDNCMD_SLABALLOC:
cmdarg3);
break;
case IDNCMD_SLABFREE:
cmdarg3);
break;
case IDNCMD_SLABREAP:
/*
* We only care if successful.
*/
cmdarg3);
break;
case IDNCMD_NODENAME:
cmdarg3);
break;
}
switch (nack) {
case IDNNACK_NOCONN:
case IDNNACK_RETRY:
/*
* Remote domain was not quite
* ready, try again.
*/
PR_PROTO("%s:%d: remote not ready "
"for %s - retrying "
"[dstate=%s]\n",
(void) timeout(idn_retry_nodename_req,
default:
break;
}
break;
default:
/*
* Unsupported command.
*/
break;
}
if (unsup_cmd_sent) {
PR_PROTO("%s:%d: unsupported command "
"requested (0x%x)\n",
}
if (unsup_cmd_recvd) {
PR_PROTO("%s:%d: unsupported command "
"response (0x%x)\n",
}
} else {
/*
* Receiving a regular cmd from a remote domain.
*/
switch (cmdtype) {
case IDNCMD_SLABALLOC:
break;
case IDNCMD_SLABFREE:
break;
case IDNCMD_SLABREAP:
break;
case IDNCMD_NODENAME:
break;
default:
/*
* Unsupported command.
*/
break;
}
if (!islocal && unsup_cmd_recvd) {
/*
* Received an unsupported IDN command.
*/
}
}
}
/*
* This is a supporting routine for idn_broadcast_cmd() to
* handle processing of the requested command for the local
* domain. Currently the only support broadcast command
* supported is reaping.
*/
/*ARGSUSED2*/
static void
{
PR_PROTO("%s: submitting local command %s on domain %d\n",
}
/*
* Terminate any outstanding commands that may have
* been targeted for the given domain. A command is
* designated as outstanding if it has an active timer.
*
* serrno = ECANCELED.
*/
static void
{
/*
* At this point the timers are effectively terminated
* since when they're t_onq indication is set false.
*/
PR_PROTO("%s:%d: no outstanding cmds found\n",
/*
* There is a window where we may have caught a
* request just prior to issuing the actual
* command (SLABALLOC). We're guaranteed if there
* was, then he will have at least registered.
* So, if we abort the command now, he'll catch
* it before going to sleep.
* Drop through.
*/
}
PR_PROTO("%s:%d: found outstanding cmd: %s\n",
case IDNCMD_SLABALLOC:
/*
* Outstanding slaballoc request may have
* slab waiters hanging around. Need to
* tell them to bail out. The given domain
* must be the master if we have an outstanding
* command to him. This also presumes that
* if there are any waiters they're only in
* the local domain's waiting area (i.e. we're
* a slave).
*/
#ifdef DEBUG
IDN_GUNLOCK();
#endif /* DEBUG */
break;
case IDNCMD_SLABFREE:
case IDNCMD_SLABREAP:
case IDNCMD_NODENAME:
/*
* Nothing really waiting for these operations
* so no biggy if we just drop.
* Note that NODENAME may have an outstanding
* buffer, however that will be reclaimed
* when we actually unlink from domain.
*/
break;
default:
ASSERT(0);
break;
}
}
/*
* As mentioned before the timers are effectively no-op'd
* once they're dequeued, however let's cleanup house and
* get rid of the useless entries in the timeout queue.
*/
if (tplist) {
}
/*
* I'm the master so it's possible I had
* outstanding commands (SLABALLOC) waiting
* to be satisfied for the given domain.
* Since we're forcing an error it's okay
* to continue holding onto the drwlock.
*/
PR_PROTO("%s:%d: abort (local domain) slaballoc waiters\n",
}
}
static void
{
#ifdef DEBUG
{
PR_PROTO("%s:%d: dstate=%s, msg=(%s/%s), "
"a1=0x%x, a2=0x%x, a3=0x%x, a4 = 0x%x\n",
} else {
PR_PROTO("%s:%d: dstate=%s, msg=(%s/%s), "
"nack=%s(0x%x)\n",
}
}
#endif /* DEBUG */
}
/*ARGSUSED0*/
static void
idn_prealloc_slab(int nslabs)
{
register int s, serrno;
smr_slab_t *sp;
/*
* Not in the proper state or slab already allocated.
*/
IDN_GUNLOCK();
return;
}
IDN_GUNLOCK();
serrno = 0;
/*
* Returns with ldp->drwlock dropped.
*/
if (serrno != 0) {
PR_PROTO("%s: FAILED to pre-alloc'd "
break;
}
/*
* State may have changed since smr_slab_alloc
* temporarily drops drwlock. Make sure we're
* still connected.
*/
break;
}
}
}
/*
* Received a request from a remote domain to
* allocate a slab from the master SMR for him.
* Allocate slab and return the response.
*/
static void
{
register idn_domain_t *dp;
PR_PROTO("%s: slaballoc req from domain %d (size=0x%x)\n",
IDN_GUNLOCK();
/*
* It's a fatal error if the remote domain thinks
* we're the master.
*/
IDN_GUNLOCK();
/*
* It's a fatal error if we don't yet have a
* connection established with the requestor.
*/
} else {
int serrno;
smr_slab_t *sp;
IDN_GUNLOCK();
/*
* We're connected and we're the master.
* smr_slab_alloc() returns with dp->drwlock dropped.
*/
/*
* Successfully allocated slab for remote slave.
*/
} else {
slab_offset = slab_size = 0;
}
/*
* The drwlock is dropped during smr_slab_alloc.
* During that time our connection with the given
* domain may have changed. Better check again.
*/
/*
* Connection broke. Keep the slab here.
*/
slab_offset = slab_size = 0;
}
/*
* Send response.
* Note that smr_slab_alloc automatically installs
* slab into domains respective idn_domain entry
* to be associated with that domain.
*/
}
}
static void
{
PR_PROTO("%s: slaballoc resp to domain %d (off=0x%x, size=0x%x) "
"[serrno = %d]\n",
}
/*
* Received the ack or nack to a previous allocation request
* made by the local domain to the master for a slab. Need
* to "put" the response into the waiting area for any
* waiters.
*/
static void
{
int rv;
PR_PROTO("%s: slaballoc resp from domain %d (off=0x%x, size=0x%x) "
"[serrno = %d]\n",
if (!serrno) {
if (domid != IDN_GET_MASTERID()) {
/*
* We should only be receiving responses from
* our master. This is either a bogus message
* or an old response. In either case dump it.
*/
PR_PROTO("%s: BOGUS slaballoc resp from domid %d "
"(master = %d)\n",
}
IDN_GUNLOCK();
if (!serrno &&
PR_PROTO("%s: slab offset (0x%x) out of range "
"(0-0x%lx)\n",
} else if (!serrno) {
}
}
/*
* Always "put" slabs back to yourself since you're a slave.
* Note that we set the forceflag so that even if there are
* no waiters we still install the slab for the domain.
*/
if (!serrno) {
}
if (!serrno) {
}
if (rv < 0) {
/*
* Some kind of error trying to install response.
* If there was a valid slab sent to us, we'll
* just have to send it back.
*/
PR_PROTO("%s: failed to install response in waiting area\n",
proc);
if (slab_size != 0) {
PR_PROTO("%s: sending slab back to domain %d "
"(master = %d)\n",
slab_offset, slab_size, 0);
}
if (sp) {
}
}
}
/*
* Note that slab reaping is effectively performed asynchronously
* since the request will be received a protocol server.
*/
static void
{
if (domid != IDN_GET_MASTERID()) {
/*
* Only the master can request that slabs be reaped.
*/
IDN_GUNLOCK();
return;
}
IDN_GUNLOCK();
if (nslabs != 0) {
}
/*
* Go ahead and send the reap response back before we start
* free'ing off the individual slabs.
*/
}
static void
{
PR_PROTO("%s: unexpected slabreap resp received "
ASSERT(0);
return;
}
PR_PROTO("%s: recvd reap response from domain %d for %d slabs "
}
/*
* Not really necessary to send slabreap response.
* XXX - perhaps useful to master for accounting or
* throttling of further reaping?
*/
static void
{
}
/*
* Slave -> Master ONLY
* Master never sends slabfree request to itself.
*/
static void
{
smr_slab_t *sp;
int serrno;
if (domid == IDN_GET_MASTERID()) {
PR_PROTO("%s: unexpected slabfree req received (domid = %d)\n",
return;
}
if (slab_size > IDN_SLAB_SIZE) {
PR_PROTO("%s: unexpected slab size. exp %d, recvd %d\n",
return;
}
/*
* Master has received a SLABFREE request (effectively a response
* to some earlier SLABREAP request.
* Find the slab associated with this slab and free it up.
*/
serrno = 0;
} else {
}
}
/*
* Master -> Slave ONLY
*/
static void
{
if (domid != IDN_GET_MASTERID()) {
PR_PROTO("%s: unexpected slabfree resp received (domid = %d)\n",
ASSERT(0);
return;
}
if (slab_size > IDN_SLAB_SIZE) {
PR_PROTO("%s: unexpected slab size. exp %d, recvd %d\n",
ASSERT(0);
return;
}
PR_PROTO("%s: recvd free resp from dom %d "
}
static void
{
}
static void
idn_retry_nodename_req(void *arg)
{
}
static void
{
int serrno;
/*
* Need to drop domain lock across
* SMR allocation.
*/
/*
* Lost connection.
*/
PR_PROTO("%s:%d: connection lost [dstate = %s]\n",
if (!serrno)
return;
}
if (serrno) {
/*
* Failed to allocate buffer, but still have
* connection so keep trying. We may have queried
* the master a little too earlier.
*/
PR_PROTO("%s:%d: buffer alloc failed [dstate = %s]\n",
hz);
return;
}
}
static void
{
}
static void
{
int length;
/*
* Local domain's nodename hasn't been
* set yet.
*/
return;
}
}
PR_PROTO("%s:%d: invalid SMR offset received (0x%x)\n",
return;
}
PR_PROTO("%s:%d: buffer not big enough (req %lu, got %d)\n",
return;
}
}
static void
{
PR_PROTO("%s:%d: invalid SMR offset received (0x%x)\n",
return;
}
if (serrno == 0) {
PR_PROTO("%s:%d: received nodename(%s)\n",
}
}
}
/*
* The master allocations the SMR management structures.
*/
static int
{
size_t reserved_size = 0;
return (0);
}
PR_PROTO("%s: initializing master data (domid = %d)\n",
/*
* Reserve an area of the SMR for mailbox usage.
* This area is allocated to other domains via
* the master. Round it up to IDN_SMR_BUFSIZE multiple.
*/
PR_PROTO("%s: reserving %lu bytes for mailbox area\n",
#ifdef DEBUG
PR_PROTO("%s: WARNING mbox area (%ld) > slab size (%d)\n",
}
#endif /* DEBUG */
/*
* Initialize the pool of slabs and SMR I/O buffers.
*/
return (-1);
}
/*
* Initialize the SMR pointers in the entire
* mailbox table.
*/
return (0);
}
static void
{
smr_slab_t *sp;
return;
}
PR_PROTO("%s: deinitializing master data (domid = %d)\n",
/*
* Master may still be holding onto slabs of his own.
*/
if (sp)
}
static int
{
}
else
awol = 0;
}
void
idn_clear_awol(int domid)
{
}
}
}
/*
* A timer expired.
*/
void
idn_timer_expired(void *arg)
{
char *op = "UNKNOWN";
PR_TIMER("%s: timer CAUGHT TERMINATION (type = %s)\n",
/*
* Timer was dequeued. Somebody is trying
* to shut it down.
*/
return;
}
#ifdef DEBUG
PR_TIMER("%s:%d: [%s] timer EXPIRED (C=0x%x, P=0x%llx, X=0x%llx)\n",
#endif /* DEBUG */
/*
* IMPORTANT:
* Each case is responsible for dropping SYNC_LOCK & DLOCK.
*/
case IDNP_DATA:
/*
* Timed out waiting for a data packet response.
* We can't close domain since he may just be
* temporarily AWOL.
* Note that dio and diocheck do not get cleared.
* This is taken care of when the domain restarts
* or is fatally closed.
* We only need a reader lock for this.
*/
/*
* Restart timer for another
* go around.
*/
} else {
}
}
break;
case IDNP_NEGO:
/*
* If we're not in a NEGO transition, then
* just ignore this timeout.
*/
op = "CONNECT";
IDN_GUNLOCK();
idn_msg_retrytime[(int)IDNRETRY_NEGO]);
}
break;
case IDNP_CMD:
/*
* Timeouts on commands typically mean that the
* the master is not responding. Furthermore, we
* can't FORCE a FIN disconnect since at this stage
* we are CONNECTED and thus other domains may
* have cache entries that we're sharing with them.
* Only choice is to completely disconnect from
* IDN and try to reestablish connection.
*
* However, timeouts attempting to get nodename
* are not fatal. Although we don't want to retry
* either since each timeout is a lost buffer to
* the remote domain.
*/
PR_PROTO("%s:%d: timedout waiting for nodename\n",
break;
}
int masterid = IDN_GET_MASTERID();
PR_PROTO("%s:%d: RECONFIG trying old masterid = %d\n",
IDN_GUNLOCK();
} else {
IDN_GUNLOCK();
}
break;
case IDNP_CON:
/*
* Timed out sending a CON-query. This is
* non-fatal. We simply need to retry.
*/
op = "CONNECT";
IDN_GUNLOCK();
idn_msg_retrytime[(int)IDNRETRY_CONQ]);
break;
}
/*FALLTHROUGH*/
case IDNP_CFG:
/*
* Any timeouts here we simply try to disconnect
* and reestablish the link. Since we haven't
* reached the connected state w.r.t. this domain
* we put his fin state to FORCE-HARD in order
* to shoot right through without involving other
* domains. Recall that other domains may have
* established connections with the given domain
* which means any FIN queries to them will always
* return connected to the given domain. Since
* neither the given domain nor the local domain
* plan on disconnecting from the IDN the connection
* to the other domains will remain thereby preventing
* the local FIN from ever completing. Recall that
* a FIN depends on all member domains FIN'ing also.
*/
op = "CONNECT";
IDN_GUNLOCK();
break;
case IDNP_FIN:
/*
* Timeouts here simply try to retry.
*/
op = "DISCONNECT";
IDN_GUNLOCK();
int d;
/*
* Timed out sending a FIN-query. This is
* non-fatal. We simply need to retry.
* If we were doing a forced unlink of any
* domains, we don't want this awol guy
* to hold us up. Looks for any forced
* unlinks and make them "ready" with
* respect to this awol domain.
*/
rdyset = 0;
for (d = 0; d < MAX_DOMAINS; d++) {
DOMAINSET_ADD(rdyset, d);
}
}
if (rdyset)
(void) idn_sync_register(domid,
idn_msg_retrytime[(int)IDNRETRY_FINQ]);
break;
}
}
/*
* Anybody that was waiting on this domain and
* had a hard-force in action gets this guy for
* free in their base ready-set.
*/
idn_msg_retrytime[(int)IDNRETRY_FIN]);
break;
default:
ASSERT(0);
break;
}
if (awol) {
"IDN: 236: domain (%s) [ID %d] not "
"responding to %s [#%d]",
} else {
"IDN: 236: domain [ID %d, CPU %d] not "
"responding to %s [#%d]",
}
}
}
#if 0
static int
{
int i, count = 0;
((key == IDN_RETRY_TYPEALL) ||
count++;
return (count);
}
#endif /* 0 */
static void
idn_retry_execute(void *arg)
{
/*
* Job has already been claimed by
* retry termination routine.
* Bail out.
*/
return;
}
}
/*
*
*/
static void
{
int c;
if (ticks < 0) {
PR_PROTO("%s: (token = 0x%x) WARNING ticks = %ld\n",
return;
}
if (ticks == 0) /* At least one tick to get into background */
ticks++;
PR_PROTO("%s: token = (%d,0x%x) already present\n",
break;
}
}
return;
}
rp = IDNRETRY_ALLOCJOB();
} else {
}
}
int
{
int i, domid;
((key == IDN_RETRY_TYPEALL) ||
/*
* Turn off onq field as a signal to
* the execution routine that this
* retry has been terminated. This
* is necessary since we can't untimeout
* while holding the rq_mutex otherwise
* we'll deadlock with the execution
* routine. We'll untimeout these guys
* _after_ we drop rq_mutex.
*/
count++;
}
}
PR_PROTO("%s: token = (%d,0x%x), dequeued = %d\n",
}
return (count);
}
/*
* -----------------------------------------------------------------------
* The sole purpose of the idn_protocol_server is to manage the IDN
* protocols between the various domains. These messages do _not_ go
* through the regular streams queues since they are not dependent on
* any user process or module necessarily having the IDN driver open.
* There may be multiple instances of these servers to enhance performance
* of domain management. Each server is assigned a idn_protoqueue_t
* from which to obtain the work they need to do.
* -----------------------------------------------------------------------
*/
int
{
int i;
register idn_protoqueue_t *protoq;
if (nservers <= 0) {
"IDN: 237: invalid number (%d) of protocol servers",
nservers);
return (-1);
}
sizeof (idn_protojob_t),
"IDN: 238: kmem_cache_create(jobcache) failed");
return (-1);
}
/*
* Initialize static cache for protojob.
*/
jp = &idn_protojob_cache[0];
}
/*
* Init morgue semaphore.
*/
/*
* Alloc server queues.
*/
/*
* Init server queues.
*/
/*
* Create protocol server thread.
*/
}
/*
* The servers are kept in the p_server[] array, however
* we'll build a linked list of them to facilitate debugging.
*/
}
void
{
register int i;
int nservers;
register idn_protoqueue_t *protoq;
if (nservers <= 0)
return;
/*
* Make sure the servers are dead.
*/
/*
* Destroy the mutexes.
*/
}
/*
* Free up the protoqueue memory.
*/
/*
* Destroy the morgue semaphore.
*/
}
}
static void
idn_protocol_server(int *id)
{
register idn_protojob_t *jp;
PR_PROTO("%s: id == NULL, thread exiting\n",
proc);
return;
}
PR_PROTO("%s: id %d starting up (pq = 0x%p)\n",
/*CONSTCOND*/
while (1) {
/*
* We've been killed. Need to check-in
* at the morgue.
*/
PR_PROTO("%s: thread (%d) killed...bye bye\n",
}
thread_exit();
/*NOTREACHED*/
}
/*
* We can process the jobs asynchronously while more are
* put on.
*/
}
}
}
/*
* Kill off all the protocol servers.
*/
static void
{
register idn_protoqueue_t *pq;
int i;
PR_PROTO("%s: killing off %d protocol servers\n",
}
}
}
idn_protojob_alloc(int kmflag)
{
} else {
}
return (jp);
}
static void
{
} else {
}
}
void
{
int serverid;
return;
PR_PROTO("%s: job (d=%d, m=0x%x, %s) submitted to "
/*
* Can't submit jobs to dying servers.
*/
if (pq->q_joblist_tail) {
} else {
}
} else {
PR_PROTO("%s: protocol server dead. freeing protojob\n",
proc);
}
}
static void
{
register int d;
PR_PROTO("%s: init mboxtbl (0x%p) ntbls = %d\n",
for (d = 0; d < ntbls; d++) {
register int ch;
/*
* Initialize the header of each mbox table
* with a cookie for identity.
*/
/*
* Format: 0xc0c0DSCC
* D = primary domain
* S = sub-domain of primary
* CC = channel of sub-domain.
*/
ch = d % IDN_MAX_NETS;
/*
* We point all sub-domains in the same channel
* to the same active sync flag since a single server
* services all domains in the same channel.
*/
}
/*
* Now that the master has initialized the entire mailbox
* region the referenced memory may not necessarily be up-to-date
* with respect to the actual SMR memory due to caching.
* In order to make sure future connecting domains get a
* consistent picture of the mailbox region, it's necessary
* for the master to flush its caches.
*/
}
{
int c;
PR_PROTO("%s: initializing main %s mailbox for domain %d\n",
for (c = 0; c < IDN_MAX_NETS; c++) {
mmp->mm_channel = (short)c;
}
/*
* The actual SMR mailbox (mmp->mm_smr_mboxp) gets setup
* when the SMR is setup.
*/
return (mmp);
}
static void
{
int c;
PR_PROTO("%s: reseting main %s mailbox for domain %d\n",
for (c = 0; c < IDN_MAX_NETS; c++) {
mmp->mm_channel = (short)c;
}
}
void
{
PR_PROTO("%s: deinitializing main %s mailbox for domain %d\n",
}
static void
{
register int c;
for (c = 0; c < IDN_MAX_NETS; c++)
}
/*
* Called upon disabling the SMR to deactivate all the mailboxes
* so that they no longer reference the SMR that's going away.
*
* stopall - Indicates to stop all channel services, across the board.
*/
static void
{
int svr_count;
if (domset == 0)
return;
PR_PROTO("%s: %s deactivating main mailboxes for domset 0x%x\n",
PR_PROTO("%s: deactivated %d chansvrs (domset 0x%x)\n",
}
static void
{
/*
* Obtain receive mailbox lock first.
*/
recv_mmp->mm_dropped = 0;
send_mmp->mm_dropped = 0;
/*
* We have to add ourselves to the respective
* channel server's service table.
* Note that the channel may not necessarily be
* active at this time.
*/
/*
* Have to get the channel server under
* control so we can add ourselves.
*/
/*
* Add the following domain (mailbox) for monitoring
* by the respective channel server.
*/
}
/*
* Unregister the given domain from the specified channel(s) for monitoring.
*/
static int
{
int c, dd_count;
PR_CHAN("%s: deactivating main mailboxes (channel %d) "
if (channel == -1) {
min_chan = 0;
} else {
}
/*
* Point all the data dispatchers to the same morgue
* so we can kill them all at once.
*/
dd_count = 0;
/*
* Have to get the channel server under
* control so we can remove ourselves.
*/
/*
* Delete the following domain (mailbox) from
* monitoring by the respective channel server.
*/
dd_count++;
}
PR_CHAN("%s: deactivated %d channel mboxes for domset 0x%x, chan %d\n",
return (dd_count);
}
/*
* Check if the given domain is registered with the given channel(s).
*/
int
{
int regcount;
return (0);
}
if (channel == -1) {
min_chan = 0;
} else {
}
regcount = 0;
/*
* Don't really need recv side lock since registeration
* can't change while we're holding send side.
* No need to wait for send side to actually suspend
* since all we want to do is prevent the registered
* information from changing.
*/
regcount++;
CHANSET_ADD(chanset, c);
}
}
PR_CHAN("%s: domid %d mbox reg'd with %d channels [0x%x] (req=%d)\n",
if (chansetp)
return (regcount);
}
static int
{
register int qi;
register idn_mboxmsg_t *mqp;
int total_count = 0;
int c, count;
int mbox_type;
char *mbox_str;
int lost_io, total_lost_io = 0;
return (0);
(mbox_type == IDNMMBOX_TYPE_RECV));
/*
* Determine which channels this domain is registered
* with. If he's not registered with any, then we
* can't touch the SMR.
*/
for (c = 0; c < IDN_MAX_NETS; c++) {
continue;
if (CHAN_IN_SET(chanset, c) == 0) {
/*
* Domain is no longer registered.
* DON'T TOUCH THE SMR - IT'S POISON!
*/
if (mmp[c].mm_smr_mboxp) {
PR_CHAN("%s:%d:%s: domain unregistered "
#ifdef DEBUG
if (mbox_type == IDNMMBOX_TYPE_RECV) {
PR_CHAN("%s:%d:%s: blowing away %d "
"incoming pkts\n",
} else {
PR_CHAN("%s:%d:%s: blowing away %d/%d "
"outstanding pkts\n",
}
#endif /* DEBUG */
}
total_lost_io += lost_io;
}
if (mmp[c].mm_smr_mboxp) {
c, mbox_csum)) {
#ifdef DEBUG
if (mbox_type == IDNMMBOX_TYPE_RECV) {
PR_CHAN("%s:%d:%s: bad mbox. blowing "
"away %d incoming pkts\n",
} else {
PR_CHAN("%s:%d:%s: bad mbox. blowing "
"away %d/%d outstanding pkts\n",
}
#endif /* DEBUG */
total_lost_io += lost_io;
}
}
continue;
}
qi = 0;
count = 0;
/*
* It's quite possible the remote domain may be accessing
* these mailbox entries at the exact same time we're
* clearing the owner bit. That's okay. All we're trying
* to do at this point is to minimize the number of packets
* the remote domain might try to process unnecessarily.
*/
do {
count++;
} while (qi);
total_lost_io += lost_io;
total_count += count;
PR_CHAN("%s:%d:%s: flushed out %d mbox entries for chan %d\n",
}
int lost_bufs;
/*
* If we lost all our outstanding I/O. We could
* possible could have slabs now with mistakenly
* outstanding I/O buffers. Need to clean them up.
* Clean up of leftovers our self.
*/
PR_CHAN("%s:%d:%s: flushed %d/%d buffers from slabs\n",
}
PR_CHAN("%s:%d:%s: flushed total of %d mailbox entries (lost %d)\n",
return (total_count);
}
void
{
int ocpuid;
"IDN: 239: invalid CPU ID (%d) specified for "
"IDN net %d",
return;
}
/*
* Thread is not yet active. Set ch_bound_cpuid
* so when thread activates it will automatically
* bind itself.
*/
} else {
if (ocpuid != -1) {
}
if (cpuid >= 0) {
}
}
}
#ifdef DEBUG
#endif /* DEBUG */
/*
* Get access to the respective channel server's synchronization
* header which resides in SMR space.
*/
static idn_mboxhdr_t *
{
return (NULL);
}
#ifdef DEBUG
PR_CHAN("%s: chan_server (%d) cookie = 0x%x (exp 0x%x)\n",
IDN_MAKE_MBOXHDR_COOKIE(0, 0, channel));
PR_CHAN("%s: chan_server (%d) actv_ptr = 0x%x (exp 0x%x)\n",
PR_CHAN("%s: chan_server (%d) ready_ptr = 0x%x (exp 0x%x)\n",
PR_CHAN("%s: chan_server (%d) mbox_cksum = 0x%x (exp 0x%x)\n",
}
#endif /* DEBUG */
mhp->mh_svr_active_ptr) ||
mhp->mh_svr_ready_ptr) ||
if (IDN_CHANNEL_IS_RECV_CORRUPTED(csp) == 0) {
"IDN: 240: (channel %d) SMR CORRUPTED "
"- RELINK", channel);
"IDN: 240: (channel %d) cookie "
"(expected 0x%x, actual 0x%x)\n",
IDN_MAKE_MBOXHDR_COOKIE(0, 0, channel),
"IDN: 240: (channel %d) actv_flg "
"(expected 0x%x, actual 0x%x)\n",
"IDN: 240: (channel %d) ready_flg "
"(expected 0x%x, actual 0x%x)\n",
}
}
return (mhp);
}
{ \
if ((csp)->ch_recv_changed) { \
register int _d; \
} else { \
} \
} \
(csp)->ch_recv_changed = 0; \
} \
}
#define CHANSVR_NEXT_DOMID(csp, i, d) \
{ \
}
#define CHANSVR_RESET_INDEX(i) ((i) = -1)
#ifdef DEBUG
#endif /* DEBUG */
static void
{
register idn_chansvr_t *csp;
register idn_mboxmsg_t *mqp;
#ifdef DEBUG
#else
#endif /* DEBUG */
register int qi;
int channel;
int cpuid;
int empty;
int tot_pktcount, tot_dropcount;
register int index;
register int domid;
register int idleloops;
#ifdef DEBUG
#else /* DEBUG */
#endif /* DEBUG */
tot_pktcount = tot_dropcount = 0;
PR_CHAN("%s: CHANNEL SERVER (channel %d) GOING ACTIVE...\n",
/*
* We've been requested to bind to
* a particular cpu.
*/
/*
* Cpu seems to have gone away or gone offline
* since originally requested.
*/
"IDN: 239: invalid CPU ID (%d) specified for "
"IDN net %d",
} else {
}
} else {
}
PR_CHAN("%s: thread bound to cpuid %d\n",
}
/*
* Only the first (main) mbox header is used for
* synchronization with data delivery since there is
* only data server for all mailboxes for this
* given channel.
*/
empty = 0;
idleloops = 0;
/*
* ---------------------------------------------
*/
/*CONSTCOND*/
while (1) {
register int pktcount;
register int dropcount;
register smr_offset_t bufoffset;
#ifdef DEBUG
register smr_pkthdr_t *hdrp;
#endif /* DEBUG */
/*
* Speed through and find the next available domid.
*/
if (!index) {
/*
* We only check state changes when
* we wrap around. Done for performance.
*/
if (!IDN_CHANNEL_IS_RECV_ACTIVE(csp) ||
PR_DATA("%s: (channel %d) %s\n",
? "DEAD" :
? "IDLED" :
? "ACTIVE" : "DISABLED");
goto cc_sleep;
}
}
goto cc_sleep;
empty = 0;
goto cc_slowdown;
}
/*
* Somebody is trying to shut things down.
*/
empty++;
continue;
}
/*
* We don't care if the mm_smr_mboxp is nullified
* after this point. The thread attempting to shut
* us down has to formally pause this channel before
* anything is official anyway. So, we can continue
* with our local SMR reference until the thread
* shutting us down really stops us.
*
* Need to get the qiget index _before_ we drop the
* lock since it might get flushed (idn_mainmbox_flush)
* once we drop the mm_mutex.
*
* We prefer not to hold the mm_mutex across the
* idn_recv_mboxdata() call since that may be time-
* consuming.
*/
/*
* Check the mailbox header if checksum is turned on.
*/
"IDN: 241: [recv] (domain %d, "
"channel %d) SMR CORRUPTED - RELINK",
}
empty = 0;
goto cc_sleep;
}
goto cc_next;
/* ASSERT(0); */
dropcount++;
} else {
PR_DATA("%s: (channel %d) pkt (off 0x%x, "
"qiget %d) from domain %d\n",
#ifdef DEBUG
#endif /* DEBUG */
if (idn_recv_mboxdata(channel,
IDN_OFFSET2ADDR(bufoffset)) < 0) {
"IDN: 241: [recv] (domain "
"%d, channel %d) SMR "
"CORRUPTED - RELINK",
}
}
pktcount++;
}
if (dropcount)
}
if (pktcount == 0) {
empty++;
} else {
empty = 0;
idleloops = 0;
PR_DATA("%s: (channel %d) dom=%d, pktcnt=%d\n",
}
continue;
#ifdef DEBUG
if (idleloops == 0) {
PR_DATA("%s: (channel %d) going SOFT IDLE...\n",
}
#endif /* DEBUG */
if (idleloops++ < IDN_NETSVR_SPIN_COUNT) {
/*
* At this level we only busy-wait.
* Get back into action.
*/
continue;
}
idleloops = 0;
if (mainhp)
mainhp->mh_svr_active = 0;
if (!IDN_CHANNEL_IS_RECV_ACTIVE(csp) &&
/*
* Time to die...
*/
PR_CHAN("%s: (channel %d) serviced %d "
PR_CHAN("%s: (channel %d) TERMINATING\n",
PR_CHAN("%s: (channel %d) ch_morguep = %p\n",
#ifdef DEBUG
index++) {
if ((int)((csp->ch_recv_scanset >>
== domid) {
PR_DATA("%s: WARNING (channel %d) "
"DROPPING domid %d...\n",
}
}
#endif /* DEBUG */
thread_exit();
/* not reached */
}
do {
if (IDN_CHANNEL_IS_DETACHED(csp)) {
PR_CHAN("%s: (channel %d) going to DIE...\n",
goto cc_die;
}
#ifdef DEBUG
if (IDN_CHANNEL_IS_RECV_ACTIVE(csp) &&
(csp->ch_recv_waittime <=
PR_CHAN("%s: (channel %d) going SOFT IDLE "
"(waittime = %d ticks)...\n",
} else {
PR_CHAN("%s: (channel %d) going "
}
#endif /* DEBUG */
/*
* If we're being asked to check-in then
* go into a hard sleep. Want to give the
* thread requesting us to checkin a chance.
*/
else
lbolt +
csp->ch_recv_waittime <<=
} while (!IDN_CHANNEL_IS_RECV_ACTIVE(csp));
/*
* Before we see the world (and touch SMR space),
* see if we've been told to die.
*/
/*
* The world may have changed since we were
* asleep. Need to resync cache and check for a
* new syncheader.
*
* Reset chansvr cache against any changes in
* mbox fields we need (mm_qiget).
*/
if (csp->ch_recv_domcount <= 0) {
/*
* Everybody disappeared on us.
* Go back to sleep.
*/
goto cc_die;
}
/*
* Bummer...we're idling...
*/
goto cc_die;
}
/*
* Reset the domid index after sleeping.
*/
empty = 0;
idleloops = 0;
}
}
#if 0
/*
* We maintain a separate function for flushing the STREAMs
* queue of a channel because it must be done outside the
* context of the idn_chan_action routine. The streams flush
* cannot occur inline with the idn_chan_action because
* the act of flushing may cause IDN send functions to be called
* directly and thus locks to be obtained which could result
* in deadlocks.
*/
static void
{
int flush_type = 0;
flush_type |= FLUSHR;
flush_type |= FLUSHW;
if (flush_type) {
if (rq) {
/*
* Flush the STREAM if possible
* to get the channel server coherent
* enough to respond to us.
*/
PR_CHAN("%s: sending FLUSH (%x) to channel %d\n",
}
}
}
#endif /* 0 */
/*
*
* - Entered with locks dropped, leave with locks held.
* DETACH - lock dropped manually.
* - Entered with locks held, leave with locks dropped.
* ATTACH
* - both enter and leave with locks dropped.
*/
static void
{
PR_CHAN("%s: requesting %s for channel %d\n",
switch (chanaction) {
case IDNCHAN_ACTION_DETACH:
/*FALLTHROUGH*/
case IDNCHAN_ACTION_STOP:
/*FALLTHROUGH*/
case IDNCHAN_ACTION_SUSPEND:
/*
* Must maintain this locking order.
* Set asynchronous check-in flags.
*/
is_running = 0;
/*
* Temporarily turn off the STREAM
* to give a chance to breath.
*/
if (is_running)
}
}
/*
* It's possible the channel server could come
* through this flow itself due to putting data upstream
* that ultimately turned around and came back down for
* sending. If this is the case we certainly don't
* want to cv_wait, otherwise we'll obviously deadlock
* waiting for ourself. So, only block if somebody
* other than the channel server we're attempting to
*/
int do_flush = 0;
do_flush++;
if (do_flush) {
/*
* Temporarily turn off the STREAM
* to give a chance to breath.
*/
is_running = 1;
}
}
}
/*
* If we have any senders in-progress
* it's possible they're stuck waiting
* down in smr_buf_alloc which may never
* arrive if we're in an unlink process.
* Rather than wait for it to timeout
* let's be proactive so we can disconnect
* asap.
*/
if (closed_slabwaiters)
do {
/*
* It's possible due to a STREAMs
* loopback from read queue to write queue
* that receiver and sender may be same
* thread, i.e. receiver's inprogress
* flag will never clear until sender's
* inprogress flag clears. So, we wait
* for sender's inprogress first.
*/
while (csend->c_inprogress) {
while (csend->c_inprogress) {
}
/*
* Maintain lock ordering.
* Eventually we will catch
* him due to the flag settings.
*/
}
if (crecv->c_inprogress) {
while (crecv->c_inprogress) {
}
}
} while (csend->c_inprogress);
}
if (is_running) {
/*
* Restore the IDNRUNNING bit in
* the flags to let them know the
* channel is still alive.
*/
}
if (closed_slabwaiters) {
/*
* We can reopen now since at this point no new
* slabwaiters will attempt to come in and wait.
*/
}
/*
* ALL leave with locks held.
*/
PR_CHAN("%s: action (%s) for channel %d - COMPLETED\n",
break;
case IDNCHAN_ACTION_ATTACH:
/*FALLTHROUGH*/
case IDNCHAN_ACTION_RESTART:
/*FALLTHROUGH*/
case IDNCHAN_ACTION_RESUME:
/*
* The channel server itself could come through this
* flow, so obviously no point in attempting to wake
* ourself up!.
*/
if (csp->ch_recv_threadp &&
PR_CHAN("%s: action (%s) for channel %d - COMPLETED\n",
/*
* Leaves with lock released.
*/
break;
default:
ASSERT(0);
break;
}
}
static void
{
register int d;
PR_CHAN("%s: adding domset 0x%x main mailboxes to channel %d\n",
/*
* Adding domains to a channel can be
* asynchonous, so we don't bother waiting.
*/
/*
* Now we have the sending and receiving sides blocked
* for this channel.
*/
for (d = 0; d < MAX_DOMAINS; d++) {
if (!DOMAIN_IN_SET(domset, d))
continue;
if (IDN_CHAN_DOMAIN_IS_REGISTERED(csp, d)) {
DOMAINSET_DEL(domset, d);
continue;
}
PR_CHAN("%s: domain %d (channel %d) RECV (pending) "
PR_CHAN("%s: domain %d (channel %d) domset = 0x%x\n",
}
if (domset)
}
static void
{
register int d;
PR_CHAN("%s: deleting domset 0x%x main mailboxes from channel %d\n",
/*
* Here we have to wait for the channel server
* as it's vital that we don't return without guaranteeing
* that the given domset is no longer registered.
*/
/*
* Now we have the sending and receiving sides blocked
* for this channel.
*/
for (d = 0; d < MAX_DOMAINS; d++) {
if (!DOMAIN_IN_SET(domset, d))
continue;
if (!IDN_CHAN_DOMAIN_IS_REGISTERED(csp, d)) {
DOMAINSET_DEL(domset, d);
continue;
}
/*
* This domain has a mailbox hanging on this channel.
* Get him out.
*
* First remove him from the receive side.
*/
PR_CHAN("%s: domain %d (channel %d) RECV (pending) "
PR_CHAN("%s: domain %d (channel %d) domset = 0x%x\n",
}
if (domset)
}
static int
{
return (0);
return (0);
return (0);
return (0);
return (0);
return (0);
return (1);
}
/*
* Packet header has already been filled in.
* RETURNS: 0
* ENOLINK
* EPROTO
* ENOSPC
*/
/*ARGSUSED*/
static int
{
int rv = 0;
return (ENOLINK);
}
PR_DATA("%s: (d %d, chn %d) mm_smr_mboxp == NULL\n",
goto send_err;
}
PR_DATA("%s: (d %d, chn %d) mbox hdr cksum (%d) "
"!= actual (%d)\n",
"IDN: 241: [send] (domain %d, "
"channel %d) SMR CORRUPTED - RELINK",
}
goto send_err;
}
PR_DATA("%s: mailbox FULL (qiput=%d, qiget=%d)\n",
goto send_err;
}
/*
* Remote domain finished with mailbox entry,
* however it has not been reclaimed yet. A reclaim
* was done before coming into this routine, however
* timing may have been such that the entry became
* free just after the reclamation, but before
* entry into here. Go ahead and reclaim this entry.
*/
PR_DATA("%s: attempting reclaim (domain %d) "
"(qiput=%d, b_off=0x%x)\n",
int recl;
}
#ifdef DEBUG
if (recl == 0) {
PR_DATA("%s: SUCCESSFULLY reclaimed buf "
} else {
PR_DATA("%s: WARNING: reclaim failed (FREE) "
}
#endif /* DEBUG */
} else {
PR_DATA("%s: WARNING: reclaim failed (BAD OFFSET) "
}
}
if (*mmp->mm_smr_readyp == 0) {
goto send_err;
}
/* membar_stst(); */
0, 0, 0);
}
return (0);
mmp->mm_dropped++;
return (rv);
}
static int
{
int pktlen;
int apktlen;
int rv = 0;
/*LINTED*/
sip = IDN_INST2SIP(0);
}
PR_DATA("%s: bad checksum(%x) != expected(%x)\n",
rv = -1;
goto recv_err;
}
PR_DATA("%s: wrong dest netaddr (0x%x), expected (0x%x)\n",
goto recv_err;
}
PR_DATA("%s: invalid packet length (%d) <= 0 || > %lu\n",
goto recv_err;
}
goto recv_err;
}
/*
* Copy data packet into its streams buffer.
* Align pointers for maximum bcopy performance.
*/
if (IDN_CHECKSUM &&
rv = -1;
goto recv_err;
}
}
return (rv);
}
/*
* When on shutdown path (idn_active_resources) must call
* idn_mainmbox_flush() _BEFORE_ calling idn_reclaim_mboxdata()
* for any final data. This is necessary incase the mailboxes
* have been unregistered. If they have then idn_mainmbox_flush()
* will set mm_smr_mboxp to NULL which prevents us from touching
* poison SMR space.
*/
int
{
int qi;
int mi;
int reclaim_cnt = 0;
int free_cnt;
/*LINTED*/
sip = IDN_INST2SIP(0);
}
PR_DATA("%s: requested %d buffers from domain %d\n",
/*
* Reclaim is already in progress, don't
* bother.
*/
return (0);
}
return (0);
do {
/* do-while continues down */
/*
* This channel is busy, move on.
*/
continue;
}
PR_DATA("%s: no smr pointer for domid %d, chan %d\n",
continue;
}
PR_DATA("%s: (d %d, chn %d) mbox hdr "
"cksum (%d) != actual (%d)\n",
continue;
}
nbufs) {
int badbuf;
badbuf = 0;
PR_DATA("%s: msg.flag ERROR(0x%x) (off=0x%x, "
"domid=%d, qiget=%d)\n", proc,
}
badbuf = 1;
} else {
/*
* Put the buffers onto a list that will be
* formally reclaimed down below. This allows
* us to free up mboxq entries as fast as
* possible.
*/
badbuf = 1;
"IDN: 241: [send] "
"(domain %d, channel "
"%d) SMR CORRUPTED - "
"RELINK",
}
} else if (reclaim_list == IDN_NIL_SMROFFSET) {
reclaim_list = curr;
} else {
}
}
if (!badbuf) {
nbufs--;
reclaim_cnt++;
}
break;
}
if (reclaim_list != IDN_NIL_SMROFFSET) {
}
PR_DATA("%s: reclaimed %d buffers from domain %d\n",
if (reclaim_cnt == 0) {
return (0);
}
/*
* Now actually go and reclaim (free) the buffers.
*/
free_cnt = 0;
/*
* Once corruption is detected we
* can't trust our list any further.
* These buffers are effectively lost.
*/
"IDN: 241: [send] (domain %d, channel %d) SMR "
break;
}
free_cnt++;
}
}
#ifdef DEBUG
if (free_cnt != reclaim_cnt) {
PR_DATA("%s: *** WARNING *** freecnt(%d) != reclaim_cnt (%d)\n",
}
#endif /* DEBUG */
return (reclaim_cnt);
}
void
{
idn_nack_t nacktype = 0;
if (domid == IDN_NIL_DOMID)
return;
/*
* Domain was previously AWOL, but no longer.
*/
IDN_GUNLOCK();
}
/*
* Do a precheck before wasting time trying to acquire the lock.
*/
/*
* Either we're not connected or somebody is busy working
* on the domain. Bail on the signal for now, we'll catch
* it on the next go around.
*/
return;
}
/*
* We didn't have the drwlock on the first check of dstate,
* but now that we do, make sure the world hasn't changed!
*/
/*
* If we reach here, then no connection.
* Send no response if this is the case.
*/
goto send_dresp;
}
/*
* No need to worry about locking mainmbox
* because we're already holding reader
* lock on domain, plus we're just reading
* fields in the mainmbox which only change
* (or go away) when the writer lock is
* held on the domain.
*/
/*
* No local mailbox.
*/
goto send_dresp;
}
goto send_dresp;
}
if (channel == IDN_BROADCAST_ALLCHAN) {
PR_DATA("%s: requested signal to ALL channels on domain %d\n",
min_chan = 0;
} else {
PR_DATA("%s: requested signal to channel %d on domain %d\n",
}
/*
* We do a quick check for a pending channel.
* If pending it will need activation and we rather
* do that through a separate (proto) thread.
*/
PR_DATA("%s: chansvr (%d) for domid %d CHECK-IN\n",
continue;
}
if (IDN_CHAN_TRYLOCK_RECV(csp) == 0) {
/*
* Failed to grab lock, server must be active.
*/
PR_DATA("%s: chansvr (%d) for domid %d already actv\n",
continue;
}
if (IDN_CHANNEL_IS_PENDING(csp)) {
/*
* Lock is pending. Submit asynchronous
* job to activate and move-on.
*/
continue;
}
/*
* If he ain't active, we ain't talkin'.
*/
if (IDN_CHANNEL_IS_RECV_ACTIVE(csp) == 0) {
PR_DATA("%s: chansvr (%d) for domid %d inactive\n",
continue;
}
continue;
}
/*
* Not registered.
*/
continue;
}
/*
* No SMR mailbox.
*/
continue;
}
/*
* Data server is already active.
*/
PR_DATA("%s: chansvr (%d) for domid %d already actv\n",
continue;
}
PR_DATA("%s: signaling data dispatcher for chan %d dom %d\n",
}
/*
* If there were no real errors or we were
* handling multiple channels, then just
* return.
*/
return;
}
PR_DATA("%s: sending NACK (%s) back to domain %d (cpu %d)\n",
}
/*ARGSUSED*/
static int
{
#ifdef DEBUG
PR_PROTO("%s:%d: DATA message received (msg = 0x%x, msgarg = 0x%x)\n",
PR_PROTO("%s:%d: xargs = (0x%x, 0x%x, 0x%x, 0x%x)\n",
#endif /* DEBUG */
return (0);
}
/*
* Only used when sending a negative response.
*/
static void
{
return;
}
/*
* Checksum routine used in checksum smr_pkthdr_t and idn_mboxhdr_t.
*/
static ushort_t
{
register int i;
for (i = 0; i < count; i++)
return (~sum);
}
/*
* ------------------------------------------------
*/
int
idn_open_channel(int channel)
{
int masterid;
if (channel >= IDN_MAX_NETS) {
"IDN: 242: maximum channels (%d) already open",
return (-1);
}
if (IDN_CHANNEL_IS_ATTACHED(csp)) {
IDN_GUNLOCK();
return (0);
}
/*
* Need to zero out the kstats now that we're activating
* this channel.
*/
break;
}
}
/*
* We increase our window threshold each time a channel
* is opened.
*/
PR_CHAN("%s: channel %d is OPEN (nchannels = %d)\n",
masterid = IDN_GET_MASTERID();
IDN_GUNLOCK();
/*
* Check if there is an active master to which
* we're connected. If so, then activate channel.
*/
if (masterid != IDN_NIL_DOMID) {
}
return (0);
}
void
{
if (IDN_CHANNEL_IS_DETACHED(csp)) {
IDN_GUNLOCK();
return;
}
if (chanop == IDNCHAN_HARD_CLOSE) {
/*
* We increase our window threshold each time a channel
* is opened.
*/
IDN_WINDOW_EMAX = 0;
else
}
PR_CHAN("%s: channel %d is (%s) CLOSED (nchannels = %d)\n",
IDN_GUNLOCK();
}
static int
{
int c, rv = 0;
PR_CHAN("%s: chanset = 0x%x, chanop = %s\n",
/*
* Can't activate any channels unless local
* domain is connected and thus has a master.
*/
PR_CHAN("%s: local domain not connected. no data servers\n",
proc);
return (-1);
}
for (c = 0; c < IDN_MAX_NETS; c++) {
if (!CHAN_IN_SET(chanset, c))
continue;
if (chanop == IDNCHAN_ONLINE) {
} else {
/*
* We don't wait to grab the global lock
* if IDNCHAN_OPEN since these occur along
* critical data paths and will be retried
* anyway if needed.
*/
if (IDN_CHAN_TRYLOCK_GLOBAL(csp) == 0) {
PR_CHAN("%s: failed to acquire global "
"lock for channel %d\n",
proc, c);
continue;
}
}
if (!IDN_CHANNEL_IS_ATTACHED(csp)) {
continue;
}
if (IDN_CHANNEL_IS_ACTIVE(csp)) {
rv++;
continue;
}
/*
* Channel activation can happen asynchronously.
*/
IDN_CHANNEL_SUSPEND(c, 0);
if (idn_activate_channel_services(c) >= 0) {
PR_CHAN("%s: Setting channel %d ACTIVE\n",
proc, c);
rv++;
}
} else if (!IDN_CHANNEL_IS_PENDING(csp) &&
(chanop == IDNCHAN_ONLINE)) {
}
/*
* Don't syncheader (i.e. touch SMR) unless
* channel is at least ENABLED. For a DISABLED
* channel, the SMR may be invalid so do NOT
* touch it.
*/
if (IDN_CHANNEL_IS_ENABLED(csp) &&
PR_CHAN("%s: marking chansvr (mhp=0x%p) %d READY\n",
}
sip = IDN_INST2SIP(c);
}
}
/*
* Returns "not active", i.e. value of 0 indicates
* no channels are activated.
*/
return (rv == 0);
}
static void
{
int c;
PR_CHAN("%s: chanset = 0x%x, chanop = %s\n",
for (c = 0; c < IDN_MAX_NETS; c++) {
if (!CHAN_IN_SET(chanset, c))
continue;
if (((chanop == IDNCHAN_SOFT_CLOSE) &&
!IDN_CHANNEL_IS_ACTIVE(csp)) ||
((chanop == IDNCHAN_HARD_CLOSE) &&
((chanop == IDNCHAN_OFFLINE) &&
!IDN_CHANNEL_IS_ENABLED(csp))) {
PR_CHAN("%s: channel %d already deactivated\n",
proc, c);
continue;
}
switch (chanop) {
case IDNCHAN_OFFLINE:
IDN_CHANNEL_STOP(c, 1);
mainhp->mh_svr_ready = 0;
break;
case IDNCHAN_HARD_CLOSE:
IDN_CHANNEL_DETACH(c, 1);
mainhp->mh_svr_ready = 0;
break;
default:
IDN_CHANNEL_SUSPEND(c, 1);
break;
}
chanop_str[chanop]);
PR_CHAN("%s: removing chanset 0x%x data svrs for "
(void) idn_deactivate_channel_services(c, chanop);
}
/*
* Returns with channels unlocked.
*/
}
/*
* The priority of the channel server must be less than that
* of the protocol server since the protocol server tasks
* are (can be) of more importance.
*
* Possible range: 60-99.
*/
static int
{
if (csp->ch_recv_threadp) {
/*
* There's an existing dispatcher!
* Must have been idle'd during an earlier
* stint.
*/
PR_CHAN("%s: existing chansvr FOUND for (c=%d)\n",
if (IDN_CHANNEL_IS_PENDING(csp) == 0)
return (-1);
PR_CHAN("%s: chansvr (c=%d) Rstate = 0x%x, Sstate = 0x%x\n",
return (0);
}
if (IDN_CHANNEL_IS_PENDING(csp) == 0)
return (-1);
return (0);
}
/*
* This routine can handle terminating a set of channel
* servers all at once, however currently only used
* for serial killing, i.e. one-at-a-time.
*
* Entered with RECV locks held on chanset.
* Acquires SEND locks if needed.
* Leaves with all RECV and SEND locks dropped.
*/
static int
{
int cs_count;
int c;
/*
* XXX
* Old code allowed us to deactivate multiple channel
* servers at once. Keep for now just in case.
*/
/*
* Point all the data dispatchers to the same morgue
* so we can kill them all at once.
*/
cs_count = 0;
for (c = 0; c < IDN_MAX_NETS; c++) {
if (!CHAN_IN_SET(chanset, c))
continue;
/*
* No channel server home.
* But we're still holding the c_mutex.
* At mark him idle incase we start him up.
*/
PR_CHAN("%s: no channel server found for chan %d\n",
proc, c);
continue;
}
/*
* Okay, now we've blocked the send and receive sides.
*/
if ((chanop == IDNCHAN_SOFT_CLOSE) ||
(chanop == IDNCHAN_OFFLINE)) {
/*
* We set turned off the ACTIVE flag, but there's
* no guarantee he stopped because of it. He may
* have already been sleeping. We need to be
* sure he recognizes the IDLE, so we need to
* signal him and give him a chance to see it.
*/
cs_count++;
continue;
}
PR_CHAN("%s: pointing chansvr %d to morgue (0x%p)\n",
: csp->ch_recv_morguep);
if (central_morguep == NULL) {
} else {
}
/*
* Save any existing binding for next reincarnation.
* Note that we're holding the local and global
* locks so we're protected against others touchers
* of the ch_bound_cpuid fields.
*/
cs_count++;
}
PR_CHAN("%s: signaled %d chansvrs for chanset 0x%x\n",
return (cs_count);
PR_CHAN("%s: waiting for %d (chnset=0x%x) chan svrs to term\n",
while (cs_count-- > 0)
if (central_morguep) {
}
return (cs_count);
}
int
{
int c;
if (idn.chan_servers)
return (0);
for (c = 0; c < IDN_MAXMAX_NETS; c++) {
}
return (c);
}
void
{
int c;
return;
for (c = 0; c < IDN_MAXMAX_NETS; c++) {
}
}
static void
idn_exec_chanactivate(void *chn)
{
int not_active, channel;
IDN_GUNLOCK();
return;
}
if (IDN_CHAN_TRYLOCK_GLOBAL(csp) == 0) {
/*
* If we can't grab the global lock, then
* something is up, skip out.
*/
IDN_GUNLOCK();
return;
}
IDN_GUNLOCK();
if (not_active)
} else {
}
}
/*
* Delayed activation of channel. We don't want to do this within
* idn_signal_data_server() since that's called within the context
* of an XDC handler so we submit it as a timeout() call to be short
* as soon as possible.
* The ch_initlck & ch_actvlck are used to synchronize activation
* of the channel so that we don't have multiple idn_activate_channel's
* attempting to activate the same channel.
*/
static void
{
return;
return;
}
/*ARGSUSED0*/
static void
idn_xmit_monitor(void *unused)
{
int c, d;
smr_slab_t *sp;
return;
}
/*
* No point in transmitting unless state
* is ONLINE.
*/
goto retry;
/*
* Try and reclaim some buffers if possible.
*/
for (d = 0; d < MAX_DOMAINS; d++) {
if (!DOMAIN_IN_SET(conset, d))
continue;
if (!IDN_DLOCK_TRY_SHARED(d))
continue;
(void) idn_reclaim_mboxdata(d, 0, -1);
IDN_DUNLOCK(d);
}
/*
* Now check if we were successful in getting
* any buffers.
*/
break;
/*
* If there are no buffers available,
* no point in reenabling the queues.
*/
goto retry;
for (c = 0; c < IDN_MAX_NETS; c++) {
int pending_bits;
continue;
if (!IDN_CHAN_TRYLOCK_GLOBAL(csp))
continue;
sip = IDN_INST2SIP(c);
(pending_bits == IDN_CHANSVC_PENDING_BITS) &&
CHANSET_ADD(wake_set, c);
PR_XMON("%s: QENABLE for channel %d\n",
proc, c);
} else {
}
}
/*
* Clear the channels we enabled.
*/
if (idn.xmit_chanset_wanted == 0)
else
}
void
{
if (chan_wanted < 0) {
/*
* Wants all channels.
*/
} else {
}
/*
* A monitor is already running, so
* he will catch the new "wants" when
* he comes around.
*/
return;
}
PR_XMON("%s: xmit_mon kicked OFF (chanset = 0x%x)\n",
}