/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#include <sys/sysmacros.h>
#include <sys/machparam.h>
#include <sys/machsystm.h>
#include <sys/prom_plat.h>
#include <vm/seg_kmem.h>
#include <sys/vm_machparam.h>
#include <sys/archsystm.h>
#include <sys/cpu_sgnblk_defs.h>
int idn_debug;
int idn_snoop;
int idn_history;
typedef enum {
} idn_gprops_t;
/*
* IDN "tunables".
*/
int idn_smr_size;
int idn_nwr_size;
int idn_lowat;
int idn_hiwat;
int idn_awolmsg_interval;
int idn_smr_bufsize;
int idn_slab_bufcount;
int idn_slab_prealloc;
int idn_slab_mintotal;
int idn_window_max;
int idn_window_incr;
int idn_window_emax;
int idn_reclaim_min;
int idn_reclaim_max;
int idn_mbox_per_net;
int idn_max_nets;
int idn_netsvr_wait_min;
int idn_netsvr_wait_max;
int idn_checksum;
int idn_msgwait_nego;
int idn_msgwait_cfg;
int idn_msgwait_con;
int idn_msgwait_fin;
int idn_msgwait_cmd;
int idn_msgwait_data;
int idn_retryfreq_nego;
int idn_retryfreq_con;
int idn_retryfreq_fin;
/*
* DMV interrupt support.
*/
int idn_pil;
int idn_dmv_pending_max;
int idn_sigbpil;
{ 0, 1, 0, /* 0 */ "idn_modunloadable" },
};
/*
* Parameters that are only accessible in a DEBUG driver.
*/
static char *idn_param_debug_only[] = {
#if 0
"idn_checksum",
#endif /* 0 */
0
};
/*
* Parameters that are READ-ONLY.
*/
static char *idn_param_read_only[] = {
#if 0
"idn_window_emax",
"idn_slab_maxperdomain",
#endif /* 0 */
0
};
static struct idn_global_props {
char *p_string;
int *p_var;
} idn_global_props[] = {
{ 0, 0, 0, "idn_debug", &idn_debug },
{ 0, IDN_SMR_MAXSIZE,
0, "idn_smr_size", &idn_smr_size },
{ 0, IDN_SMR_MAXSIZE,
0, "idn_nwr_size", &idn_nwr_size },
{ 1, 512*1024,
{ 1*1024,
1*1024*1024,
256*1024,
"idn_hiwat", &idn_hiwat },
"idn_smr_bufsize", &idn_smr_bufsize },
{ 2, MAX_DOMAINS,
{ 1, IDN_MAXMAX_NETS,
{ 0, 10000, 500, "idn_netsvr_spin_count",
{ 1, 5, 1, "idn_netsvr_wait_shift",
{ 1, MAX_DOMAINS,
"idn_protocol_nservers",
{ 0, 3600, IDN_AWOLMSG_INTERVAL,
"idn_awolmsg_interval", &idn_awolmsg_interval },
"idn_msgwait_nego", &idn_msgwait_nego },
"idn_msgwait_cfg", &idn_msgwait_cfg },
"idn_msgwait_con", &idn_msgwait_con },
"idn_msgwait_fin", &idn_msgwait_fin },
"idn_msgwait_cmd", &idn_msgwait_cmd },
"idn_msgwait_data", &idn_msgwait_data },
"idn_retryfreq_nego", &idn_retryfreq_nego },
"idn_retryfreq_con", &idn_retryfreq_con },
"idn_retryfreq_fin", &idn_retryfreq_fin },
"idn_pil", &idn_pil },
"idn_sigbpil", &idn_sigbpil },
"idn_dmv_pending_max", &idn_dmv_pending_max },
};
static int idn_size_check();
static void idn_xmit_monitor_init();
static void idn_xmit_monitor_deinit();
static void idn_init_msg_waittime();
static void idn_init_msg_retrytime();
static int idn_deinit();
static void idn_sigbhandler_create();
static void idn_sigbhandler_kill();
static int idn_init_smr();
static void idn_deinit_smr();
static int idn_init_handler();
static void idn_deinit_handler();
/*
* ioctl services
*/
static void idn_domains_deinit();
static void idn_retrytask_init();
static void idn_retrytask_deinit();
static void idn_gkstat_init();
static void idn_gkstat_deinit();
static int idn_gkstat_update();
static void idn_timercache_init();
static void idn_timercache_deinit();
static void idn_dopers_init();
static void idn_dopers_deinit();
static void idn_param_cleanup();
/*
* String definitions used for DEBUG and non-DEBUG.
*/
const char *idnm_str[] = {
/* 0 */ "null",
/* 1 */ "nego",
/* 2 */ "con",
/* 3 */ "cfg",
/* 4 */ "fin",
/* 5 */ "cmd",
/* 6 */ "data",
};
const char *idnds_str[] = {
/* 0 */ "CLOSED",
/* 1 */ "NEGO_PEND",
/* 2 */ "NEGO_SENT",
/* 3 */ "NEGO_RCVD",
/* 4 */ "CONFIG",
/* 5 */ "CON_PEND",
/* 6 */ "CON_SENT",
/* 7 */ "CON_RCVD",
/* 8 */ "CON_READY",
/* 9 */ "CONNECTED",
/* 10 */ "FIN_PEND",
/* 11 */ "FIN_SENT",
/* 12 */ "FIN_RCVD",
/* 13 */ "DMAP"
};
const char *idnxs_str[] = {
/* 0 */ "PEND",
/* 1 */ "SENT",
/* 2 */ "RCVD",
/* 3 */ "FINAL",
/* 4 */ "NIL"
};
const char *idngs_str[] = {
/* 0 */ "OFFLINE",
/* 1 */ "CONNECT",
/* 2 */ "ONLINE",
/* 3 */ "DISCONNECT",
/* 4 */ "RECONFIG",
/* 5 */ "unknown",
/* 6 */ "unknown",
/* 7 */ "unknown",
/* 8 */ "unknown",
/* 9 */ "unknown",
/* 10 */ "IGNORE"
};
const char *idncmd_str[] = {
/* 0 */ "unknown",
/* 1 */ "SLABALLOC",
/* 2 */ "SLABFREE",
/* 3 */ "SLABREAP",
/* 4 */ "NODENAME"
};
const char *idncon_str[] = {
/* 0 */ "OFF",
/* 1 */ "NORMAL",
/* 2 */ "QUERY"
};
const char *idnfin_str[] = {
/* 0 */ "OFF",
/* 1 */ "NORMAL",
/* 2 */ "FORCE_SOFT",
/* 3 */ "FORCE_HARD",
/* 4 */ "QUERY"
};
const char *idnfinopt_str[] = {
/* 0 */ "NONE",
/* 1 */ "UNLINK",
/* 2 */ "RELINK"
};
const char *idnfinarg_str[] = {
/* 0 */ "NONE",
/* 1 */ "SMRBAD",
/* 2 */ "CPUCFG",
/* 3 */ "HWERR",
/* 4 */ "CFGERR_FATAL",
/* 5 */ "CFGERR_MTU",
/* 6 */ "CFGERR_BUF",
/* 7 */ "CFGERR_SLAB",
/* 8 */ "CFGERR_NWR",
/* 9 */ "CFGERR_NETS",
/* 10 */ "CFGERR_MBOX",
/* 11 */ "CFGERR_NMCADR",
/* 12 */ "CFGERR_MCADR",
/* 13 */ "CFGERR_CKSUM",
/* 14 */ "CFGERR_SMR",
};
const char *idnsync_str[] = {
/* 0 */ "NIL",
/* 1 */ "CONNECT",
/* 2 */ "DISCONNECT"
};
const char *idnreg_str[] = {
/* 0 */ "REG",
/* 1 */ "NEW",
/* 2 */ "QUERY"
};
const char *idnnack_str[] = {
/* 0 */ "unknown",
/* 1 */ "NOCONN",
/* 2 */ "BADCHAN",
/* 3 */ "BADCFG",
/* 4 */ "BADCMD",
/* 5 */ "RETRY",
/* 6 */ "DUP",
/* 7 */ "EXIT",
/* 8 */ "--reserved1",
/* 9 */ "--reserved2",
/* 10 */ "--reserved3"
};
const char *idnop_str[] = {
/* 0 */ "DISCONNECTED",
/* 1 */ "CONNECTED",
/* 2 */ "ERROR"
};
const char *chanop_str[] = {
/* 0 */ "OPEN",
/* 1 */ "SOFT_CLOSE",
/* 2 */ "HARD_CLOSE",
/* 3 */ "OFFLINE",
/* 4 */ "ONLINE"
};
const char *chanaction_str[] = {
/* 0 */ "DETACH",
/* 1 */ "STOP",
/* 2 */ "SUSPEND",
/* 3 */ "RESUME",
/* 4 */ "RESTART",
/* 5 */ "ATTACH"
};
const char *timer_str[] = {
/* 0 */ "NIL",
/* 1 */ "MSG"
};
IDNIDNUM, /* mi_idnum */
IDNNAME, /* mi_idname */
IDNMINPSZ, /* mi_minpsz */
IDNMAXPSZ, /* mi_maxpsz */
0, /* mi_hiwat - see IDN_HIWAT */
0 /* mi_lowat - see IDN_LOWAT */
};
IDNIDNUM, /* mi_idnum */
IDNNAME, /* mi_idname */
IDNMINPSZ, /* mi_minpsz */
IDNMAXPSZ, /* mi_maxpsz */
0, /* mi_hiwat - see IDN_HIWAT */
0 /* mi_lowat - see IDN_LOWAT */
};
idnrput, /* qi_putp */
NULL, /* qi_srvp */
idnopen, /* qi_qopen */
idnclose, /* qi_qclose */
NULL, /* qi_qadmin */
&idnrinfo, /* qi_minfo */
NULL, /* qi_mstat */
NULL, /* qi_rwp */
NULL, /* qi_infop */
STRUIOT_DONTCARE /* qi_struiot */
};
idnwput, /* qi_putp */
idnwsrv, /* qi_srvp */
NULL, /* qi_qopen */
NULL, /* qi_qclose */
NULL, /* qi_qadmin */
&idnwinfo, /* qi_minfo */
NULL, /* qi_mstat */
NULL, /* qi_rwp */
NULL, /* qi_infop */
STRUIOT_DONTCARE /* qi_struiot */
};
&idnrinit, /* st_rdinit */
&idnwinit, /* st_wrinit */
NULL, /* st_muxrinit */
NULL, /* st_muxwinit */
};
/*
* Module linkage information (cb_ops & dev_ops) for the kernel.
*/
nulldev, /* cb_open */
nulldev, /* cb_close */
nodev, /* cb_strategy */
nodev, /* cb_print */
nodev, /* cb_dump */
nodev, /* cb_read */
nodev, /* cb_write */
nodev, /* cb_ioctl */
nodev, /* cb_devmap */
nodev, /* cb_mmap */
nodev, /* cb_segmap */
nochpoll, /* cb_chpoll */
ddi_prop_op, /* cb_prop_op */
&idninfo, /* cb_stream */
D_MP, /* cb_flag */
CB_REV, /* cb_rev */
nodev, /* cb_aread */
nodev, /* cb_awrite */
};
DEVO_REV, /* devo_rev */
0, /* devo_refcnt */
ddi_no_info, /* devo_getinfo */
nulldev, /* devo_identify */
nulldev, /* devo_probe */
idnattach, /* devo_attach */
idndetach, /* devo_detach */
nodev, /* devo_reset */
&cb_idnops, /* devo_cb_ops */
NULL, /* devo_power */
ddi_quiesce_not_needed, /* quiesce */
};
extern cpuset_t cpu_ready_set;
&mod_driverops, /* This module is a pseudo driver */
IDNDESC " 1.58",
};
&modldrv,
};
/*
* --------------------------------------------------
*/
int
_init(void)
{
return (mod_install(&modlinkage));
}
int
_fini(void)
{
return (mod_remove(&modlinkage));
}
int
{
}
/*
* ----------------------------------------------
*/
static int
{
int instance;
int doinit = 0;
#ifndef lint
#endif /* lint */
switch (cmd) {
case DDI_RESUME:
/*
* sip may have not yet been set if the
* OBP environment variable (idn-smr-size)
* was not set.
*/
return (DDI_FAILURE);
/*
* RESUME IDN services.
*/
"IDN: 101: not in expected OFFLINE state "
"for DDI_RESUME");
ASSERT(0);
}
IDN_GUNLOCK();
/*
* RESUME DLPI services.
*/
doinit = 1;
break;
}
if (doinit)
(void) idndl_init(sip);
return (DDI_SUCCESS);
case DDI_ATTACH:
break;
default:
return (DDI_FAILURE);
}
return (DDI_FAILURE);
return (DDI_FAILURE);
}
if (idn_init_smr() == 0) {
#ifdef DEBUG
#endif /* DEBUG */
} else {
"!IDN: 102: driver disabled "
"- check OBP environment "
"(idn-smr-size)");
return (DDI_SUCCESS);
}
}
doinit = 1;
if (idn_size_check()) {
return (DDI_FAILURE);
}
return (DDI_FAILURE);
}
}
/*
* This must occur _after_ idn_init() since
* it assumes idn_chanservers_init() has been
* called.
*/
/*
* DLPI supporting stuff.
*/
if (doinit)
idndl_dlpi_init(); /* initializes idninfoack */
/*
* Get our local IDN ethernet address.
*/
if (doinit) {
/*
* Add our sigblock SSP interrupt handler.
*/
if (sgnblk_poll_register(idn_sigbhandler) == 0) {
(void) idn_deinit();
return (DDI_FAILURE);
}
/*
* We require sigblkp[cpu0] to be mapped for hardware
* configuration determination and also auto-linking
* on bootup.
*/
(void) sgnblk_poll_unregister(idn_sigbhandler);
(void) idn_deinit();
"IDN: 103: unable to reference sigblock area");
return (DDI_FAILURE);
}
}
return (DDI_SUCCESS);
}
/*
* ----------------------------------------------
*/
static int
{
int err = 0;
int instance;
switch (cmd) {
case DDI_SUSPEND:
return (DDI_FAILURE);
/*
* SUSPEND IDN services.
* - Actually don't suspend anything, we just
* make sure we're not connected per DR protocol.
* If we really wanted to suspend it should
* be done _after_ DLPI is suspended so that
* we're not competing with that traffic.
*/
int d;
"IDN: 104: cannot suspend while active "
"(state = %s)",
for (d = 0; d < MAX_DOMAINS; d++) {
dp = &idn_domain[d];
continue;
"IDN: 121: domain %d (CPU %d, name "
"\"%s\", state %s)\n",
}
err = 1;
}
IDN_GUNLOCK();
if (err)
return (DDI_FAILURE);
/*
* SUSPEND DLPI services.
*/
return (DDI_FAILURE);
case DDI_DETACH:
return (DDI_SUCCESS);
}
if (!IDN_MODUNLOADABLE)
return (DDI_FAILURE);
break;
default:
return (DDI_FAILURE);
}
/*
* No resources allocated.
*/
return (DDI_SUCCESS);
}
/*
* This is our last stream connection
* going away. Time to deinit and flag
* the SSP we're (IDN) DOWN.
*/
if (idn_deinit()) {
/*
* Must still be active.
*/
return (DDI_FAILURE);
}
/*
* Remove our sigblock SSP interrupt handler.
*/
(void) sgnblk_poll_unregister(idn_sigbhandler);
/*
* Remove our reference to the sigblock area.
*/
}
/*
* Remove this instance from our linked list.
*/
} else {
;
if (hsip)
}
return (DDI_SUCCESS);
}
/*
* ----------------------------------------------
*/
static idn_gprops_t
{
if (global_props == IDN_GPROPS_UNCHECKED) {
int p;
for (p = 0; idn_global_props[p].p_string; p++) {
char *str;
int *var;
"IDN: 105: driver parameter "
"(%s) specified (%d) out of "
"range [%d - %d]",
} else {
}
}
}
"bind_cpu", -1);
return (global_props);
}
static int
{
int i, cnt;
int rv = 0;
int max_num_slabs;
if (IDN_NWR_SIZE == 0)
if (IDN_NWR_SIZE > IDN_SMR_SIZE) {
"IDN: 106: idn_nwr_size(%d) > idn_smr_size(%d)"
" - Limiting to %d MB",
}
"IDN: 107: memory region(%lu) < slab size(%u)",
rv = -1;
}
"IDN: 108: idn_lowat(%d) >= idn_hiwat(%d)",
rv = -1;
}
#ifdef DEBUG
PR_DRV("%s: slab size(%d) < mailbox area(%ld)",
/* not fatal */
}
#endif /* DEBUG */
"IDN: 109: mailbox area(%lu) + slab size(%u) "
"> nwr region(%lu)",
MB2B(IDN_NWR_SIZE));
rv = -1;
}
if (max_num_slabs < IDN_SLAB_MINTOTAL) {
"IDN: 110: maximum number of slabs(%d) < "
"minimum required(%d)",
rv = -1;
} else {
}
#if 0
"IDN: (IDN_MTU(%d) + ether_header(%d)) "
"> IDN_DATA_SIZE(%lu)",
IDN_MTU, sizeof (struct ether_header),
rv = -1;
}
#endif /* 0 */
"IDN: 111: idn_smr_bufsize(%d) not on a "
"64 byte boundary", IDN_SMR_BUFSIZE);
rv = -1;
}
for (i = cnt = 0;
i++)
if ((1 << i) & IDN_SMR_BUFSIZE)
cnt++;
"IDN: 112: idn_smr_bufsize(%d) not a power of 2",
rv = -1;
}
if ((IDN_MBOX_PER_NET & 1) == 0) {
"IDN: 113: idn_mbox_per_net(%d) must be an "
"odd number", IDN_MBOX_PER_NET);
rv = -1;
}
if (IDN_NETSVR_WAIT_MIN > IDN_NETSVR_WAIT_MAX) {
"IDN: 115: idn_netsvr_wait_min(%d) cannot be "
"greater than idn_netsvr_wait_max(%d)",
rv = -1;
}
return (rv);
}
static int
{
return (0);
return (-1);
PR_PROTO("%s: smr_size = %d, obp_paddr = 0x%lx, obp_size = 0x%lx\n",
if (IDN_SMR_SIZE)
return (0);
}
static void
{
return;
IDN_SMR_SIZE = 0;
}
/*ARGSUSED1*/
static void
{
return;
}
}
static int
{
"IDN: 117: IDN not enabled");
return (-1);
}
PR_DRV("%s: already initialized (dip = 0x%p)\n",
return (0);
}
/*
* Determine our local domain's hardware configuration.
*/
if (get_hw_config(&local_hw)) {
"IDN: 118: hardware config not appropriate");
return (-1);
}
/*
* Calculate proper value for idn.bframe_shift.
* Kind of hokey as it assume knowledge of the format
* of the idnparam_t structure.
*/
{
int s;
for (s = 0; (1 << s) < IDN_SMR_BUFSIZE_MIN; s++)
;
idn.bframe_shift = s;
PR_DRV("%s: idn.bframe_shift = %d, minbuf = %d\n",
(1 << 24));
}
/*
* Initialize the domain op (dopers) stuff.
*/
/*
* Initialize the timer (kmem) cache used for timeout
* structures.
*/
/*
* Initialize the slab waiting areas.
*/
(void) smr_slabwaiter_init();
/*
* Initialize retryjob kmem cache.
*/
/*
* Initialize idn_domains[] and local domains information
* include idn_global information.
*/
/*
* Start up IDN protocol servers.
*/
if (idn_protocol_init(idn_protocol_nservers) <= 0) {
"IDN: 119: failed to initialize %d protocol servers",
return (-1);
}
/*
* Initialize chan_servers array.
*/
(void) idn_chanservers_init();
/*
* Need to register the IDN handler with the DMV subsystem.
*
* Need to prevent the IDN driver from being unloaded
* once loaded since DMV's may come in at any time.
* If the driver is not loaded and the idn_dmv_handler
* has been registered with the DMV, system will crash.
*/
(void) idn_init_handler();
IDN_GUNLOCK();
return (0);
}
static int
{
int d;
"IDN: 120: cannot deinit while active "
for (d = 0; d < MAX_DOMAINS; d++) {
dp = &idn_domain[d];
continue;
"IDN: 121: domain %d (CPU %d, "
"name \"%s\", state %s)\n",
}
IDN_GUNLOCK();
return (-1);
}
IDN_GUNLOCK();
return (0);
}
IDN_GUNLOCK();
return (0);
}
static void
{
}
static void
{
} else {
}
}
static void
{
}
static void
{
}
/*
* ----------------------------------------------
*/
/*ARGSUSED*/
static int
{
register int err = 0;
int minordev;
PR_DRV("%s: Driver disabled (check OBP:idn-smr-size)\n",
proc);
IDN_GUNLOCK();
return (EACCES);
}
if (!idn_ndlist &&
IDN_GUNLOCK();
return (ENOMEM);
}
IDN_GUNLOCK();
minordev = 0;
break;
minordev++;
}
} else {
}
goto done;
/*
* DLPI stuff
*/
stp->ss_mccount = 0;
/*
* Link new entry into list of actives.
*/
/*
* Disable automatic enabling of our write service
* procedure. We control this explicitly.
*/
/*
* Set our STREAMs queue maximum packet size that
*/
done:
return (err);
}
/*
* ----------------------------------------------
*/
/*ARGSUSED1*/
static int
{
/*
* Guaranteed to be single threaded with respect
* to this stream at this point.
*/
break;
return (0);
}
/*
* ----------------------------------------------
*/
static int
{
case M_IOCTL:
break;
case M_DATA:
PR_DLPI("%s: fl=0x%x, st=0x%x, ret(EPROTO)\n",
/*
* We're only holding the reader lock,
* but that's okay since this field
* is just a soft-flag.
*/
} else {
}
} else {
PR_DLPI("%s: idndl_start(sip=0x%p)\n",
}
break;
case M_PROTO:
case M_PCPROTO:
/*
* Break the association between the current thread
* and the thread that calls idndl_proto() to resolve
* the problem of idn_chan_server() threads which
* loop back around to call idndl_proto and try to
* recursively acquire internal locks.
*/
break;
case M_FLUSH:
PR_STR("%s: M_FLUSH request (flush = %d)\n",
}
else
break;
default:
PR_STR("%s: unexpected DB_TYPE 0x%x\n",
break;
}
return (0);
}
/*
* ----------------------------------------------
*/
static int
{
int err = 0;
case M_DATA:
if (sip) {
PR_DLPI("%s: idndl_start(sip=0x%p)\n",
if (err)
goto done;
} else {
}
break;
case M_PROTO:
case M_PCPROTO:
break;
default:
ASSERT(0);
PR_STR("%s: unexpected db_type (%d)\n",
break;
}
}
done:
return (0);
}
/*
* ----------------------------------------------
*/
static int
{
register int err = 0;
case M_DATA:
/*
* Should not reach here with data packets
* if running DLPI.
*/
"IDN: 123: unexpected M_DATA packets for "
break;
case M_FLUSH:
PR_STR("%s: M_FLUSH request (flush = %d)\n",
break;
case M_ERROR:
PR_STR("%s: M_ERROR (error = %d) coming through\n",
break;
default:
PR_STR("%s: unexpected DB_TYPE 0x%x\n",
break;
}
return (err);
}
/*
* ----------------------------------------------
* Not allowed to enqueue messages! Only M_DATA messages
* can be enqueued on the write stream.
* ----------------------------------------------
*/
static void
{
register int cmd;
int error = 0;
int argsize;
/*
* Intercept DLPI ioctl's.
*/
if (VALID_DLPIOP(cmd)) {
goto done;
}
/*
* Validate expected arguments.
*/
if (!VALID_IDNIOCTL(cmd)) {
goto done;
} else if (!VALID_NDOP(cmd)) {
if (error != 0) {
PR_STR("%s: idnioc(cmd = 0x%x) miocpullup "
goto done;
}
}
switch (cmd) {
case IDNIOC_LINK:
break;
case IDNIOC_UNLINK:
break;
case IDNIOC_MEM_RW:
break;
case IDNIOC_PING:
break;
case ND_SET:
IDN_GUNLOCK();
break;
}
IDN_GUNLOCK();
return;
case ND_GET:
IDN_GUNLOCK();
break;
}
IDN_GUNLOCK();
return;
default:
break;
}
done:
if (error == 0)
else
}
/*
* asynchronously that come via BBSRAM. This is necessary
* since we can't process them from within the context of
* the interrupt handler in which idn_sigbhandler() is
* called.
*/
static void
{
PR_PROTO("%s: KICKED OFF (sigbintr pointer = 0x%p)\n",
PR_PROTO("%s: AWAKENED (busy = %d)\n",
}
break;
}
"IDN: 124: sigblk for CPU ID %d "
continue;
}
PR_PROTO("%s: sigblk mbox flag (%d) != BUSY (%d)\n",
continue;
}
/*
* The sb_busy bit is set and the mailbox flag
* indicates BUSY also, so we effectively have things locked.
* So, we can drop the critical sb_mutex which we want to
* do since it pushes us to PIL 14 while we hold it and we
* don't want to run at PIL 14 across IDN code.
*/
PR_PROTO("%s: sigblk mbox length (%d) != "
sizeof (idnsb_data_t));
goto sberr;
}
#ifdef DEBUG
"IDN: 102: driver disabled "
"- check OBP environment "
"(idn-smr-size)");
#else /* DEBUG */
"!IDN: 102: driver disabled "
"- check OBP environment "
"(idn-smr-size)");
#endif /* DEBUG */
goto sberr;
}
case SSI_LINK:
{
if (slp.master_pri < 0) {
} else if (slp.master_pri > 0) {
/*
* If I'm already in a IDN network,
* then my vote priority is set to
* the max, otherwise it's one-less.
*/
pri--;
IDN_GUNLOCK();
} else {
}
PR_PROTO("%s: SSI_LINK(cpuid = %d, domid = %d, "
"pri = %d (req = %d), t/o = %d)\n",
break;
}
case SSI_UNLINK:
{
PR_PROTO("%s: SSI_UNLINK(c = %d, d = %d, bs = 0x%x, "
"f = %d, is = 0x%x, t/o = %d)\n",
for (d = 0; d < MAX_DOMAINS; d++) {
xdp = &idn_domain[d];
!DOMAIN_IN_SET(domset, d))
continue;
break;
}
}
for (d = 0; d < MAX_DOMAINS; d++) {
xdp = &idn_domain[d];
!DOMAIN_IN_SET(domset, d))
continue;
break;
}
}
goto sberr;
} else {
}
case SSIFORCE_OFF:
break;
case SSIFORCE_SOFT:
break;
case SSIFORCE_HARD:
break;
default:
goto sberr;
}
break;
}
case SSI_INFO:
if (rv != 0) {
}
break;
default:
ASSERT(0);
break;
}
if (GET_IDNKERR_ERRNO(sep) != 0) {
#ifdef DEBUG
"IDN: 125: op (%s) failed, returning "
"(%d/0x%x [%d, %d, %d])",
#else /* DEBUG */
"!IDN: 125: op (%s) failed, returning "
"(%d/0x%x [%d, %d, %d])",
#endif /* DEBUG */
"INFO" : "UNKNOWN",
}
PR_PROTO("%s: returning errno = %d, idnerr = %d, "
"params = [%d, %d, %d]\n",
/*
* Set flag which kicks off response to SSP.
*/
}
/*
* Wake up the dude that killed us!
*/
thread_exit();
}
/*
* Create the thread that will service sigb interrupts.
*/
static void
{
if (idn.sigb_threadp) {
"IDN: 126: sigbhandler thread already "
return;
}
}
static void
{
if (idn.sigb_threadp) {
}
}
/*ARGSUSED0*/
static uint_t
{
}
return (DDI_INTR_CLAIMED);
}
static void
{
int sigb_lock = 0;
/*
* Not a valid IDN command. Just bail out.
*/
return;
}
SET_IDNKERR_ERRNO(sep, 0);
/*
* Hmmm...weird, the ACK bit is set.
*/
goto sigb_done;
}
/*
* Couldn't get the lock. Driver is either
* not quite all the way up or is shutting down
* for some reason. Caller should spin again.
*/
goto sigb_done;
}
sigb_lock = 1;
goto sigb_done;
}
goto sigb_done;
}
/*
* The sb_busy bit is set and the mailbox flag
* indicates BUSY also, so we effectively have things locked.
* So, we can drop the critical sb_mutex which we want to
* do since it pushes us to PIL 14 while we hold it and we
* don't want to run at PIL 14 across IDN code.
*
* Send interrupt to cause idn_sigbhandler_thread to wakeup.
* We cannot do wakeup (cv_signal) directly from here since
* we're executing from a high-level (14) interrupt.
*/
if (GET_IDNKERR_ERRNO(sep) != 0) {
}
if (sigb_lock)
}
static int
{
int count, d;
case IDNGS_OFFLINE:
PR_PROTO("%s: idn_state (%s) = INACTIVE\n",
break;
case IDNGS_IGNORE:
IDN_GUNLOCK();
return (EIO);
default:
PR_PROTO("%s: idn_state (%s) = ACTIVE\n",
break;
}
/*
* Need to drop idn.grwlock before acquiring domain locks.
*/
IDN_GUNLOCK();
count = 0;
for (d = 0; d < MAX_DOMAINS; d++) {
dp = &idn_domain[d];
continue;
IDN_DLOCK_SHARED(d);
IDN_DUNLOCK(d);
continue;
}
count++;
if (d == local_id) {
PR_PROTO("%s: domid %d is LOCAL (cpuid = %d)\n",
}
if (d == master_id) {
PR_PROTO("%s: domid %d is MASTER (cpuid = %d)\n",
}
IDN_DUNLOCK(d);
}
return (0);
}
/*
* ----------------------------------------------
* ndd param support routines.
* - Borrowed from tcp.
* ----------------------------------------------
*/
static void
{
IDN_GUNLOCK();
}
/*ARGSUSED*/
static int
{
/*
* lock grabbed before calling nd_getset.
*/
return (0);
}
/*ARGSUSED*/
static int
{
char *end;
/*
* lock grabbed before calling nd_getset.
*/
return (EINVAL);
#ifdef DEBUG
"IDN: 102: driver disabled "
"- check OBP environment "
"(idn-smr-size)");
#else /* DEBUG */
"!IDN: 102: driver disabled "
"- check OBP environment "
"(idn-smr-size)");
#endif /* DEBUG */
return (EACCES);
}
return (0);
}
static int
{
register int i;
char *p;
/*
* Don't advertise in non-DEBUG parameters.
*/
for (i = 0; idn_param_debug_only[i]; i++) {
p = idn_param_debug_only[i];
break;
}
if (idn_param_debug_only[i])
continue;
/*
* Do not register a "set" function for
* read-only parameters.
*/
for (i = 0; idn_param_read_only[i]; i++) {
p = idn_param_read_only[i];
break;
}
if (idn_param_read_only[i])
else
return (-1);
}
}
}
return (-1);
}
return (-1);
}
NULL, MBXTBL_PART_REPORT)) {
return (-1);
}
NULL, MBXTBL_FULL_REPORT)) {
return (-1);
}
return (-1);
}
return (-1);
}
return (-1);
}
return (-1);
}
idn_set_net_binding, NULL)) {
return (-1);
}
return (0);
}
/*ARGSUSED*/
static int
{
long net;
/*
* lock grabbed before calling nd_getset.
*/
return (EINVAL);
*cpup++ = '\0';
return (EINVAL);
(!VALID_CPUID(cpuid) ||
return (EINVAL);
return (0);
}
/*ARGSUSED*/
static int
{
int c;
/*
* lock grabbed before calling nd_getset.
*/
(void) mi_mpprintf(mp,
"IDN network interfaces/channels active = %d",
return (0);
for (c = 0; c < IDN_MAX_NETS; c++) {
int bc;
continue;
if (c < 10)
else
}
return (0);
}
static int
{
int rv;
int pri;
else
PR_DRV("%s: domid = %d, cpuid = %d, pri = %d\n",
return (rv);
}
static int
{
PR_DRV("%s: domid = %d, cpuid = %d, force = %d\n",
if (domid == IDN_NIL_DOMID)
if (VALID_DOMAINID(domid)) {
PR_PROTO("%s: ERROR: invalid cpuid "
"(%d) for domain (%d) [cset = 0x%x.x%x]\n",
}
} else if (VALID_CPUID(cpuid)) {
for (d = 0; d < MAX_DOMAINS; d++) {
xdp = &idn_domain[d];
continue;
break;
}
}
return (0);
case SSIFORCE_OFF:
break;
case SSIFORCE_SOFT:
break;
case SSIFORCE_HARD:
break;
default:
PR_PROTO("%s: invalid force parameter \"%d\"",
return (EINVAL);
}
return (rv);
}
static int
{
int ocpuid;
"IDN: %s: no valid domain ID or CPU ID given",
proc);
return (EINVAL);
}
if (domid == IDN_NIL_DOMID)
"IDN: %s: no valid target CPU specified",
proc);
return (EINVAL);
}
if (cpuid == IDN_NIL_DCPU)
/*
* XXX - Need a special PING IDN command.
*/
return (0);
}
/*
* ----------------------------------------------
*/
static void
{
int i;
return;
for (i = 0; i < (IDNOP_CACHE_SIZE-1); i++)
}
static void
{
return;
if (!IDNOP_IN_CACHE(dwl))
}
}
/*
* Reset the dop_errset field in preparation for an
* IDN operation attempt. This is only called from
* idn_link() and idn_unlink().
*/
void *
{
/*
* Clear any outstanding error ops in preparation
*/
} else {
}
return (dwl);
}
/*
* Anybody waiting on a opflag operation for any one
* of the domains in domset, needs to be updated to
* additionally wait for new domains in domset.
* This is used, for example, when needing to connect
* to more domains than known at the time of the
* original request.
*/
void
{
return;
}
}
/*
* Mechanism to wakeup any potential users which may be waiting
* don't update dop_errset unless there was no previous error.
*/
void
{
int do_wakeup = 0;
/*
* If there are no waiters, or nobody is waiting for
* the particular domainset in question, then
* just bail.
*/
PR_PROTO("%s: NO waiters exist (domset=0x%x)\n",
return;
}
int d;
continue;
if (opflag == IDNOP_ERROR) {
if (sep) {
for (d = 0; d < MAX_DOMAINS; d++) {
if (!DOMAIN_IN_SET(dset, d))
continue;
(short)GET_IDNKERR_ERRNO(sep);
}
}
}
/*
* Check if all the domains are spoken for that
* a particular waiter may have been waiting for.
* If there's at least one, we'll need to broadcast.
*/
do_wakeup++;
}
if (do_wakeup > 0)
}
void
{
if (IDNOP_IN_CACHE(dwl)) {
} else {
}
} else {
hw;
break;
}
}
/*
* Recompute domainset for which waiters might be waiting.
* It's possible there may be other waiters waiting for
* the same domainset that the current waiter that's leaving
* may have been waiting for, so we can't simply delete
* the leaving waiter's domainset from dop_domset.
*/
}
/*
* Wait until the specified operation succeeds or fails with
* respect to the given domains. Note the function terminates
* if at least one error occurs.
* asynchronously and we need some way of waiting to find out
* if it indeed completed.
* Timeout value is received indirectly from the SSP and
* represents seconds.
*/
int
{
ASSERT(wait_timeout > 0);
break;
switch (rv) {
case -1:
/*
* timed out
*/
"!IDN: 129: %s operation timed out",
"UNKNOWN");
/*FALLTHROUGH*/
case 0:
/*
* signal, e.g. kill(2)
*/
err = 1;
break;
default:
break;
}
}
rv = 0;
} else {
/*
* Op failed for some domains or we were awakened.
*/
}
return (rv);
}
/*
* --------------------------------------------------
* Return any valid (& ready) cpuid for the given board based on
* the given cpuset.
* --------------------------------------------------
*/
int
{
int base_cpuid;
board *= ncpu_board;
for (base_cpuid = board;
base_cpuid++)
return (base_cpuid);
return (-1);
}
void
{
register int i;
dp->dcookie_err = 0;
PR_PROTO("%s: WARNING: MSG timerq not empty (count = %d)\n",
}
for (i = 0; i < NCPU; i++)
}
int
{
int c, new_cpuid;
if (!VALID_DOMAINID(domid)) {
PR_PROTO("%s: INVALID domainid (%d) "
"[cpuid = %d, ticket = 0x%x]\n",
return (-1);
}
PR_PROTO("%s:%d: domain already OPEN (state = %s)\n",
return (1);
}
else
} else {
}
if (new_cpuid == IDN_NIL_DCPU) {
PR_PROTO("%s:%d: WARNING: invalid cpuid (%d) specified\n",
return (-1);
}
PR_STATE("%s:%d: requested cpuid %d, assigning cpuid %d\n",
for (c = 0; c < NCPU; c++)
/*
* We're attempting to connect to our first domain.
* Recheck our local hardware configuration before
* we go any further in case it changed due to a DR,
* and update any structs dependent on this.
* ASSUMPTION:
* IDN is unlinked before performing any DRs.
*/
if (get_hw_config(&local_hw)) {
"IDN: 118: hardware config not appropriate");
IDN_GUNLOCK();
return (-1);
}
}
IDN_GUNLOCK();
} else {
/*
* mailboxes in its idn_domain[] entry.
*/
}
PR_PROTO("%s:%d: new domain (cpu = %d, vote = 0x%x)\n",
return (0);
}
/*
* The local domain never "closes" itself unless the driver
* is doing a idndetach. It will be reopened during idnattach
* when idn_domains_init is called.
*/
void
{
PR_PROTO("%s:%d: DOMAIN ALREADY CLOSED!\n",
return;
}
(void) idn_retry_terminate(token);
IDN_GUNLOCK();
}
}
"!IDN: 142: link (domain %d, CPU %d) disconnected",
}
/*
* -----------------------------------------------------------------------
*/
static void
{
register int i, d;
for (d = 0; d < MAX_DOMAINS; d++) {
dp = &idn_domain[d];
IDN_DLOCK_EXCL(d);
IDN_GUNLOCK();
IDN_DUNLOCK(d);
}
/*
* Update local domain information.
*/
ASSERT(d == 0);
i = -1;
for (d = 0; d < NCPU; d++) {
}
/*
* Setting the state for ourselves is only relevant
* for loopback performance testing. Anyway, it
* makes sense that we always have an established
* connection with ourself regardless of IDN :-o
*/
IDN_GUNLOCK();
}
static void
{
register int d;
for (d = 0; d < MAX_DOMAINS; d++) {
dp = &idn_domain[d];
}
}
/*
* -----------------------------------------------------------------------
*/
static void
{
sizeof (idn_retry_job_t),
}
static void
{
return;
}
/*
* -----------------------------------------------------------------------
*/
static void
{
sizeof (idn_timer_t),
}
static void
{
return;
}
{
return (tp);
}
void
{
return;
}
void
{
}
void
{
}
/*
* Dequeue all the timers of the given subtype from the
* given timerQ. If subtype is 0, then dequeue all the
* timers.
*/
{
return (NULL);
if (!type) {
} else {
int count;
do {
} else {
}
}
} while (--count > 0);
}
if (tphead) {
}
return (tphead);
}
{
/*
* Assign a unique non-zero 8-bit cookie to this timer
* if the caller hasn't already preassigned one.
*/
/*
* Calculated cookie must never conflict
* with the public timer cookie.
*/
}
/*
* First have to remove old timers of the
* same type and cookie, and get rid of them.
*/
} else {
/*
* Put me at the end of the list.
*/
}
PR_TIMER("%s: started %s timer (domain = %d, cookie = 0x%x)\n",
if (otp)
(void) idn_timer_stopall(otp);
return (tcookie);
}
/*
* Stop all timers of the given subtype.
* If subtype is 0, then stop all timers
* in this timerQ.
*/
void
{
return;
}
#ifdef DEBUG
PR_TIMER("%s: found no %s (cookie = 0x%x) "
"timers (count=%d)!!\n",
#endif /* DEBUG */
if (tphead)
(void) idn_timer_stopall(tphead);
}
int
{
int count = 0;
int nonactive;
nonactive = 0;
if (tp) {
/*
* Circle should have been broken.
*/
}
count++;
nonactive++;
PR_TIMER("%s: bad %s untimeout (domain=%d)\n",
} else {
PR_TIMER("%s: good %s untimeout (domain=%d)\n",
}
/*
* There are two possible outcomes from
* the untimeout(). Each ultimately result
* in us having to free the timeout structure.
*
* 1. We successfully aborted a timeout call.
*
* 2. We failed to find the given timer. He
* probably just fired off.
*/
}
PR_TIMER("%s: stopped %d of %d %s timers\n",
return (count);
}
void
{
/*
* We've already been dequeued.
*/
} else {
/*
* We're still in the queue, get out.
*/
}
}
}
/*
* -----------------------------------------------------------------------
*/
/*ARGSUSED*/
static int
{
register int p, nfree;
(void) mi_mpprintf(mp,
"IDN slabpool not initialized (masterid = %d)",
IDN_GET_MASTERID());
return (0);
}
(void) mi_mpprintf(mp,
"IDN slabpool (ntotal_slabs = %d, nalloc = %d, "
"npools = %d)",
register int d, s;
domset = 0;
short dd;
if (dd != (short)IDN_NIL_DOMID)
}
dsetstr[0] = '\0';
if (domset) {
for (d = 0; d < MAX_DOMAINS; d++) {
if (!DOMAIN_IN_SET(domset, d))
continue;
if (dsetstr[0] == '\0')
else
dsetstr, d);
}
}
if (p < 10)
dsetstr);
else
dsetstr);
}
return (0);
}
/*ARGSUSED*/
static int
{
register int d, cnt;
int spl;
return (0);
}
return (0);
}
cnt = 0;
;
cnt++;
}
}
if (cnt == 0)
return (0);
for (d = 0; d < MAX_DOMAINS; d++)
if (bufcount[d]) {
if (d < 10)
d, bufcount[d]);
else
d, bufcount[d]);
}
return (0);
}
static const char *
_get_spaces(int w, int s, int W)
{
static const char *const _spaces[] = {
"", /* 0 */
" ", /* 1 */
" ", /* 2 */
" ", /* 3 */
" ", /* 4 */
" ", /* 5 */
" ", /* 6 */
" ", /* 7 */
" ", /* 8 */
" ", /* 9 */
" ", /* 10 */
" ", /* 11 */
" ", /* 12 */
" ", /* 13 */
" ", /* 14 */
" ", /* 15 */
" ", /* 16 */
" ", /* 17 */
" ", /* 18 */
" ", /* 19 */
};
return (_spaces[w+s-W]);
}
#define _SSS(X, W, w, s) \
(((w) >= (W)) && (X)) ? _get_spaces((w), (s), (W))
static const char *
{
int diff;
while (sz-- > 0) {
maxnbl--;
maxnbl--;
np++;
}
}
#define DECSPACE(n, w, s) \
_get_spaces((w), (s), 1))
#define DECSPACE16(n, w, s) \
_get_spaces((w), (s), 1))
DECSPACE16(*(ushort_t *) \
1, 1), \
DECSPACE16(*(ushort_t *) \
1, 5), \
/*ARGSUSED*/
static int
{
if (IDN_GLOCK_TRY_SHARED() == 0) {
return (0);
}
(void) mi_mpprintf(mp,
"WARNING: Local domain is not master, "
"ASSUMING idn.smr.vaddr.");
}
if (map) {
(void *)map);
} else {
goto repdone;
}
goto repdone;
}
for (c = 0; c < IDN_MAX_NETS; c++) {
continue;
}
(void) mi_mpprintf(mp,
"Channel %d ---------------------------"
"--------------------------"
"-----------------------------", c);
(void) mi_mpprintf(mp,
" Domain Header "
"busy");
register int busy_count;
if ((cp == MBXTBL_PART_REPORT) &&
continue;
subdomid++) {
if (subdomid == 0)
(void) mi_mpprintf(mp,
" %x.%x-%d%s%s",
/*CONSTCOND*/
"-- unused --");
else
(void) mi_mpprintf(mp,
" .%x-%d%s%s",
subdomid, c,
/*CONSTCOND*/
"-- unused --");
continue;
}
busy_count = 0;
for (n = 0; n < IDN_MMBOX_NUMENTRIES; n++) {
busy_count++;
}
if (subdomid == 0) {
(void) mi_mpprintf(mp,
" %x.%x-%d%s%p%s%x%s/ %x%s"
"%d%s/ %d%s%x%s%p%s%d%s",
/*CONSTCOND*/
} else {
(void) mi_mpprintf(mp,
" .%x-%d%s%p%s%x%s/ %x%s"
"%d%s/ %d%s%x%s%p%s%d%s",
subdomid, c,
/*CONSTCOND*/
}
}
}
}
IDN_GUNLOCK();
return (0);
}
/*ARGSUSED*/
static void
{
register int c;
return;
}
for (c = 0; c < IDN_MAX_NETS; mmp++, c++) {
int mm_count;
continue;
}
(int)mmp->mm_channel,
/*CONSTCOND*/
(void *)mmp->mm_smr_mboxp,
(void *)mmp->mm_smr_readyp,
(void *)mmp->mm_smr_activep,
}
}
/*ARGSUSED2*/
static int
{
int domid;
int header = 0;
/*
* don't bother printing him.
*/
continue;
continue;
}
if (!header) {
(void) mi_mpprintf(mp,
"Domain Chan PktCntK "
"PktDrop SMRMbox "
"ReadyPtr "
header = 1;
}
"snd");
"rcv");
(void) mi_mpprintf(mp,
" ---------------------------------------"
"------------------------"
"----------------------------");
}
if (!header)
return (0);
}
/*ARGSUSED*/
static int
{
if (IDN_SYNC_TRYLOCK() == 0) {
return (0);
}
if (IDN_GLOCK_TRY_SHARED() == 0) {
return (0);
}
dbp = alt_dbuffer;
masterid = IDN_GET_MASTERID();
rempfn_upper = rempfn_lower = 0;
} else {
}
(void) mi_mpprintf(mp,
" [ mbox area = 0x%x.%x Bytes, "
"iobuf area = 0x%x.%x Bytes ]",
(void) mi_mpprintf(mp,
"\nIDNnet (local domain [id:%d] [name:%s] is %s)",
"SLAVE");
nactive = 0;
for (i = 0; i < IDN_MAX_NETS; i++) {
nactive++;
}
"Active = %d, Max = %d)",
/*
* During connect domains can possibly be in ds_connected
* while still in ds_trans_on. Only once they leave ds_trans_on
* are they really connected.
*/
retryset = 0;
int domid;
if (VALID_DOMAINID(domid)) {
}
}
if (masterid == IDN_NIL_DOMID) {
} else {
(void) mi_mpprintf(mp,
else
if (masterid < 10)
else
}
} else {
int d;
(void) mi_mpprintf(mp,
for (d = 0; d < MAX_DOMAINS; d++) {
dp = &idn_domain[d];
continue;
else
if (d < 10)
d, dbp,
else
d, dbp,
}
}
} else {
int d;
for (d = 0; d < MAX_DOMAINS; d++) {
dp = &idn_domain[d];
continue;
else
if (d < 10)
d, dbp);
else
d, dbp);
}
}
/*CONSTCOND*/
} else {
(void) mi_mpprintf(mp,
" "
"%x: x_set =%s0x%x, r_set =%s0x%x",
}
}
/*CONSTCOND*/
} else {
(void) mi_mpprintf(mp,
" "
"%x: x_set =%s0x%x, r_set =%s0x%x",
}
}
IDN_GUNLOCK();
if (dbuffer) {
}
return (0);
}
/*ARGSUSED*/
static int
{
int d, nchan;
if (IDN_SYNC_TRYLOCK() == 0) {
return (0);
}
if (IDN_GLOCK_TRY_SHARED() == 0) {
return (0);
}
dbp = alt_dbuffer;
else
for (d = 0; d < MAX_DOMAINS; d++) {
if (DOMAIN_IN_SET(domset, d) == 0)
continue;
dp = &idn_domain[d];
continue;
if (IDN_DLOCK_TRY_SHARED(d) == 0) {
if (d < 10)
(void) mi_mpprintf(mp,
"Domain %d (0x%p) busy...",
d, (void *)dp);
else
(void) mi_mpprintf(mp,
"Domain %d (0x%p) busy...",
d, (void *)dp);
continue;
}
IDN_DUNLOCK(d);
continue;
}
if (d < 10)
d, (void *)dp);
else
d, (void *)dp);
else
if (dbuffer)
else
if (dbuffer)
else
(void) mi_mpprintf(mp,
" MsgTimer = %s (cnt = %d)",
? "active" : "idle",
"(lastcpu = %d, cpuindex = %d)",
"(ioerr = %d, iochk = %d, iowanted = %d)",
} else {
(void) mi_mpprintf(mp,
" Dsync = %s "
"(x_set = 0x%x, r_set = 0x%x)",
}
"NO");
dp->dcookie_errcnt);
IDN_DUNLOCK(d);
}
IDN_GUNLOCK();
if (dbuffer) {
}
return (0);
}
struct snoop_buffer {
int snoop_index;
static char _bd2hexascii[] = {
'0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
};
{ \
if (idn_snoop) { \
mutex_enter(&snoop_mutex); \
if (snoop_data == NULL) { \
snoop_data = (struct snoop_buffer *) \
~0xf); \
} \
snoop_index++; \
mutex_exit(&snoop_mutex); \
} \
}
/*
* Allocate the circular buffers to be used for
* DMV interrupt processing.
*/
static int
{
int i, c;
"IDN: 130: IDN DMV handler already initialized");
return (-1);
}
/*
* This memory will be touched by the low-level
* DMV trap handler for IDN.
*/
len = sizeof (idn_dmv_data_t);
PR_PROTO("%s: sizeof (idn_dmv_data_t) = %lu\n",
proc, sizeof (idn_dmv_data_t));
sizeof (idn_dmv_data_t),
sizeof (uint64_t));
ivp_offset = 0;
/*
* The buffer queues are allocated per-cpu.
*/
idn_iv_queue[c] = ivp;
ivp_offset += sizeof (idn_dmv_msg_t);
ivp_offset += sizeof (idn_dmv_msg_t);
}
}
/*
* Make sure everything is out there before
* we effectively set it free for use.
*/
(caddr_t)idn_dmv_data)) {
return (-1);
}
return (0);
}
static void
{
return;
}
/*
* High-level (soft interrupt) handler for DMV interrupts
*/
/*ARGSUSED0*/
static uint_t
{
#ifdef DEBUG
int count = 0;
#endif /* DEBUG */
/*
* Clear the synchronization flag to indicate that
* processing has started. As long as idn_dmv_active
* is non-zero, idn_dmv_handler will queue work without
* initiating a soft interrupt. Since we clear it
* first thing at most one pil-interrupt for IDN will
* queue up behind the currently active one. We don't
* want to clear this flag at the end because it leaves
* a window where an interrupt could get lost (unless it's
* pushed by a subsequent interrupt). The objective in
* doing this is to prevent exhausting a cpu's intr_vec
* structures with interrupts of the same pil level.
*/
/*
* As long as there's stuff that's READY in the
* queue, keep processing.
*/
#ifdef DEBUG
if ((mtype & IDNP_MSGTYPE_MASK) == 0) {
}
count++;
PR_XDC("%s:%d:%d RECV: scpu = %d, msg = 0x%x(%s)\n",
PR_XDC("%s:%d:%d R-DATA: a0 = 0x%x, a1 = 0x%x\n",
PR_XDC("%s:%d:%d R-DATA: a2 = 0x%x, a3 = 0x%x\n",
#endif /* DEBUG */
/*
* The only time we receive pure
* data messages at this level is
* to wake up the channel server.
* Since this is often an urgent
* request we'll do it from here
* instead of waiting for a proto
* server to do it.
*/
} else {
/*
* If the allocation fails, just drop
* the message and get on with life.
* If memory pressure is this great then
* dropping this message is probably
* the least of our worries!
*/
if (jp) {
}
}
if (jp)
} else {
}
}
return (DDI_INTR_CLAIMED);
}
void
{
"IDN: 134: unable to mark boardset (0x%x) AWOL\n",
boardset);
return;
}
if (boardset == 0) {
PR_PROTO("%s: AWOL BOARDSET is 0, NO EVENT <<<<<<<<<<<<<<<\n",
proc);
return;
} else {
}
}
void
{
"IDN: 134: unable to mark boardset (0x%x) AWOL\n",
boardset);
return;
}
if (boardset == 0) {
PR_PROTO("%s: AWOL BOARDSET is 0, NO EVENT <<<<<<<<<<<<<<<\n",
proc);
return;
} else {
}
}
static void
{
#ifdef kstat
sizeof (struct idn_gkstat_named) / sizeof (kstat_named_t),
KSTAT_FLAG_PERSISTENT)) == NULL) {
#else
sizeof (struct idn_gkstat_named) /
sizeof (kstat_named_t), 0)) == NULL) {
#endif /* kstat */
IDNNAME, "kstat_create failed");
return;
}
}
static void
{
}
static int
{
if (rw == KSTAT_WRITE) {
} else {
}
return (0);
}
#ifdef DEBUG
#endif /* DEBUG */
static int
{
int cpuid;
register int n, idx;
char *smraddr;
#define RANDOM(a, b) \
(((a) >= (b)) ? \
RANDOM_INIT();
return (EINVAL);
}
IDN_GUNLOCK();
"IDN: Local domain restoring original state %s(%d)",
IDN_GUNLOCK();
}
/*
* Just requested AWOL.
*/
if (num == 0)
return (0);
/*
* Default READ only.
*/
if (rw == 1) {
/*
* WRITE only.
*/
} else if (rw == 2) {
/*
*/
break;
}
"IDN: blksize (%d) too large", blksize);
return (EINVAL);
}
}
"IDN: starting %s of %d blocks of %d bytes each...",
for (n = 0; n < num; n++) {
else
#ifdef DEBUG
#endif /* DEBUG */
switch (rw) {
case 0:
break;
case 1:
break;
case 2:
if (n & 1)
else
break;
default:
break;
}
if (!(n % 1000)) {
int rv;
mutex_enter(&slock);
mutex_exit(&slock);
if (rv == 0)
break;
}
}
cv_destroy(&scv);
if (ibuf)
if (obuf)
return (0);
}
void
{
str[0] = '\0';
inum &= ~IDNP_ACKNACK_MASK;
return;
}
if (inum == 0) {
} else {
if (inum < IDN_NUM_MSGTYPES)
else
if (acknack) {
else
}
}
}
{
register int c;
bset = 0;
for (c = 0; c < NCPU; )
if (CPU_IN_SET(portset, c)) {
c = (c + 4) & ~3;
} else {
c++;
}
return (bset);
}
void
{
register int c, n;
buffer[0] = '\0';
for (c = n = 0; c < NCPU; c++) {
if (!CPU_IN_SET(cset, c))
continue;
#ifdef DEBUG
PR_PROTO("************* WARNING WARNING WARNING\n");
PR_PROTO("cpuset2str(cpu = %d) buffer "
"OVERFLOW <<<<<<\n", c);
PR_PROTO("*******************************\n");
return;
}
#endif /* DEBUG */
if (n == 0)
else
n++;
}
}
void
{
/*
* Since domainset_t and boardset_t are the
* same (max = MAX_DOMAINS = MAX_BOARDS) we
* can just overload boardset2str().
*/
}
void
{
}
void
{
int n, i;
buffer[0] = '\0';
for (i = n = 0; i < maxnum; i++) {
if ((mask & (1 << i)) == 0)
continue;
if (n == 0)
else
n++;
}
}
int
{
extern kmutex_t xc_sys_mutex;
extern int xc_spl_enter[];
if (idn_snoop) {
int bd;
} else {
}
bd = -1;
else
}
/*
* For NEGO messages we send the remote domain the cookie we
* expect it to use in subsequent messages that it sends
* to us (dcookie_recv).
* For other messages, we must use the cookie that the
* remote domain assigned to us for sending (dcookie_send).
*/
else
if (tcpuid == IDN_NIL_DCPU) {
return (-1);
}
xc_spl_enter[cpuid] = 0;
return (rv);
}
void
{
int d;
for (d = 0; d < MAX_DOMAINS; d++) {
if (!DOMAIN_IN_SET(domset, d))
continue;
dp = &idn_domain[d];
continue;
}
}
/*
* Locate the idn-smr-size property to determine the size of the SMR
*/
static int
{
int found = 0;
int len;
struct smraddr {
} smraddr;
/*
* idn-smr-size is a property of the "memory" node and
* is defined in megabytes.
*/
if (nodeid != OBP_NONODE) {
found |= PROM_SMRSIZE;
}
found |= PROM_SMRADDR;
}
}
if (found != PROM_SMRPROPS) {
if ((found & PROM_SMRSIZE) == 0)
"IDN: 136: \"%s\" property not found, "
"disabling IDN",
"IDN: 136: \"%s\" property not found, "
"disabling IDN",
return (-1);
}
if (smrsize == 0) {
} else if (smrsize > IDN_SMR_MAXSIZE) {
PR_SMR("%s: IDN DISABLED (idn_smr_size too big %d > %d MB)\n",
"!IDN: 138: SMR size (%dMB) is too big (max = %dMB), "
"disabling IDN",
smrsize = 0;
} else {
found &= ~PROM_SMRSIZE;
}
if (obpsize == 0) {
if (smrsize > 0) {
"SMR is 0 length");
}
"!IDN: 140: OBP region (%ld B) smaller "
"than requested size (%ld B)",
"!IDN: 141: OBP region (0x%lx) not on (0x%x) "
} else {
found &= ~PROM_SMRADDR;
}
return (found ? -1 : 0);
}
void
{
return;
}
}
void
{
return;
}
}
void
{
int c;
CPUSET_ZERO(*csetp);
for (c = 0; c < 32; c++) {
if (lower & (1 << c)) {
CPUSET_ADD(*csetp, c);
}
}
}
}
{
int c;
for (c = 0; c < 32; c++)
if (CPU_IN_SET(cset, c))
set |= 1 << c;
return (set);
}
{
int c;
for (c = 32; c < NCPU; c++)
if (CPU_IN_SET(cset, c))
return (set);
}
#ifdef DEBUG
int
{
static int xx = 0;
xx++;
} else {
}
bd = -1;
else
PR_XDC("%s:%d:%d SENT: scpu = %d, msg = 0x%x(%s)\n",
PR_XDC("%s:%d:%d S-DATA: a1 = 0x%x, a2 = 0x%x\n",
PR_XDC("%s:%d:%d S-DATA: a3 = 0x%x, a4 = 0x%x\n",
if (rv != 0) {
PR_XDC("%s:%d:%d: WARNING: idnxdc(cpu %d) FAILED\n",
}
return (rv);
}
{
PR_ALLOC("%s: ptr 0x%p, struct(%s), size = %d\n",
return (ptr);
}
void
{
PR_ALLOC("%s: ptr 0x%p, struct(%s), size = %d\n",
}
#endif /* DEBUG */