diff options
Diffstat (limited to 'usr/src/uts')
82 files changed, 94 insertions, 42401 deletions
diff --git a/usr/src/uts/common/io/consconfig_dacf.c b/usr/src/uts/common/io/consconfig_dacf.c index edeb0f93d2..444cb9ce33 100644 --- a/usr/src/uts/common/io/consconfig_dacf.c +++ b/usr/src/uts/common/io/consconfig_dacf.c @@ -25,6 +25,10 @@ */ /* + * Copyright 2019 Peter Tribble. + */ + +/* * This module performs two functions. First, it kicks off the driver loading * of the console devices during boot in dynamic_console_config(). * The loading of the drivers for the console devices triggers the @@ -1533,29 +1537,6 @@ dynamic_console_config(void) consconfig_load_drivers(consconfig_sp); consconfig_sp->cons_input_type = cons_get_input_type(consconfig_sp); - /* - * This is legacy special case code for the "cool" virtual console - * for the Starfire project. Starfire has a dummy "ssp-serial" - * node in the OBP device tree and cvc is a pseudo driver. - */ - if (consconfig_sp->cons_stdout_path != NULL && stdindev == NODEV && - strstr(consconfig_sp->cons_stdout_path, "ssp-serial")) { - /* - * Setup the virtual console driver for Starfire - * Note that console I/O will still go through prom for now - * (notice we don't open the driver here). The cvc driver - * will be activated when /dev/console is opened by init. - * During that time, a cvcd daemon will be started that - * will open the cvcredirection driver to facilitate - * the redirection of console I/O from cvc to cvcd. - */ - rconsvp = i_consconfig_createvp(CVC_PATH); - if (rconsvp == NULL) - goto done; - rconsdev = rconsvp->v_rdev; - goto done; - } - rwsconsvp = consconfig_sp->cons_wc_vp; rwsconsdev = consconfig_sp->cons_wc_vp->v_rdev; @@ -1574,7 +1555,6 @@ dynamic_console_config(void) mousedev, kbddev, fbdev, rconsdev); flush_deferred_console_buf(); -done: consconfig_sp->cons_initialized = B_TRUE; } diff --git a/usr/src/uts/i86pc/sys/sbd_ioctl.h b/usr/src/uts/i86pc/sys/sbd_ioctl.h index 1eab543aa3..1ca9473dc2 100644 --- a/usr/src/uts/i86pc/sys/sbd_ioctl.h +++ b/usr/src/uts/i86pc/sys/sbd_ioctl.h @@ -26,6 +26,9 @@ * Copyright (c) 2010, Intel Corporation. * All rights reserved. */ +/* + * Copyright 2019 Peter Tribble. + */ #ifndef _SBD_IOCTL_H #define _SBD_IOCTL_H @@ -508,34 +511,6 @@ typedef struct { #define ESTC_NWSWITCH 1037 /* Cannot unconfigure I/O board: network switch failed */ -/* Starfire error codes */ - -#define ESTF_NONE 2000 /* No error */ -#define ESTF_GETPROP 2001 /* Cannot read property value */ -#define ESTF_GETPROPLEN 2002 /* Cannot determine property length */ -#define ESTF_BNUM 2003 /* Invalid board number */ -#define ESTF_CONFIGBUSY 2004 - /* Cannot proceed; Board is configured or busy */ -#define ESTF_NOCPUID 2005 /* No CPU specified for connect */ -#define ESTF_PROBE 2006 /* Firmware probe failed */ -#define ESTF_DEPROBE 2007 /* Firmware deprobe failed */ -#define ESTF_MOVESIGB 2008 /* Firmware move-cpu0 failed */ -#define ESTF_JUGGLE 2009 /* Cannot move SIGB assignment */ -#define ESTF_HASSIGB 2010 - /* Cannot disconnect CPU; SIGB is currently assigned */ -#define ESTF_SUPPORT 2011 /* Operation not supported */ -#define ESTF_DRVFAIL 2012 /* Device driver failure */ -#define ESTF_SETCPUVAL 2013 - /* Must specify a CPU on the given board */ -#define ESTF_NODEV 2014 /* No such device */ -#define ESTF_INTERBOARD 2015 - /* Memory configured with inter-board interleaving */ -#define ESTF_UNKPTCMD 2016 /* Unrecognized platform command */ -#define ESTF_NOTID 2017 /* drmach parameter is not a valid ID */ -#define ESTF_INAPPROP 2018 - /* drmach parameter is inappropriate for operation */ -#define ESTF_INTERNAL 2019 /* Unexpected internal condition */ - /* Daktari error codes */ #define EDAK_NONE 3000 /* no error */ diff --git a/usr/src/uts/sun4/os/intr.c b/usr/src/uts/sun4/os/intr.c index 8036ca5bcb..3a7143115d 100644 --- a/usr/src/uts/sun4/os/intr.c +++ b/usr/src/uts/sun4/os/intr.c @@ -25,6 +25,9 @@ /* * Copyright (c) 2013, Joyent, Inc. All rights reserved. */ +/* + * Copyright 2019 Peter Tribble. + */ #include <sys/sysmacros.h> #include <sys/stack.h> @@ -115,7 +118,6 @@ intr_init(cpu_t *cp) extern uint_t softlevel1(); init_ivintr(); - REGISTER_BBUS_INTR(); /* * Register these software interrupts for ddi timer. diff --git a/usr/src/uts/sun4/sys/cpu_sgnblk_defs.h b/usr/src/uts/sun4/sys/cpu_sgnblk_defs.h index 0b18ca88f3..9e1a125308 100644 --- a/usr/src/uts/sun4/sys/cpu_sgnblk_defs.h +++ b/usr/src/uts/sun4/sys/cpu_sgnblk_defs.h @@ -23,12 +23,13 @@ * Copyright 2004 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ +/* + * Copyright 2019 Peter Tribble. + */ #ifndef _CPU_SGNBLK_DEFS_H #define _CPU_SGNBLK_DEFS_H -#pragma ident "%Z%%M% %I% %E% SMI" - #ifdef __cplusplus extern "C" { #endif @@ -124,38 +125,6 @@ typedef union { extern void (*cpu_sgn_func)(ushort_t, uchar_t, uchar_t, int); - - -#ifdef _STARFIRE - -extern void register_bbus_intr(); -extern void cpu_sgn_mapin(int); -extern void cpu_sgn_mapout(int); -extern int cpu_sgn_exists(int); -extern ushort_t get_cpu_sgn(int); -extern uchar_t get_cpu_sgn_state(int); - -#define REGISTER_BBUS_INTR() register_bbus_intr() -#define CPU_SGN_MAPIN(cpuid) cpu_sgn_mapin(cpuid) -#define CPU_SGN_MAPOUT(cpuid) cpu_sgn_mapout(cpuid) -#define CPU_SGN_EXISTS(cpuid) cpu_sgn_exists(cpuid) -#define SGN_CPU_IS_OS(cpuid) (get_cpu_sgn(cpuid) == OS_SIG) -#define SGN_CPU_IS_OBP(cpuid) (get_cpu_sgn(cpuid) == OBP_SIG) -#define SGN_CPU_STATE_IS_DETACHED(cpuid) \ - (get_cpu_sgn_state(cpuid) == SIGST_DETACHED) - -#else - -#define REGISTER_BBUS_INTR() -#define CPU_SGN_MAPIN(cpuid) -#define CPU_SGN_MAPOUT(cpuid) -#define CPU_SGN_EXISTS(cpuid) (0) -#define SGN_CPU_IS_OS(cpuid) (0) -#define SGN_CPU_IS_OBP(cpuid) (0) -#define SGN_CPU_STATE_IS_DETACHED(cpuid) (0) - -#endif /* _STARFIRE */ - #endif /* _KERNEL */ #ifdef __cplusplus diff --git a/usr/src/uts/sun4u/Makefile.files b/usr/src/uts/sun4u/Makefile.files index 5cfcd6025f..a2b45242cb 100644 --- a/usr/src/uts/sun4u/Makefile.files +++ b/usr/src/uts/sun4u/Makefile.files @@ -22,6 +22,7 @@ # # Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. +# Copyright 2019 Peter Tribble. # # This Makefile defines all file modules for the directory uts/sun4u # and it's children. These are the source files which are sun4u @@ -160,7 +161,6 @@ SHA1_OBJS += sha1_asm.o TODMOSTEK_OBJS += todmostek.o TODDS1287_OBJS += todds1287.o TODDS1337_OBJS += todds1337.o -TODSTARFIRE_OBJS += todstarfire.o TODSTARCAT_OBJS += todstarcat.o TODBLADE_OBJS += todblade.o TODM5819_OBJS += todm5819.o diff --git a/usr/src/uts/sun4u/Makefile.sun4u b/usr/src/uts/sun4u/Makefile.sun4u index d2b2b5cba7..f5e29d2a13 100644 --- a/usr/src/uts/sun4u/Makefile.sun4u +++ b/usr/src/uts/sun4u/Makefile.sun4u @@ -23,6 +23,7 @@ # Copyright 2010 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # Copyright (c) 2013 Andrew Stormont. All rights reserved. +# Copyright 2019 Peter Tribble. # # This makefile contains the common definitions for the sun4u unix # and all sun4u implementation architecture dependent modules. @@ -158,7 +159,6 @@ include $(UTSBASE)/Makefile.uts # These come after Makefile.uts. IMPLEMENTATIONS = tazmo -IMPLEMENTATIONS += starfire IMPLEMENTATIONS += javelin IMPLEMENTATIONS += darwin IMPLEMENTATIONS += quasar @@ -459,7 +459,7 @@ CPU_KMODS += cheetah cheetahplus jalapeno serrano spitfire hummingbird # # sun4u 'TOD' Modules (/platform/.../kernel/tod): # -TOD_KMODS += todds1287 todds1337 todmostek todstarfire +TOD_KMODS += todds1287 todds1337 todmostek TOD_KMODS += todm5819 todblade todbq4802 todsg todopl TOD_KMODS += todm5819p_rmc todstarcat diff --git a/usr/src/uts/sun4u/io/mach_rootnex.c b/usr/src/uts/sun4u/io/mach_rootnex.c index 8c0653d84a..b2a7ca8f1d 100644 --- a/usr/src/uts/sun4u/io/mach_rootnex.c +++ b/usr/src/uts/sun4u/io/mach_rootnex.c @@ -22,8 +22,9 @@ * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ - -#pragma ident "%Z%%M% %I% %E% SMI" +/* + * Copyright 2019 Peter Tribble. + */ /* * sun4u root nexus driver @@ -329,13 +330,7 @@ rootnex_name_child_impl(dev_info_t *child, char *name, int namelen) if ((strcmp(node_name, "fhc") == 0) || (strcmp(node_name, "mem-unit") == 0) || (strcmp(node_name, "central") == 0)) { -#ifdef _STARFIRE - portid = ((((rp->regspec_bustype) & 0x6) >> 1) | - (((rp->regspec_bustype) & 0xF0) >> 2) | - (((rp->regspec_bustype) & 0x8) << 3)); -#else portid = (rp->regspec_bustype >> 1) & 0x1f; -#endif /* * The port-id must go on the hardware property list, diff --git a/usr/src/uts/sun4u/io/pci/pci_cb.c b/usr/src/uts/sun4u/io/pci/pci_cb.c index be0c9cf208..a22f1ca219 100644 --- a/usr/src/uts/sun4u/io/pci/pci_cb.c +++ b/usr/src/uts/sun4u/io/pci/pci_cb.c @@ -23,8 +23,9 @@ * Copyright 2005 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ - -#pragma ident "%Z%%M% %I% %E% SMI" +/* + * Copyright 2019 Peter Tribble. + */ /* * PCI Control Block object @@ -38,10 +39,6 @@ #include <sys/pci/pci_obj.h> #include <sys/machsystm.h> -#ifdef _STARFIRE -#include <sys/starfire.h> -#endif /* _STARFIRE */ - /*LINTLIBRARY*/ void @@ -101,11 +98,6 @@ cb_enable_nintr(pci_t *pci_p, enum cb_nintr_index idx) mutex_enter(&cb_p->cb_intr_lock); cpu_id = intr_dist_cpuid(); -#ifdef _STARFIRE - cpu_id = pc_translate_tgtid(cb_p->cb_ittrans_cookie, cpu_id, - IB_GET_MAPREG_INO(ino)); -#endif /* _STARFIRE */ - reg = ib_get_map_reg(mondo, cpu_id); stdphysio(pa, reg); @@ -167,10 +159,6 @@ cb_disable_nintr(cb_t *cb_p, enum cb_nintr_index idx, int wait) cb_set_nintr_reg(cb_p, ino, COMMON_CLEAR_INTR_REG_PENDING); cb_p->cb_inos[idx] = 0; mutex_exit(&cb_p->cb_intr_lock); -#ifdef _STARFIRE - pc_ittrans_cleanup(cb_p->cb_ittrans_cookie, - (volatile uint64_t *)(uintptr_t)ino); -#endif /* _STARFIRE */ } void @@ -206,13 +194,8 @@ cb_intr_dist(void *arg) mondo = CB_INO_TO_MONDO(cb_p, ino); cpu_id = intr_dist_cpuid(); -#ifdef _STARFIRE - cpu_id = pc_translate_tgtid(cb_p->cb_ittrans_cookie, cpu_id, - IB_GET_MAPREG_INO(ino)); -#else if (ib_map_reg_get_cpu(imr) == cpu_id) continue; /* same cpu target, no re-program */ -#endif cb_disable_nintr_reg(cb_p, ino, IB_INTR_WAIT); stdphysio(mr_pa, ib_get_map_reg(mondo, cpu_id)); (void) lddphysio(mr_pa); /* flush previous write */ diff --git a/usr/src/uts/sun4u/io/pci/pci_ib.c b/usr/src/uts/sun4u/io/pci/pci_ib.c index cedfc35e05..65d3a5c571 100644 --- a/usr/src/uts/sun4u/io/pci/pci_ib.c +++ b/usr/src/uts/sun4u/io/pci/pci_ib.c @@ -22,6 +22,9 @@ * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ +/* + * Copyright 2019 Peter Tribble. + */ /* * PCI Interrupt Block (RISCx) implementation @@ -41,10 +44,6 @@ #include <sys/cpuvar.h> #include <sys/pci/pci_obj.h> -#ifdef _STARFIRE -#include <sys/starfire.h> -#endif /* _STARFIRE */ - /*LINTLIBRARY*/ static uint_t ib_intr_reset(void *arg); @@ -156,10 +155,6 @@ ib_intr_enable(pci_t *pci_p, ib_ino_t ino) */ mutex_enter(&ib_p->ib_intr_lock); cpu_id = intr_dist_cpuid(); -#ifdef _STARFIRE - cpu_id = pc_translate_tgtid(IB2CB(ib_p)->cb_ittrans_cookie, cpu_id, - IB_GET_MAPREG_INO(ino)); -#endif /* _STARFIRE */ DEBUG2(DBG_IB, pci_p->pci_dip, "ib_intr_enable: ino=%x cpu_id=%x\n", ino, cpu_id); @@ -202,10 +197,6 @@ ib_intr_disable(ib_t *ib_p, ib_ino_t ino, int wait) } wait_done: IB_INO_INTR_PEND(ib_clear_intr_reg_addr(ib_p, ino)); -#ifdef _STARFIRE - pc_ittrans_cleanup(IB2CB(ib_p)->cb_ittrans_cookie, - (volatile uint64_t *)(uintptr_t)ino); -#endif /* _STARFIRE */ } /* can only used for psycho internal interrupts thermal, power, ue, ce, pbm */ @@ -231,15 +222,8 @@ ib_intr_dist_nintr(ib_t *ib_p, ib_ino_t ino, volatile uint64_t *imr_p) cpu_id = intr_dist_cpuid(); -#ifdef _STARFIRE - if (ino) { - cpu_id = pc_translate_tgtid(IB2CB(ib_p)->cb_ittrans_cookie, - cpu_id, IB_GET_MAPREG_INO(ino)); - } -#else /* _STARFIRE */ if (ib_map_reg_get_cpu(*imr_p) == cpu_id) return; -#endif /* _STARFIRE */ *imr_p = ib_get_map_reg(IB_IMR2MONDO(imr), cpu_id); imr = *imr_p; /* flush previous write */ @@ -286,20 +270,8 @@ ib_intr_dist(ib_t *ib_p, ib_ino_info_t *ino_p) imr_p = ib_intr_map_reg_addr(ib_p, ino); state_reg = IB_INO_INTR_STATE_REG(ib_p, ino); -#ifdef _STARFIRE - /* - * For Starfire it is a pain to check the current target for - * the mondo since we have to read the PC asics ITTR slot - * assigned to this mondo. It will be much easier to assume - * the current target is always different and do the target - * reprogram all the time. - */ - cpu_id = pc_translate_tgtid(IB2CB(ib_p)->cb_ittrans_cookie, cpu_id, - IB_GET_MAPREG_INO(ino)); -#else if (ib_map_reg_get_cpu(*imr_p) == cpu_id) /* same cpu, no reprog */ return; -#endif /* _STARFIRE */ /* disable interrupt, this could disrupt devices sharing our slot */ IB_INO_INTR_OFF(imr_p); diff --git a/usr/src/uts/sun4u/io/pci/pci_intr.c b/usr/src/uts/sun4u/io/pci/pci_intr.c index 7d8760474b..493cc08f59 100644 --- a/usr/src/uts/sun4u/io/pci/pci_intr.c +++ b/usr/src/uts/sun4u/io/pci/pci_intr.c @@ -22,6 +22,9 @@ * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ +/* + * Copyright 2019 Peter Tribble. + */ /* * PCI nexus interrupt handling: @@ -41,10 +44,6 @@ #include <sys/sdt.h> #include <sys/clock.h> -#ifdef _STARFIRE -#include <sys/starfire.h> -#endif /* _STARFIRE */ - /* * interrupt jabber: * @@ -579,10 +578,6 @@ pci_add_intr(dev_info_t *dip, dev_info_t *rdip, ddi_intr_handle_impl_t *hdlp) weight = pci_class_to_intr_weight(rdip); intr_dist_cpuid_add_device_weight(cpu_id, rdip, weight); -#ifdef _STARFIRE - cpu_id = pc_translate_tgtid(cb_p->cb_ittrans_cookie, cpu_id, - IB_GET_MAPREG_INO(ino)); -#endif /* _STARFIRE */ if (!ipil_list) { *ino_p->ino_map_reg = ib_get_map_reg(mondo, cpu_id); *ino_p->ino_map_reg; diff --git a/usr/src/uts/sun4u/io/pci/pcipsy.c b/usr/src/uts/sun4u/io/pci/pcipsy.c index 93e93d1008..06a4a71e06 100644 --- a/usr/src/uts/sun4u/io/pci/pcipsy.c +++ b/usr/src/uts/sun4u/io/pci/pcipsy.c @@ -22,8 +22,9 @@ * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ - -#pragma ident "%Z%%M% %I% %E% SMI" +/* + * Copyright 2019 Peter Tribble. + */ /* * Psycho+ specifics implementation: @@ -55,10 +56,6 @@ #include <sys/pci/pci_obj.h> #include <sys/pci/pcipsy.h> -#ifdef _STARFIRE -#include <sys/starfire.h> -#endif /* _STARFIRE */ - static uint32_t pci_identity_init(pci_t *pci_p); static int pci_intr_setup(pci_t *pci_p); static void pci_pbm_errstate_get(pci_t *pci_p, pbm_errstate_t *pbm_err_p); @@ -706,9 +703,6 @@ pci_cb_teardown(pci_t *pci_p) cb_disable_nintr(cb_p, CBNINTR_THERMAL, IB_INTR_WAIT); VERIFY(rem_ivintr(mondo, pci_pil[CBNINTR_THERMAL]) == 0); } -#ifdef _STARFIRE - pc_ittrans_uninit(cb_p->cb_ittrans_cookie); -#endif /* _STARFIRE */ } int @@ -961,27 +955,6 @@ pbm_configure(pbm_t *pbm_p) */ l &= ~PSYCHO_PCI_CTRL_WAKEUP_EN; -#ifdef _STARFIRE - /* - * Hack to determine whether we do Starfire special handling - * For starfire, we simply program a constant odd-value - * (0x1D) in the MID field. - * - * Zero out the MID field before ORing. We leave the LSB of - * the MID field intact since we cannot have a zero (even) - * MID value. - */ - l &= 0xFF0FFFFFFFFFFFFFULL; - l |= 0x1DULL << 51; - - /* - * Program in the Interrupt Group Number. Here we have to - * convert the starfire 7bit upaid into a 5bit value. - */ - l |= (uint64_t)STARFIRE_UPAID2HWIGN(pbm_p->pbm_pci_p->pci_id) - << COMMON_CB_CONTROL_STATUS_IGN_SHIFT; -#endif /* _STARFIRE */ - /* * Now finally write the control register with the appropriate value. */ @@ -1160,11 +1133,6 @@ pci_cb_setup(pci_t *pci_p) csr &= ~COMMON_CB_CONTROL_STATUS_IAP; stdphysio(csr_pa, csr); -#ifdef _STARFIRE - /* Setup Starfire interrupt target translation */ - pc_ittrans_init(pci_p->pci_id, &cb_p->cb_ittrans_cookie); -#endif /* _STARFIRE */ - } void diff --git a/usr/src/uts/sun4u/io/sbd_cpu.c b/usr/src/uts/sun4u/io/sbd_cpu.c index efee104249..5db48f7572 100644 --- a/usr/src/uts/sun4u/io/sbd_cpu.c +++ b/usr/src/uts/sun4u/io/sbd_cpu.c @@ -23,8 +23,9 @@ * Copyright 2005 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ - -#pragma ident "%Z%%M% %I% %E% SMI" +/* + * Copyright 2019 Peter Tribble. + */ /* * CPU support routines for DR @@ -514,9 +515,6 @@ sbd_pre_attach_cpu(sbd_handle_t *hp, sbd_devlist_t *devlist, int devnum) */ PR_CPU("%s: unmapping sigblk for cpu %d\n", f, cpuid); - - /* platform specific release of sigblk */ - CPU_SGN_MAPOUT(cpuid); } } diff --git a/usr/src/uts/sun4u/io/sysioerr.c b/usr/src/uts/sun4u/io/sysioerr.c index 75a5f3d59c..4242915e23 100644 --- a/usr/src/uts/sun4u/io/sysioerr.c +++ b/usr/src/uts/sun4u/io/sysioerr.c @@ -23,8 +23,9 @@ * Copyright 1990-2002 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ - -#pragma ident "%Z%%M% %I% %E% SMI" +/* + * Copyright 2019 Peter Tribble. + */ #include <sys/types.h> #include <sys/conf.h> @@ -53,16 +54,6 @@ int oven_test = 0; */ static int thermal_interrupt_enabled = 0; -#ifdef _STARFIRE -#include <sys/starfire.h> - -int -pc_translate_tgtid(caddr_t, int, volatile uint64_t *); - -void -pc_ittrans_cleanup(caddr_t, volatile uint64_t *); -#endif /* _STARFIRE */ - /* * adb debug_sysio_errs to 1 if you don't want your system to panic on * sbus ue errors. adb sysio_err_flag to 0 if you don't want your system @@ -235,29 +226,17 @@ sysio_init_err(struct sbus_soft_state *softsp) */ mondo_vec_reg = (uint64_t *)(softsp->intr_mapping_reg + UE_ECC_MAPREG); cpu_id = acpu_id; -#ifdef _STARFIRE - cpu_id = pc_translate_tgtid(softsp->ittrans_cookie, cpu_id, - mondo_vec_reg); -#endif /* _STARFIRE */ tmp_mondo_vec = (cpu_id << INTERRUPT_CPU_FIELD) | INTERRUPT_VALID; *mondo_vec_reg = tmp_mondo_vec; mondo_vec_reg = (uint64_t *)(softsp->intr_mapping_reg + CE_ECC_MAPREG); cpu_id = acpu_id; -#ifdef _STARFIRE - cpu_id = pc_translate_tgtid(softsp->ittrans_cookie, cpu_id, - mondo_vec_reg); -#endif /* _STARFIRE */ tmp_mondo_vec = (cpu_id << INTERRUPT_CPU_FIELD) | INTERRUPT_VALID; *mondo_vec_reg = tmp_mondo_vec; mondo_vec_reg = (uint64_t *)(softsp->intr_mapping_reg + SBUS_ERR_MAPREG); cpu_id = acpu_id; -#ifdef _STARFIRE - cpu_id = pc_translate_tgtid(softsp->ittrans_cookie, cpu_id, - mondo_vec_reg); -#endif /* _STARFIRE */ tmp_mondo_vec = (cpu_id << INTERRUPT_CPU_FIELD) | INTERRUPT_VALID; *mondo_vec_reg = tmp_mondo_vec; @@ -312,11 +291,6 @@ sysio_dis_err(struct sbus_soft_state *softsp) *mondo_vec_reg = 0; -#ifdef _STARFIRE - /* do cleanup for starfire interrupt target translation */ - pc_ittrans_cleanup(softsp->ittrans_cookie, mondo_vec_reg); -#endif /* _STARFIRE */ - *clear_vec_reg = 0; mondo_vec_reg = (softsp->intr_mapping_reg + CE_ECC_MAPREG); @@ -324,11 +298,6 @@ sysio_dis_err(struct sbus_soft_state *softsp) *mondo_vec_reg = 0; -#ifdef _STARFIRE - /* Do cleanup for starfire interrupt target translation */ - pc_ittrans_cleanup(softsp->ittrans_cookie, mondo_vec_reg); -#endif /* _STARFIRE */ - *clear_vec_reg = 0; mondo_vec_reg = (softsp->intr_mapping_reg + SBUS_ERR_MAPREG); @@ -336,11 +305,6 @@ sysio_dis_err(struct sbus_soft_state *softsp) *mondo_vec_reg = 0; -#ifdef _STARFIRE - /* Do cleanup for starfire interrupt target translation */ - pc_ittrans_cleanup(softsp->ittrans_cookie, mondo_vec_reg); -#endif /* _STARFIRE */ - *clear_vec_reg = 0; /* Flush store buffers */ diff --git a/usr/src/uts/sun4u/io/sysiosbus.c b/usr/src/uts/sun4u/io/sysiosbus.c index 71ec224b19..20b75c8a0b 100644 --- a/usr/src/uts/sun4u/io/sysiosbus.c +++ b/usr/src/uts/sun4u/io/sysiosbus.c @@ -27,6 +27,10 @@ * Copyright 2012 Garrett D'Amore <garrett@damore.org>. All rights reserved. */ +/* + * Copyright 2019 Peter Tribble. + */ + #include <sys/types.h> #include <sys/conf.h> #include <sys/ddi.h> @@ -50,9 +54,6 @@ #include <sys/machsystm.h> #include <sys/intreg.h> #include <sys/ddi_subrdefs.h> -#ifdef _STARFIRE -#include <sys/starfire.h> -#endif /* _STARFIRE */ #include <sys/sdt.h> /* Useful debugging Stuff */ @@ -287,20 +288,6 @@ static int sbus_update_intr_state(dev_info_t *dip, dev_info_t *rdip, ddi_intr_handle_impl_t *hdlp, uint_t new_intr_state); -#ifdef _STARFIRE -void -pc_ittrans_init(int, caddr_t *); - -void -pc_ittrans_uninit(caddr_t); - -int -pc_translate_tgtid(caddr_t, int, volatile uint64_t *); - -void -pc_ittrans_cleanup(caddr_t, volatile uint64_t *); -#endif /* _STARFIRE */ - /* * Configuration data structures */ @@ -693,11 +680,6 @@ sbus_do_detach(dev_info_t *devi) } mutex_exit(&sbus_attachcnt_mutex); -#ifdef _STARFIRE - /* free starfire specific soft intr mapping structure */ - pc_ittrans_uninit(softsp->ittrans_cookie); -#endif /* _STARFIRE */ - /* free the soft state structure */ ddi_soft_state_free(sbusp, instance); @@ -740,11 +722,6 @@ sbus_init(struct sbus_soft_state *softsp, caddr_t address) "SBUS Control reg: 0x%p", (void *)softsp->sysio_ctrl_reg, (void *)softsp->sbus_ctrl_reg)); -#ifdef _STARFIRE - /* Setup interrupt target translation for starfire */ - pc_ittrans_init(softsp->upa_id, &softsp->ittrans_cookie); -#endif /* _STARFIRE */ - softsp->intr_mapping_ign = UPAID_TO_IGN(softsp->upa_id) << IMR_IGN_SHIFT; @@ -815,27 +792,6 @@ sbus_resume_init(struct sbus_soft_state *softsp, int resume) * (RAZ) Get rid of this later!!! */ -#ifdef _STARFIRE - /* - * For Starfire, we need to program a - * constant odd value. - * Zero out the MID field before ORing - * We leave the LSB of the MID field intact since - * we cannot have a zero(even) MID value - */ - uint64_t tmpconst = 0x1DULL; - *softsp->sysio_ctrl_reg &= 0xFF0FFFFFFFFFFFFFULL; - *softsp->sysio_ctrl_reg |= tmpconst << 51; - - /* - * Program in the interrupt group number - * Here we have to convert the starfire - * 7 bit upaid into a 5bit value. - */ - *softsp->sysio_ctrl_reg |= - (uint64_t)STARFIRE_UPAID2HWIGN(softsp->upa_id) - << SYSIO_IGN; -#else /* for the rest of sun4u's */ *softsp->sysio_ctrl_reg |= (uint64_t)softsp->upa_id << 51; @@ -843,7 +799,6 @@ sbus_resume_init(struct sbus_soft_state *softsp, int resume) /* Program in the interrupt group number */ *softsp->sysio_ctrl_reg |= (uint64_t)softsp->upa_id << SYSIO_IGN; -#endif /* _STARFIRE */ /* * Set appropriate fields of sbus control register. @@ -1821,16 +1776,10 @@ sbus_add_intr_impl(dev_info_t *dip, dev_info_t *rdip, (softsp->intr_hndlr_cnt[slot] == 0)) { cpu_id = intr_dist_cpuid(); -#ifdef _STARFIRE - tmp_mondo_vec = pc_translate_tgtid( - softsp->ittrans_cookie, cpu_id, - mondo_vec_reg) << IMR_TID_SHIFT; -#else tmp_mondo_vec = cpu_id << IMR_TID_SHIFT; DPRINTF(SBUS_INTERRUPT_DEBUG, ("Add intr: initial " "mapping reg 0x%lx\n", tmp_mondo_vec)); -#endif /* _STARFIRE */ } else { /* * There is already a different @@ -2004,10 +1953,6 @@ sbus_remove_intr_impl(dev_info_t *dip, dev_info_t *rdip, if ((softsp->intr_hndlr_cnt[slot] == 0) || (slot >= EXT_SBUS_SLOTS)) { ASSERT(sbus_arg->handler_list == NULL); -#ifdef _STARFIRE - /* Do cleanup for interrupt target translation */ - pc_ittrans_cleanup(softsp->ittrans_cookie, mondo_vec_reg); -#endif /* _STARFIRE */ } @@ -2245,20 +2190,10 @@ sbus_intrdist(void *arg) last_mondo_vec_reg = (uint64_t *)mondo_vec_reg; cpu_id = intr_dist_cpuid(); -#ifdef _STARFIRE - /* - * For Starfire it is a pain to check the current target for - * the mondo since we have to read the PC asics ITTR slot - * assigned to this mondo. It will be much easier to assume - * the current target is always different and do the target - * reprogram all the time. - */ -#else if (((*mondo_vec_reg & IMR_TID) >> IMR_TID_SHIFT) == cpu_id) { /* It is the same, don't reprogram */ return; } -#endif /* _STARFIRE */ /* So it's OK to reprogram the CPU target */ @@ -2315,14 +2250,7 @@ sbus_intrdist(void *arg) } /* re-target the mondo and turn it on */ -#ifdef _STARFIRE - mondo_vec = (pc_translate_tgtid(softsp->ittrans_cookie, - cpu_id, mondo_vec_reg) << - INTERRUPT_CPU_FIELD) | - INTERRUPT_VALID; -#else mondo_vec = (cpu_id << INTERRUPT_CPU_FIELD) | INTERRUPT_VALID; -#endif /* _STARFIRE */ /* write it back to the hardware. */ *mondo_vec_reg = mondo_vec; diff --git a/usr/src/uts/sun4u/io/todstarfire.c b/usr/src/uts/sun4u/io/todstarfire.c deleted file mode 100644 index b8571c49f8..0000000000 --- a/usr/src/uts/sun4u/io/todstarfire.c +++ /dev/null @@ -1,196 +0,0 @@ -/* - * 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 - * or http://www.opensolaris.org/os/licensing. - * 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 2008 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -/* - * tod driver module for Starfire - * This module implements a soft tod since - * starfire has no tod part. - */ - -#include <sys/types.h> -#include <sys/param.h> -#include <sys/sysmacros.h> -#include <sys/systm.h> -#include <sys/errno.h> -#include <sys/modctl.h> -#include <sys/autoconf.h> -#include <sys/debug.h> -#include <sys/clock.h> -#include <sys/cmn_err.h> -#include <sys/promif.h> -#include <sys/cpuvar.h> -#include <sys/cpu_sgnblk_defs.h> -#include <starfire/sys/cpu_sgn.h> - -static timestruc_t todsf_get(void); -static void todsf_set(timestruc_t); -static uint_t todsf_set_watchdog_timer(uint_t); -static uint_t todsf_clear_watchdog_timer(void); -static void todsf_set_power_alarm(timestruc_t); -static void todsf_clear_power_alarm(void); -static uint64_t todsf_get_cpufrequency(void); - -/* - * Module linkage information for the kernel. - */ -static struct modlmisc modlmisc = { - &mod_miscops, "Soft tod module for Starfire" -}; - -static struct modlinkage modlinkage = { - MODREV_1, (void *)&modlmisc, NULL -}; - -int -_init(void) -{ - if (strcmp(tod_module_name, "todstarfire") == 0) { - int ssp_time32; - char obp_string[40]; - - /* Set the string to pass to OBP */ - (void) sprintf(obp_string, "h# %p unix-gettod", - (void *)&ssp_time32); - - /* Get OBP to get TOD from ssp */ - prom_interpret(obp_string, 0, 0, 0, 0, 0); - - hrestime.tv_sec = (time_t)ssp_time32; - - tod_ops.tod_get = todsf_get; - tod_ops.tod_set = todsf_set; - tod_ops.tod_set_watchdog_timer = todsf_set_watchdog_timer; - tod_ops.tod_clear_watchdog_timer = todsf_clear_watchdog_timer; - tod_ops.tod_set_power_alarm = todsf_set_power_alarm; - tod_ops.tod_clear_power_alarm = todsf_clear_power_alarm; - tod_ops.tod_get_cpufrequency = todsf_get_cpufrequency; - - /* - * Flag warning if user tried to use hardware watchdog - */ - if (watchdog_enable) { - cmn_err(CE_WARN, "Hardware watchdog unavailable"); - } - } - - return (mod_install(&modlinkage)); -} - -int -_fini(void) -{ - if (strcmp(tod_module_name, "todstarfire") == 0) - return (EBUSY); - else - return (mod_remove(&modlinkage)); -} - -int -_info(struct modinfo *modinfop) -{ - return (mod_info(&modlinkage, modinfop)); -} - - -/* - * Simply return hrestime value - * Must be called with tod_lock held. - */ -static timestruc_t -todsf_get(void) -{ - timestruc_t ts; - extern cpu_sgnblk_t *cpu_sgnblkp[]; - - ASSERT(MUTEX_HELD(&tod_lock)); - - ts = hrestime; - - /* Update the heartbeat */ - if (cpu_sgnblkp[CPU->cpu_id] != NULL) - cpu_sgnblkp[CPU->cpu_id]->sigb_heartbeat++; - return (ts); -} - -/* - * Null function for now. - * Must be called with tod_lock held. - */ -/* ARGSUSED */ -static void -todsf_set(timestruc_t ts) -{ - ASSERT(MUTEX_HELD(&tod_lock)); -} - - -/* - * No watchdog function. - */ -/* ARGSUSED */ -static uint_t -todsf_set_watchdog_timer(uint_t timeoutval) -{ - ASSERT(MUTEX_HELD(&tod_lock)); - return (0); -} - -/* - * No watchdog function - */ -static uint_t -todsf_clear_watchdog_timer(void) -{ - ASSERT(MUTEX_HELD(&tod_lock)); - return (0); -} - -/* - * Null function. - */ -/* ARGSUSED */ -static void -todsf_set_power_alarm(timestruc_t ts) -{ - ASSERT(MUTEX_HELD(&tod_lock)); -} - -/* - * Null function - */ -static void -todsf_clear_power_alarm() -{ - ASSERT(MUTEX_HELD(&tod_lock)); -} - -/* - * Get clock freq from the cpunode - */ -uint64_t -todsf_get_cpufrequency(void) -{ - return (cpunodes[CPU->cpu_id].clock_freq); -} diff --git a/usr/src/uts/sun4u/ngdr/Makefile.files b/usr/src/uts/sun4u/ngdr/Makefile.files index 32e9af4eed..f03fb7a323 100644 --- a/usr/src/uts/sun4u/ngdr/Makefile.files +++ b/usr/src/uts/sun4u/ngdr/Makefile.files @@ -20,15 +20,14 @@ # CDDL HEADER END # # -#pragma ident "%Z%%M% %I% %E% SMI" -# # Copyright (c) 2001 by Sun Microsystems, Inc. # All rights reserved. +# Copyright 2019 Peter Tribble. # # # This Makefile defines the shared dr module that is used by -# directories uts/sun4u/starfire and uts/sun4u/starcat. +# directory uts/sun4u/starcat. # # diff --git a/usr/src/uts/sun4u/ngdr/Makefile.rules b/usr/src/uts/sun4u/ngdr/Makefile.rules index f72c79102f..3cbdbbbeed 100644 --- a/usr/src/uts/sun4u/ngdr/Makefile.rules +++ b/usr/src/uts/sun4u/ngdr/Makefile.rules @@ -19,15 +19,14 @@ # CDDL HEADER END # # -#pragma ident "%Z%%M% %I% %E% SMI" -# # Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. +# Copyright 2019 Peter Tribble. # # # This Makefile defines the build rules for the shared dr -# module used by uts/sun4u/starfire and uts/sun4u/starcat. +# module used by uts/sun4u/starcat. # # diff --git a/usr/src/uts/sun4u/ngdr/io/dr_cpu.c b/usr/src/uts/sun4u/ngdr/io/dr_cpu.c index 17a96f378c..87b5cc7fef 100644 --- a/usr/src/uts/sun4u/ngdr/io/dr_cpu.c +++ b/usr/src/uts/sun4u/ngdr/io/dr_cpu.c @@ -25,6 +25,10 @@ */ /* + * Copyright 2019 Peter Tribble. + */ + +/* * CPU support routines for DR */ @@ -70,13 +74,8 @@ #include <sys/dr.h> #include <sys/dr_util.h> -#ifdef _STARFIRE -#include <sys/starfire.h> -extern struct cpu *SIGBCPU; -#else /* for the DR*INTERNAL_ERROR macros. see sys/dr.h. */ static char *dr_ie_fmt = "dr_cpu.c %d"; -#endif /* _STARFIRE */ int dr_cpu_unit_is_sane(dr_board_t *bp, dr_cpu_unit_t *cp) @@ -145,14 +144,7 @@ dr_cpu_set_prop(dr_cpu_unit_t *cp) } if (dip == NULL) { -#ifndef _STARFIRE - /* - * Do not report an error on Starfire since - * the dip will not be created until after - * the CPU has been configured. - */ DR_DEV_INTERNAL_ERROR(&cp->sbc_cm); -#endif /* !_STARFIRE */ return; } @@ -309,8 +301,6 @@ dr_pre_attach_cpu(dr_handle_t *hp, dr_common_unit_t **devlist, int devnum) */ PR_CPU("%s: unmapping sigblk for cpu %d\n", f, up->sbc_cpu_id); - - CPU_SGN_MAPOUT(up->sbc_cpu_id); } } @@ -671,10 +661,6 @@ dr_fill_cpu_stat(dr_cpu_unit_t *cp, drmach_status_t *pstat, sbd_cpu_stat_t *csp) /* CPU specific status data */ csp->cs_cpuid = cp->sbc_cpu_id; -#ifdef _STARFIRE - csp->cs_isbootproc = (SIGBCPU->cpu_id == cp->sbc_cpu_id) ? 1 : 0; -#endif /* _STARFIRE */ - /* * If the speed and ecache properties have not been * cached yet, read them in from the device tree. diff --git a/usr/src/uts/sun4u/ngdr/io/dr_mem.c b/usr/src/uts/sun4u/ngdr/io/dr_mem.c index ccb70b83cb..436d899ef7 100644 --- a/usr/src/uts/sun4u/ngdr/io/dr_mem.c +++ b/usr/src/uts/sun4u/ngdr/io/dr_mem.c @@ -25,6 +25,10 @@ */ /* + * Copyright 2019 Peter Tribble. + */ + +/* * DR memory support routines. */ @@ -628,7 +632,6 @@ dr_detach_mem(dr_handle_t *hp, dr_common_unit_t *cp) } } -#ifndef _STARFIRE /* * XXX workaround for certain lab configurations (see also starcat drmach.c) * Temporary code to get around observed incorrect results from @@ -698,7 +701,6 @@ again: } #define kphysm_del_span_query dr_del_span_query -#endif /* _STARFIRE */ /* * NOTE: This routine is only partially smart about multiple diff --git a/usr/src/uts/sun4u/os/mach_mp_startup.c b/usr/src/uts/sun4u/os/mach_mp_startup.c index e513f902c4..279aafcd36 100644 --- a/usr/src/uts/sun4u/os/mach_mp_startup.c +++ b/usr/src/uts/sun4u/os/mach_mp_startup.c @@ -22,6 +22,9 @@ * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ +/* + * Copyright 2019 Peter Tribble. + */ #include <sys/machsystm.h> #include <sys/cpu_module.h> @@ -64,10 +67,6 @@ init_cpu_info(struct cpu *cp) (void) strcpy(pi->pi_processor_type, "sparcv9"); (void) strcpy(pi->pi_fputypes, "sparcv9"); - /* - * StarFire requires the signature block stuff setup here - */ - CPU_SGN_MAPIN(cpuid); if (cpuid == cpu0.cpu_id) { /* * cpu0 starts out running. Other cpus are diff --git a/usr/src/uts/sun4u/starfire/Makefile b/usr/src/uts/sun4u/starfire/Makefile deleted file mode 100644 index 7a08af878a..0000000000 --- a/usr/src/uts/sun4u/starfire/Makefile +++ /dev/null @@ -1,122 +0,0 @@ -# -# 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 -# or http://www.opensolaris.org/os/licensing. -# 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 -# -# -#ident "%Z%%M% %I% %E% SMI" -# -# Copyright 2005 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# -# This makefile drives the production of the sun4u starfire platform -# module. -# -# sun4u starfire implementation architecture dependent -# - -# -# Path to the base of the uts directory tree (usually /usr/src/uts). -# -UTSBASE = ../.. - -include $(UTSBASE)/sun4u/starfire/Makefile.starfire - -# -# The following are SPARC specific (rather than sun4u) specific modules -# which are required for the sun4u kernel to completely lint. They are -# not involved in the build in any other way. In order to minimize -# build time, it is assumed that they are up to date. But since sun4u -# is really a separate architecture we cannot use the v7 sparc modules. -# -SPARC_LIB_DIR = $(UTSBASE)/sparc/lint-libs/$(OBJS_DIR) - -SPARC_LINTS = - -SUN4U_LIB_DIR = $(UTSBASE)/sun4u/lint-libs/$(OBJS_DIR) - -# -# -# -LINT_LIBS = $(LINT_LIB) \ - $(SPARC_LINTS:%=$(SPARC_LIB_DIR)/llib-l%.ln) \ - $(LINT_KMODS:%=$(SUN4U_LIB_DIR)/llib-l%.ln) \ - $(CLOSED_LINT_KMODS:%=$(SUN4U_LIB_DIR)/llib-l%.ln) - -def := TARGET= def -all := TARGET= all -install := TARGET= install -install_h := TARGET= install_h -clean := TARGET= clean -clobber := TARGET= clobber -lint := TARGET= lint -lintlib := TARGET= lintlib -modlintlib := TARGET= modlintlib -modlist := TARGET= modlist -modlist := NO_STATE= -K $$MODSTATE$$$$ -clean.lint := TARGET= clean.lint -check := TARGET= check - -IMPLEMENTED_PLATFORM = SUNW,Ultra-Enterprise-10000 - -# -# Default build targets. -# -.KEEP_STATE: - -.PARALLEL: $(STARFIRE_KMODS) - -.NO_PARALLEL: $(STARFIRE_CPU_KMODS) - -def all clean clobber clean.lint: genassym unix .WAIT \ - $(STARFIRE_CPU_KMODS) $(STARFIRE_KMODS) - -modlist: unix $(STARFIRE_CPU_KMODS) $(STARFIRE_KMODS) - -install: $(ROOT_STARFIRE_DIR) $(USR_STARFIRE_DIR) \ - $(USR_STARFIRE_INC_DIR) \ - $(USR_STARFIRE_SBIN_DIR) \ - $(USR_STARFIRE_LIB_DIR) \ - genassym unix .WAIT $(STARFIRE_CPU_KMODS) $(STARFIRE_KMODS) - -lintlib: unix - -modlintlib: $(STARFIRE_KMODS) $(STARFIRE_CPU_KMODS) - -genassym unix $(STARFIRE_CPU_KMODS) $(STARFIRE_KMODS): FRC - @cd $@; pwd; $(MAKE) $(NO_STATE) $(TARGET) - -install_h check: FRC - @cd sys; pwd; $(MAKE) $(TARGET) - -# -# Full kernel lint target. -# -LINT_TARGET = globallint - -globallint: - @-$(ECHO) "\nStarfire KERNEL: global crosschecks:" - @-$(LINT) $(LINTFLAGS) $(LINT_LIBS) 2>&1 | $(LGREP.2) - -lint: lintlib .WAIT modlintlib .WAIT $(LINT_DEPS) - -# -# Include common targets. -# -include $(UTSBASE)/sun4u/starfire/Makefile.targ diff --git a/usr/src/uts/sun4u/starfire/Makefile.files b/usr/src/uts/sun4u/starfire/Makefile.files deleted file mode 100644 index 96c4d9a102..0000000000 --- a/usr/src/uts/sun4u/starfire/Makefile.files +++ /dev/null @@ -1,67 +0,0 @@ -# -# 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 -# or http://www.opensolaris.org/os/licensing. -# 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 -# -# -# ident "%Z%%M% %I% %E% SMI" -# -# Copyright 1997-2001, 2003 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# -# This Makefile defines all file modules for the directory -# uts/sun4u/starfire and its children. These are the source files which -# are starfire "implementation architecture" dependent. -# - -# -# Object lists -# -# Starfire specific kernel modules - -CORE_OBJS += cpu_sgnblk.o bbus_intr.o portctrl.o - -# -# Starfire specific driver related modules -# -CVC_OBJS += cvc.o - -CVCREDIR_OBJS += cvcredir.o - -NGDRMACH_OBJS += drmach.o drmach_asm.o pda.o memctrl.o \ - dr_util.o drmach_err.o - -IDN_OBJS += idn.o idn_proto.o idn_dlpi.o idn_xf.o idn_smr.o idn_asm.o \ - mi.o nd.o inet_common.o \ - memctrl.o pda.o -IDN_DEPS += idn_asm.o - -# -# Miscellaneous -# -INC_PATH += -I$(UTSBASE)/sun4u/starfire - -# -# Since assym.h is a derived file, the dependency must be explicit for -# all files including this file. (This is only actually required in the -# instance when the .nse_depinfo file does not exist.) It may seem that -# the lint targets should also have a similar dependency, but they don't -# since only C headers are included when #defined(lint) is true. -# -ASSYM_DEPS += drmach_asm.o idn_asm.o diff --git a/usr/src/uts/sun4u/starfire/Makefile.rules b/usr/src/uts/sun4u/starfire/Makefile.rules deleted file mode 100644 index 5da6c4cce3..0000000000 --- a/usr/src/uts/sun4u/starfire/Makefile.rules +++ /dev/null @@ -1,106 +0,0 @@ -# -# 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 -# or http://www.opensolaris.org/os/licensing. -# See the License for the specific language governing permissions -# and limitations under the License. -# -# When distributing Covered Code, include this CDDL HEADER in each -# file and include the License file at usr/src/OPENSOLARIS.LICENSE. -# If applicable, add the following below this CDDL HEADER, with the -# fields enclosed by brackets "[]" replaced with your own identifying -# information: Portions Copyright [yyyy] [name of copyright owner] -# -# CDDL HEADER END -# -# -# Copyright 2006 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# -# ident "%Z%%M% %I% %E% SMI" -# -# This Makefile defines the build rules for the directory -# uts/sun4u/starfire and its children. -# -# The following two-level ordering must be maintained in this file. -# Lines are sorted first in order of decreasing specificity based on -# the first directory component. That is, sun4u rules come before -# sparc rules come before common rules. -# -# Lines whose initial directory components are equal are sorted -# alphabetically by the remaining components. - -# -# inline support for DR. -# - -IL_CPP=$(CPP) -P -DINLINE -D_ASM $(AS_INC_PATH) \ - $(CPP_DEFS) $(ALWAYS_DEFS) $(ALL_DEFS) $(CONFIG_DEFS) - -# -# Section 1a: C object build rules -# - -$(OBJS_DIR)/%.o: $(UTSBASE)/sun4u/starfire/cvc/%.c - $(COMPILE.c) -o $@ $< - $(CTFCONVERT_O) - -$(OBJS_DIR)/%.o: $(UTSBASE)/sun4u/starfire/cvcredir/%.c - $(COMPILE.c) -o $@ $< - $(CTFCONVERT_O) - -DRMACH_IL= $(OBJS_DIR)/drmach.il -$(OBJS_DIR)/drmach.o := CC_XARCH_32 = -xarch=v8plusa -$(OBJS_DIR)/drmach.o: $(UTSBASE)/sun4u/starfire/io/drmach.c $(DRMACH_IL) - $(COMPILE.c) $(DRMACH_IL) -o $@ $(UTSBASE)/sun4u/starfire/io/drmach.c - $(CTFCONVERT_O) - -$(OBJS_DIR)/%.o: $(UTSBASE)/sun4u/starfire/io/%.c - $(COMPILE.c) -o $@ $< - $(CTFCONVERT_O) - -$(OBJS_DIR)/%.o: $(UTSBASE)/sun4u/starfire/ml/%.s - $(COMPILE.s) -o $@ $< - -$(OBJS_DIR)/%.o: $(UTSBASE)/sun4u/starfire/os/%.c - $(COMPILE.c) -o $@ $< - $(CTFCONVERT_O) - -STARFIRE_IO= $(UTSBASE)/sun4u/starfire/io - -CLEANFILES += $(STARFIRE_IO)/drmach_err.c - -$(STARFIRE_IO)/drmach_err.c: $(SBDGENERR) $(SBD_IOCTL) - $(RM) $@ - $(SBDGENERRCMD) ESTF < $(SBD_IOCTL) > $@ - -# inline stuff - -CLEANFILES += $(DRMACH_IL) - -$(DRMACH_IL): $(UTSBASE)/sun4u/starfire/ml/drmach.il.cpp - $(IL_CPP) $(UTSBASE)/sun4u/starfire/ml/drmach.il.cpp > $@ - -# -# Section 1b: Lint object build rules -# - -$(LINTS_DIR)/%.ln: $(UTSBASE)/sun4u/starfire/cvc/%.c - @($(LHEAD) $(LINT.c) $< $(LTAIL)) - -$(LINTS_DIR)/%.ln: $(UTSBASE)/sun4u/starfire/cvcredir/%.c - @($(LHEAD) $(LINT.c) $< $(LTAIL)) - -$(LINTS_DIR)/%.ln: $(UTSBASE)/sun4u/starfire/io/%.c - @($(LHEAD) $(LINT.c) $< $(LTAIL)) - -$(LINTS_DIR)/%.ln: $(UTSBASE)/sun4u/starfire/ml/%.s - @($(LHEAD) $(LINT.s) $< $(LTAIL)) - -$(LINTS_DIR)/%.ln: $(UTSBASE)/sun4u/starfire/os/%.c - @($(LHEAD) $(LINT.c) $< $(LTAIL)) diff --git a/usr/src/uts/sun4u/starfire/Makefile.starfire b/usr/src/uts/sun4u/starfire/Makefile.starfire deleted file mode 100644 index ce706f8681..0000000000 --- a/usr/src/uts/sun4u/starfire/Makefile.starfire +++ /dev/null @@ -1,132 +0,0 @@ -# -# 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 -# or http://www.opensolaris.org/os/licensing. -# 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 2008 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# -# Global definitions for sun4u starfire implementation specific modules. -# - -# -# Define directories. -# -ROOT_STARFIRE_DIR = $(ROOT_PLAT_DIR)/SUNW,Ultra-Enterprise-10000 -ROOT_STARFIRE_MOD_DIR = $(ROOT_STARFIRE_DIR)/kernel -ROOT_STARFIRE_KERN_DIR_32 = $(ROOT_STARFIRE_MOD_DIR) -ROOT_STARFIRE_KERN_DIR_64 = $(ROOT_STARFIRE_MOD_DIR)/$(SUBDIR64) -ROOT_STARFIRE_MISC_DIR_32 = $(ROOT_STARFIRE_MOD_DIR)/misc -ROOT_STARFIRE_MISC_DIR_64 = $(ROOT_STARFIRE_MOD_DIR)/misc/$(SUBDIR64) -ROOT_STARFIRE_DRV_DIR_32 = $(ROOT_STARFIRE_MOD_DIR)/drv -ROOT_STARFIRE_DRV_DIR_64 = $(ROOT_STARFIRE_MOD_DIR)/drv/$(SUBDIR64) -ROOT_STARFIRE_CPU_DIR_32 = $(ROOT_STARFIRE_MOD_DIR)/cpu -ROOT_STARFIRE_CPU_DIR_64 = $(ROOT_STARFIRE_MOD_DIR)/cpu/$(SUBDIR64) - -ROOT_STARFIRE_KERN_DIR = $(ROOT_STARFIRE_KERN_DIR_$(CLASS)) -ROOT_STARFIRE_MISC_DIR = $(ROOT_STARFIRE_MISC_DIR_$(CLASS)) -ROOT_STARFIRE_DRV_DIR = $(ROOT_STARFIRE_DRV_DIR_$(CLASS)) -ROOT_STARFIRE_CPU_DIR = $(ROOT_STARFIRE_CPU_DIR_$(CLASS)) - -ROOT_PLAT_MOD_DIRS += $(ROOT_STARFIRE_MOD_DIR) -ROOT_PLAT_MISC_DIRS_32 += $(ROOT_STARFIRE_MISC_DIR_32) - -USR_STARFIRE_DIR = $(USR_PLAT_DIR)/SUNW,Ultra-Enterprise-10000 -USR_STARFIRE_INC_DIR = $(USR_STARFIRE_DIR)/include -USR_STARFIRE_ISYS_DIR = $(USR_STARFIRE_INC_DIR)/sys -USR_STARFIRE_SBIN_DIR = $(USR_STARFIRE_DIR)/sbin -USR_STARFIRE_LIB_DIR = $(USR_STARFIRE_DIR)/lib - -# -# Define objects. -# -STARFIRE_OBJS = starfire.o - -# -# Define modules. -# -STARFIRE_KMODS = platmod -STARFIRE_KMODS += rootnex sbus pcipsy -STARFIRE_KMODS += cvc cvcredir -STARFIRE_KMODS += ngdr ngdrmach -STARFIRE_KMODS += idn - -# -# CPU modules. -# -STARFIRE_CPU_KMODS += spitfire - -# -# Include the makefiles which define build rule templates, the -# collection of files per module, and a few specific flags. Note -# that order is significant, just as with an include path. The -# first build rule template which matches the files name will be -# used. By including these in order from most machine dependent -# to most machine independent, we allow a machine dependent file -# to be used in preference over a machine independent version -# (Such as a machine specific optimization, which preserves the -# interfaces.) -# -include $(UTSBASE)/sun4u/ngdr/Makefile.files -include $(UTSBASE)/sun4u/starfire/Makefile.files - -# -# Include common rules. -# -include $(UTSBASE)/sun4u/Makefile.sun4u - -# -# Everybody needs to know how to build modstubs.o and to locate unix.o -# -UNIX_DIR = $(UTSBASE)/$(PLATFORM)/starfire/unix -MODSTUBS_DIR = $(UNIX_DIR) -DSF_DIR = $(UTSBASE)/$(PLATFORM)/starfire/genassym -LINTS_DIR = $(OBJS_DIR) -LINT_LIB_DIR = $(UTSBASE)/$(PLATFORM)/starfire/lint-libs/$(OBJS_DIR) - -UNIX_O = $(UNIX_DIR)/$(OBJS_DIR)/unix.o - -LINT_LIB = $(LINT_LIB_DIR)/llib-lunix.ln - -# -# Define the actual specific platforms -# -MACHINE_DEFS = -D$(PLATFORM) -D_MACHDEP -DSFMMU -MACHINE_DEFS += -D_STARFIRE -D_CPU_SIGNATURE - -# -# Define for inline pre-processing since -# cpp not smart about v9 yet. -# -CPP_DEFS_32 = -CPP_DEFS_64 = -D__sparcv9 -CPP_DEFS = $(CPP_DEFS_$(CLASS)) - -# -# For now, disable these lint checks; maintainers should endeavor -# to investigate and remove these for maximum lint coverage. -# Please do not carry these forward to new Makefiles. -# -LINTTAGS += -erroff=E_SUSPICIOUS_COMPARISON -LINTTAGS += -erroff=E_BAD_PTR_CAST_ALIGN -LINTTAGS += -erroff=E_SUPPRESSION_DIRECTIVE_UNUSED -LINTTAGS += -erroff=E_STATIC_UNUSED -LINTTAGS += -erroff=E_PTRDIFF_OVERFLOW -LINTTAGS += -erroff=E_ASSIGN_NARROW_CONV -LINTTAGS += -erroff=E_BAD_FORMAT_STR2 diff --git a/usr/src/uts/sun4u/starfire/Makefile.targ b/usr/src/uts/sun4u/starfire/Makefile.targ deleted file mode 100644 index e746704e81..0000000000 --- a/usr/src/uts/sun4u/starfire/Makefile.targ +++ /dev/null @@ -1,93 +0,0 @@ -# -# 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 -# or http://www.opensolaris.org/os/licensing. -# 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. -# -# Common targets for sun4u starfire implementation specific modules. -# - -.KEEP_STATE: - -# -# Rules for implementation subdirectories. -# -$(ROOT_STARFIRE_DIR): $(ROOT_PLAT_DIR) - -$(INS.dir) - -$(ROOT_STARFIRE_MOD_DIR): $(ROOT_STARFIRE_DIR) - -$(INS.dir) - -$(ROOT_STARFIRE_KERN_DIR): $(ROOT_STARFIRE_MOD_DIR) - -$(INS.dir) - -$(ROOT_STARFIRE_DRV_DIR_32): $(ROOT_STARFIRE_MOD_DIR) - -$(INS.dir) - -$(ROOT_STARFIRE_DRV_DIR_64): $(ROOT_STARFIRE_DRV_DIR_32) - -$(INS.dir) - -$(ROOT_STARFIRE_CPU_DIR_32): $(ROOT_STARFIRE_MOD_DIR) - -$(INS.dir) - -$(ROOT_STARFIRE_CPU_DIR_64): $(ROOT_STARFIRE_CPU_DIR_32) - -$(INS.dir) - -$(ROOT_STARFIRE_MISC_DIR_32): $(ROOT_STARFIRE_MOD_DIR) - -$(INS.dir) - -$(ROOT_STARFIRE_MISC_DIR_64): $(ROOT_STARFIRE_MISC_DIR_32) - -$(INS.dir) - -$(USR_STARFIRE_DIR): $(USR_PLAT_DIR) - -$(INS.dir) - -$(USR_STARFIRE_INC_DIR): $(USR_STARFIRE_DIR) $(USR_PSM_INCL_DIR) - $(INS.slink4) - -$(USR_STARFIRE_SBIN_DIR): $(USR_STARFIRE_DIR) $(USR_PSM_SBIN_DIR) - -$(INS.slink5) - -$(USR_STARFIRE_LIB_DIR): $(USR_STARFIRE_DIR) $(USR_PSM_LIB_DIR) - -$(INS.dir) - -$(USR_STARFIRE_ISYS_DIR): $(USR_STARFIRE_INC_DIR) - $(INS.dir) - -$(ROOT_STARFIRE_KERN_DIR)/%: $(OBJS_DIR)/% $(ROOT_STARFIRE_KERN_DIR) FRC - $(INS.file) - -$(ROOT_STARFIRE_DRV_DIR)/%: $(OBJS_DIR)/% $(ROOT_STARFIRE_DRV_DIR) FRC - $(INS.file) - -$(ROOT_STARFIRE_CPU_DIR)/%: $(OBJS_DIR)/% $(ROOT_STARFIRE_CPU_DIR) FRC - $(INS.file) - -$(ROOT_STARFIRE_MISC_DIR)/%: $(OBJS_DIR)/% $(ROOT_STARFIRE_MISC_DIR) FRC - $(INS.file) - -# -# Include common targets. -# -include $(UTSBASE)/sun4u/ngdr/Makefile.rules -include $(UTSBASE)/sun4u/starfire/Makefile.rules -include $(UTSBASE)/sun4u/Makefile.targ diff --git a/usr/src/uts/sun4u/starfire/cvc/Makefile b/usr/src/uts/sun4u/starfire/cvc/Makefile deleted file mode 100644 index f450a72f3b..0000000000 --- a/usr/src/uts/sun4u/starfire/cvc/Makefile +++ /dev/null @@ -1,88 +0,0 @@ -# -# 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 -# or http://www.opensolaris.org/os/licensing. -# 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 2004 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# -# This makefile drives the production of the cvc driver module. -# -# sun4u starfire implementation architecture dependent -# - -# -# Path to the base of the uts directory tree (usually /usr/src/uts). -# -UTSBASE = ../../.. - -# -# Define the module and object file sets. -# -MODULE = cvc -OBJECTS = $(CVC_OBJS:%=$(OBJS_DIR)/%) -LINTS = $(CVC_OBJS:%.o=$(LINTS_DIR)/%.ln) -ROOTMODULE = $(ROOT_STARFIRE_DRV_DIR)/$(MODULE) -CONF_SRCDIR = $(UTSBASE)/sun4u/starfire/cvc - -# -# Include common rules. -# -include $(UTSBASE)/sun4u/starfire/Makefile.starfire - -# -# Define targets -# -ALL_TARGET = $(BINARY) $(SRC_CONFFILE) -LINT_TARGET = $(MODULE).lint -INSTALL_TARGET = $(BINARY) $(ROOTMODULE) $(ROOT_CONFFILE) - -# -# lint pass one enforcement -# -CFLAGS += $(CCVERBOSE) -CERRWARN += -_gcc=-Wno-unused-function -CERRWARN += -_gcc=-Wno-uninitialized - -# -# Default build targets. -# -.KEEP_STATE: - -def: $(DEF_DEPS) - -all: $(ALL_DEPS) - -clean: $(CLEAN_DEPS) - -clobber: $(CLOBBER_DEPS) - -lint: $(LINT_DEPS) - -modlintlib: $(MODLINTLIB_DEPS) - -clean.lint: $(CLEAN_LINT_DEPS) - -install: $(INSTALL_DEPS) - -# -# Include common targets. -# -include $(UTSBASE)/sun4u/starfire/Makefile.targ diff --git a/usr/src/uts/sun4u/starfire/cvc/cvc.c b/usr/src/uts/sun4u/starfire/cvc/cvc.c deleted file mode 100644 index 1538db559c..0000000000 --- a/usr/src/uts/sun4u/starfire/cvc/cvc.c +++ /dev/null @@ -1,1200 +0,0 @@ -/* - * 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 - * or http://www.opensolaris.org/os/licensing. - * 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. - */ - - -/* - * MT STREAMS Virtual Console Device Driver - */ - -#include <sys/types.h> -#include <sys/sysmacros.h> -#include <sys/processor.h> -#include <sys/cpuvar.h> -#include <sys/open.h> -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/signal.h> -#include <sys/cred.h> -#include <sys/user.h> -#include <sys/proc.h> -#include <sys/vnode.h> -#include <sys/uio.h> -#include <sys/buf.h> -#include <sys/file.h> -#include <sys/kmem.h> -#include <sys/vmem.h> -#include <sys/stat.h> -#include <sys/stream.h> -#include <sys/stropts.h> -#include <sys/strsubr.h> -#include <sys/strsun.h> -#include <sys/tty.h> -#include <sys/ptyvar.h> -#include <sys/poll.h> -#include <sys/debug.h> -#include <sys/conf.h> - -#include <sys/starfire.h> -#include <sys/mman.h> -#include <vm/seg_kmem.h> - -#include <sys/ddi.h> -#include <sys/sunddi.h> -#include <sys/errno.h> -#include <sys/modctl.h> -#include <sys/cpu_sgnblk_defs.h> -#include <sys/cvc.h> -#include <sys/cpu_sgn.h> - -extern void prom_printf(char *fmt, ...); - -static int cvc_info(dev_info_t *, ddi_info_cmd_t, void *, void **); -static int cvc_attach(dev_info_t *, ddi_attach_cmd_t); -static int cvc_detach(dev_info_t *, ddi_detach_cmd_t); -static int cvc_open(register queue_t *, dev_t *, int, int, cred_t *); -static int cvc_close(queue_t *, int, cred_t *); -static int cvc_wput(queue_t *, mblk_t *); -static int cvc_wsrv(queue_t *); -static void cvc_ioctl(queue_t *, mblk_t *); -static void cvc_ack(mblk_t *, mblk_t *, uint_t); -static void cvc_reioctl(void *); -static void cvc_input_daemon(void); -static void cvc_putc(register int); -static void cvc_flush_buf(void *); -static void cvc_bbsram_ops(volatile uchar_t *); - -static caddr_t cvc_iobuf_mapin(processorid_t); -static void cvc_iobuf_mapout(processorid_t); - void cvc_assign_iocpu(processorid_t); - -/* - * Private copy of devinfo pointer; cvc_info uses it. - */ -static dev_info_t *cvcdip; - -/* - * This buffer is used to manage mapping in the I/O buffer that CVC - * uses when communicating with the SSP Client (netcon_server) via bbsram. - */ -static caddr_t cvc_iobufp[NCPU]; - -typedef struct cvc_s { - bufcall_id_t cvc_wbufcid; - tty_common_t cvc_tty; -} cvc_t; - -cvc_t cvc_common_tty; - -static struct module_info cvcm_info = { - 1313, /* mi_idnum Bad luck number ;-) */ - "cvc", /* mi_idname */ - 0, /* mi_minpsz */ - INFPSZ, /* mi_maxpsz */ - 2048, /* mi_hiwat */ - 2048 /* mi_lowat */ -}; - -static struct qinit cvcrinit = { - NULL, /* qi_putp */ - NULL, /* qi_srvp */ - cvc_open, /* qi_qopen */ - cvc_close, /* qi_qclose */ - NULL, /* qi_qadmin */ - &cvcm_info, /* qi_minfo */ - NULL /* qi_mstat */ -}; - -static struct qinit cvcwinit = { - cvc_wput, /* qi_putp */ - cvc_wsrv, /* qi_srvp */ - cvc_open, /* qi_qopen */ - cvc_close, /* qi_qclose */ - NULL, /* qi_qadmin */ - &cvcm_info, /* qi_minfo */ - NULL /* qi_mstat */ -}; - -struct streamtab cvcinfo = { - &cvcrinit, /* st_rdinit */ - &cvcwinit, /* st_wrinit */ - NULL, /* st_muxrinit */ - NULL /* st_muxwrinit */ -}; - -#define TIMEOUT_DELAY 100000 - -#define BBSRAM_INPUT_BUF ((volatile char *)(cvc_iobufp[cvc_iocpu] \ - + BBSRAM_INPUT_COUNT_OFF)) - -#define BBSRAM_OUTPUT_BUF ((volatile char *)(cvc_iobufp[cvc_iocpu] \ - + BBSRAM_OUTPUT_COUNT_OFF)) - -#define BBSRAM_INPUT_COUNT (*((volatile short *)BBSRAM_INPUT_BUF)) - -#define BBSRAM_OUTPUT_COUNT (*((volatile short *)BBSRAM_OUTPUT_BUF)) - -#define CVC_OUT_MAXSPIN 1024 - -/* The bbsram control reg is located at the end of the I/O buffers */ -#define BBSRAM_CONTROL_REG ((volatile uchar_t *)(cvc_iobufp[cvc_iocpu] \ - + CVC_IN_SIZE + CVC_OUT_SIZE)) - -static krwlock_t cvclock; /* lock protecting everything here */ -static queue_t *cvcinput_q; /* queue for console input */ -static queue_t *cvcoutput_q; /* queue for console output */ -static int cvc_instance = -1; -static int cvc_stopped = 0; -static int cvc_suspended = 0; -static int cvc_hangup_ok = 0; - -static kthread_id_t cvc_input_daemon_thread; -static kmutex_t cvcmutex; /* protects input */ -static kmutex_t cvc_buf_mutex; /* protects internal output buffer */ -static kmutex_t cvc_bbsram_input_mutex; /* protects BBSRAM inp buff */ -static int input_ok = 0; /* true when stream is valid */ -static int stop_bbsram = 1; /* true when BBSRAM is not usable */ -static int stop_timeout = 0; -static uchar_t cvc_output_buffer[MAX_XFER_OUTPUT]; /* output buffer */ -static ushort_t cvc_output_count = 0; -static int via_bbsram = 0; /* toggle switch */ -static timeout_id_t cvc_timeout_id = (timeout_id_t)-1; -static processorid_t cvc_iocpu = -1; /* cpu id of cpu zero */ - -/* - * Module linkage information for the kernel. - */ - -DDI_DEFINE_STREAM_OPS(cvcops, nulldev, nulldev, cvc_attach, cvc_detach, - nodev, cvc_info, (D_MTPERQ | D_MP), &cvcinfo, - ddi_quiesce_not_supported); - -static struct modldrv modldrv = { - &mod_driverops, /* Type of module. This one is a pseudo driver */ - "CVC driver 'cvc'", - &cvcops, /* driver ops */ -}; - -static struct modlinkage modlinkage = { - MODREV_1, - &modldrv, - NULL -}; - -int -_init(void) -{ - int status; - - status = mod_install(&modlinkage); - if (status == 0) { - mutex_init(&cvcmutex, NULL, MUTEX_DEFAULT, NULL); - } - return (status); -} - -int -_fini(void) -{ - return (EBUSY); -} - -int -_info(struct modinfo *modinfop) -{ - return (mod_info(&modlinkage, modinfop)); -} - -/* - * DDI glue routines. - */ - -/* ARGSUSED */ -static int -cvc_attach(dev_info_t *devi, ddi_attach_cmd_t cmd) -{ - static char been_here = 0; - - if (cmd == DDI_RESUME) { - cvc_suspended = 0; - return (DDI_SUCCESS); - } - - mutex_enter(&cvcmutex); - if (!been_here) { - been_here = 1; - mutex_init(&cvc_buf_mutex, NULL, MUTEX_DEFAULT, NULL); - mutex_init(&cvc_bbsram_input_mutex, NULL, MUTEX_DEFAULT, NULL); - rw_init(&cvclock, NULL, RW_DRIVER, NULL); - rw_enter(&cvclock, RW_WRITER); - cvc_timeout_id = timeout(cvc_flush_buf, NULL, - drv_usectohz(TIMEOUT_DELAY)); - rw_exit(&cvclock); - cvc_instance = ddi_get_instance(devi); - } else { -#if defined(DEBUG) - cmn_err(CE_NOTE, - "cvc_attach: called multiple times!! (instance = %d)", - ddi_get_instance(devi)); -#endif /* DEBUG */ - return (DDI_SUCCESS); - } - mutex_exit(&cvcmutex); - - if (ddi_create_minor_node(devi, "cvc", S_IFCHR, - 0, DDI_PSEUDO, NULL) == DDI_FAILURE) { - ddi_remove_minor_node(devi, NULL); - return (-1); - } - cvcdip = devi; - cvcinput_q = NULL; - cvcoutput_q = NULL; - return (DDI_SUCCESS); -} - -static int -cvc_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) -{ - if (cmd == DDI_SUSPEND) { - cvc_suspended = 1; - } else { - if (cmd != DDI_DETACH) { - return (DDI_FAILURE); - } - /* - * XXX this doesn't even begin to address the detach - * issues - it doesn't terminate the outstanding thread, - * it doesn't clean up mutexes, kill the timeout routine - * etc. - */ - if (cvc_instance == ddi_get_instance(dip)) { - ddi_remove_minor_node(dip, NULL); - } - } - return (DDI_SUCCESS); -} - -/* ARGSUSED */ -static int -cvc_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result) -{ - register int error; - - switch (infocmd) { - case DDI_INFO_DEVT2DEVINFO: - if (cvcdip == NULL) { - error = DDI_FAILURE; - } else { - *result = (void *)cvcdip; - error = DDI_SUCCESS; - } - break; - case DDI_INFO_DEVT2INSTANCE: - *result = (void *)0; - error = DDI_SUCCESS; - break; - default: - error = DDI_FAILURE; - } - return (error); -} - -/* ARGSUSED */ -static int -cvc_open(register queue_t *q, dev_t *devp, int flag, int sflag, cred_t *crp) -{ - register int unit = getminor(*devp); - register int err = 0; - tty_common_t *tty; - cvc_t *cp; - static int input_daemon_started; - - if (unit != 0) - return (ENXIO); - - if (q->q_ptr) - return (0); - - cp = (cvc_t *)&cvc_common_tty; - bzero((caddr_t)cp, sizeof (cvc_t)); - cp->cvc_wbufcid = 0; - tty = &cp->cvc_tty; - tty->t_readq = q; - tty->t_writeq = WR(q); - WR(q)->q_ptr = q->q_ptr = (caddr_t)cp; - cvcinput_q = RD(q); /* save for cvc_redir */ - qprocson(q); - mutex_enter(&cvcmutex); - input_ok = 1; - if (!input_daemon_started) { - extern struct cpu *SIGBCPU; /* bugid4141050 */ - extern cpu_sgnblk_t *cpu_sgnblkp[]; - - input_daemon_started = 1; - mutex_exit(&cvcmutex); - - ASSERT(cpu_sgnblkp[SIGBCPU->cpu_id] != NULL); - cvc_assign_iocpu(SIGBCPU->cpu_id); - - cvc_input_daemon_thread = thread_create(NULL, 0, - cvc_input_daemon, NULL, 0, &p0, TS_RUN, minclsyspri); - } else { - mutex_exit(&cvcmutex); - } -#ifdef lint - cvc_input_daemon_thread = cvc_input_daemon_thread; -#endif - return (err); -} - -/* ARGSUSED */ -static int -cvc_close(queue_t *q, int flag, cred_t *crp) -{ - register int err = 0; - register cvc_t *cp; - - mutex_enter(&cvcmutex); - input_ok = 0; - mutex_exit(&cvcmutex); - - cp = q->q_ptr; - if (cp->cvc_wbufcid != 0) { - unbufcall(cp->cvc_wbufcid); - } - ttycommon_close(&cp->cvc_tty); - WR(q)->q_ptr = q->q_ptr = NULL; - cvcinput_q = NULL; - bzero((caddr_t)cp, sizeof (cvc_t)); - qprocsoff(q); - return (err); -} - - -/* - * cvc_wput() - * cn driver does a strwrite of console output data to rconsvp which - * has been set by consconfig. The data enters the cvc stream at the - * streamhead and flows thru ttycompat and ldterm which have been - * pushed on the stream. Console output data gets sent out either - * by cvcredir (if there is a cvcd running) or bbsram (if there - * isn't). - * Data is sent to the cvcredir via it's read q which is cvcoutput_q - * and was set in cvc_register(). - */ -static int -cvc_wput(register queue_t *q, register mblk_t *mp) -{ - int error = 0; - - rw_enter(&cvclock, RW_READER); - switch (mp->b_datap->db_type) { - - case M_IOCTL: - case M_CTL: - cvc_ioctl(q, mp); - break; - - case M_FLUSH: - if (*mp->b_rptr & FLUSHW) { - /* - * Flush our write queue. - */ - flushq(q, FLUSHDATA); - *mp->b_rptr &= ~FLUSHW; - } - if (*mp->b_rptr & FLUSHR) { - flushq(RD(q), FLUSHDATA); - qreply(q, mp); - } else - freemsg(mp); - break; - - case M_STOP: - cvc_stopped = 1; - freemsg(mp); - break; - - case M_START: - cvc_stopped = 0; - freemsg(mp); - qenable(q); /* Start up delayed messages */ - break; - - case M_READ: - /* - * ldterm handles this (VMIN/VTIME processing). - */ - freemsg(mp); - break; - default: - cmn_err(CE_WARN, "cvc_wput: illegal mblk = 0x%p", - (void *)mp); - cmn_err(CE_WARN, "cvc_wput: type = 0x%x", - mp->b_datap->db_type); - /* FALLTHROUGH */ -#ifdef lint - break; -#endif - - case M_DATA: - if (cvc_stopped == 1 || cvc_suspended == 1) { - (void) putq(q, mp); - break; - } - if (cvcoutput_q != NULL && !via_bbsram) { - /* - * Send it up past cvcredir module. - */ - putnext(cvcoutput_q, mp); - } else { - char *msgp, c; - mblk_t *mp2 = mp; - int count; - - while (mp2 != NULL) { - count = mp2->b_wptr - mp2->b_rptr; - msgp = (char *)mp2->b_rptr; - while (count > 0) { - count--; - if ((c = *msgp++) != '\0') { - /* don't print NULs */ - cvc_putc(c); - } - } - mp2 = mp2->b_cont; - } - freemsg(mp); - } - break; - - } - rw_exit(&cvclock); - return (error); -} - -static int cvc_wsrv_count = 0; - -static int -cvc_wsrv(queue_t *q) -{ - register mblk_t *mp; - - cvc_wsrv_count++; - - if (cvc_stopped == 1 || cvc_suspended == 1) { - return (0); - } - - rw_enter(&cvclock, RW_READER); - while ((mp = getq(q)) != NULL) { - if (cvcoutput_q != NULL && !via_bbsram) { - /* - * Send it up past cvcredir module. - */ - putnext(cvcoutput_q, mp); - } else { - char *msgp, c; - mblk_t *mp2 = mp; - int count; - - while (mp2 != NULL) { - count = mp2->b_wptr - mp2->b_rptr; - msgp = (char *)mp2->b_rptr; - while (count > 0) { - count--; - if ((c = *msgp++) != '\0') { - /* don't print NULs */ - cvc_putc(c); - } - } - mp2 = mp2->b_cont; - } - freemsg(mp); - } - } - rw_exit(&cvclock); - return (0); -} - - -/* - * cvc_ioctl() - * handle normal console ioctls. - */ -static void -cvc_ioctl(register queue_t *q, register mblk_t *mp) -{ - register struct iocblk *iocp; - register tty_common_t *tty; - register cvc_t *cp; - int datasize; - int error = 0; - mblk_t *tmp; - - cp = q->q_ptr; - tty = &cp->cvc_tty; - if (tty->t_iocpending != NULL) { - freemsg(tty->t_iocpending); - tty->t_iocpending = NULL; - } - datasize = ttycommon_ioctl(tty, q, mp, &error); - if (datasize != 0) { - if (cp->cvc_wbufcid) - unbufcall(cp->cvc_wbufcid); - cp->cvc_wbufcid = bufcall(datasize, BPRI_HI, cvc_reioctl, cp); - return; - } - if (error < 0) { - iocp = (struct iocblk *)mp->b_rptr; - /* - * "ttycommon_ioctl" didn't do anything; we process it here. - */ - error = 0; - switch (iocp->ioc_cmd) { - - /* - * Set modem bit ioctls. These are NOPs for us, since we - * dont control any hardware. - */ - case TCSBRK: - case TIOCSBRK: - case TIOCCBRK: - case TIOCMSET: - case TIOCMBIS: - case TIOCMBIC: - if (iocp->ioc_count != TRANSPARENT) { - mioc2ack(mp, NULL, 0, 0); - } else { - mcopyin(mp, NULL, sizeof (int), NULL); - } - /* qreply done below */ - break; - - /* - * Get modem bits, we return 0 in mblk. - */ - case TIOCMGET: - tmp = allocb(sizeof (int), BPRI_MED); - if (tmp == NULL) { - miocnak(q, mp, 0, EAGAIN); - return; - } - *(int *)tmp->b_rptr = 0; - - if (iocp->ioc_count != TRANSPARENT) - mioc2ack(mp, tmp, sizeof (int), 0); - else - mcopyout(mp, NULL, sizeof (int), NULL, tmp); - /* qreply done below */ - break; - - default: - /* - * If we don't understand it, it's an error. NAK it. - */ - error = EINVAL; - break; - } - } - if (error != 0) { - iocp->ioc_error = error; - mp->b_datap->db_type = M_IOCNAK; - } - qreply(q, mp); - -} - - -/* - * cvc_redir() - * called from cvcredir:cvcr_wput() to handle console input - * data. This routine puts the cvcredir write (downstream) data - * onto the cvc read (upstream) queues. Note that if `mp' is - * an M_IOCTL, then it may be reused by the caller to send back - * an M_IOCACK or M_IOCNAK. - */ -int -cvc_redir(mblk_t *mp) -{ - register struct iocblk *iocp; - register tty_common_t *tty; - register cvc_t *cp; - struct winsize *ws; - int error; - - if (cvcinput_q == NULL) { - cmn_err(CE_WARN, "cvc_redir: cvcinput_q NULL!"); - return (EINVAL); - } - - if (DB_TYPE(mp) != M_IOCTL) { - putnext(cvcinput_q, mp); - return (0); - } - - iocp = (struct iocblk *)mp->b_rptr; - if (iocp->ioc_cmd == TIOCSWINSZ) { - error = miocpullup(mp, sizeof (struct winsize)); - if (error != 0) - return (error); - - ws = (struct winsize *)mp->b_cont->b_rptr; - cp = cvcinput_q->q_ptr; - tty = &cp->cvc_tty; - mutex_enter(&tty->t_excl); - if (bcmp(&tty->t_size, ws, sizeof (struct winsize)) != 0) { - tty->t_size = *ws; - mutex_exit(&tty->t_excl); - (void) putnextctl1(cvcinput_q, M_PCSIG, SIGWINCH); - } else - mutex_exit(&tty->t_excl); - } else { - /* - * It must be a CVC_DISCONNECT, send hangup. - */ - ASSERT(iocp->ioc_cmd == CVC_DISCONNECT); - if (cvc_hangup_ok) - (void) putnextctl(cvcinput_q, M_HANGUP); - } - - return (0); -} - - -/* - * cvc_register() - * called from cvcredir to register it's queues. cvc - * receives data from cn via the streamhead and sends it to cvcredir - * via pointers to cvcredir's queues. - */ -int -cvc_register(queue_t *q) -{ - int error = -1; - - if (cvcinput_q == NULL) - cmn_err(CE_WARN, "cvc_register: register w/ no console open!"); - rw_enter(&cvclock, RW_WRITER); - if (cvcoutput_q == NULL) { - cvcoutput_q = RD(q); /* Make sure its the upstream q */ - qprocson(cvcoutput_q); /* must be done within cvclock */ - error = 0; - } else { - /* - * cmn_err will call us, so release lock. - */ - rw_exit(&cvclock); - if (cvcoutput_q == q) - cmn_err(CE_WARN, "cvc_register: duplicate q!"); - else - cmn_err(CE_WARN, "cvc_register: nondup q = 0x%p", - (void *)q); - return (error); - } - - /* - * Unless "via_bbsram" is set, i/o will be going through cvcd, so - * stop flushing output to BBSRAM. - */ - if ((cvc_timeout_id != (timeout_id_t)-1) && (!via_bbsram)) { - stop_timeout = 1; - (void) untimeout(cvc_timeout_id); - cvc_timeout_id = (timeout_id_t)-1; - cvc_hangup_ok = 1; - } - rw_exit(&cvclock); - return (error); -} - - -/* - * cvc_unregister() - * called from cvcredir to clear pointers to its queues. - * cvcredir no longer wants to send or receive data. - */ -void -cvc_unregister(queue_t *q) -{ - rw_enter(&cvclock, RW_WRITER); - if (q == cvcoutput_q) { - qprocsoff(cvcoutput_q); /* must be done within cvclock */ - cvcoutput_q = NULL; - } else { - rw_exit(&cvclock); - cmn_err(CE_WARN, "cvc_unregister: q = 0x%p not registered", - (void *)q); - return; - } - - /* - * i/o will not be going through cvcd, start flushing output to - * BBSRAM - */ - if (cvc_timeout_id == (timeout_id_t)-1) { - stop_timeout = 0; - cvc_timeout_id = timeout(cvc_flush_buf, NULL, - drv_usectohz(TIMEOUT_DELAY)); - } - rw_exit(&cvclock); -} - -/* - * cvc_reioctl() - * Retry an "ioctl", now that "bufcall" claims we may be able - * to allocate the buffer we need. - */ -static void -cvc_reioctl(void *unit) -{ - register queue_t *q; - register mblk_t *mp; - register cvc_t *cp = (cvc_t *)unit; - - /* - * The bufcall is no longer pending. - */ - if (!cp->cvc_wbufcid) { - return; - } - cp->cvc_wbufcid = 0; - if ((q = cp->cvc_tty.t_writeq) == NULL) { - return; - } - if ((mp = cp->cvc_tty.t_iocpending) != NULL) { - /* not pending any more */ - cp->cvc_tty.t_iocpending = NULL; - cvc_ioctl(q, mp); - } -} - - -/* - * cvc_bbsram_ops() - * Process commands sent to cvc from netcon_server via BBSRAM - */ -static void -cvc_bbsram_ops(volatile unsigned char *op_reg) -{ - uchar_t op; - - if ((op = *op_reg) == 0) - return; - - ASSERT(MUTEX_HELD(&cvc_bbsram_input_mutex)); - - switch (op) { - case CVC_BBSRAM_BREAK: /* A console break (L1-A) */ - abort_sequence_enter((char *)NULL); - break; - case CVC_BBSRAM_DISCONNECT: /* Break connection, hang up */ - if (cvcinput_q && cvc_hangup_ok) - (void) putnextctl(cvcinput_q, M_HANGUP); - break; - case CVC_BBSRAM_VIA_NET: /* console via network */ - via_bbsram = 0; - /* - * stop periodic flushing of output to BBSRAM - * only if cvcredir/cvcd are present - */ - rw_enter(&cvclock, RW_WRITER); - if (cvcoutput_q != NULL) { - stop_timeout = 1; - if (cvc_timeout_id != (timeout_id_t)-1) { - (void) untimeout(cvc_timeout_id); - cvc_timeout_id = (timeout_id_t)-1; - } - } - rw_exit(&cvclock); - break; - case CVC_BBSRAM_VIA_BBSRAM: /* console via bbsram */ - via_bbsram = 1; - /* start periodic flushing of ouput to BBSRAM */ - rw_enter(&cvclock, RW_WRITER); - if (cvc_timeout_id == (timeout_id_t)-1) { - stop_timeout = 0; - cvc_timeout_id = timeout(cvc_flush_buf, - NULL, drv_usectohz(TIMEOUT_DELAY)); - } - rw_exit(&cvclock); - break; - case CVC_BBSRAM_CLOSE_NET: - /* - * Send a hangup control message upstream to cvcd - * thru cvcredir. This is an attempt to close - * out any existing network connection(if any). - * cvcoutput_q should point to the cvcredir's read - * queue. - */ - rw_enter(&cvclock, RW_READER); - if (cvcoutput_q != NULL) { - (void) putnextctl(cvcoutput_q, M_HANGUP); - } - rw_exit(&cvclock); - break; - default: - cmn_err(CE_WARN, "cvc: unknown BBSRAM opcode %d\n", - (unsigned int)op); - break; - } - *op_reg = 0; -} - - -/* - * cvc_putc() - * Put a single character out to BBSRAM if space available. - */ -static void -cvc_putc(register int c) -{ - static int output_lost = 0; - - if (c == '\n') - cvc_putc('\r'); - - mutex_enter(&cvc_buf_mutex); - /* - * Just exit if the buffer is already full. - * It will be up to cvc_flush_buf() to flush the buffer. - */ - if (cvc_output_count == MAX_XFER_OUTPUT) { - output_lost = 1; - mutex_exit(&cvc_buf_mutex); - return; - } - if (output_lost) - prom_printf("WARNING: overflow of cvc output buffer, " - "output lost!"); - output_lost = 0; - cvc_output_buffer[cvc_output_count] = (unsigned char)c; - cvc_output_count++; - if ((cvc_output_count == MAX_XFER_OUTPUT) || (c == '\n')) { - /* flush cvc's internal output buffer to BBSRAM */ - - /* - * Wait for the BBSRAM output buffer to be emptied. - * This may hang if netcon_server isn't running on the SSP - */ - int maxspin = CVC_OUT_MAXSPIN; - while ((BBSRAM_OUTPUT_COUNT != 0) && --maxspin) { - if (stop_bbsram) { - mutex_exit(&cvc_buf_mutex); - return; - } - DELAY(1000); - } - bcopy((caddr_t)cvc_output_buffer, - (caddr_t)(BBSRAM_OUTPUT_BUF - cvc_output_count), - cvc_output_count); - - BBSRAM_OUTPUT_COUNT = cvc_output_count; - cvc_output_count = 0; - } - mutex_exit(&cvc_buf_mutex); -} - - -/* - * cvc_flush_buf() - * Flush cvc's internal output buffer to BBSRAM at regular intervals. - * This should only be done if cvcd is not running or the user (via the cvc - * application on the SSP) has requested that i/o go through BBSRAM. - */ -/* ARGSUSED */ -static void -cvc_flush_buf(void *notused) -{ - if (stop_timeout) - return; - - mutex_enter(&cvc_buf_mutex); - if (cvc_output_count != 0) { - /* - * Wait for the BBSRAM output buffer to be emptied. - * This may hang if netcon_server isn't running on the SSP. - */ - int maxspin = CVC_OUT_MAXSPIN; - while ((BBSRAM_OUTPUT_COUNT != 0) && --maxspin) { - if (stop_bbsram) - goto exit; - DELAY(1000); - } - - bcopy((caddr_t)cvc_output_buffer, - (caddr_t)BBSRAM_OUTPUT_BUF - cvc_output_count, - cvc_output_count); - - BBSRAM_OUTPUT_COUNT = cvc_output_count; - cvc_output_count = 0; - } -exit: - mutex_exit(&cvc_buf_mutex); - /* rw_enter(&cvclock, RW_WRITER); */ - cvc_timeout_id = timeout(cvc_flush_buf, NULL, - drv_usectohz(TIMEOUT_DELAY)); - /* rw_exit(&cvclock); */ -} - - -/* - * cvc_getstr() - * Poll BBSRAM for console input while available. - */ -static void -cvc_getstr(char *cp) -{ - short count; - volatile char *lp; - - mutex_enter(&cvc_bbsram_input_mutex); - /* Poll BBSRAM for input */ - do { - if (stop_bbsram) { - *cp = '\0'; /* set string to zero-length */ - mutex_exit(&cvc_bbsram_input_mutex); - return; - } - /* - * Use a smaller delay between checks of BBSRAM for input - * when cvcd/cvcredir are not running or "via_bbsram" has - * been set. - * We don't go away completely when i/o is going through the - * network via cvcd since a command may be sent via BBSRAM - * to switch if the network is down or hung. - */ - if ((cvcoutput_q == NULL) || (via_bbsram)) - delay(drv_usectohz(100000)); - else - delay(drv_usectohz(1000000)); - cvc_bbsram_ops(BBSRAM_CONTROL_REG); - count = BBSRAM_INPUT_COUNT; - } while (count == 0); - - lp = BBSRAM_INPUT_BUF - count; - - while (count--) { - *cp++ = *lp++; - } - *cp = '\0'; - - BBSRAM_INPUT_COUNT = 0; - mutex_exit(&cvc_bbsram_input_mutex); -} - - -/* - * cvc_input_daemon() - * this function runs as a separate kernel thread and polls BBSRAM for - * input, and possibly put it on read stream for the console. - * There are two poll rates (implemented in cvc_getstr): - * 100 000 uS (10 Hz) - no cvcd communications || via_bbsram - * 1000 000 uS ( 1 Hz) - cvcd communications - * This continues to run even if there are network console communications - * in order to handle out-of-band signaling. - */ -static void -cvc_input_daemon(void) -{ - char linebuf[MAX_XFER_INPUT]; - char *cp; - mblk_t *mbp; - int c; - int dropped_read = 0; - - for (;;) { - cvc_getstr(linebuf); - - mbp = allocb(strlen(linebuf), BPRI_MED); - if (mbp == NULL) { /* drop it & go on if no buffer */ - if (!dropped_read) { - cmn_err(CE_WARN, - "cvc_input_daemon: " - "dropping BBSRAM reads\n"); - } - dropped_read++; - continue; - } - if (dropped_read) { - cmn_err(CE_WARN, - "cvc_input_daemon: dropped %d BBSRAM reads\n", - dropped_read); - dropped_read = 0; - } - - for (cp = linebuf; *cp != '\0'; cp++) { - c = (int)*cp; - if (c == '\r') - c = '\n'; - c &= 0177; - *mbp->b_wptr = (char)c; - mbp->b_wptr++; - } - mutex_enter(&cvcmutex); - if (input_ok) { - if (cvcinput_q == NULL) { - cmn_err(CE_WARN, - "cvc_input_daemon: cvcinput_q is NULL!"); - } else { - putnext(cvcinput_q, mbp); - } - } else { - freemsg(mbp); - } - mutex_exit(&cvcmutex); - } - - /* NOTREACHED */ -} - - -/* - * cvc_bbsram_stop() - * Prevents accesses to BBSRAM. used by cvc_assign_iocpu() when - * mapping in BBSRAM to a virtual address. - */ -static void -cvc_bbsram_stop(void) -{ - stop_bbsram = 1; - mutex_enter(&cvc_bbsram_input_mutex); - mutex_enter(&cvc_buf_mutex); -} - - -/* - * cvc_bbsram_start() - * Allow accesses to BBSRAM, used by cvc_assign_iocpu() after - * BBSRAM has been mapped to a virtual address. - */ -static void -cvc_bbsram_start(void) -{ - stop_bbsram = 0; - mutex_exit(&cvc_buf_mutex); - mutex_exit(&cvc_bbsram_input_mutex); -} - - -/* - * cvc_assign_iocpu() - * Map in BBSRAM to a virtual address - * This called by the kernel with the cpu id of cpu zero. - */ -void -cvc_assign_iocpu(processorid_t newcpu) -{ - processorid_t oldcpu = cvc_iocpu; - - if (newcpu == oldcpu) - return; - - cvc_iobufp[newcpu] = cvc_iobuf_mapin(newcpu); - - cvc_bbsram_stop(); - - cvc_iocpu = newcpu; - - cvc_bbsram_start(); - - if (oldcpu != -1) - cvc_iobuf_mapout(oldcpu); -} - - -/* - * cvc_iobuf_mapin() - * Map in the cvc bbsram i/o buffer into kernel space. - */ -static caddr_t -cvc_iobuf_mapin(processorid_t cpu_id) -{ - caddr_t cvaddr; - uint64_t cvc_iobuf_physaddr; - pfn_t pfn; - uint_t num_pages; - extern cpu_sgnblk_t *cpu_sgnblkp[]; - - ASSERT(cpu_sgnblkp[cpu_id] != NULL); - - /* - * First construct the physical base address of the bbsram - * in Starfire PSI space associated with this cpu in question. - */ - cvc_iobuf_physaddr = STARFIRE_UPAID2UPS(cpu_id) | STARFIRE_PSI_BASE; - - /* - * Next add the cvc i/o buffer offset obtained from the - * sigblock to get cvc iobuf physical address - */ - cvc_iobuf_physaddr += cpu_sgnblkp[cpu_id]->sigb_cvc_off; - - /* Get the page frame number */ - pfn = (cvc_iobuf_physaddr >> MMU_PAGESHIFT); - - /* Calculate how many pages we need to map in */ - num_pages = mmu_btopr(((uint_t)(cvc_iobuf_physaddr - & MMU_PAGEOFFSET) + sizeof (sigb_cvc_t))); - - /* - * Map in the cvc iobuf - */ - cvaddr = vmem_alloc(heap_arena, ptob(num_pages), VM_SLEEP); - - hat_devload(kas.a_hat, cvaddr, mmu_ptob(num_pages), pfn, - PROT_READ | PROT_WRITE, HAT_LOAD_LOCK); - - return ((caddr_t)(cvaddr + (uint_t)(cvc_iobuf_physaddr - & MMU_PAGEOFFSET))); -} - - -/* - * cvc_iobuf_mapout() - * Map out the cvc iobuf from kernel space - */ -static void -cvc_iobuf_mapout(processorid_t cpu_id) -{ - caddr_t cvaddr; - size_t num_pages; - - if ((cvaddr = cvc_iobufp[cpu_id]) == 0) { - /* already unmapped - return */ - return; - } - - /* Calculate how many pages we need to map out */ - num_pages = mmu_btopr(((size_t)((uint64_t)cvaddr & MMU_PAGEOFFSET) + - sizeof (sigb_cvc_t))); - - /* Get cvaddr to the start of the page boundary */ - cvaddr = (caddr_t)(((uint64_t)cvaddr & MMU_PAGEMASK)); - - hat_unload(kas.a_hat, cvaddr, mmu_ptob(num_pages), HAT_UNLOAD_UNLOCK); - vmem_free(heap_arena, cvaddr, ptob(num_pages)); - - cvc_iobufp[cpu_id] = NULL; -} diff --git a/usr/src/uts/sun4u/starfire/cvc/cvc.conf b/usr/src/uts/sun4u/starfire/cvc/cvc.conf deleted file mode 100644 index 50abb823fe..0000000000 --- a/usr/src/uts/sun4u/starfire/cvc/cvc.conf +++ /dev/null @@ -1,28 +0,0 @@ -# -# 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 -# or http://www.opensolaris.org/os/licensing. -# 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 -# -# -# ident "%Z%%M% %I% %E% SMI" -# -# Copyright (c) 1996 by Sun Microsystems, Inc. -# All rights reserved. -# -name="cvc" parent="pseudo" instance=0; diff --git a/usr/src/uts/sun4u/starfire/cvcredir/Makefile b/usr/src/uts/sun4u/starfire/cvcredir/Makefile deleted file mode 100644 index 6725d33bef..0000000000 --- a/usr/src/uts/sun4u/starfire/cvcredir/Makefile +++ /dev/null @@ -1,92 +0,0 @@ -# -# 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 -# or http://www.opensolaris.org/os/licensing. -# 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 2004 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# Copyright (c) 2011 Bayard G. Bell. All rights reserved. -# -# This makefile drives the production of the cvcredir driver module. -# -# sun4u starfire implementation architecture dependent -# - -# -# Path to the base of the uts directory tree (usually /usr/src/uts). -# -UTSBASE = ../../.. - -# -# Define the module and object file sets. -# -MODULE = cvcredir -OBJECTS = $(CVCREDIR_OBJS:%=$(OBJS_DIR)/%) -LINTS = $(CVCREDIR_OBJS:%.o=$(LINTS_DIR)/%.ln) -ROOTMODULE = $(ROOT_STARFIRE_DRV_DIR)/$(MODULE) -CONF_SRCDIR = $(UTSBASE)/sun4u/starfire/cvcredir - -# -# Include common rules. -# -include $(UTSBASE)/sun4u/starfire/Makefile.starfire - -# -# Define targets -# -ALL_TARGET = $(BINARY) $(SRC_CONFFILE) -LINT_TARGET = $(MODULE).lint -INSTALL_TARGET = $(BINARY) $(ROOTMODULE) $(ROOT_CONFFILE) - -# -# lint pass one enforcement -# -CFLAGS += $(CCVERBOSE) - -# -# Define dependency on cvc -# -LDFLAGS += -dy -N drv/cvc - -# -# Default build targets. -# -.KEEP_STATE: - -def: $(DEF_DEPS) - -all: $(ALL_DEPS) - -clean: $(CLEAN_DEPS) - -clobber: $(CLOBBER_DEPS) - -lint: $(LINT_DEPS) - -modlintlib: $(MODLINTLIB_DEPS) - -clean.lint: $(CLEAN_LINT_DEPS) - -install: $(INSTALL_DEPS) - -# -# Include common targets. -# -include $(UTSBASE)/sun4u/starfire/Makefile.targ diff --git a/usr/src/uts/sun4u/starfire/cvcredir/cvcredir.c b/usr/src/uts/sun4u/starfire/cvcredir/cvcredir.c deleted file mode 100644 index 05e9784933..0000000000 --- a/usr/src/uts/sun4u/starfire/cvcredir/cvcredir.c +++ /dev/null @@ -1,278 +0,0 @@ -/* - * 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 - * or http://www.opensolaris.org/os/licensing. - * 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. - * Copyright (c) 2011 Bayard G. Bell. All rights reserved. - */ - - -/* - * MT STREAMS Virtual Console Redirection Device Driver - */ - -#include <sys/types.h> -#include <sys/param.h> -#include <sys/errno.h> -#include <sys/kmem.h> -#include <sys/stat.h> -#include <sys/stream.h> -#include <sys/stropts.h> -#include <sys/strsun.h> -#include <sys/debug.h> -#include <sys/thread.h> -#include <sys/conf.h> -#include <sys/ddi.h> -#include <sys/sunddi.h> -#include <sys/tty.h> -#include <sys/cvc.h> -#include <sys/conf.h> -#include <sys/modctl.h> - - -/* - * Routine to to register/unregister our queue for console output and pass - * redirected data to the console. The cvc driver will do a putnext using - * our queue, so we will not see the redirected console data. - */ -extern int cvc_redir(mblk_t *); -extern int cvc_register(queue_t *); -extern int cvc_unregister(queue_t *); - -static int cvcr_info(dev_info_t *, ddi_info_cmd_t, void *, void **); -static int cvcr_attach(dev_info_t *, ddi_attach_cmd_t); -static int cvcr_detach(dev_info_t *, ddi_detach_cmd_t); -static int cvcr_wput(queue_t *, mblk_t *); -static int cvcr_open(queue_t *, dev_t *, int, int, cred_t *); -static int cvcr_close(queue_t *, int, cred_t *); -static void cvcr_ioctl(queue_t *, mblk_t *); - -static dev_info_t *cvcr_dip; -static int cvcr_suspend = 0; - -static struct module_info minfo = { - 1314, /* mi_idnum Bad luck number +1 ;-) */ - "cvcredir", /* mi_idname */ - 0, /* mi_minpsz */ - INFPSZ, /* mi_maxpsz */ - 2048, /* mi_hiwat */ - 2048 /* mi_lowat */ -}; - -static struct qinit cvcr_rinit = { - NULL, /* qi_putp */ - NULL, /* qi_srvp */ - cvcr_open, /* qi_qopen */ - cvcr_close, /* qi_qclose */ - NULL, /* qi_qadmin */ - &minfo, /* qi_minfo */ - NULL /* qi_mstat */ -}; - -static struct qinit cvcr_winit = { - cvcr_wput, /* qi_putp */ - NULL, /* qi_srvp */ - cvcr_open, /* qi_qopen */ - cvcr_close, /* qi_qclose */ - NULL, /* qi_qadmin */ - &minfo, /* qi_minfo */ - NULL /* qi_mstat */ -}; - -struct streamtab cvcrinfo = { - &cvcr_rinit, /* st_rdinit */ - &cvcr_winit, /* st_wrinit */ - NULL, /* st_muxrinit */ - NULL /* st_muxwrinit */ -}; - -DDI_DEFINE_STREAM_OPS(cvcrops, nulldev, nulldev, cvcr_attach, - cvcr_detach, nodev, cvcr_info, (D_MTPERQ | D_MP), &cvcrinfo, - ddi_quiesce_not_supported); - -static struct modldrv modldrv = { - &mod_driverops, /* Type of module. This one is a pseudo driver */ - "CVC redirect driver 'cvcredir'", - &cvcrops, /* driver ops */ -}; - -static struct modlinkage modlinkage = { - MODREV_1, - &modldrv, - NULL -}; - -int -_init(void) -{ - return (mod_install(&modlinkage)); -} - -int -_fini(void) -{ - return (mod_remove(&modlinkage)); -} - -int -_info(struct modinfo *modinfop) -{ - return (mod_info(&modlinkage, modinfop)); -} - -static int -cvcr_attach(dev_info_t *devi, ddi_attach_cmd_t cmd) -{ -#ifdef lint - cvcr_suspend = cvcr_suspend; -#endif - if (cmd == DDI_RESUME) { - cvcr_suspend = 0; - } else { - if (ddi_create_minor_node(devi, "cvcredir", S_IFCHR, - 0, DDI_PSEUDO, NULL) == DDI_FAILURE) { - ddi_remove_minor_node(devi, NULL); - return (-1); - } - cvcr_dip = devi; - } - return (DDI_SUCCESS); -} - -static int -cvcr_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) -{ - if (cmd == DDI_SUSPEND) { - cvcr_suspend = 1; - } else { - if (cmd != DDI_DETACH) { - return (DDI_FAILURE); - } - ddi_remove_minor_node(dip, NULL); - } - return (DDI_SUCCESS); -} - -/* ARGSUSED */ -static int -cvcr_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result) -{ - register int error; - - switch (infocmd) { - case DDI_INFO_DEVT2DEVINFO: - if (cvcr_dip == NULL) { - error = DDI_FAILURE; - } else { - *result = (void *)cvcr_dip; - error = DDI_SUCCESS; - } - break; - case DDI_INFO_DEVT2INSTANCE: - *result = (void *)0; - error = DDI_SUCCESS; - break; - default: - error = DDI_FAILURE; - } - return (error); -} - -/* ARGSUSED */ -static int -cvcr_open(queue_t *q, dev_t *dev, int flag, int sflag, cred_t *cred) -{ - WR(q)->q_ptr = q->q_ptr = (char *)2; - /* - * call into the cvc driver to register our queue. cvc will use - * our queue to send console output data upstream (our stream)to - * cvcd which has us open and is reading console data. - */ - if (cvc_register(RD(q)) == -1) { - cmn_err(CE_WARN, "cvcr_open: cvc_register failed for q = 0x%p", - (void *)q); - } - return (0); -} - -/* ARGSUSED */ -static int -cvcr_close(queue_t *q, int flag, cred_t *cred) -{ - /* - * call into the cvc driver to un-register our queue. cvc will - * no longer use our queue to send console output data upstream. - */ - (void) cvc_unregister(RD(q)); - WR(q)->q_ptr = q->q_ptr = NULL; - return (0); -} - -static int -cvcr_wput(queue_t *q, mblk_t *mp) -{ - /* - * Handle BREAK key for debugger and TIOCSWINSZ. - */ - if (mp->b_datap->db_type == M_IOCTL) { - cvcr_ioctl(q, mp); - return (0); - } - /* - * Call into the cvc driver to put console input data on - * its upstream queue to be picked up by the console driver. - */ - if (cvc_redir(mp) != 0) - freemsg(mp); - return (0); -} - -static void -cvcr_ioctl(queue_t *q, mblk_t *mp) -{ - struct iocblk *iocp = (struct iocblk *)mp->b_rptr; - int error; - - switch (iocp->ioc_cmd) { - case CVC_BREAK: - abort_sequence_enter(NULL); - miocack(q, mp, 0, 0); - break; - - case CVC_DISCONNECT: - case TIOCSWINSZ: - /* - * Generate a SIGHUP or SIGWINCH to the console. Note in this - * case cvc_redir does not free up mp, so we can reuse it for - * the ACK/NAK. - */ - error = cvc_redir(mp); - if (error != 0) - miocnak(q, mp, 0, error); - else - miocack(q, mp, 0, 0); - break; - - default: - miocnak(q, mp, 0, EINVAL); - break; - } -} diff --git a/usr/src/uts/sun4u/starfire/cvcredir/cvcredir.conf b/usr/src/uts/sun4u/starfire/cvcredir/cvcredir.conf deleted file mode 100644 index 64ed7ee2a3..0000000000 --- a/usr/src/uts/sun4u/starfire/cvcredir/cvcredir.conf +++ /dev/null @@ -1,28 +0,0 @@ -# -# 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 -# or http://www.opensolaris.org/os/licensing. -# 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 -# -# -# ident "%Z%%M% %I% %E% SMI" -# -# Copyright (c) 1996 by Sun Microsystems, Inc. -# All rights reserved. -# -name="cvcredir" parent="pseudo" instance=0; diff --git a/usr/src/uts/sun4u/starfire/genassym/Makefile b/usr/src/uts/sun4u/starfire/genassym/Makefile deleted file mode 100644 index 1d2dd04248..0000000000 --- a/usr/src/uts/sun4u/starfire/genassym/Makefile +++ /dev/null @@ -1,94 +0,0 @@ -# -# 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 -# or http://www.opensolaris.org/os/licensing. -# 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 -# -# -# ident "%Z%%M% %I% %E% SMI" -# -# Copyright 2004 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# -# This makefile drives the production of assym.h through genconst/stabs. -# -# sun4u starfire implementation architecture dependent -# - -# -# Path to the base of the uts directory tree (usually /usr/src/uts). -# -UTSBASE = ../../.. - -ASSYM_H = $(DSF_DIR)/$(OBJS_DIR)/assym.h -GENCONST = $(DSF_DIR)/$(OBJS_DIR)/genconst - -# -# Include common rules. -# -include $(UTSBASE)/sun4u/starfire/Makefile.starfire - -# -# Define targets -# -ALL_TARGET = $(ASSYM_H) - -# -# This is DSF_DIR. Use a short path. -# -DSF_DIR = . - -# -# Overrides -# -CLEANFILES = $(GENCONST) Nothing_to_remove -CLOBBERFILES = $(ASSYM_H) $(CLEANFILES) Nothing_to_remove - -# -# Default build targets. -# -.KEEP_STATE: - -def: $(DEF_DEPS) - -all: $(ALL_DEPS) - -clean: $(CLEAN_DEPS) - -clobber: $(CLOBBER_DEPS) - -clean.lint: - -install: def - -# -# create assym.h -# -$(GENCONST): $(GENCONST_SRC) - $(NATIVECC) -w $(ALWAYS_DEFS) $(GENCONST_DEFS) $(NATIVE_INC_PATH) \ - -o $(GENCONST) $(GENCONST_SRC) - -$(ASSYM_H): $(GENCONST) $(OFFSETS) $(PLATFORM_OFFSETS) - $(OFFSETS_CREATE) <$(OFFSETS) >$@ - $(OFFSETS_CREATE) <$(PLATFORM_OFFSETS) >>$@ - $(GENCONST) >>$@ - -# -# Include common targets. -# -include $(UTSBASE)/sun4u/starfire/Makefile.targ diff --git a/usr/src/uts/sun4u/starfire/idn/Makefile b/usr/src/uts/sun4u/starfire/idn/Makefile deleted file mode 100644 index 3d7de4962e..0000000000 --- a/usr/src/uts/sun4u/starfire/idn/Makefile +++ /dev/null @@ -1,103 +0,0 @@ -# -# 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 -# or http://www.opensolaris.org/os/licensing. -# 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 2004 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# - -# -# This makefile drives the production of the idn driver module. -# -# sun4u starfire implementation architecture dependent -# - -# -# Path to the base of the uts directory tree (usually /usr/src/uts). -# -UTSBASE = ../../.. - -# -# Define the module and object file sets. -# -MODULE = idn -OBJECTS = $(IDN_OBJS:%=$(OBJS_DIR)/%) -LINTS = $(IDN_OBJS:%.o=$(LINTS_DIR)/%.ln) -ROOTMODULE = $(ROOT_STARFIRE_DRV_DIR)/$(MODULE) -CONF_SRCDIR = $(UTSBASE)/sun4u/starfire/io - -IDN_OFFSETS = $(UTSBASE)/sun4u/starfire/ml/idn_offsets.in -IDN_OFFSETS_H = $(OBJS_DIR)/idn_offsets.h - -# -# Include common rules. -# -include $(UTSBASE)/sun4u/starfire/Makefile.starfire - -# -# Define targets -# -ALL_TARGET = $(BINARY) $(SRC_CONFFILE) -LINT_TARGET = $(MODULE).lint -INSTALL_TARGET = $(BINARY) $(ROOTMODULE) $(ROOT_CONFFILE) - -# -# lint pass one enforcement -# -CFLAGS += $(CCVERBOSE) -DIPV6 -CERRWARN += -_gcc=-Wno-unused-function -CERRWARN += -_gcc=-Wno-parentheses -CERRWARN += -_gcc=-Wno-uninitialized -CERRWARN += -_gcc=-Wno-type-limits - -# -# Default build targets. -# -.KEEP_STATE: - -def: $(DEF_DEPS) - -all: $(ALL_DEPS) - -clean: $(CLEAN_DEPS) - -clobber: $(CLOBBER_DEPS) - -lint: $(LINT_DEPS) - -modlintlib: $(MODLINTLIB_DEPS) - -clean.lint: $(CLEAN_LINT_DEPS) - -install: $(INSTALL_DEPS) - -AS_INC_PATH += -I$(OBJS_DIR) - -$(IDN_DEPS:%=$(OBJS_DIR)/%): $(IDN_OFFSETS_H) - -$(IDN_OFFSETS_H): $(GENCONST) $(IDN_OFFSETS) - $(OFFSETS_CREATE) <$(IDN_OFFSETS) >$@ - $(GENCONST) >>$@ - -# -# Include common targets. -# -include $(UTSBASE)/sun4u/starfire/Makefile.targ diff --git a/usr/src/uts/sun4u/starfire/io/drmach.c b/usr/src/uts/sun4u/starfire/io/drmach.c deleted file mode 100644 index dc51df3d6f..0000000000 --- a/usr/src/uts/sun4u/starfire/io/drmach.c +++ /dev/null @@ -1,3857 +0,0 @@ -/* - * 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 - * or http://www.opensolaris.org/os/licensing. - * 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 2010 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - * Copyright (c) 2011 Bayard G. Bell. All rights reserved. - * Copyright (c) 2016 by Delphix. All rights reserved. - */ - -#include <sys/debug.h> -#include <sys/types.h> -#include <sys/varargs.h> -#include <sys/errno.h> -#include <sys/cred.h> -#include <sys/dditypes.h> -#include <sys/devops.h> -#include <sys/modctl.h> -#include <sys/poll.h> -#include <sys/conf.h> -#include <sys/ddi.h> -#include <sys/sunddi.h> -#include <sys/sunndi.h> -#include <sys/ndi_impldefs.h> -#include <sys/stat.h> -#include <sys/kmem.h> -#include <sys/vmem.h> -#include <sys/processor.h> -#include <sys/spitregs.h> -#include <sys/cpuvar.h> -#include <sys/cpupart.h> -#include <sys/mem_config.h> -#include <sys/ddi_impldefs.h> -#include <sys/systm.h> -#include <sys/machsystm.h> -#include <sys/autoconf.h> -#include <sys/cmn_err.h> -#include <sys/sysmacros.h> -#include <sys/x_call.h> -#include <sys/promif.h> -#include <sys/prom_plat.h> -#include <sys/membar.h> -#include <vm/seg_kmem.h> -#include <sys/mem_cage.h> -#include <sys/stack.h> -#include <sys/archsystm.h> -#include <vm/hat_sfmmu.h> -#include <sys/pte.h> -#include <sys/mmu.h> -#include <sys/cpu_module.h> -#include <sys/obpdefs.h> -#include <sys/note.h> - -#include <sys/starfire.h> /* plat_max_... decls */ -#include <sys/cvc.h> -#include <sys/cpu_sgnblk_defs.h> -#include <sys/drmach.h> -#include <sys/dr_util.h> -#include <sys/pda.h> - -#include <sys/sysevent.h> -#include <sys/sysevent/dr.h> -#include <sys/sysevent/eventdefs.h> - - -extern void bcopy32_il(uint64_t, uint64_t); -extern void flush_ecache_il( - uint64_t physaddr, int size, int linesz); -extern uint_t ldphysio_il(uint64_t physaddr); -extern void stphysio_il(uint64_t physaddr, uint_t value); - -extern uint64_t mc_get_mem_alignment(void); -extern uint64_t mc_get_asr_addr(pnode_t); -extern uint64_t mc_get_idle_addr(pnode_t); -extern uint64_t mc_get_alignment_mask(pnode_t); -extern int mc_read_asr(pnode_t, uint_t *); -extern int mc_write_asr(pnode_t, uint_t); -extern uint64_t mc_asr_to_pa(uint_t); -extern uint_t mc_pa_to_asr(uint_t, uint64_t); - -extern int pc_madr_add(int, int, int, int); - -typedef struct { - struct drmach_node *node; - void *data; -} drmach_node_walk_args_t; - -typedef struct drmach_node { - void *here; - - pnode_t (*get_dnode)(struct drmach_node *node); - int (*walk)(struct drmach_node *node, void *data, - int (*cb)(drmach_node_walk_args_t *args)); -} drmach_node_t; - -typedef struct { - int min_index; - int max_index; - int arr_sz; - drmachid_t *arr; -} drmach_array_t; - -typedef struct { - void *isa; - - sbd_error_t *(*release)(drmachid_t); - sbd_error_t *(*status)(drmachid_t, drmach_status_t *); - - char name[MAXNAMELEN]; -} drmach_common_t; - -typedef struct { - drmach_common_t cm; - int bnum; - int assigned; - int powered; - int connect_cpuid; - int cond; - drmach_node_t *tree; - drmach_array_t *devices; -} drmach_board_t; - -typedef struct { - drmach_common_t cm; - drmach_board_t *bp; - int unum; - int busy; - int powered; - const char *type; - drmach_node_t *node; -} drmach_device_t; - -typedef struct { - int flags; - drmach_device_t *dp; - sbd_error_t *err; - dev_info_t *dip; -} drmach_config_args_t; - -typedef struct { - uint64_t idle_addr; - drmach_device_t *mem; -} drmach_mc_idle_script_t; - -typedef struct { - uint64_t masr_addr; - uint_t masr; - uint_t _filler; -} drmach_rename_script_t; - -typedef struct { - void (*run)(void *arg); - caddr_t data; - pda_handle_t *ph; - struct memlist *c_ml; - uint64_t s_copybasepa; - uint64_t t_copybasepa; - drmach_device_t *restless_mc; /* diagnostic output */ -} drmach_copy_rename_program_t; - -typedef enum { - DO_IDLE, - DO_UNIDLE, - DO_PAUSE, - DO_UNPAUSE -} drmach_iopc_op_t; - -typedef struct { - drmach_board_t *obj; - int ndevs; - void *a; - sbd_error_t *(*found)(void *a, const char *, int, drmachid_t); - sbd_error_t *err; -} drmach_board_cb_data_t; - -static caddr_t drmach_shutdown_va; - -static int drmach_initialized; -static drmach_array_t *drmach_boards; - -static int drmach_cpu_delay = 100; -static int drmach_cpu_ntries = 50000; - -volatile uchar_t *drmach_xt_mb; - -/* - * Do not change the drmach_shutdown_mbox structure without - * considering the drmach_shutdown_asm assembly language code. - */ -struct drmach_shutdown_mbox { - uint64_t estack; - uint64_t flushaddr; - int size; - int linesize; - uint64_t physaddr; -}; -struct drmach_shutdown_mbox *drmach_shutdown_asm_mbox; - -static int drmach_fini(void); -static sbd_error_t *drmach_device_new(drmach_node_t *, - drmach_board_t *, drmach_device_t **); -static sbd_error_t *drmach_cpu_new(drmach_device_t *); -static sbd_error_t *drmach_mem_new(drmach_device_t *); -static sbd_error_t *drmach_io_new(drmach_device_t *); -static sbd_error_t *drmach_board_release(drmachid_t); -static sbd_error_t *drmach_board_status(drmachid_t, drmach_status_t *); -static sbd_error_t *drmach_cpu_release(drmachid_t); -static sbd_error_t *drmach_cpu_status(drmachid_t, drmach_status_t *); -static sbd_error_t *drmach_io_release(drmachid_t); -static sbd_error_t *drmach_io_status(drmachid_t, drmach_status_t *); -static sbd_error_t *drmach_mem_release(drmachid_t); -static sbd_error_t *drmach_mem_status(drmachid_t, drmach_status_t *); - -extern struct cpu *SIGBCPU; - -#ifdef DEBUG - -#define DRMACH_PR if (drmach_debug) printf -int drmach_debug = 0; /* set to non-zero to enable debug messages */ -#else - -#define DRMACH_PR _NOTE(CONSTANTCONDITION) if (0) printf -#endif /* DEBUG */ - -#define DRMACH_OBJ(id) ((drmach_common_t *)id) - -#define DRMACH_IS_BOARD_ID(id) \ - ((id != 0) && \ - (DRMACH_OBJ(id)->isa == (void *)drmach_board_new)) - -#define DRMACH_IS_CPU_ID(id) \ - ((id != 0) && \ - (DRMACH_OBJ(id)->isa == (void *)drmach_cpu_new)) - -#define DRMACH_IS_MEM_ID(id) \ - ((id != 0) && \ - (DRMACH_OBJ(id)->isa == (void *)drmach_mem_new)) - -#define DRMACH_IS_IO_ID(id) \ - ((id != 0) && \ - (DRMACH_OBJ(id)->isa == (void *)drmach_io_new)) - -#define DRMACH_IS_DEVICE_ID(id) \ - ((id != 0) && \ - (DRMACH_OBJ(id)->isa == (void *)drmach_cpu_new || \ - DRMACH_OBJ(id)->isa == (void *)drmach_mem_new || \ - DRMACH_OBJ(id)->isa == (void *)drmach_io_new)) - -#define DRMACH_IS_ID(id) \ - ((id != 0) && \ - (DRMACH_OBJ(id)->isa == (void *)drmach_board_new || \ - DRMACH_OBJ(id)->isa == (void *)drmach_cpu_new || \ - DRMACH_OBJ(id)->isa == (void *)drmach_mem_new || \ - DRMACH_OBJ(id)->isa == (void *)drmach_io_new)) - -#define DRMACH_CPUID2BNUM(cpuid) \ - ((cpuid) / MAX_CPU_UNITS_PER_BOARD) - -#define DRMACH_INTERNAL_ERROR() \ - drerr_new(1, ESTF_INTERNAL, drmach_ie_fmt, __LINE__) -static char *drmach_ie_fmt = "drmach.c %d"; - -static struct { - const char *name; - const char *type; - sbd_error_t *(*new)(drmach_device_t *); -} name2type[] = { - { "SUNW,UltraSPARC", DRMACH_DEVTYPE_CPU, drmach_cpu_new }, - { "mem-unit", DRMACH_DEVTYPE_MEM, drmach_mem_new }, - { "pci", DRMACH_DEVTYPE_PCI, drmach_io_new }, - { "sbus", DRMACH_DEVTYPE_SBUS, drmach_io_new }, -}; - -/* node types to cleanup when a board is unconfigured */ -#define MISC_COUNTER_TIMER_DEVNAME "counter-timer" -#define MISC_PERF_COUNTER_DEVNAME "perf-counter" - -/* utility */ -#define MBYTE (1048576ull) - -/* - * drmach autoconfiguration data structures and interfaces - */ - -extern struct mod_ops mod_miscops; - -static struct modlmisc modlmisc = { - &mod_miscops, - "Sun Enterprise 10000 DR" -}; - -static struct modlinkage modlinkage = { - MODREV_1, - (void *)&modlmisc, - NULL -}; - -static kmutex_t drmach_i_lock; - -int -_init(void) -{ - int err; - - /* check that we have the correct version of obp */ - if (prom_test("SUNW,UE10000,add-brd") != 0) { - - cmn_err(CE_WARN, "!OBP/SSP upgrade is required to enable " - "DR Functionality"); - - return (-1); - } - - mutex_init(&drmach_i_lock, NULL, MUTEX_DRIVER, NULL); - - drmach_xt_mb = (uchar_t *)vmem_alloc(static_alloc_arena, - NCPU * sizeof (uchar_t), VM_SLEEP); - drmach_shutdown_asm_mbox = (struct drmach_shutdown_mbox *) - vmem_alloc(static_alloc_arena, sizeof (struct drmach_shutdown_mbox), - VM_SLEEP); - - if ((err = mod_install(&modlinkage)) != 0) { - mutex_destroy(&drmach_i_lock); - vmem_free(static_alloc_arena, (void *)drmach_xt_mb, - NCPU * sizeof (uchar_t)); - vmem_free(static_alloc_arena, (void *)drmach_shutdown_asm_mbox, - sizeof (struct drmach_shutdown_mbox)); - } - - return (err); -} - -int -_fini(void) -{ - if (drmach_fini()) - return (DDI_FAILURE); - else - return (mod_remove(&modlinkage)); -} - -int -_info(struct modinfo *modinfop) -{ - return (mod_info(&modlinkage, modinfop)); -} - -static pnode_t -drmach_node_obp_get_dnode(drmach_node_t *np) -{ - return ((pnode_t)(uintptr_t)np->here); -} - -static int -drmach_node_obp_walk(drmach_node_t *np, void *data, - int (*cb)(drmach_node_walk_args_t *args)) -{ - pnode_t nodeid; - int rv; - drmach_node_walk_args_t args; - - /* initialized args structure for callback */ - args.node = np; - args.data = data; - - nodeid = prom_childnode(prom_rootnode()); - - /* save our new position with in the tree */ - np->here = (void *)(uintptr_t)nodeid; - - rv = 0; - while (nodeid != OBP_NONODE) { - rv = (*cb)(&args); - if (rv) - break; - - nodeid = prom_nextnode(nodeid); - - /* save our new position with in the tree */ - np->here = (void *)(uintptr_t)nodeid; - } - - return (rv); -} - -static drmach_node_t * -drmach_node_new(void) -{ - drmach_node_t *np; - - np = kmem_zalloc(sizeof (drmach_node_t), KM_SLEEP); - - np->get_dnode = drmach_node_obp_get_dnode; - np->walk = drmach_node_obp_walk; - - return (np); -} - -static void -drmach_node_dispose(drmach_node_t *np) -{ - kmem_free(np, sizeof (*np)); -} - -static dev_info_t * -drmach_node_get_dip(drmach_node_t *np) -{ - pnode_t nodeid; - - nodeid = np->get_dnode(np); - if (nodeid == OBP_NONODE) - return (NULL); - else { - dev_info_t *dip; - - /* The root node doesn't have to be held */ - dip = e_ddi_nodeid_to_dip(nodeid); - if (dip) { - /* - * Branch rooted at dip is already held, so release - * hold acquired in e_ddi_nodeid_to_dip() - */ - ddi_release_devi(dip); - ASSERT(e_ddi_branch_held(dip)); - } - - return (dip); - } - /*NOTREACHED*/ -} - -static pnode_t -drmach_node_get_dnode(drmach_node_t *np) -{ - return (np->get_dnode(np)); -} - -static int -drmach_node_walk(drmach_node_t *np, void *param, - int (*cb)(drmach_node_walk_args_t *args)) -{ - return (np->walk(np, param, cb)); -} - -static int -drmach_node_get_prop(drmach_node_t *np, char *name, void *buf) -{ - pnode_t nodeid; - int rv; - - nodeid = np->get_dnode(np); - if (nodeid == OBP_NONODE) - rv = -1; - else if (prom_getproplen(nodeid, (caddr_t)name) < 0) - rv = -1; - else { - (void) prom_getprop(nodeid, (caddr_t)name, (caddr_t)buf); - rv = 0; - } - - return (rv); -} - -static int -drmach_node_get_proplen(drmach_node_t *np, char *name, int *len) -{ - pnode_t nodeid; - int rv; - - nodeid = np->get_dnode(np); - if (nodeid == OBP_NONODE) - rv = -1; - else { - *len = prom_getproplen(nodeid, (caddr_t)name); - rv = (*len < 0 ? -1 : 0); - } - - return (rv); -} - -static drmachid_t -drmach_node_dup(drmach_node_t *np) -{ - drmach_node_t *dup; - - dup = drmach_node_new(); - dup->here = np->here; - - return (dup); -} - -/* - * drmach_array provides convenient array construction, access, - * bounds checking and array destruction logic. - */ - -static drmach_array_t * -drmach_array_new(int min_index, int max_index) -{ - drmach_array_t *arr; - - arr = kmem_zalloc(sizeof (drmach_array_t), KM_SLEEP); - - arr->arr_sz = (max_index - min_index + 1) * sizeof (void *); - if (arr->arr_sz > 0) { - arr->min_index = min_index; - arr->max_index = max_index; - - arr->arr = kmem_zalloc(arr->arr_sz, KM_SLEEP); - return (arr); - } else { - kmem_free(arr, sizeof (*arr)); - return (0); - } -} - -static int -drmach_array_set(drmach_array_t *arr, int idx, drmachid_t val) -{ - if (idx < arr->min_index || idx > arr->max_index) - return (-1); - else { - arr->arr[idx - arr->min_index] = val; - return (0); - } - /*NOTREACHED*/ -} - -static int -drmach_array_get(drmach_array_t *arr, int idx, drmachid_t *val) -{ - if (idx < arr->min_index || idx > arr->max_index) - return (-1); - else { - *val = arr->arr[idx - arr->min_index]; - return (0); - } - /*NOTREACHED*/ -} - -static int -drmach_array_first(drmach_array_t *arr, int *idx, drmachid_t *val) -{ - int rv; - - *idx = arr->min_index; - while ((rv = drmach_array_get(arr, *idx, val)) == 0 && *val == NULL) - *idx += 1; - - return (rv); -} - -static int -drmach_array_next(drmach_array_t *arr, int *idx, drmachid_t *val) -{ - int rv; - - *idx += 1; - while ((rv = drmach_array_get(arr, *idx, val)) == 0 && *val == NULL) - *idx += 1; - - return (rv); -} - -static void -drmach_array_dispose(drmach_array_t *arr, void (*disposer)(drmachid_t)) -{ - drmachid_t val; - int idx; - int rv; - - rv = drmach_array_first(arr, &idx, &val); - while (rv == 0) { - (*disposer)(val); - rv = drmach_array_next(arr, &idx, &val); - } - - kmem_free(arr->arr, arr->arr_sz); - kmem_free(arr, sizeof (*arr)); -} - -/*ARGSUSED*/ -static int -drmach_prom_select(pnode_t nodeid, void *arg, uint_t flags) -{ - int rprop[64]; - pnode_t saved; - drmach_config_args_t *ap = (drmach_config_args_t *)arg; - drmach_device_t *dp = ap->dp; - sbd_error_t *err; - - saved = drmach_node_get_dnode(dp->node); - - if (nodeid != saved) - return (DDI_FAILURE); - - if (saved == OBP_NONODE) { - err = DRMACH_INTERNAL_ERROR(); - DRERR_SET_C(&ap->err, &err); - return (DDI_FAILURE); - } - - if (prom_getprop(nodeid, OBP_REG, (caddr_t)rprop) <= 0) { - return (DDI_FAILURE); - } - - return (DDI_SUCCESS); -} - -/*ARGSUSED*/ -static void -drmach_branch_callback(dev_info_t *rdip, void *arg, uint_t flags) -{ - drmach_config_args_t *ap = (drmach_config_args_t *)arg; - - ASSERT(ap->dip == NULL); - - ap->dip = rdip; -} - -sbd_error_t * -drmach_configure(drmachid_t id, int flags) -{ - drmach_device_t *dp; - sbd_error_t *err; - drmach_config_args_t ca; - devi_branch_t b = {0}; - dev_info_t *fdip = NULL; - - if (!DRMACH_IS_DEVICE_ID(id)) - return (drerr_new(0, ESTF_INAPPROP, NULL)); - dp = id; - - ca.dp = dp; - ca.flags = flags; - ca.err = NULL; /* will be set if error detected */ - ca.dip = NULL; - - b.arg = &ca; - b.type = DEVI_BRANCH_PROM; - b.create.prom_branch_select = drmach_prom_select; - b.devi_branch_callback = drmach_branch_callback; - - if (e_ddi_branch_create(ddi_root_node(), &b, &fdip, - DEVI_BRANCH_CHILD | DEVI_BRANCH_CONFIGURE) != 0) { - char *path = kmem_alloc(MAXPATHLEN, KM_SLEEP); - - /* - * If non-NULL, fdip is returned held and must be released. - */ - if (fdip != NULL) { - (void) ddi_pathname(fdip, path); - ddi_release_devi(fdip); - } else if (ca.dip != NULL) { - /* safe to call ddi_pathname as dip already held */ - (void) ddi_pathname(ca.dip, path); - } else { - (void) strcpy(path, "<none>"); - } - - err = drerr_new(1, ESTF_DRVFAIL, path); - DRERR_SET_C(&ca.err, &err); - kmem_free(path, MAXPATHLEN); - } - - return (ca.err); -} - -static sbd_error_t * -drmach_device_new(drmach_node_t *node, - drmach_board_t *bp, drmach_device_t **dpp) -{ - int i; - int rv; - drmach_device_t *dp; - sbd_error_t *err; - char name[OBP_MAXDRVNAME]; - - rv = drmach_node_get_prop(node, OBP_NAME, name); - if (rv) { - /* every node is expected to have a name */ - err = drerr_new(1, ESTF_GETPROP, - "PROM Node 0x%x: property %s", - (uint_t)node->get_dnode(node), OBP_NAME); - - return (err); - } - - /* - * The node currently being examined is not listed in the name2type[] - * array. In this case, the node is no interest to drmach. Both - * dp and err are initialized here to yield nothing (no device or - * error structure) for this case. - */ - for (i = 0; i < sizeof (name2type) / sizeof (name2type[0]); i++) - if (strcmp(name2type[i].name, name) == 0) - break; - - if (i < sizeof (name2type) / sizeof (name2type[0])) { - dp = kmem_zalloc(sizeof (drmach_device_t), KM_SLEEP); - - dp->bp = bp; - dp->unum = -1; - dp->node = drmach_node_dup(node); - dp->type = name2type[i].type; - - err = (name2type[i].new)(dp); - if (err) { - drmach_node_dispose(node); - kmem_free(dp, sizeof (*dp)); - dp = NULL; - } - - *dpp = dp; - return (err); - } - - /* - * The node currently being examined is not listed in the name2type[] - * array. In this case, the node is no interest to drmach. Both - * dp and err are initialized here to yield nothing (no device or - * error structure) for this case. - */ - *dpp = NULL; - return (NULL); -} - -static void -drmach_device_dispose(drmachid_t id) -{ - drmach_device_t *self = id; - - if (self->node) - drmach_node_dispose(self->node); - - kmem_free(self, sizeof (*self)); -} - -static sbd_error_t * -drmach_device_get_prop(drmach_device_t *dp, char *name, void *buf) -{ - sbd_error_t *err = NULL; - int rv; - - rv = drmach_node_get_prop(dp->node, name, buf); - if (rv) { - err = drerr_new(1, ESTF_GETPROP, - "%s::%s: property %s", - dp->bp->cm.name, dp->cm.name, name); - } - - return (err); -} - -static sbd_error_t * -drmach_device_get_proplen(drmach_device_t *dp, char *name, int *len) -{ - sbd_error_t *err = NULL; - int rv; - - rv = drmach_node_get_proplen(dp->node, name, len); - if (rv) { - err = drerr_new(1, ESTF_GETPROPLEN, - "%s::%s: property %s", - dp->bp->cm.name, dp->cm.name, name); - } - - return (err); -} - -static drmach_board_t * -drmach_board_new(int bnum) -{ - drmach_board_t *bp; - - bp = kmem_zalloc(sizeof (drmach_board_t), KM_SLEEP); - - bp->cm.isa = (void *)drmach_board_new; - bp->cm.release = drmach_board_release; - bp->cm.status = drmach_board_status; - - (void) drmach_board_name(bnum, bp->cm.name, sizeof (bp->cm.name)); - - bp->bnum = bnum; - bp->devices = NULL; - bp->connect_cpuid = -1; - bp->tree = drmach_node_new(); - bp->assigned = !drmach_initialized; - bp->powered = !drmach_initialized; - - (void) drmach_array_set(drmach_boards, bnum, bp); - return (bp); -} - -static void -drmach_board_dispose(drmachid_t id) -{ - drmach_board_t *bp; - - ASSERT(DRMACH_IS_BOARD_ID(id)); - bp = id; - - if (bp->tree) - drmach_node_dispose(bp->tree); - - if (bp->devices) - drmach_array_dispose(bp->devices, drmach_device_dispose); - - kmem_free(bp, sizeof (*bp)); -} - -static sbd_error_t * -drmach_board_status(drmachid_t id, drmach_status_t *stat) -{ - sbd_error_t *err = NULL; - drmach_board_t *bp; - - if (!DRMACH_IS_BOARD_ID(id)) - return (drerr_new(0, ESTF_INAPPROP, NULL)); - bp = id; - - stat->assigned = bp->assigned; - stat->powered = bp->powered; - stat->busy = 0; /* assume not busy */ - stat->configured = 0; /* assume not configured */ - stat->empty = 0; - stat->cond = bp->cond = SBD_COND_OK; - (void) strncpy(stat->type, "System Brd", sizeof (stat->type)); - stat->info[0] = '\0'; - - if (bp->devices) { - int rv; - int d_idx; - drmachid_t d_id; - - rv = drmach_array_first(bp->devices, &d_idx, &d_id); - while (rv == 0) { - drmach_status_t d_stat; - - err = drmach_status(d_id, &d_stat); - if (err) - break; - - stat->busy |= d_stat.busy; - stat->configured |= d_stat.configured; - - rv = drmach_array_next(bp->devices, &d_idx, &d_id); - } - } - - return (err); -} - -/* a simple routine to reduce redundancy of this common logic */ -static pda_handle_t -drmach_pda_open(void) -{ - pda_handle_t ph; - - ph = pda_open(); - if (ph == NULL) { - /* catch in debug kernels */ - ASSERT(0); - cmn_err(CE_WARN, "pda_open failed"); - } - - return (ph); -} - -#ifdef DEBUG -int drmach_init_break = 0; -#endif - -static int -hold_rele_branch(dev_info_t *rdip, void *arg) -{ - int i; - int *holdp = (int *)arg; - char *name = ddi_node_name(rdip); - - /* - * For Starfire, we must be children of the root devinfo node - */ - ASSERT(ddi_get_parent(rdip) == ddi_root_node()); - - for (i = 0; i < sizeof (name2type) / sizeof (name2type[0]); i++) - if (strcmp(name2type[i].name, name) == 0) - break; - - if (i == sizeof (name2type) / sizeof (name2type[0])) { - /* Not of interest to us */ - return (DDI_WALK_PRUNECHILD); - } - - if (*holdp) { - ASSERT(!e_ddi_branch_held(rdip)); - e_ddi_branch_hold(rdip); - } else { - ASSERT(e_ddi_branch_held(rdip)); - e_ddi_branch_rele(rdip); - } - - return (DDI_WALK_PRUNECHILD); -} - -static int -drmach_init(void) -{ - pnode_t nodeid; - dev_info_t *rdip; - int hold, circ; - -#ifdef DEBUG - if (drmach_init_break) - debug_enter("drmach_init: drmach_init_break set\n"); -#endif - mutex_enter(&drmach_i_lock); - if (drmach_initialized) { - mutex_exit(&drmach_i_lock); - return (0); - } - - drmach_boards = drmach_array_new(0, MAX_BOARDS - 1); - - nodeid = prom_childnode(prom_rootnode()); - do { - int bnum; - drmachid_t id; - - bnum = -1; - (void) prom_getprop(nodeid, OBP_BOARDNUM, (caddr_t)&bnum); - if (bnum == -1) - continue; - - if (drmach_array_get(drmach_boards, bnum, &id) == -1) { - cmn_err(CE_WARN, "OBP node 0x%x has" - " invalid property value, %s=%d", - nodeid, OBP_BOARDNUM, bnum); - - /* clean up */ - drmach_array_dispose( - drmach_boards, drmach_board_dispose); - - mutex_exit(&drmach_i_lock); - return (-1); - } else if (id == NULL) - (void) drmach_board_new(bnum); - } while ((nodeid = prom_nextnode(nodeid)) != OBP_NONODE); - - drmach_shutdown_va = vmem_alloc(heap_arena, PAGESIZE, VM_SLEEP); - - /* - * Walk immediate children of devinfo root node and hold - * all devinfo branches of interest. - */ - hold = 1; - rdip = ddi_root_node(); - - ndi_devi_enter(rdip, &circ); - ddi_walk_devs(ddi_get_child(rdip), hold_rele_branch, &hold); - ndi_devi_exit(rdip, circ); - - drmach_initialized = 1; - - mutex_exit(&drmach_i_lock); - - return (0); -} - -static int -drmach_fini(void) -{ - dev_info_t *rdip; - int hold, circ; - - if (drmach_initialized) { - int busy = 0; - int rv; - int idx; - drmachid_t id; - - ASSERT(drmach_boards != NULL); - - rv = drmach_array_first(drmach_boards, &idx, &id); - while (rv == 0) { - sbd_error_t *err; - drmach_status_t stat; - - err = drmach_board_status(id, &stat); - if (err) { - /* catch in debug kernels */ - ASSERT(0); - sbd_err_clear(&err); - busy = 1; - } else - busy |= stat.busy; - - rv = drmach_array_next(drmach_boards, &idx, &id); - } - - if (busy) - return (-1); - - drmach_array_dispose(drmach_boards, drmach_board_dispose); - drmach_boards = NULL; - - vmem_free(heap_arena, drmach_shutdown_va, PAGESIZE); - - /* - * Walk immediate children of the root devinfo node - * releasing holds acquired on branches in drmach_init() - */ - hold = 0; - rdip = ddi_root_node(); - - ndi_devi_enter(rdip, &circ); - ddi_walk_devs(ddi_get_child(rdip), hold_rele_branch, &hold); - ndi_devi_exit(rdip, circ); - - mutex_destroy(&drmach_i_lock); - - drmach_initialized = 0; - } - if (drmach_xt_mb != NULL) { - vmem_free(static_alloc_arena, (void *)drmach_xt_mb, - NCPU * sizeof (uchar_t)); - } - if (drmach_shutdown_asm_mbox != NULL) { - vmem_free(static_alloc_arena, (void *)drmach_shutdown_asm_mbox, - sizeof (struct drmach_shutdown_mbox)); - } - return (0); -} - -static sbd_error_t * -drmach_get_mc_asr_addr(drmachid_t id, uint64_t *pa) -{ - drmach_device_t *dp; - pnode_t nodeid; - uint64_t addr; - - if (!DRMACH_IS_MEM_ID(id)) - return (drerr_new(0, ESTF_INAPPROP, NULL)); - dp = id; - - nodeid = drmach_node_get_dnode(dp->node); - if (nodeid == OBP_NONODE || nodeid == OBP_BADNODE) - return (DRMACH_INTERNAL_ERROR()); - - addr = mc_get_asr_addr(nodeid); - if (addr == (uint64_t)-1) - return (DRMACH_INTERNAL_ERROR()); - - *pa = addr; - return (NULL); -} - -static sbd_error_t * -drmach_get_mc_idle_addr(drmachid_t id, uint64_t *pa) -{ - drmach_device_t *dp; - pnode_t nodeid; - uint64_t addr; - - if (!DRMACH_IS_MEM_ID(id)) - return (drerr_new(0, ESTF_INAPPROP, NULL)); - dp = id; - - nodeid = drmach_node_get_dnode(dp->node); - if (nodeid == OBP_NONODE || nodeid == OBP_BADNODE) - return (DRMACH_INTERNAL_ERROR()); - - addr = mc_get_idle_addr(nodeid); - if (addr == (uint64_t)-1) - return (DRMACH_INTERNAL_ERROR()); - - *pa = addr; - return (NULL); -} - -static sbd_error_t * -drmach_read_mc_asr(drmachid_t id, uint_t *mcregp) -{ - drmach_device_t *dp; - pnode_t nodeid; - sbd_error_t *err; - - if (!DRMACH_IS_MEM_ID(id)) - return (drerr_new(0, ESTF_INAPPROP, NULL)); - dp = id; - - nodeid = drmach_node_get_dnode(dp->node); - if (nodeid == OBP_NONODE || nodeid == OBP_BADNODE) - err = DRMACH_INTERNAL_ERROR(); - else if (mc_read_asr(nodeid, mcregp) == -1) - err = DRMACH_INTERNAL_ERROR(); - else - err = NULL; - - return (err); -} - -static sbd_error_t * -drmach_write_mc_asr(drmachid_t id, uint_t mcreg) -{ - drmach_device_t *dp; - pnode_t nodeid; - sbd_error_t *err; - - if (!DRMACH_IS_MEM_ID(id)) - return (drerr_new(0, ESTF_INAPPROP, NULL)); - dp = id; - - nodeid = drmach_node_get_dnode(dp->node); - if (nodeid == OBP_NONODE || nodeid == OBP_BADNODE) - err = DRMACH_INTERNAL_ERROR(); - else if (mc_write_asr(nodeid, mcreg) == -1) - err = DRMACH_INTERNAL_ERROR(); - else - err = NULL; - - return (err); -} - -static sbd_error_t * -drmach_prep_rename_script(drmach_device_t *s_mem, drmach_device_t *t_mem, - uint64_t t_slice_offset, caddr_t buf, int buflen) -{ - int i, b, m; - drmach_mc_idle_script_t *isp; - drmach_rename_script_t *rsp; - int s_bd, t_bd; - uint_t s_masr, t_masr; - uint64_t s_new_basepa, t_new_basepa; - int b_idx, rv; - sbd_error_t *err; - drmachid_t b_id; - drmach_board_t *brd; - -#ifdef DEBUG - /* - * Starfire CPU/MEM/IO boards have only one MC per board. - * This function has been coded with that fact in mind. - */ - ASSERT(MAX_MEM_UNITS_PER_BOARD == 1); - - /* - * calculate the maximum space that could be consumed, - * then verify the available buffer space is adequate. - */ - m = sizeof (drmach_mc_idle_script_t *) * 2; /* two MCs */ - b = sizeof (drmach_rename_script_t *) * 3 * MAX_CPU_UNITS_PER_BOARD; - b += sizeof (drmach_rename_script_t *) * 3 * MAX_IO_UNITS_PER_BOARD; - b *= MAX_BOARDS; - b += sizeof (drmach_rename_script_t *) * 3; - b += sizeof (drmach_rename_script_t *) * 1; - ASSERT(m + b < buflen); -#endif - - /* - * construct an array of MC idle register addresses of - * both MCs. The array is zero terminated -- as expected - * by drmach_copy_rename_prog__relocatable(). - */ - isp = (drmach_mc_idle_script_t *)buf; - - /* source mc */ - err = drmach_get_mc_idle_addr(s_mem, &isp->idle_addr); - if (err) - return (err); - isp->mem = s_mem; - isp += 1; - - /* target mc */ - err = drmach_get_mc_idle_addr(t_mem, &isp->idle_addr); - if (err) - return (err); - isp->mem = t_mem; - isp += 1; - - /* terminator */ - isp->idle_addr = 0; - isp->mem = NULL; - isp += 1; - - /* fetch source mc asr register value */ - err = drmach_read_mc_asr(s_mem, &s_masr); - if (err) - return (err); - else if (s_masr & STARFIRE_MC_INTERLEAVE_MASK) { - return (drerr_new(1, ESTF_INTERBOARD, "%s::%s", - s_mem->bp->cm.name, s_mem->cm.name)); - } - - /* fetch target mc asr register value */ - err = drmach_read_mc_asr(t_mem, &t_masr); - if (err) - return (err); - else if (t_masr & STARFIRE_MC_INTERLEAVE_MASK) { - return (drerr_new(1, ESTF_INTERBOARD, "%s::%s", - t_mem->bp->cm.name, t_mem->cm.name)); - } - - /* get new source base pa from target's masr */ - s_new_basepa = mc_asr_to_pa(t_masr); - - /* - * remove any existing slice offset to realign - * memory with board's slice boundary - */ - s_new_basepa &= ~ (mc_get_mem_alignment() - 1); - - /* get new target base pa from source's masr */ - t_new_basepa = mc_asr_to_pa(s_masr); - - /* remove any existing slice offset, then apply new offset */ - t_new_basepa &= ~ (mc_get_mem_alignment() - 1); - t_new_basepa += t_slice_offset; - - /* encode new base pa into s_masr. turn off mem present bit */ - s_masr = mc_pa_to_asr(s_masr, s_new_basepa); - s_masr &= ~STARFIRE_MC_MEM_PRESENT_MASK; - - /* encode new base pa into t_masr. turn on mem present bit */ - t_masr = mc_pa_to_asr(t_masr, t_new_basepa); - t_masr |= STARFIRE_MC_MEM_PRESENT_MASK; - - /* - * Step 0: Mark source memory as not present. - */ - m = 0; - rsp = (drmach_rename_script_t *)isp; - err = drmach_get_mc_asr_addr(s_mem, &rsp[m].masr_addr); - if (err) - return (err); - rsp[m].masr = s_masr; - m++; - - /* - * Step 1: Write source base address to target MC - * with present bit off. - */ - err = drmach_get_mc_asr_addr(t_mem, &rsp[m].masr_addr); - if (err) - return (err); - rsp[m].masr = t_masr & ~STARFIRE_MC_MEM_PRESENT_MASK; - m++; - - /* - * Step 2: Now rewrite target reg with present bit on. - */ - rsp[m].masr_addr = rsp[m-1].masr_addr; - rsp[m].masr = t_masr; - m++; - - s_bd = s_mem->bp->bnum; - t_bd = t_mem->bp->bnum; - - DRMACH_PR("preparing script for CPU and IO units:\n"); - - rv = drmach_array_first(drmach_boards, &b_idx, &b_id); - if (rv) { - /* catch this in debug kernels */ - ASSERT(0); - return (DRMACH_INTERNAL_ERROR()); - } - - do { - int d_idx; - drmachid_t d_id; - drmach_device_t *device; - - ASSERT(DRMACH_IS_BOARD_ID(b_id)); - brd = b_id; - b = brd->bnum; - - /* - * Step 3: Update PC MADR tables for CPUs. - */ - if (brd->devices == NULL) { - /* devices not initialized */ - continue; - } - - rv = drmach_array_first(brd->devices, &d_idx, &d_id); - if (rv) { - /* must mean no devices on this board */ - break; - } - - DRMACH_PR("\t%s\n", brd->cm.name); - - do { - ASSERT(DRMACH_IS_DEVICE_ID(d_id)); - - if (!DRMACH_IS_CPU_ID(d_id)) - continue; - - device = d_id; - i = device->unum; - - DRMACH_PR("\t\t%s\n", device->cm.name); - - /* - * Disabled detaching mem node. - */ - rsp[m].masr_addr = STARFIRE_PC_MADR_ADDR(b, s_bd, i); - rsp[m].masr = s_masr; - m++; - /* - * Always write masr with present bit - * off and then again with it on. - */ - rsp[m].masr_addr = STARFIRE_PC_MADR_ADDR(b, t_bd, i); - rsp[m].masr = t_masr & ~STARFIRE_MC_MEM_PRESENT_MASK; - m++; - rsp[m].masr_addr = rsp[m-1].masr_addr; - rsp[m].masr = t_masr; - m++; - - } while (drmach_array_next(brd->devices, &d_idx, &d_id) == 0); - - /* - * Step 4: Update PC MADR tables for IOs. - */ - rv = drmach_array_first(brd->devices, &d_idx, &d_id); - /* this worked for previous loop, must work here too */ - ASSERT(rv == 0); - - do { - ASSERT(DRMACH_IS_DEVICE_ID(d_id)); - - if (!DRMACH_IS_IO_ID(d_id)) - continue; - - device = d_id; - i = device->unum; - - DRMACH_PR("\t\t%s\n", device->cm.name); - - /* - * Disabled detaching mem node. - */ - rsp[m].masr_addr = STARFIRE_PC_MADR_ADDR(b, s_bd, i+4); - rsp[m].masr = s_masr; - m++; - /* - * Always write masr with present bit - * off and then again with it on. - */ - rsp[m].masr_addr = STARFIRE_PC_MADR_ADDR(b, t_bd, i+4); - rsp[m].masr = t_masr & ~STARFIRE_MC_MEM_PRESENT_MASK; - m++; - rsp[m].masr_addr = rsp[m-1].masr_addr; - rsp[m].masr = t_masr; - m++; - - } while (drmach_array_next(brd->devices, &d_idx, &d_id) == 0); - } while (drmach_array_next(drmach_boards, &b_idx, &b_id) == 0); - - /* - * Zero masr_addr value indicates the END. - */ - rsp[m].masr_addr = 0ull; - rsp[m].masr = 0; - DRMACH_PR("number of steps in rename script = %d\n", m); - m++; - - /* paranoia */ - ASSERT((caddr_t)&rsp[m] <= buf + buflen); - -#ifdef DEBUG - { - int j; - - DRMACH_PR("mc idle register address list:"); - isp = (drmach_mc_idle_script_t *)buf; - DRMACH_PR("source mc idle addr 0x%lx, mem id %p", - isp[0].idle_addr, (void *)isp[0].mem); - DRMACH_PR("target mc idle addr 0x%lx, mem id %p", - isp[1].idle_addr, (void *)isp[1].mem); - ASSERT(isp[2].idle_addr == 0); - - DRMACH_PR("copy-rename script:"); - for (j = 0; j < m; j++) { - DRMACH_PR("0x%lx = 0x%08x", - rsp[j].masr_addr, rsp[j].masr); - } - - DELAY(1000000); - } -#endif - - /* return number of bytes consumed */ - b = (caddr_t)&rsp[m] - buf; - DRMACH_PR("total number of bytes consumed is %d\n", b); - ASSERT(b <= buflen); - -#ifdef lint - buflen = buflen; -#endif - - return (NULL); -} - -/* - * The routine performs the necessary memory COPY and MC adr SWITCH. - * Both operations MUST be at the same "level" so that the stack is - * maintained correctly between the copy and switch. The switch - * portion implements a caching mechanism to guarantee the code text - * is cached prior to execution. This is to guard against possible - * memory access while the MC adr's are being modified. - * - * IMPORTANT: The _drmach_copy_rename_end() function must immediately - * follow drmach_copy_rename_prog__relocatable() so that the correct - * "length" of the drmach_copy_rename_prog__relocatable can be - * calculated. This routine MUST be a LEAF function, i.e. it can - * make NO function calls, primarily for two reasons: - * - * 1. We must keep the stack consistent across the "switch". - * 2. Function calls are compiled to relative offsets, and - * we execute this function we'll be executing it from - * a copied version in a different area of memory, thus - * the relative offsets will be bogus. - * - * Moreover, it must have the "__relocatable" suffix to inform DTrace - * providers (and anything else, for that matter) that this - * function's text is manually relocated elsewhere before it is - * executed. That is, it cannot be safely instrumented with any - * methodology that is PC-relative. - */ -static void -drmach_copy_rename_prog__relocatable(drmach_copy_rename_program_t *prog) -{ - extern void drmach_exec_script_il(drmach_rename_script_t *rsp); - - drmach_mc_idle_script_t *isp; - struct memlist *ml; - int csize; - int lnsize; - uint64_t caddr; - - isp = (drmach_mc_idle_script_t *)prog->data; - - caddr = ecache_flushaddr; - csize = (cpunodes[CPU->cpu_id].ecache_size << 1); - lnsize = cpunodes[CPU->cpu_id].ecache_linesize; - - /* - * DO COPY. - */ - for (ml = prog->c_ml; ml; ml = ml->ml_next) { - uint64_t s_pa, t_pa; - uint64_t nbytes; - - s_pa = prog->s_copybasepa + ml->ml_address; - t_pa = prog->t_copybasepa + ml->ml_address; - nbytes = ml->ml_size; - - while (nbytes != 0ull) { - /* - * This copy does NOT use an ASI - * that avoids the Ecache, therefore - * the dst_pa addresses may remain - * in our Ecache after the dst_pa - * has been removed from the system. - * A subsequent write-back to memory - * will cause an ARB-stop because the - * physical address no longer exists - * in the system. Therefore we must - * flush out local Ecache after we - * finish the copy. - */ - - /* copy 32 bytes at src_pa to dst_pa */ - bcopy32_il(s_pa, t_pa); - - /* increment by 32 bytes */ - s_pa += (4 * sizeof (uint64_t)); - t_pa += (4 * sizeof (uint64_t)); - - /* decrement by 32 bytes */ - nbytes -= (4 * sizeof (uint64_t)); - } - } - - /* - * Since bcopy32_il() does NOT use an ASI to bypass - * the Ecache, we need to flush our Ecache after - * the copy is complete. - */ - flush_ecache_il(caddr, csize, lnsize); /* inline version */ - - /* - * Wait for MCs to go idle. - */ - do { - register int t = 10; - register uint_t v; - - /* loop t cycles waiting for each mc to indicate it's idle */ - do { - v = ldphysio_il(isp->idle_addr) - & STARFIRE_MC_IDLE_MASK; - - } while (v != STARFIRE_MC_IDLE_MASK && t-- > 0); - - /* bailout if timedout */ - if (t <= 0) { - prog->restless_mc = isp->mem; - return; - } - - isp += 1; - - /* stop if terminating zero has been reached */ - } while (isp->idle_addr != 0); - - /* advance passed terminating zero */ - isp += 1; - - /* - * The following inline assembly routine caches - * the rename script and then caches the code that - * will do the rename. This is necessary - * so that we don't have any memory references during - * the reprogramming. We accomplish this by first - * jumping through the code to guarantee it's cached - * before we actually execute it. - */ - drmach_exec_script_il((drmach_rename_script_t *)isp); -} - -static void -drmach_copy_rename_end(void) -{ - /* - * IMPORTANT: This function's location MUST be located immediately - * following drmach_copy_rename_prog__relocatable to - * accurately estimate its size. Note that this assumes - * the compiler keeps these functions in the order in - * which they appear :-o - */ -} - -sbd_error_t * -drmach_copy_rename_init(drmachid_t t_id, uint64_t t_slice_offset, - drmachid_t s_id, struct memlist *c_ml, drmachid_t *pgm_id) -{ - drmach_device_t *s_mem; - drmach_device_t *t_mem; - struct memlist *x_ml; - uint64_t off_mask, s_copybasepa, t_copybasepa, t_basepa; - int len; - caddr_t bp, wp; - pda_handle_t ph; - sbd_error_t *err; - drmach_copy_rename_program_t *prog; - - if (!DRMACH_IS_MEM_ID(s_id)) - return (drerr_new(0, ESTF_INAPPROP, NULL)); - if (!DRMACH_IS_MEM_ID(t_id)) - return (drerr_new(0, ESTF_INAPPROP, NULL)); - s_mem = s_id; - t_mem = t_id; - - /* get starting physical address of target memory */ - err = drmach_mem_get_base_physaddr(t_id, &t_basepa); - if (err) - return (err); - - /* calculate slice offset mask from slice size */ - off_mask = mc_get_mem_alignment() - 1; - - /* calculate source and target base pa */ - s_copybasepa = c_ml->ml_address; - t_copybasepa = - t_basepa + ((c_ml->ml_address & off_mask) - t_slice_offset); - - /* paranoia */ - ASSERT((c_ml->ml_address & off_mask) >= t_slice_offset); - - /* adjust copy memlist addresses to be relative to copy base pa */ - x_ml = c_ml; - while (x_ml != NULL) { - x_ml->ml_address -= s_copybasepa; - x_ml = x_ml->ml_next; - } - -#ifdef DEBUG - { - uint64_t s_basepa, s_size, t_size; - - x_ml = c_ml; - while (x_ml->ml_next != NULL) - x_ml = x_ml->ml_next; - - DRMACH_PR("source copy span: base pa 0x%lx, end pa 0x%lx\n", - s_copybasepa, - s_copybasepa + x_ml->ml_address + x_ml->ml_size); - - DRMACH_PR("target copy span: base pa 0x%lx, end pa 0x%lx\n", - t_copybasepa, - t_copybasepa + x_ml->ml_address + x_ml->ml_size); - - DRMACH_PR("copy memlist (relative to copy base pa):\n"); - MEMLIST_DUMP(c_ml); - - err = drmach_mem_get_base_physaddr(s_id, &s_basepa); - ASSERT(err == NULL); - - err = drmach_mem_get_size(s_id, &s_size); - ASSERT(err == NULL); - - err = drmach_mem_get_size(t_id, &t_size); - ASSERT(err == NULL); - - DRMACH_PR("current source base pa 0x%lx, size 0x%lx\n", - s_basepa, s_size); - DRMACH_PR("current target base pa 0x%lx, size 0x%lx\n", - t_basepa, t_size); - - ASSERT(s_copybasepa + x_ml->ml_address + x_ml->ml_size <= - s_basepa + s_size); - ASSERT(t_copybasepa + x_ml->ml_address + x_ml->ml_size <= - t_basepa + t_size); - } -#endif - - ph = drmach_pda_open(); - if (ph == NULL) - return (DRMACH_INTERNAL_ERROR()); - - /* - * bp will be page aligned, since we're calling - * kmem_zalloc() with an exact multiple of PAGESIZE. - */ - wp = bp = kmem_zalloc(PAGESIZE, KM_SLEEP); - - /* allocate space for copy rename struct */ - len = sizeof (drmach_copy_rename_program_t); - DRMACH_PR("prog = 0x%p, header len %d\n", (void *)wp, len); - prog = (drmach_copy_rename_program_t *)wp; - wp += (len + ecache_alignsize - 1) & ~ (ecache_alignsize - 1); - - /* - * Copy the code for the copy-rename routine into - * a page aligned piece of memory. We do this to guarantee - * that we're executing within the same page and thus reduce - * the possibility of cache collisions between different - * pages. - */ - len = (int)((ulong_t)drmach_copy_rename_end - - (ulong_t)drmach_copy_rename_prog__relocatable); - ASSERT(wp + len < bp + PAGESIZE); - bcopy((caddr_t)drmach_copy_rename_prog__relocatable, wp, len); - - DRMACH_PR("copy-rename function 0x%p, len %d\n", (void *)wp, len); - prog->run = (void (*)())wp; - wp += (len + ecache_alignsize - 1) & ~ (ecache_alignsize - 1); - - /* - * Prepare data page that will contain script of - * operations to perform during copy-rename. - * Allocate temporary buffer to hold script. - */ - err = drmach_prep_rename_script(s_mem, t_mem, t_slice_offset, - wp, PAGESIZE - (wp - bp)); - if (err) { - (void) drmach_copy_rename_fini(prog); - return (err); - } - - DRMACH_PR("copy-rename script 0x%p, len %d\n", (void *)wp, len); - prog->data = wp; - wp += (len + ecache_alignsize - 1) & ~ (ecache_alignsize - 1); - - prog->ph = ph; - prog->s_copybasepa = s_copybasepa; - prog->t_copybasepa = t_copybasepa; - prog->c_ml = c_ml; - *pgm_id = prog; - - return (NULL); -} - -sbd_error_t * -drmach_copy_rename_fini(drmachid_t id) -{ - drmach_copy_rename_program_t *prog = id; - sbd_error_t *err = NULL; - - if (prog->c_ml != NULL) - memlist_delete(prog->c_ml); - - if (prog->ph != NULL) - pda_close(prog->ph); - - if (prog->restless_mc != 0) { - cmn_err(CE_WARN, "MC did not idle; OBP Node 0x%x", - (uint_t)drmach_node_get_dnode(prog->restless_mc->node)); - - err = DRMACH_INTERNAL_ERROR(); - } - - kmem_free(prog, PAGESIZE); - - return (err); -} - -static sbd_error_t * -drmach_io_new(drmach_device_t *dp) -{ - sbd_error_t *err; - int portid; - - err = drmach_device_get_prop(dp, "upa-portid", &portid); - if (err == NULL) { - ASSERT(portid & 0x40); - dp->unum = portid & 1; - } - - dp->cm.isa = (void *)drmach_io_new; - dp->cm.release = drmach_io_release; - dp->cm.status = drmach_io_status; - - (void) snprintf(dp->cm.name, sizeof (dp->cm.name), "%s%d", dp->type, - dp->unum); - - return (err); -} - -static void -drmach_iopc_op(pda_handle_t ph, drmach_iopc_op_t op) -{ - register int b; - - for (b = 0; b < MAX_BOARDS; b++) { - int p; - ushort_t bda_ioc; - board_desc_t *bdesc; - - if (pda_board_present(ph, b) == 0) - continue; - - bdesc = (board_desc_t *)pda_get_board_info(ph, b); - /* - * Update PCs for IOCs. - */ - bda_ioc = bdesc->bda_ioc; - for (p = 0; p < MAX_IOCS; p++) { - u_longlong_t idle_addr; - uchar_t value; - - if (BDA_NBL(bda_ioc, p) != BDAN_GOOD) - continue; - - idle_addr = STARFIRE_BB_PC_ADDR(b, p, 1); - - switch (op) { - case DO_PAUSE: - value = STARFIRE_BB_PC_PAUSE(p); - break; - - case DO_IDLE: - value = STARFIRE_BB_PC_IDLE(p); - break; - - case DO_UNPAUSE: - value = ldbphysio(idle_addr); - value &= ~STARFIRE_BB_PC_PAUSE(p); - break; - - case DO_UNIDLE: - value = ldbphysio(idle_addr); - value &= ~STARFIRE_BB_PC_IDLE(p); - break; - - default: - cmn_err(CE_PANIC, - "drmach_iopc_op: unknown op (%d)", - (int)op); - /*NOTREACHED*/ - } - stbphysio(idle_addr, value); - } - } -} - -void -drmach_copy_rename(drmachid_t id) -{ - drmach_copy_rename_program_t *prog = id; - uint64_t neer; - - /* - * UPA IDLE - * Protocol = PAUSE -> IDLE -> UNPAUSE - * In reality since we only "idle" the IOPCs it's sufficient - * to just issue the IDLE operation since (in theory) all IOPCs - * in the field are PC6. However, we'll be robust and do the - * proper workaround protocol so that we never have to worry! - */ - drmach_iopc_op(prog->ph, DO_PAUSE); - drmach_iopc_op(prog->ph, DO_IDLE); - DELAY(100); - drmach_iopc_op(prog->ph, DO_UNPAUSE); - DELAY(100); - - /* disable CE reporting */ - neer = get_error_enable(); - set_error_enable(neer & ~EER_CEEN); - - /* run the copy/rename program */ - prog->run(prog); - - /* enable CE reporting */ - set_error_enable(neer); - - /* - * UPA UNIDLE - * Protocol = UNIDLE - */ - drmach_iopc_op(prog->ph, DO_UNIDLE); - DELAY(100); -} - -/* - * The counter-timer and perf-counter nodes are not being cleaned - * up after a board that was present at start of day is detached. - * If the board has become unconfigured with this operation, walk - * the prom tree and find all counter-timer and perf-counter nodes - * that have the same board number as the board that was just - * unconfigured and remove them. - */ -static sbd_error_t * -drmach_remove_counter_nodes(drmachid_t id) -{ - int num; - char name[OBP_MAXDRVNAME]; - pnode_t child; - dev_info_t *dip; - sbd_error_t *err; - drmach_status_t stat; - drmach_board_t *bp; - - if (!DRMACH_IS_BOARD_ID(id)) { - return (drerr_new(0, ESTF_INAPPROP, NULL)); - } - - if ((err = drmach_board_status(id, &stat)) != NULL) { - return (err); - } - - /* - * Only clean up the counter-timer and perf-counter - * nodes when the entire board is unconfigured. - */ - if (stat.configured) { - return (NULL); - } - - bp = (drmach_board_t *)id; - - err = NULL; - - for (child = prom_childnode(prom_rootnode()); child != OBP_NONODE; - child = prom_nextnode(child)) { - - if (prom_getprop(child, OBP_BOARDNUM, (caddr_t)&num) == -1) { - continue; - } - - if (bp->bnum != num) { - continue; - } - - if (prom_getprop(child, OBP_NAME, (caddr_t)name) == -1) { - continue; - } - - if (strncmp(name, MISC_COUNTER_TIMER_DEVNAME, OBP_MAXDRVNAME) && - strncmp(name, MISC_PERF_COUNTER_DEVNAME, OBP_MAXDRVNAME)) { - continue; - } - - /* Root node doesn't have to be held */ - dip = e_ddi_nodeid_to_dip(child); - - /* - * If the node is only in the OBP tree, then - * we don't have to remove it. - */ - if (dip) { - dev_info_t *fdip = NULL; - - DRMACH_PR("removing %s devinfo node\n", name); - - e_ddi_branch_hold(dip); - ddi_release_devi(dip); /* held in e_ddi_nodeid_to_dip */ - - if (e_ddi_branch_destroy(dip, &fdip, 0)) { - char *path = kmem_alloc(MAXPATHLEN, KM_SLEEP); - - /* - * If non-NULL, fdip is held and must be - * released. - */ - if (fdip != NULL) { - (void) ddi_pathname(fdip, path); - ddi_release_devi(fdip); - } else { - (void) ddi_pathname(dip, path); - } - - err = drerr_new(1, ESTF_DRVFAIL, path); - kmem_free(path, MAXPATHLEN); - e_ddi_branch_rele(dip); - break; - } - } - } - - return (err); -} - -/*ARGSUSED*/ -sbd_error_t * -drmach_pre_op(int cmd, drmachid_t id, drmach_opts_t *opts) -{ - /* allow status and ncm operations to always succeed */ - if ((cmd == SBD_CMD_STATUS) || (cmd == SBD_CMD_GETNCM)) { - return (NULL); - } - - /* check all other commands for the required option string */ - if ((opts->size > 0) && (opts->copts != NULL)) { - - DRMACH_PR("platform options: %s\n", opts->copts); - - if (strstr(opts->copts, "xfdr") != NULL) { - return (NULL); - } - } - - return (drerr_new(0, ESTF_SUPPORT, NULL)); -} - -/*ARGSUSED*/ -sbd_error_t * -drmach_post_op(int cmd, drmachid_t id, drmach_opts_t *opts) -{ - sbd_error_t *err = NULL; - - switch (cmd) { - case SBD_CMD_UNCONFIGURE: - - err = drmach_remove_counter_nodes(id); - break; - - case SBD_CMD_CONFIGURE: - case SBD_CMD_DISCONNECT: - case SBD_CMD_CONNECT: - case SBD_CMD_GETNCM: - case SBD_CMD_STATUS: - break; - - default: - break; - } - - return (err); -} - -sbd_error_t * -drmach_board_assign(int bnum, drmachid_t *id) -{ - sbd_error_t *err; - - if (!drmach_initialized && drmach_init() == -1) { - err = DRMACH_INTERNAL_ERROR(); - } else if (drmach_array_get(drmach_boards, bnum, id) == -1) { - err = drerr_new(1, ESTF_BNUM, "%d", bnum); - } else if (*id != NULL) { - err = NULL; - } else { - drmach_board_t *bp; - - *id = (drmachid_t)drmach_board_new(bnum); - bp = *id; - bp->assigned = 1; - err = NULL; - } - - return (err); -} - -static int -drmach_attach_board(void *arg) -{ - drmach_board_t *obj = (drmach_board_t *)arg; - cpuset_t cset; - int retval; - - /* - * OBP disables traps during the board probe. - * So, in order to prevent cross-call/cross-trap timeouts, - * and thus panics, we effectively block anybody from - * issuing xc's/xt's by doing a promsafe_xc_attention. - * In the previous version of Starfire DR (2.6), a timeout - * suspension mechanism was implemented in the send-mondo - * assembly. That mechanism is unnecessary with the - * existence of xc_attention/xc_dismissed. - */ - cset = cpu_ready_set; - promsafe_xc_attention(cset); - - retval = prom_starfire_add_brd(obj->connect_cpuid); - - xc_dismissed(cset); - - return (retval); -} - -sbd_error_t * -drmach_board_connect(drmachid_t id, drmach_opts_t *opts) -{ - drmach_board_t *obj = (drmach_board_t *)id; - int retval; - sbd_error_t *err; - char *cptr, *copts; - - if (!DRMACH_IS_BOARD_ID(id)) - return (drerr_new(0, ESTF_INAPPROP, NULL)); - - if (opts->size > 0) - copts = opts->copts; - - if ((cptr = strstr(copts, "cpuid=")) != NULL) { - int cpuid; - - cptr += strlen("cpuid="); - cpuid = stoi(&cptr); - - if (DRMACH_CPUID2BNUM(cpuid) == obj->bnum) { - obj->connect_cpuid = cpuid; - obj->assigned = 1; - } else - return (drerr_new(1, ESTF_SETCPUVAL, "%d", cpuid)); - } else { - /* cpuid was not specified */ - obj->connect_cpuid = -1; - } - - if (obj->connect_cpuid == -1) { - err = drerr_new(1, ESTF_NOCPUID, obj->cm.name); - return (err); - } - - cmn_err(CE_CONT, "DRMACH: PROM attach %s CPU %d\n", - obj->cm.name, obj->connect_cpuid); - - retval = prom_tree_update(drmach_attach_board, obj); - - if (retval == 0) - err = NULL; - else { - cmn_err(CE_WARN, "prom error: prom_starfire_add_brd(%d) " - "returned %d", obj->connect_cpuid, retval); - - err = drerr_new(1, ESTF_PROBE, obj->cm.name); - } - - obj->connect_cpuid = -1; - - return (err); -} - -/*ARGSUSED*/ -sbd_error_t * -drmach_board_disconnect(drmachid_t id, drmach_opts_t *opts) -{ - drmach_board_t *bp; - int rv; - int d_idx; /* device index */ - drmachid_t d_id; /* device ID */ - sbd_error_t *err; - - if (!DRMACH_IS_BOARD_ID(id)) - return (drerr_new(0, ESTF_INAPPROP, NULL)); - - bp = id; - - /* - * We need to make sure all of the board's device nodes - * have been removed from the Solaris device tree before - * continuing with the disconnect. Otherwise, we could - * disconnect the board and remove the OBP device tree - * nodes with Solaris device tree nodes remaining. - * - * On Starfire, Solaris device tree nodes are deleted - * during unconfigure by drmach_unconfigure(). It's - * necessary to do this here because drmach_unconfigure() - * failures are not handled during unconfigure. - */ - if (bp->devices) { - rv = drmach_array_first(bp->devices, &d_idx, &d_id); - while (rv == 0) { - err = drmach_unconfigure(d_id, DRMACH_DEVI_REMOVE); - if (err) - return (err); - - rv = drmach_array_next(bp->devices, &d_idx, &d_id); - } - } - - /* - * Starfire board Solaris device tree counter nodes, - * which are only present on start-of-day boards, are - * removed in the dr_post_op() code flow after the - * board is unconfigured. We call the counter node - * removal function here because unconfigure errors - * can cause the dr_post_op() function to be skipped - * after an unconfigure operation even though all of - * the board's devices have been transitioned to the - * unconfigured state. - */ - err = drmach_remove_counter_nodes(id); - if (err) - return (err); - - return (NULL); -} - -static int -drmach_board_find_devices_cb(drmach_node_walk_args_t *args) -{ - drmach_node_t *node = args->node; - drmach_board_cb_data_t *data = args->data; - drmach_board_t *obj = data->obj; - - int rv; - int bnum; - drmach_device_t *device; - - rv = drmach_node_get_prop(node, OBP_BOARDNUM, &bnum); - if (rv) { - /* - * if the node does not have a board# property, then - * by that information alone it is known that drmach - * is not interested in it. - */ - return (0); - } else if (bnum != obj->bnum) - return (0); - - /* - * Create a device data structure from this node data. - * The call may yield nothing if the node is not of interest - * to drmach. - */ - data->err = drmach_device_new(node, obj, &device); - if (data->err) - return (-1); - else if (device == NULL) { - /* - * drmach_device_new examined the node we passed in - * and determined that it was one not of interest to - * drmach. So, it is skipped. - */ - return (0); - } - - rv = drmach_array_set(obj->devices, data->ndevs++, device); - if (rv) { - drmach_device_dispose(device); - data->err = DRMACH_INTERNAL_ERROR(); - return (-1); - } - - data->err = (*data->found)(data->a, device->type, device->unum, device); - return (data->err == NULL ? 0 : -1); -} - -sbd_error_t * -drmach_board_find_devices(drmachid_t id, void *a, - sbd_error_t *(*found)(void *a, const char *, int, drmachid_t)) -{ - extern int plat_max_cpu_units_per_board(); - extern int plat_max_mem_units_per_board(); - extern int plat_max_io_units_per_board(); - - drmach_board_t *obj = (drmach_board_t *)id; - sbd_error_t *err; - int max_devices; - int rv; - drmach_board_cb_data_t data; - - max_devices = plat_max_cpu_units_per_board(); - max_devices += plat_max_mem_units_per_board(); - max_devices += plat_max_io_units_per_board(); - - obj->devices = drmach_array_new(0, max_devices); - - data.obj = obj; - data.ndevs = 0; - data.found = found; - data.a = a; - data.err = NULL; - - rv = drmach_node_walk(obj->tree, &data, drmach_board_find_devices_cb); - if (rv == 0) - err = NULL; - else { - drmach_array_dispose(obj->devices, drmach_device_dispose); - obj->devices = NULL; - - if (data.err) - err = data.err; - else - err = DRMACH_INTERNAL_ERROR(); - } - - return (err); -} - -int -drmach_board_lookup(int bnum, drmachid_t *id) -{ - int rv = 0; - - if (!drmach_initialized && drmach_init() == -1) { - *id = 0; - rv = -1; - } else if (drmach_array_get(drmach_boards, bnum, id)) { - *id = 0; - rv = -1; - } - return (rv); -} - -sbd_error_t * -drmach_board_name(int bnum, char *buf, int buflen) -{ - (void) snprintf(buf, buflen, "SB%d", bnum); - return (NULL); -} - -sbd_error_t * -drmach_board_poweroff(drmachid_t id) -{ - drmach_board_t *bp; - sbd_error_t *err; - drmach_status_t stat; - - if (!DRMACH_IS_BOARD_ID(id)) - return (drerr_new(0, ESTF_INAPPROP, NULL)); - bp = id; - - err = drmach_board_status(id, &stat); - if (err) - return (err); - else if (stat.configured || stat.busy) - return (drerr_new(0, ESTF_CONFIGBUSY, bp->cm.name)); - else { - /* board power off is essentially a noop for Starfire */ - bp->powered = 0; - return (NULL); - } - /*NOTREACHED*/ -} - -sbd_error_t * -drmach_board_poweron(drmachid_t id) -{ - drmach_board_t *bp; - - if (!DRMACH_IS_BOARD_ID(id)) - return (drerr_new(0, ESTF_INAPPROP, NULL)); - bp = id; - - /* board power on is essentially a noop for Starfire */ - bp->powered = 1; - - return (NULL); -} - -static sbd_error_t * -drmach_board_release(drmachid_t id) -{ - if (!DRMACH_IS_BOARD_ID(id)) - return (drerr_new(0, ESTF_INAPPROP, NULL)); - return (NULL); -} - -/*ARGSUSED*/ -sbd_error_t * -drmach_board_test(drmachid_t id, drmach_opts_t *opts, int force) -{ - return (NULL); -} - -sbd_error_t * -drmach_board_unassign(drmachid_t id) -{ - drmach_board_t *bp; - sbd_error_t *err; - drmach_status_t stat; - - if (!DRMACH_IS_BOARD_ID(id)) - return (drerr_new(0, ESTF_INAPPROP, NULL)); - bp = id; - - err = drmach_board_status(id, &stat); - if (err) - return (err); - else if (stat.configured || stat.busy) - return (drerr_new(0, ESTF_CONFIGBUSY, bp->cm.name)); - else if (drmach_array_set(drmach_boards, bp->bnum, 0) != 0) - return (DRMACH_INTERNAL_ERROR()); - else { - drmach_board_dispose(bp); - return (NULL); - } - /*NOTREACHED*/ -} - -static sbd_error_t * -drmach_cpu_new(drmach_device_t *dp) -{ - sbd_error_t *err; - int portid; - - err = drmach_device_get_prop(dp, "upa-portid", &portid); - if (err == NULL) - dp->unum = portid & 3; - - dp->cm.isa = (void *)drmach_cpu_new; - dp->cm.release = drmach_cpu_release; - dp->cm.status = drmach_cpu_status; - - (void) snprintf(dp->cm.name, sizeof (dp->cm.name), "%s%d", dp->type, - dp->unum); - - return (err); -} - -/* - * drmach_cpu_obp_detach() - * This requires two steps, first, we must put the cpuid into the OBP - * idle loop (Idle in Program) state. Then we call OBP to place the CPU - * into the "Detached" state, which does any special processing to - * actually detach the cpu, such as flushing ecache, and also ensures - * that a subsequent breakpoint won't restart the cpu (if it was just in - * Idle in Program state). - */ -static void -drmach_cpu_obp_detach(int cpuid) -{ - /* - * Cpu may not be under OBP's control. Eg, if cpu exited to download - * helper on a prior attach. - */ - if (CPU_SGN_EXISTS(cpuid) && - !SGN_CPU_IS_OS(cpuid) && - !SGN_CPU_IS_OBP(cpuid)) { - cmn_err(CE_WARN, - "unexpected signature (0x%x) for cpu %d", - get_cpu_sgn(cpuid), cpuid); - } - - /* - * Now we place the CPU into the "Detached" idle loop in OBP. - * This is so that the CPU won't be restarted if we break into - * OBP with a breakpoint or BREAK key from the console, and also - * if we need to do any special processing, such as flushing the - * cpu's ecache, disabling interrupts (by turning of the ET bit in - * the PSR) and/or spinning in BBSRAM rather than global memory. - */ - DRMACH_PR("prom_starfire_rm_cpu(%d)\n", cpuid); - prom_starfire_rm_cpu(cpuid); -} - -/* - * drmach_cpu_obp_is_detached() returns TRUE if the cpu sigblock signature state - * is SIGBST_DETACHED; otherwise it returns FALSE. This routine should only - * be called after we have asked OBP to detach the CPU. It should NOT be - * called as a check during any other flow. - */ -static int -drmach_cpu_obp_is_detached(int cpuid) -{ - if (!CPU_SGN_EXISTS(cpuid) || - (SGN_CPU_IS_OS(cpuid) && SGN_CPU_STATE_IS_DETACHED(cpuid))) - return (1); - else - return (0); -} - -static int -drmach_cpu_start(struct cpu *cp) -{ - int cpuid = cp->cpu_id; - int ntries = drmach_cpu_ntries; - extern void restart_other_cpu(int); - - ASSERT(MUTEX_HELD(&cpu_lock)); - ASSERT(cpunodes[cpuid].nodeid != (pnode_t)0); - - cp->cpu_flags &= ~CPU_POWEROFF; - - /* - * NOTE: restart_other_cpu pauses cpus during the - * slave cpu start. This helps to quiesce the - * bus traffic a bit which makes the tick sync - * routine in the prom more robust. - */ - DRMACH_PR("COLD START for cpu (%d)\n", cpuid); - - prom_starfire_add_cpu(cpuid); - - restart_other_cpu(cpuid); - - /* - * Wait for the cpu to reach its idle thread before - * we zap it with a request to blow away the mappings - * it (might) have for the drmach_shutdown_asm code - * it may have executed on unconfigure. - */ - while ((cp->cpu_thread != cp->cpu_idle_thread) && (ntries > 0)) { - DELAY(drmach_cpu_delay); - ntries--; - } - - DRMACH_PR("waited %d out of %d loops for cpu %d\n", - drmach_cpu_ntries - ntries, drmach_cpu_ntries, cpuid); - - xt_one(cpuid, vtag_flushpage_tl1, - (uint64_t)drmach_shutdown_va, (uint64_t)ksfmmup); - - return (0); -} - -/* - * A detaching CPU is xcalled with an xtrap to drmach_cpu_stop_self() after - * it has been offlined. The function of this routine is to get the cpu - * spinning in a safe place. The requirement is that the system will not - * reference anything on the detaching board (memory and i/o is detached - * elsewhere) and that the CPU not reference anything on any other board - * in the system. This isolation is required during and after the writes - * to the domain masks to remove the board from the domain. - * - * To accomplish this isolation the following is done: - * 1) Create a locked mapping to a location in BBSRAM where - * the cpu will execute. - * 2) Copy the target function (drmach_shutdown_asm) in which - * the cpu will execute into BBSRAM. - * 3) Jump into function with BBSRAM. - * Function will: - * 3.1) Flush its Ecache (displacement). - * 3.2) Flush its Dcache with HW mechanism. - * 3.3) Flush its Icache with HW mechanism. - * 3.4) Flush all valid and _unlocked_ D-TLB entries. - * 3.5) Flush all valid and _unlocked_ I-TLB entries. - * 3.6) Clear xt_mb to signal completion. Note: cache line is - * recovered by drmach_cpu_poweroff(). - * 4) Jump into a tight loop. - */ -#define DRMACH_BBSRAM_OFFSET 0x1000 - -static void -drmach_cpu_stop_self(void) -{ - int cpuid = (int)CPU->cpu_id; - tte_t tte; - volatile uint_t *src, *dst; - size_t funclen; - uint64_t bbsram_pa, bbsram_offset; - uint_t bbsram_pfn; - uint64_t bbsram_addr; - void (*bbsram_func)(uint64_t); - extern void drmach_shutdown_asm(uint64_t); - extern void drmach_shutdown_asm_end(void); - - funclen = (uintptr_t)drmach_shutdown_asm_end - - (uintptr_t)drmach_shutdown_asm; - ASSERT(funclen <= MMU_PAGESIZE); - /* - * We'll start from the 0th's base. - */ - bbsram_pa = STARFIRE_UPAID2UPS(cpuid) | STARFIRE_PSI_BASE; - bbsram_offset = bbsram_pa | 0xfe0ULL; - bbsram_pa += ldphysio(bbsram_offset) + DRMACH_BBSRAM_OFFSET; - - bbsram_pfn = (uint_t)(bbsram_pa >> MMU_PAGESHIFT); - - bbsram_addr = (uint64_t)drmach_shutdown_va; - drmach_shutdown_asm_mbox->estack = bbsram_addr + funclen; - - tte.tte_inthi = TTE_VALID_INT | TTE_SZ_INT(TTE8K) | - TTE_PFN_INTHI(bbsram_pfn); - tte.tte_intlo = TTE_PFN_INTLO(bbsram_pfn) | - TTE_HWWR_INT | TTE_PRIV_INT | TTE_LCK_INT; - sfmmu_dtlb_ld_kva(drmach_shutdown_va, &tte); /* load dtlb */ - sfmmu_itlb_ld_kva(drmach_shutdown_va, &tte); /* load itlb */ - - for (src = (uint_t *)drmach_shutdown_asm, dst = (uint_t *)bbsram_addr; - src < (uint_t *)drmach_shutdown_asm_end; src++, dst++) - *dst = *src; - - bbsram_func = (void (*)())bbsram_addr; - drmach_shutdown_asm_mbox->flushaddr = ecache_flushaddr; - drmach_shutdown_asm_mbox->size = (cpunodes[cpuid].ecache_size << 1); - drmach_shutdown_asm_mbox->linesize = cpunodes[cpuid].ecache_linesize; - drmach_shutdown_asm_mbox->physaddr = - va_to_pa((void *)&drmach_xt_mb[cpuid]); - - /* - * Signal to drmach_cpu_poweroff() is via drmach_xt_mb cleared - * by asm code - */ - - (*bbsram_func)(va_to_pa((void *)drmach_shutdown_asm_mbox)); -} - -static void -drmach_cpu_shutdown_self(void) -{ - cpu_t *cp = CPU; - int cpuid = cp->cpu_id; - extern void flush_windows(void); - - flush_windows(); - - (void) spl8(); - - ASSERT(cp->cpu_intr_actv == 0); - ASSERT(cp->cpu_thread == cp->cpu_idle_thread || - cp->cpu_thread == cp->cpu_startup_thread); - - cp->cpu_flags = CPU_OFFLINE | CPU_QUIESCED | CPU_POWEROFF; - - drmach_cpu_stop_self(); - - cmn_err(CE_PANIC, "CPU %d FAILED TO SHUTDOWN", cpuid); -} - -/* a helper routine to keep the math in one place */ -static processorid_t -drmach_cpu_calc_id(drmach_device_t *dp) -{ - return (dp->bp->bnum * MAX_CPU_UNITS_PER_BOARD + dp->unum); -} - -/* - * Move bootproc (SIGBCPU) to another cpu. If dst_cpu is NULL, a - * destination cpu is chosen from the set of cpus not located on the - * same board as the current bootproc cpu. - */ -static sbd_error_t * -drmach_cpu_juggle_bootproc(drmach_device_t *dst_cpu) -{ - processorid_t cpuid; - struct cpu *cp; - sbd_error_t *err; - int rv; - - ASSERT(MUTEX_HELD(&cpu_lock)); - - /* dst_cpu is NULL when target cpu is unspecified. So, pick one. */ - if (dst_cpu == NULL) { - int avoid_board = DRMACH_CPUID2BNUM(SIGBCPU->cpu_id); - int max_cpuid = MAX_BOARDS * MAX_CPU_UNITS_PER_BOARD; - - for (cpuid = 0; cpuid < max_cpuid; cpuid++) - if (DRMACH_CPUID2BNUM(cpuid) != avoid_board) { - cp = cpu_get(cpuid); - if (cp != NULL && cpu_is_online(cp)) - break; - } - - if (cpuid == max_cpuid) { - err = drerr_new(1, ESTF_JUGGLE, NULL); - return (err); - } - - /* else, cp points to the selected target cpu */ - } else { - cpuid = drmach_cpu_calc_id(dst_cpu); - - if ((cp = cpu_get(cpuid)) == NULL) { - err = drerr_new(1, ESTF_NODEV, "%s::%s", - dst_cpu->bp->cm.name, dst_cpu->cm.name); - return (err); - } - - if (cpuid == SIGBCPU->cpu_id) { - cmn_err(CE_WARN, - "SIGBCPU(%d) same as new selection(%d)", - SIGBCPU->cpu_id, cpuid); - - /* technically not an error, but a no-op */ - return (NULL); - } - } - - cmn_err(CE_NOTE, "?relocating SIGBCPU from %d to %d", - SIGBCPU->cpu_id, cpuid); - - DRMACH_PR("moving SIGBCPU to CPU %d\n", cpuid); - - /* - * Tell OBP to initialize cvc-offset field of new CPU0 - * so that it's in sync with OBP and cvc_server - */ - prom_starfire_init_console(cpuid); - - /* - * Assign cvc to new cpu0's bbsram for I/O. This has to be - * done BEFORE cpu0 is moved via obp, since this logic - * will cause obp_helper to switch to a different bbsram for - * cvc I/O. We don't want cvc writing to a buffer from which - * nobody will pick up the data! - */ - cvc_assign_iocpu(cpuid); - - rv = prom_starfire_move_cpu0(cpuid); - - if (rv == 0) { - SIGBCPU = cp; - - DRMACH_PR("successfully juggled to CPU %d\n", cpuid); - return (NULL); - } else { - DRMACH_PR("prom error: prom_starfire_move_cpu0(%d) " - "returned %d\n", cpuid, rv); - - /* - * The move failed, hopefully obp_helper is still back - * at the old bootproc. Move cvc back there. - */ - cvc_assign_iocpu(SIGBCPU->cpu_id); - - - err = drerr_new(1, ESTF_MOVESIGB, "CPU %d", cpuid); - return (err); - } - /*NOTREACHED*/ -} - -static sbd_error_t * -drmach_cpu_release(drmachid_t id) -{ - drmach_device_t *dp; - processorid_t cpuid; - struct cpu *cp; - sbd_error_t *err; - - if (!DRMACH_IS_CPU_ID(id)) - return (drerr_new(0, ESTF_INAPPROP, NULL)); - dp = id; - cpuid = drmach_cpu_calc_id(dp); - - ASSERT(MUTEX_HELD(&cpu_lock)); - - cp = cpu_get(cpuid); - if (cp == NULL) - err = DRMACH_INTERNAL_ERROR(); - else if (SIGBCPU->cpu_id == cp->cpu_id) - err = drmach_cpu_juggle_bootproc(NULL); - else - err = NULL; - - return (err); -} - -static sbd_error_t * -drmach_cpu_status(drmachid_t id, drmach_status_t *stat) -{ - drmach_device_t *dp; - - ASSERT(DRMACH_IS_CPU_ID(id)); - dp = id; - - stat->assigned = dp->bp->assigned; - stat->powered = dp->bp->powered; - mutex_enter(&cpu_lock); - stat->configured = (cpu_get(drmach_cpu_calc_id(dp)) != NULL); - mutex_exit(&cpu_lock); - stat->busy = dp->busy; - (void) strncpy(stat->type, dp->type, sizeof (stat->type)); - stat->info[0] = '\0'; - - return (NULL); -} - -sbd_error_t * -drmach_cpu_disconnect(drmachid_t id) -{ - drmach_device_t *cpu; - int cpuid; - int ntries; - int p; - u_longlong_t pc_addr; - uchar_t rvalue; - - if (!DRMACH_IS_CPU_ID(id)) - return (drerr_new(0, ESTF_INAPPROP, NULL)); - cpu = id; - - cpuid = drmach_cpu_calc_id(cpu); - if (SIGBCPU->cpu_id == cpuid) { - /* this cpu is SIGBCPU, can't disconnect */ - return (drerr_new(1, ESTF_HASSIGB, "%s::%s", - cpu->bp->cm.name, cpu->cm.name)); - } - - /* - * Make sure SIGBST_DETACHED is set before - * mapping out the sig block. - */ - ntries = drmach_cpu_ntries; - while (!drmach_cpu_obp_is_detached(cpuid) && ntries) { - DELAY(drmach_cpu_delay); - ntries--; - } - if (!drmach_cpu_obp_is_detached(cpuid)) { - cmn_err(CE_WARN, "failed to mark cpu %d detached in sigblock", - cpuid); - } - - /* map out signature block */ - if (CPU_SGN_EXISTS(cpuid)) { - CPU_SGN_MAPOUT(cpuid); - } - - /* - * We now PC IDLE the processor to guarantee we - * stop any transactions from coming from it. - */ - p = cpu->unum & 1; - pc_addr = STARFIRE_BB_PC_ADDR(cpu->bp->bnum, cpu->unum, 0); - - DRMACH_PR("PC idle cpu %d (addr = 0x%llx, port = %d, p = %d)", - drmach_cpu_calc_id(cpu), pc_addr, cpu->unum, p); - - rvalue = ldbphysio(pc_addr); - rvalue |= STARFIRE_BB_PC_IDLE(p); - stbphysio(pc_addr, rvalue); - DELAY(50000); - - return (NULL); -} - -sbd_error_t * -drmach_cpu_get_id(drmachid_t id, processorid_t *cpuid) -{ - drmach_device_t *cpu; - - if (!DRMACH_IS_CPU_ID(id)) - return (drerr_new(0, ESTF_INAPPROP, NULL)); - cpu = id; - - *cpuid = drmach_cpu_calc_id(cpu); - return (NULL); -} - -sbd_error_t * -drmach_cpu_get_impl(drmachid_t id, int *ip) -{ - drmach_device_t *cpu; - int impl; - - if (!DRMACH_IS_CPU_ID(id)) - return (drerr_new(0, ESTF_INAPPROP, NULL)); - - cpu = id; - - if (drmach_node_get_prop(cpu->node, "implementation#", &impl) == -1) { - return (DRMACH_INTERNAL_ERROR()); - } - - *ip = impl; - - return (NULL); -} - -void -drmach_cpu_flush_ecache_sync(void) -{ - ASSERT(curthread->t_bound_cpu == CPU); - - /* - * Now let's flush our ecache thereby removing all references - * to the target (detaching) memory from all ecache's in - * system. - */ - cpu_flush_ecache(); - - /* - * Delay 100 usec out of paranoia to insure everything - * (hardware queues) has drained before we start reprogramming - * the hardware. - */ - DELAY(100); -} - -sbd_error_t * -drmach_get_dip(drmachid_t id, dev_info_t **dip) -{ - drmach_device_t *dp; - - if (!DRMACH_IS_DEVICE_ID(id)) - return (drerr_new(0, ESTF_INAPPROP, NULL)); - dp = id; - - *dip = drmach_node_get_dip(dp->node); - return (NULL); -} - -sbd_error_t * -drmach_io_is_attached(drmachid_t id, int *yes) -{ - drmach_device_t *dp; - dev_info_t *dip; - int state; - - if (!DRMACH_IS_IO_ID(id)) - return (drerr_new(0, ESTF_INAPPROP, NULL)); - dp = id; - - dip = drmach_node_get_dip(dp->node); - if (dip == NULL) { - *yes = 0; - return (NULL); - } - - state = ddi_get_devstate(dip); - *yes = (i_ddi_devi_attached(dip) || (state == DDI_DEVSTATE_UP)); - - return (NULL); -} - -sbd_error_t * -drmach_io_pre_release(drmachid_t id) -{ - if (!DRMACH_IS_IO_ID(id)) - return (drerr_new(0, ESTF_INAPPROP, NULL)); - return (NULL); -} - -static sbd_error_t * -drmach_io_release(drmachid_t id) -{ - if (!DRMACH_IS_IO_ID(id)) - return (drerr_new(0, ESTF_INAPPROP, NULL)); - return (NULL); -} - -sbd_error_t * -drmach_io_unrelease(drmachid_t id) -{ - if (!DRMACH_IS_IO_ID(id)) - return (drerr_new(0, ESTF_INAPPROP, NULL)); - return (NULL); -} - -/*ARGSUSED*/ -sbd_error_t * -drmach_io_post_release(drmachid_t id) -{ - return (NULL); -} - -/*ARGSUSED*/ -sbd_error_t * -drmach_io_post_attach(drmachid_t id) -{ - return (NULL); -} - -static sbd_error_t * -drmach_io_status(drmachid_t id, drmach_status_t *stat) -{ - drmach_device_t *dp; - sbd_error_t *err; - int configured; - - ASSERT(DRMACH_IS_IO_ID(id)); - dp = id; - - err = drmach_io_is_attached(id, &configured); - if (err) - return (err); - - stat->assigned = dp->bp->assigned; - stat->powered = dp->bp->powered; - stat->configured = (configured != 0); - stat->busy = dp->busy; - (void) strncpy(stat->type, dp->type, sizeof (stat->type)); - stat->info[0] = '\0'; - - return (NULL); -} - -static sbd_error_t * -drmach_mem_new(drmach_device_t *dp) -{ - dp->unum = 0; - dp->cm.isa = (void *)drmach_mem_new; - dp->cm.release = drmach_mem_release; - dp->cm.status = drmach_mem_status; - - (void) snprintf(dp->cm.name, sizeof (dp->cm.name), "%s", dp->type); - - return (NULL); -} - -sbd_error_t * -drmach_mem_add_span(drmachid_t id, uint64_t basepa, uint64_t size) -{ - pfn_t basepfn = (pfn_t)(basepa >> PAGESHIFT); - pgcnt_t npages = (pgcnt_t)(size >> PAGESHIFT); - pda_handle_t ph; - int rv; - - ASSERT(size != 0); - - if (!DRMACH_IS_MEM_ID(id)) - return (drerr_new(0, ESTF_INAPPROP, NULL)); - - rv = kcage_range_add(basepfn, npages, KCAGE_DOWN); - if (rv == ENOMEM) { - cmn_err(CE_WARN, "%lu megabytes not available to kernel cage", - (ulong_t)(size == 0 ? 0 : size / MBYTE)); - } else if (rv != 0) { - /* catch this in debug kernels */ - ASSERT(0); - - cmn_err(CE_WARN, "unexpected kcage_range_add" - " return value %d", rv); - } - - /* - * Update the PDA (post2obp) structure with the - * range of the newly added memory. - */ - ph = drmach_pda_open(); - if (ph != NULL) { - pda_mem_add_span(ph, basepa, size); - pda_close(ph); - } - - return (NULL); -} - -sbd_error_t * -drmach_mem_del_span(drmachid_t id, uint64_t basepa, uint64_t size) -{ - drmach_device_t *mem = id; - pfn_t basepfn = (pfn_t)(basepa >> PAGESHIFT); - pgcnt_t npages = (pgcnt_t)(size >> PAGESHIFT); - uint_t mcreg; - sbd_error_t *err; - pda_handle_t ph; - int rv; - - err = drmach_read_mc_asr(id, &mcreg); - if (err) - return (err); - else if (mcreg & STARFIRE_MC_INTERLEAVE_MASK) { - return (drerr_new(1, ESTF_INTERBOARD, "%s::%s", - mem->bp->cm.name, mem->cm.name)); - } - - if (size > 0) { - rv = kcage_range_delete_post_mem_del(basepfn, npages); - if (rv != 0) { - cmn_err(CE_WARN, - "unexpected kcage_range_delete_post_mem_del" - " return value %d", rv); - return (DRMACH_INTERNAL_ERROR()); - } - } - - /* - * Update the PDA (post2obp) structure with the - * range of removed memory. - */ - ph = drmach_pda_open(); - if (ph != NULL) { - if (size > 0) - pda_mem_del_span(ph, basepa, size); - - /* update PDA to board's new mc register settings */ - pda_mem_sync(ph, mem->bp->bnum, 0); - - pda_close(ph); - } - - return (NULL); -} - -/* support routine for enable and disable */ -static sbd_error_t * -drmach_mem_update_interconnect(drmachid_t id, uint_t mcreg) -{ - drmach_device_t *dp; - pda_handle_t ph; - int b; - - if (!DRMACH_IS_MEM_ID(id)) - return (drerr_new(0, ESTF_INAPPROP, NULL)); - dp = id; - - ph = drmach_pda_open(); - if (ph == NULL) - return (DRMACH_INTERNAL_ERROR()); - - for (b = 0; b < MAX_BOARDS; b++) { - int p; - int rv; - ushort_t bda_proc, bda_ioc; - board_desc_t *bdesc; - - if (pda_board_present(ph, b) == 0) - continue; - - bdesc = (board_desc_t *)pda_get_board_info(ph, b); - - /* - * Update PCs for CPUs. - */ - - /* make sure definition in platmod is in sync with pda */ - ASSERT(MAX_PROCMODS == MAX_CPU_UNITS_PER_BOARD); - - bda_proc = bdesc->bda_proc; - for (p = 0; p < MAX_PROCMODS; p++) { - if (BDA_NBL(bda_proc, p) != BDAN_GOOD) - continue; - - rv = pc_madr_add(b, dp->bp->bnum, p, mcreg); - if (rv) { - pda_close(ph); - return (DRMACH_INTERNAL_ERROR()); - } - } - - /* - * Update PCs for IOCs. - */ - - /* make sure definition in platmod is in sync with pda */ - ASSERT(MAX_IOCS == MAX_IO_UNITS_PER_BOARD); - - bda_ioc = bdesc->bda_ioc; - for (p = 0; p < MAX_IOCS; p++) { - if (BDA_NBL(bda_ioc, p) != BDAN_GOOD) - continue; - - rv = pc_madr_add(b, dp->bp->bnum, p + 4, mcreg); - if (rv) { - pda_close(ph); - return (DRMACH_INTERNAL_ERROR()); - } - } - } - - pda_close(ph); - return (NULL); -} - -sbd_error_t * -drmach_mem_disable(drmachid_t id) -{ - sbd_error_t *err; - uint_t mcreg; - - err = drmach_read_mc_asr(id, &mcreg); - if (err == NULL) { - ASSERT(mcreg & STARFIRE_MC_MEM_PRESENT_MASK); - - /* Turn off presence bit. */ - mcreg &= ~STARFIRE_MC_MEM_PRESENT_MASK; - - err = drmach_mem_update_interconnect(id, mcreg); - if (err == NULL) - err = drmach_write_mc_asr(id, mcreg); - } - - return (err); -} - -sbd_error_t * -drmach_mem_enable(drmachid_t id) -{ - sbd_error_t *err; - uint_t mcreg; - - err = drmach_read_mc_asr(id, &mcreg); - if (err == NULL) { - mcreg |= STARFIRE_MC_MEM_PRESENT_MASK; - - err = drmach_write_mc_asr(id, mcreg); - if (err == NULL) - err = drmach_mem_update_interconnect(id, mcreg); - } - - return (err); -} - -sbd_error_t * -drmach_mem_get_alignment(drmachid_t id, uint64_t *mask) -{ - drmach_device_t *mem; - sbd_error_t *err; - pnode_t nodeid; - - if (!DRMACH_IS_MEM_ID(id)) - return (drerr_new(0, ESTF_INAPPROP, NULL)); - mem = id; - - nodeid = drmach_node_get_dnode(mem->node); - if (nodeid == OBP_NONODE || nodeid == OBP_BADNODE) - err = DRMACH_INTERNAL_ERROR(); - else { - uint64_t size; - - size = mc_get_alignment_mask(nodeid); - if (size == (uint64_t)-1) - err = DRMACH_INTERNAL_ERROR(); - else { - *mask = size - 1; - err = NULL; - } - } - - return (err); -} - -sbd_error_t * -drmach_mem_get_base_physaddr(drmachid_t id, uint64_t *pa) -{ - sbd_error_t *err; - uint_t mcreg; - - err = drmach_read_mc_asr(id, &mcreg); - if (err == NULL) - *pa = mc_asr_to_pa(mcreg); - - return (err); -} - -/* - * Use of this routine after copy/rename will yield incorrect results, - * because the OBP MEMAVAIL property will not correctly reflect the - * programming of the MCs. - */ -sbd_error_t * -drmach_mem_get_memlist(drmachid_t id, struct memlist **ml) -{ - drmach_device_t *mem; - int rv, i, rlen, rblks; - sbd_error_t *err; - struct memlist *mlist; - struct sf_memunit_regspec *rlist; - - if (!DRMACH_IS_MEM_ID(id)) - return (drerr_new(0, ESTF_INAPPROP, NULL)); - mem = id; - - err = drmach_device_get_proplen(mem, "dr-available", &rlen); - if (err) - return (err); - - rlist = kmem_zalloc(rlen, KM_SLEEP); - - err = drmach_device_get_prop(mem, "dr-available", rlist); - if (err) { - kmem_free(rlist, rlen); - return (err); - } - - mlist = NULL; - rblks = rlen / sizeof (struct sf_memunit_regspec); - for (i = 0; i < rblks; i++) { - uint64_t addr, size; - - addr = (uint64_t)rlist[i].regspec_addr_hi << 32; - addr |= (uint64_t)rlist[i].regspec_addr_lo; - size = (uint64_t)rlist[i].regspec_size_hi << 32; - size |= (uint64_t)rlist[i].regspec_size_lo; - - mlist = memlist_add_span(mlist, addr, size); - } - - kmem_free(rlist, rlen); - - /* - * Make sure the incoming memlist doesn't already - * intersect with what's present in the system (phys_install). - */ - memlist_read_lock(); - rv = memlist_intersect(phys_install, mlist); - memlist_read_unlock(); - if (rv) { -#ifdef DEBUG - DRMACH_PR("OBP derived memlist intersects" - " with phys_install\n"); - memlist_dump(mlist); - - DRMACH_PR("phys_install memlist:\n"); - memlist_dump(phys_install); -#endif - - memlist_delete(mlist); - return (DRMACH_INTERNAL_ERROR()); - } - -#ifdef DEBUG - DRMACH_PR("OBP derived memlist:"); - memlist_dump(mlist); -#endif - - *ml = mlist; - return (NULL); -} - -sbd_error_t * -drmach_mem_get_size(drmachid_t id, uint64_t *bytes) -{ - drmach_device_t *mem; - pda_handle_t ph; - pgcnt_t npages; - - if (!DRMACH_IS_MEM_ID(id)) - return (drerr_new(0, ESTF_INAPPROP, NULL)); - mem = id; - - ph = drmach_pda_open(); - if (ph == NULL) - return (DRMACH_INTERNAL_ERROR()); - - npages = pda_get_mem_size(ph, mem->bp->bnum); - *bytes = (uint64_t)npages << PAGESHIFT; - - pda_close(ph); - return (NULL); -} - -sbd_error_t * -drmach_mem_get_slice_size(drmachid_t id, uint64_t *bytes) -{ - if (!DRMACH_IS_MEM_ID(id)) - return (drerr_new(0, ESTF_INAPPROP, NULL)); - - *bytes = mc_get_mem_alignment(); - return (NULL); -} - -/* field debugging tool */ -processorid_t drmach_mem_cpu_affinity_nail = 0; - -processorid_t -drmach_mem_cpu_affinity(drmachid_t id) -{ - drmach_device_t *mp; - drmach_board_t *bp; - processorid_t cpuid; - - if (!DRMACH_IS_MEM_ID(id)) - return (CPU_CURRENT); - - if (drmach_mem_cpu_affinity_nail) { - cpuid = drmach_mem_cpu_affinity_nail; - - if (cpuid < 0 || cpuid > NCPU) - return (CPU_CURRENT); - - mutex_enter(&cpu_lock); - if (cpu[cpuid] == NULL || !CPU_ACTIVE(cpu[cpuid])) - cpuid = CPU_CURRENT; - mutex_exit(&cpu_lock); - - return (cpuid); - } - - /* try to choose a proc on the target board */ - mp = id; - bp = mp->bp; - if (bp->devices) { - int rv; - int d_idx; - drmachid_t d_id; - - rv = drmach_array_first(bp->devices, &d_idx, &d_id); - while (rv == 0) { - if (DRMACH_IS_CPU_ID(d_id)) { - cpuid = drmach_cpu_calc_id(d_id); - - mutex_enter(&cpu_lock); - if (cpu[cpuid] && CPU_ACTIVE(cpu[cpuid])) { - mutex_exit(&cpu_lock); - DRMACH_PR("drmach_mem_cpu_affinity: " - "selected cpuid=%d\n", cpuid); - return (cpuid); - } else { - mutex_exit(&cpu_lock); - } - } - - rv = drmach_array_next(bp->devices, &d_idx, &d_id); - } - } - - /* otherwise, this proc, wherever it is */ - DRMACH_PR("drmach_mem_cpu_affinity: using default CPU_CURRENT\n"); - - return (CPU_CURRENT); -} - -static sbd_error_t * -drmach_mem_release(drmachid_t id) -{ - if (!DRMACH_IS_MEM_ID(id)) - return (drerr_new(0, ESTF_INAPPROP, NULL)); - return (NULL); -} - -static sbd_error_t * -drmach_mem_status(drmachid_t id, drmach_status_t *stat) -{ - drmach_device_t *dp; - sbd_error_t *err; - uint64_t pa, slice_size; - struct memlist *ml; - - ASSERT(DRMACH_IS_MEM_ID(id)); - dp = id; - - /* get starting physical address of target memory */ - err = drmach_mem_get_base_physaddr(id, &pa); - if (err) - return (err); - - /* round down to slice boundary */ - slice_size = mc_get_mem_alignment(); - pa &= ~ (slice_size - 1); - - /* stop at first span that is in slice */ - memlist_read_lock(); - for (ml = phys_install; ml; ml = ml->ml_next) - if (ml->ml_address >= pa && ml->ml_address < pa + slice_size) - break; - memlist_read_unlock(); - - stat->assigned = dp->bp->assigned; - stat->powered = dp->bp->powered; - stat->configured = (ml != NULL); - stat->busy = dp->busy; - (void) strncpy(stat->type, dp->type, sizeof (stat->type)); - stat->info[0] = '\0'; - - return (NULL); -} - -static int -drmach_detach_board(void *arg) -{ - cpuset_t cset; - int retval; - drmach_board_t *bp = (drmach_board_t *)arg; - - cset = cpu_ready_set; - promsafe_xc_attention(cset); - - retval = prom_starfire_rm_brd(bp->bnum); - - xc_dismissed(cset); - - return (retval); -} - -sbd_error_t * -drmach_board_deprobe(drmachid_t id) -{ - drmach_board_t *bp; - int retval; - - if (!DRMACH_IS_BOARD_ID(id)) - return (drerr_new(0, ESTF_INAPPROP, NULL)); - bp = id; - - cmn_err(CE_CONT, "DR: PROM detach board %d\n", bp->bnum); - - retval = prom_tree_update(drmach_detach_board, bp); - - if (retval == 0) - return (NULL); - else { - cmn_err(CE_WARN, "prom error: prom_starfire_rm_brd(%d) " - "returned %d", bp->bnum, retval); - return (drerr_new(1, ESTF_DEPROBE, "%s", bp->cm.name)); - } -} - -/*ARGSUSED*/ -static sbd_error_t * -drmach_pt_juggle_bootproc(drmachid_t id, drmach_opts_t *opts) -{ - drmach_device_t *cpu; - sbd_error_t *err; - - if (!DRMACH_IS_CPU_ID(id)) - return (drerr_new(0, ESTF_INAPPROP, NULL)); - cpu = id; - - mutex_enter(&cpu_lock); - - err = drmach_cpu_juggle_bootproc(cpu); - - mutex_exit(&cpu_lock); - - return (err); -} - -/*ARGSUSED*/ -static sbd_error_t * -drmach_pt_dump_pdainfo(drmachid_t id, drmach_opts_t *opts) -{ - drmach_board_t *bp; - int board; - int i; - pda_handle_t ph; - board_desc_t *bdesc; - - if (!DRMACH_IS_BOARD_ID(id)) - return (drerr_new(0, ESTF_INAPPROP, NULL)); - bp = id; - board = bp->bnum; - - ph = drmach_pda_open(); - if (ph == NULL) - return (DRMACH_INTERNAL_ERROR()); - - if (pda_board_present(ph, board) == 0) { - cmn_err(CE_CONT, "board %d is MISSING\n", board); - pda_close(ph); - return (DRMACH_INTERNAL_ERROR()); - } - - cmn_err(CE_CONT, "board %d is PRESENT\n", board); - - bdesc = (board_desc_t *)pda_get_board_info(ph, board); - if (bdesc == NULL) { - cmn_err(CE_CONT, - "no board descriptor found for board %d\n", - board); - pda_close(ph); - return (DRMACH_INTERNAL_ERROR()); - } - - /* make sure definition in platmod is in sync with pda */ - ASSERT(MAX_PROCMODS == MAX_CPU_UNITS_PER_BOARD); - - for (i = 0; i < MAX_PROCMODS; i++) { - if (BDA_NBL(bdesc->bda_proc, i) == BDAN_GOOD) - cmn_err(CE_CONT, - "proc %d.%d PRESENT\n", board, i); - else - cmn_err(CE_CONT, - "proc %d.%d MISSING\n", board, i); - } - - for (i = 0; i < MAX_MGROUPS; i++) { - if (BDA_NBL(bdesc->bda_mgroup, i) == BDAN_GOOD) - cmn_err(CE_CONT, - "mgroup %d.%d PRESENT\n", board, i); - else - cmn_err(CE_CONT, - "mgroup %d.%d MISSING\n", board, i); - } - - /* make sure definition in platmod is in sync with pda */ - ASSERT(MAX_IOCS == MAX_IO_UNITS_PER_BOARD); - - for (i = 0; i < MAX_IOCS; i++) { - int s; - - if (BDA_NBL(bdesc->bda_ioc, i) == BDAN_GOOD) { - cmn_err(CE_CONT, - "ioc %d.%d PRESENT\n", board, i); - for (s = 0; s < MAX_SLOTS_PER_IOC; s++) { - if (BDA_NBL(bdesc->bda_ios[i], s) != BDAN_GOOD) - continue; - cmn_err(CE_CONT, - "..scard %d.%d.%d PRESENT\n", - board, i, s); - } - } else { - cmn_err(CE_CONT, - "ioc %d.%d MISSING\n", - board, i); - } - } - - cmn_err(CE_CONT, - "board %d memsize = %d pages\n", - board, pda_get_mem_size(ph, board)); - - pda_close(ph); - - return (NULL); -} - -/*ARGSUSED*/ -sbd_error_t * -drmach_pt_readmem(drmachid_t id, drmach_opts_t *opts) -{ - struct memlist *ml; - uint64_t src_pa; - uint64_t dst_pa; - uint64_t dst; - - dst_pa = va_to_pa(&dst); - - memlist_read_lock(); - for (ml = phys_install; ml; ml = ml->ml_next) { - uint64_t nbytes; - - src_pa = ml->ml_address; - nbytes = ml->ml_size; - - while (nbytes != 0ull) { - - /* copy 32 bytes at arc_pa to dst_pa */ - bcopy32_il(src_pa, dst_pa); - - /* increment by 32 bytes */ - src_pa += (4 * sizeof (uint64_t)); - - /* decrement by 32 bytes */ - nbytes -= (4 * sizeof (uint64_t)); - } - } - memlist_read_unlock(); - - return (NULL); -} - -static struct { - const char *name; - sbd_error_t *(*handler)(drmachid_t id, drmach_opts_t *opts); -} drmach_pt_arr[] = { - { "juggle", drmach_pt_juggle_bootproc }, - { "pda", drmach_pt_dump_pdainfo }, - { "readmem", drmach_pt_readmem }, - - /* the following line must always be last */ - { NULL, NULL } -}; - -/*ARGSUSED*/ -sbd_error_t * -drmach_passthru(drmachid_t id, drmach_opts_t *opts) -{ - int i; - sbd_error_t *err; - - i = 0; - while (drmach_pt_arr[i].name != NULL) { - int len = strlen(drmach_pt_arr[i].name); - - if (strncmp(drmach_pt_arr[i].name, opts->copts, len) == 0) - break; - - i += 1; - } - - if (drmach_pt_arr[i].name == NULL) - err = drerr_new(0, ESTF_UNKPTCMD, opts->copts); - else - err = (*drmach_pt_arr[i].handler)(id, opts); - - return (err); -} - -sbd_error_t * -drmach_release(drmachid_t id) -{ - drmach_common_t *cp; - if (!DRMACH_IS_DEVICE_ID(id)) - return (drerr_new(0, ESTF_INAPPROP, NULL)); - cp = id; - - return (cp->release(id)); -} - -sbd_error_t * -drmach_status(drmachid_t id, drmach_status_t *stat) -{ - drmach_common_t *cp; - - if (!DRMACH_IS_ID(id)) - return (drerr_new(0, ESTF_NOTID, NULL)); - cp = id; - - return (cp->status(id, stat)); -} - -sbd_error_t * -drmach_unconfigure(drmachid_t id, int flags) -{ - drmach_device_t *dp; - pnode_t nodeid; - dev_info_t *dip, *fdip = NULL; - - if (!DRMACH_IS_DEVICE_ID(id)) - return (drerr_new(0, ESTF_INAPPROP, NULL)); - - dp = id; - - nodeid = drmach_node_get_dnode(dp->node); - if (nodeid == OBP_NONODE) - return (DRMACH_INTERNAL_ERROR()); - - dip = e_ddi_nodeid_to_dip(nodeid); - if (dip == NULL) - return (NULL); - - /* - * Branch already held, so hold acquired in - * e_ddi_nodeid_to_dip() can be released - */ - ddi_release_devi(dip); - - if (flags & DEVI_BRANCH_DESTROY) - flags |= DEVI_BRANCH_EVENT; - - /* - * Force flag is no longer necessary. See starcat/io/drmach.c - * for details. - */ - ASSERT(e_ddi_branch_held(dip)); - if (e_ddi_branch_unconfigure(dip, &fdip, flags)) { - sbd_error_t *err; - char *path = kmem_alloc(MAXPATHLEN, KM_SLEEP); - - /* - * If non-NULL, fdip is returned held and must be released. - */ - if (fdip != NULL) { - (void) ddi_pathname(fdip, path); - ndi_rele_devi(fdip); - } else { - (void) ddi_pathname(dip, path); - } - - err = drerr_new(1, ESTF_DRVFAIL, path); - - kmem_free(path, MAXPATHLEN); - - return (err); - } - - return (NULL); -} - -/* - * drmach interfaces to legacy Starfire platmod logic - * linkage via runtime symbol look up, called from plat_cpu_power* - */ - -/* - * Start up a cpu. It is possible that we're attempting to restart - * the cpu after an UNCONFIGURE in which case the cpu will be - * spinning in its cache. So, all we have to do is wake it up. - * Under normal circumstances the cpu will be coming from a previous - * CONNECT and thus will be spinning in OBP. In both cases, the - * startup sequence is the same. - */ -int -drmach_cpu_poweron(struct cpu *cp) -{ - DRMACH_PR("drmach_cpu_poweron: starting cpuid %d\n", cp->cpu_id); - - ASSERT(MUTEX_HELD(&cpu_lock)); - - if (drmach_cpu_start(cp) != 0) - return (EBUSY); - else - return (0); -} - -int -drmach_cpu_poweroff(struct cpu *cp) -{ - int ntries, cnt; - processorid_t cpuid = cp->cpu_id; - void drmach_cpu_shutdown_self(void); - - DRMACH_PR("drmach_cpu_poweroff: stopping cpuid %d\n", cp->cpu_id); - - ASSERT(MUTEX_HELD(&cpu_lock)); - - /* - * Capture all CPUs (except for detaching proc) to prevent - * crosscalls to the detaching proc until it has cleared its - * bit in cpu_ready_set. - * - * The CPU's remain paused and the prom_mutex is known to be free. - * This prevents the x-trap victim from blocking when doing prom - * IEEE-1275 calls at a high PIL level. - */ - promsafe_pause_cpus(); - - /* - * Quiesce interrupts on the target CPU. We do this by setting - * the CPU 'not ready'- (i.e. removing the CPU from cpu_ready_set) to - * prevent it from receiving cross calls and cross traps. - * This prevents the processor from receiving any new soft interrupts. - */ - mp_cpu_quiesce(cp); - - /* setup xt_mb, will be cleared by drmach_shutdown_asm when ready */ - drmach_xt_mb[cpuid] = 0x80; - - xt_one_unchecked(cpuid, (xcfunc_t *)idle_stop_xcall, - (uint64_t)drmach_cpu_shutdown_self, NULL); - - ntries = drmach_cpu_ntries; - cnt = 0; - while (drmach_xt_mb[cpuid] && ntries) { - DELAY(drmach_cpu_delay); - ntries--; - cnt++; - } - - drmach_xt_mb[cpuid] = 0; /* steal the cache line back */ - - start_cpus(); - - DRMACH_PR("waited %d out of %d tries for " - "drmach_cpu_shutdown_self on cpu%d", - drmach_cpu_ntries - ntries, drmach_cpu_ntries, cp->cpu_id); - - drmach_cpu_obp_detach(cpuid); - - CPU_SIGNATURE(OS_SIG, SIGST_DETACHED, SIGSUBST_NULL, cpuid); - - return (0); -} - -/*ARGSUSED*/ -int -drmach_verify_sr(dev_info_t *dip, int sflag) -{ - return (0); -} - -void -drmach_suspend_last(void) -{ -} - -void -drmach_resume_first(void) -{ -} - -/* - * Log a DR sysevent. - * Return value: 0 success, non-zero failure. - */ -int -drmach_log_sysevent(int board, char *hint, int flag, int verbose) -{ - sysevent_t *ev; - sysevent_id_t eid; - int rv, km_flag; - sysevent_value_t evnt_val; - sysevent_attr_list_t *evnt_attr_list = NULL; - char attach_pnt[MAXNAMELEN]; - - km_flag = (flag == SE_SLEEP) ? KM_SLEEP : KM_NOSLEEP; - attach_pnt[0] = '\0'; - if (drmach_board_name(board, attach_pnt, MAXNAMELEN)) { - rv = -1; - goto logexit; - } - if (verbose) - DRMACH_PR("drmach_log_sysevent: %s %s, flag: %d, verbose: %d\n", - attach_pnt, hint, flag, verbose); - - if ((ev = sysevent_alloc(EC_DR, ESC_DR_AP_STATE_CHANGE, - SUNW_KERN_PUB"dr", km_flag)) == NULL) { - rv = -2; - goto logexit; - } - evnt_val.value_type = SE_DATA_TYPE_STRING; - evnt_val.value.sv_string = attach_pnt; - if ((rv = sysevent_add_attr(&evnt_attr_list, DR_AP_ID, - &evnt_val, km_flag)) != 0) - goto logexit; - - evnt_val.value_type = SE_DATA_TYPE_STRING; - evnt_val.value.sv_string = hint; - if ((rv = sysevent_add_attr(&evnt_attr_list, DR_HINT, - &evnt_val, km_flag)) != 0) { - sysevent_free_attr(evnt_attr_list); - goto logexit; - } - - (void) sysevent_attach_attributes(ev, evnt_attr_list); - - /* - * Log the event but do not sleep waiting for its - * delivery. This provides insulation from syseventd. - */ - rv = log_sysevent(ev, SE_NOSLEEP, &eid); - -logexit: - if (ev) - sysevent_free(ev); - if ((rv != 0) && verbose) - cmn_err(CE_WARN, - "drmach_log_sysevent failed (rv %d) for %s %s\n", - rv, attach_pnt, hint); - - return (rv); -} - -/*ARGSUSED*/ -int -drmach_allow_memrange_modify(drmachid_t id) -{ - return (1); /* TRUE */ -} diff --git a/usr/src/uts/sun4u/starfire/io/idn.c b/usr/src/uts/sun4u/starfire/io/idn.c deleted file mode 100644 index 79eb65f819..0000000000 --- a/usr/src/uts/sun4u/starfire/io/idn.c +++ /dev/null @@ -1,5787 +0,0 @@ -/* - * 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 - * or http://www.opensolaris.org/os/licensing. - * 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. - * Copyright (c) 2016 by Delphix. All rights reserved. - */ - -#include <sys/types.h> -#include <sys/sysmacros.h> -#include <sys/open.h> -#include <sys/param.h> -#include <sys/machparam.h> -#include <sys/systm.h> -#include <sys/signal.h> -#include <sys/cred.h> -#include <sys/user.h> -#include <sys/proc.h> -#include <sys/vnode.h> -#include <sys/uio.h> -#include <sys/buf.h> -#include <sys/file.h> -#include <sys/kmem.h> -#include <sys/stat.h> -#include <sys/stream.h> -#include <sys/stropts.h> -#include <sys/strsubr.h> -#include <sys/strsun.h> -#include <inet/common.h> -#include <inet/mi.h> -#include <inet/nd.h> -#include <sys/poll.h> -#include <sys/utsname.h> -#include <sys/debug.h> -#include <sys/conf.h> -#include <sys/ddi.h> -#include <sys/sunddi.h> -#include <sys/errno.h> -#include <sys/modctl.h> -#include <sys/machsystm.h> -#include <sys/promif.h> -#include <sys/prom_plat.h> -#include <sys/obpdefs.h> -#include <vm/seg_kmem.h> -#include <vm/seg_kp.h> -#include <sys/kstat.h> -#include <sys/membar.h> -#include <sys/ivintr.h> -#include <sys/vm_machparam.h> -#include <sys/x_call.h> -#include <sys/cpuvar.h> -#include <sys/archsystm.h> -#include <sys/dmv.h> - -#include <sys/idn.h> -#include <sys/idn_xf.h> -#include <sys/cpu_sgnblk_defs.h> -#include <sys/cpu_sgn.h> - -struct idn_gkstat sg_kstat; - -#define MBXTBL_PART_REPORT ((caddr_t)1) -#define MBXTBL_FULL_REPORT ((caddr_t)2) - -idn_domain_t idn_domain[MAX_DOMAINS]; -idn_global_t idn; -int idn_debug; -int idn_snoop; -int idn_history; - -typedef enum { - IDN_GPROPS_OKAY, - IDN_GPROPS_UNCHECKED, - IDN_GPROPS_ERROR -} idn_gprops_t; - -struct idn_history idnhlog; - -/* - * IDN "tunables". - */ -int idn_smr_size; -int idn_nwr_size; -int idn_lowat; -int idn_hiwat; -int idn_protocol_nservers; -int idn_awolmsg_interval; -int idn_smr_bufsize; -int idn_slab_bufcount; -int idn_slab_prealloc; -int idn_slab_maxperdomain; -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_spin_count; -int idn_netsvr_wait_min; -int idn_netsvr_wait_max; -int idn_netsvr_wait_shift; - -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; - -int idn_window_emax; /* calculated */ -int idn_slab_maxperdomain; /* calculated */ - -/* - * DMV interrupt support. - */ -int idn_pil; -int idn_dmv_pending_max; -idn_dmv_msg_t *idn_iv_queue[NCPU]; -int idn_intr_index[NCPU]; /* idn_handler ONLY */ -static idn_dmv_data_t *idn_dmv_data; - -int idn_sigbpil; - -idnparam_t idn_param_arr[] = { -{ 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 { - int p_min, p_max, p_def; - char *p_string; - int *p_var; -} idn_global_props[] = { -{ 0, 0, 0, "idn_debug", &idn_debug }, -{ 0, 1, 0, "idn_history", &idn_history }, -{ 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, "idn_lowat", &idn_lowat }, -{ 1*1024, - 1*1024*1024, - 256*1024, - "idn_hiwat", &idn_hiwat }, -{ IDN_SMR_BUFSIZE_MIN, - IDN_SMR_BUFSIZE_MAX, - IDN_SMR_BUFSIZE_DEF, - "idn_smr_bufsize", &idn_smr_bufsize }, -{ 4, 1024, 32, "idn_slab_bufcount", &idn_slab_bufcount }, -{ 0, 10, 0, "idn_slab_prealloc", &idn_slab_prealloc }, -{ 2, MAX_DOMAINS, - 8, "idn_slab_mintotal", &idn_slab_mintotal }, -{ 8, 256, 64, "idn_window_max", &idn_window_max }, -{ 0, 32, 8, "idn_window_incr", &idn_window_incr }, -{ 1, 128, 5, "idn_reclaim_min", &idn_reclaim_min }, -{ 0, 128, 0, "idn_reclaim_max", &idn_reclaim_max }, -{ 1, IDN_MAXMAX_NETS, - 8, "idn_max_nets", &idn_max_nets }, -{ 31, 511, 127, "idn_mbox_per_net", &idn_mbox_per_net }, -{ 0, 1, 1, "idn_checksum", &idn_checksum }, -{ 0, 10000, 500, "idn_netsvr_spin_count", - &idn_netsvr_spin_count }, -{ 0, 30*100, 40, "idn_netsvr_wait_min", &idn_netsvr_wait_min }, -{ 0, 60*100, 16*100, "idn_netsvr_wait_max", &idn_netsvr_wait_max }, -{ 1, 5, 1, "idn_netsvr_wait_shift", - &idn_netsvr_wait_shift }, -{ 1, MAX_DOMAINS, - IDN_PROTOCOL_NSERVERS, - "idn_protocol_nservers", - &idn_protocol_nservers }, -{ 0, 3600, IDN_AWOLMSG_INTERVAL, - "idn_awolmsg_interval", &idn_awolmsg_interval }, -{ 10, 300, IDN_MSGWAIT_NEGO, - "idn_msgwait_nego", &idn_msgwait_nego }, -{ 10, 300, IDN_MSGWAIT_CFG, - "idn_msgwait_cfg", &idn_msgwait_cfg }, -{ 10, 300, IDN_MSGWAIT_CON, - "idn_msgwait_con", &idn_msgwait_con }, -{ 10, 300, IDN_MSGWAIT_FIN, - "idn_msgwait_fin", &idn_msgwait_fin }, -{ 10, 300, IDN_MSGWAIT_CMD, - "idn_msgwait_cmd", &idn_msgwait_cmd }, -{ 10, 300, IDN_MSGWAIT_DATA, - "idn_msgwait_data", &idn_msgwait_data }, -{ 1, 60, IDN_RETRYFREQ_NEGO, - "idn_retryfreq_nego", &idn_retryfreq_nego }, -{ 1, 60, IDN_RETRYFREQ_CON, - "idn_retryfreq_con", &idn_retryfreq_con }, -{ 1, 60, IDN_RETRYFREQ_FIN, - "idn_retryfreq_fin", &idn_retryfreq_fin }, -{ 1, 9, IDN_PIL, - "idn_pil", &idn_pil }, -{ 1, 9, IDN_SIGBPIL, - "idn_sigbpil", &idn_sigbpil }, -{ 8, 512, IDN_DMV_PENDING_MAX, - "idn_dmv_pending_max", &idn_dmv_pending_max }, -{ 0, 0, 0, NULL, NULL } -}; - -struct idn *idn_i2s_table[IDN_MAXMAX_NETS << 1]; -clock_t idn_msg_waittime[IDN_NUM_MSGTYPES]; -clock_t idn_msg_retrytime[(int)IDN_NUM_RETRYTYPES]; - -static caddr_t idn_ndlist; /* head of 'named dispatch' var list */ - -static int idnattach(dev_info_t *, ddi_attach_cmd_t); -static int idndetach(dev_info_t *, ddi_detach_cmd_t); -static int idnopen(register queue_t *, dev_t *, int, int, cred_t *); -static int idnclose(queue_t *, int, cred_t *); -static int idnwput(queue_t *, mblk_t *); -static int idnwsrv(queue_t *); -static int idnrput(queue_t *, mblk_t *); -static void idnioctl(queue_t *, mblk_t *); -static idn_gprops_t idn_check_conf(dev_info_t *dip, processorid_t *cpuid); -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 void idn_sigb_setup(cpu_sgnblk_t *sigbp, void *arg); -static int idn_init(dev_info_t *dip); -static int idn_deinit(); -static void idn_sigbhandler_create(); -static void idn_sigbhandler_kill(); -static uint_t idn_sigbhandler_wakeup(caddr_t arg1, caddr_t arg2); -static void idn_sigbhandler_thread(struct sigbintr **sbpp); -static void idn_sigbhandler(processorid_t cpuid, cpu_sgnblk_t *sgnblkp); -static int idn_info(idnsb_info_t *sfp); -static int idn_init_smr(); -static void idn_deinit_smr(); -static int idn_prom_getsmr(uint_t *smrsz, uint64_t *paddrp, - uint64_t *sizep); -static int idn_init_handler(); -static void idn_deinit_handler(); -static uint_t idn_handler(caddr_t unused, caddr_t unused2); -/* - * ioctl services - */ -static int idnioc_link(idnop_t *idnop); -static int idnioc_unlink(idnop_t *idnop); -static int idn_rw_mem(idnop_t *idnop); -static int idn_send_ping(idnop_t *idnop); - -static void idn_domains_init(struct hwconfig *local_hw); -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(); -static int idn_param_get(queue_t *q, mblk_t *mp, caddr_t cp, cred_t *cr); -static int idn_param_set(queue_t *q, mblk_t *mp, char *value, caddr_t cp, - cred_t *cr); -static int idn_param_register(register idnparam_t *idnpa, int count); -static int idn_slabpool_report(queue_t *wq, mblk_t *mp, caddr_t cp, - cred_t *cr); -static int idn_buffer_report(queue_t *wq, mblk_t *mp, caddr_t cp, - cred_t *cr); -static int idn_mboxtbl_report(queue_t *wq, mblk_t *mp, caddr_t cp, - cred_t *cr); -static int idn_mainmbox_report(queue_t *wq, mblk_t *mp, caddr_t cp, - cred_t *cr); -static void idn_mainmbox_domain_report(queue_t *wq, mblk_t *mp, int domid, - idn_mainmbox_t *mmp, char *mbxtype); -static int idn_global_report(queue_t *wq, mblk_t *mp, caddr_t cp, - cred_t *cr); -static int idn_domain_report(queue_t *wq, mblk_t *mp, caddr_t cp, - cred_t *cr); -static int idn_get_net_binding(queue_t *wq, mblk_t *mp, caddr_t cp, - cred_t *cr); -static int idn_set_net_binding(queue_t *wq, mblk_t *mp, char *value, - caddr_t cp, cred_t *cr); - -/* - * 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" -}; - -static struct module_info idnrinfo = { - IDNIDNUM, /* mi_idnum */ - IDNNAME, /* mi_idname */ - IDNMINPSZ, /* mi_minpsz */ - IDNMAXPSZ, /* mi_maxpsz */ - 0, /* mi_hiwat - see IDN_HIWAT */ - 0 /* mi_lowat - see IDN_LOWAT */ -}; - -static struct module_info idnwinfo = { - IDNIDNUM, /* mi_idnum */ - IDNNAME, /* mi_idname */ - IDNMINPSZ, /* mi_minpsz */ - IDNMAXPSZ, /* mi_maxpsz */ - 0, /* mi_hiwat - see IDN_HIWAT */ - 0 /* mi_lowat - see IDN_LOWAT */ -}; - -static struct qinit idnrinit = { - 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 */ -}; - -static struct qinit idnwinit = { - 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 */ -}; - -struct streamtab idninfo = { - &idnrinit, /* st_rdinit */ - &idnwinit, /* st_wrinit */ - NULL, /* st_muxrinit */ - NULL, /* st_muxwinit */ -}; - -/* - * Module linkage information (cb_ops & dev_ops) for the kernel. - */ - -static struct cb_ops cb_idnops = { - 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 */ -}; - -static struct dev_ops idnops = { - 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 */ - (struct bus_ops *)NULL, /* devo_bus_ops */ - NULL, /* devo_power */ - ddi_quiesce_not_needed, /* quiesce */ -}; - -extern cpuset_t cpu_ready_set; - -static struct modldrv modldrv = { - &mod_driverops, /* This module is a pseudo driver */ - IDNDESC " 1.58", - &idnops -}; - -static struct modlinkage modlinkage = { - MODREV_1, - &modldrv, - NULL -}; - -/* - * -------------------------------------------------- - */ -int -_init(void) -{ - idn.version = IDN_VERSION; - - return (mod_install(&modlinkage)); -} - -int -_fini(void) -{ - return (mod_remove(&modlinkage)); -} - -int -_info(struct modinfo *modinfop) -{ - return (mod_info(&modlinkage, modinfop)); -} - -/* - * ---------------------------------------------- - */ -static int -idnattach(dev_info_t *dip, ddi_attach_cmd_t cmd) -{ - int instance; - int doinit = 0; - processorid_t bcpuid; - struct idn *sip; - struct idnstr *stp; - procname_t proc = "idnattach"; - - -#ifndef lint - ASSERT(sizeof (idnsb_t) == IDNSB_SIZE); - ASSERT(offsetof(struct idnsb, id_hwchkpt[0]) == 0x40); -#endif /* lint */ - - switch (cmd) { - case DDI_RESUME: - sip = ddi_get_driver_private(dip); - /* - * sip may have not yet been set if the - * OBP environment variable (idn-smr-size) - * was not set. - */ - if (sip == NULL) - return (DDI_FAILURE); - /* - * RESUME IDN services. - */ - IDN_GLOCK_SHARED(); - if (idn.state != IDNGS_OFFLINE) { - cmn_err(CE_WARN, - "IDN: 101: not in expected OFFLINE state " - "for DDI_RESUME"); - ASSERT(0); - } - IDN_GUNLOCK(); - - /* - * RESUME DLPI services. - */ - sip->si_flags &= ~IDNSUSPENDED; - - rw_enter(&idn.struprwlock, RW_READER); - for (stp = idn.strup; stp; stp = stp->ss_nextp) - if (stp->ss_sip == sip) { - doinit = 1; - break; - } - rw_exit(&idn.struprwlock); - if (doinit) - (void) idndl_init(sip); - - return (DDI_SUCCESS); - - case DDI_ATTACH: - break; - - default: - return (DDI_FAILURE); - } - - instance = ddi_get_instance(dip); - - PR_DRV("%s: instance = %d\n", proc, instance); - - if (idn_check_conf(dip, &bcpuid) == IDN_GPROPS_ERROR) - return (DDI_FAILURE); - - mutex_enter(&idn.siplock); - - if (ddi_create_minor_node(dip, IDNNAME, S_IFCHR, instance, - DDI_NT_NET, CLONE_DEV) == DDI_FAILURE) { - mutex_exit(&idn.siplock); - return (DDI_FAILURE); - } - - if (idn.smr.ready == 0) { - if (idn_init_smr() == 0) { - idn.enabled = 1; -#ifdef DEBUG - cmn_err(CE_NOTE, "!IDN: Driver enabled"); -#endif /* DEBUG */ - } else { - cmn_err(CE_NOTE, - "!IDN: 102: driver disabled " - "- check OBP environment " - "(idn-smr-size)"); - mutex_exit(&idn.siplock); - return (DDI_SUCCESS); - } - } - - ASSERT(idn.smr.ready || idn.enabled); - - if (idn.dip == NULL) { - doinit = 1; - - if (idn_size_check()) { - idn_deinit_smr(); - ddi_remove_minor_node(dip, NULL); - mutex_exit(&idn.siplock); - return (DDI_FAILURE); - } - - if (idn_init(dip)) { - idn_deinit_smr(); - ddi_remove_minor_node(dip, NULL); - mutex_exit(&idn.siplock); - return (DDI_FAILURE); - } - } - - ASSERT(idn.dip); - - /* - * This must occur _after_ idn_init() since - * it assumes idn_chanservers_init() has been - * called. - */ - idn_chanserver_bind(ddi_get_instance(dip), bcpuid); - - /* - * DLPI supporting stuff. - */ - sip = GETSTRUCT(struct idn, 1); - sip->si_dip = dip; - ddi_set_driver_private(dip, sip); - sip->si_nextp = idn.sip; - idn.sip = sip; - IDN_SET_INST2SIP(instance, sip); - mutex_exit(&idn.siplock); - - if (doinit) - idndl_dlpi_init(); /* initializes idninfoack */ - /* - * Get our local IDN ethernet address. - */ - idndl_localetheraddr(sip, &sip->si_ouraddr); - idndl_statinit(sip); - - if (doinit) { - idn_gkstat_init(); - /* - * Add our sigblock SSP interrupt handler. - */ - mutex_enter(&idn.sigbintr.sb_mutex); - idn_sigbhandler_create(); - mutex_exit(&idn.sigbintr.sb_mutex); - - if (sgnblk_poll_register(idn_sigbhandler) == 0) { - mutex_enter(&idn.sigbintr.sb_mutex); - idn_sigbhandler_kill(); - idn.sigbintr.sb_cpuid = (uchar_t)-1; - idn.sigbintr.sb_busy = IDNSIGB_INACTIVE; - mutex_exit(&idn.sigbintr.sb_mutex); - - idn_gkstat_deinit(); - - mutex_enter(&idn.siplock); - (void) idn_deinit(); - IDN_SET_INST2SIP(instance, NULL); - idn.sip = sip->si_nextp; - mutex_exit(&idn.siplock); - - ddi_remove_minor_node(dip, NULL); - - return (DDI_FAILURE); - } - /* - * We require sigblkp[cpu0] to be mapped for hardware - * configuration determination and also auto-linking - * on bootup. - */ - if (sgnblk_poll_reference(idn_sigb_setup, NULL) != 0) { - (void) sgnblk_poll_unregister(idn_sigbhandler); - mutex_enter(&idn.sigbintr.sb_mutex); - idn_sigbhandler_kill(); - idn.sigbintr.sb_cpuid = (uchar_t)-1; - idn.sigbintr.sb_busy = IDNSIGB_INACTIVE; - mutex_exit(&idn.sigbintr.sb_mutex); - - idn_gkstat_deinit(); - - mutex_enter(&idn.siplock); - (void) idn_deinit(); - IDN_SET_INST2SIP(instance, NULL); - idn.sip = sip->si_nextp; - mutex_exit(&idn.siplock); - - ddi_remove_minor_node(dip, NULL); - - cmn_err(CE_WARN, - "IDN: 103: unable to reference sigblock area"); - - return (DDI_FAILURE); - } - - idn_init_autolink(); - } - - ddi_report_dev(dip); - - return (DDI_SUCCESS); -} - -/* - * ---------------------------------------------- - */ -static int -idndetach(dev_info_t *dip, ddi_detach_cmd_t cmd) -{ - int err = 0; - int instance; - struct idn *sip, *hsip, *tsip; - procname_t proc = "idndetach"; - - sip = ddi_get_driver_private(dip); - instance = ddi_get_instance(dip); - - switch (cmd) { - case DDI_SUSPEND: - if (sip == NULL) - 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. - */ - IDN_GLOCK_SHARED(); - - if (idn.state != IDNGS_OFFLINE) { - int d; - - cmn_err(CE_WARN, - "IDN: 104: cannot suspend while active " - "(state = %s)", - idngs_str[idn.state]); - - for (d = 0; d < MAX_DOMAINS; d++) { - idn_domain_t *dp; - - dp = &idn_domain[d]; - if (dp->dcpu < 0) - continue; - - cmn_err(CE_CONT, - "IDN: 121: domain %d (CPU %d, name " - "\"%s\", state %s)\n", - d, dp->dcpu, dp->dname, - idnds_str[dp->dstate]); - } - err = 1; - } - - IDN_GUNLOCK(); - - if (err) - return (DDI_FAILURE); - /* - * SUSPEND DLPI services. - */ - sip->si_flags |= IDNSUSPENDED; - - idndl_uninit(sip); - - return (DDI_FAILURE); - - case DDI_DETACH: - if (idn.enabled == 0) { - ddi_remove_minor_node(dip, NULL); - ASSERT(idn.dip == NULL); - return (DDI_SUCCESS); - } - if (!IDN_MODUNLOADABLE) - return (DDI_FAILURE); - break; - - default: - return (DDI_FAILURE); - } - - PR_DRV("%s: instance = %d\n", proc, instance); - - if (sip == NULL) { - /* - * No resources allocated. - */ - return (DDI_SUCCESS); - } - - mutex_enter(&idn.siplock); - if (idn.sip && (idn.sip->si_nextp == NULL)) { - /* - * 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. - */ - mutex_exit(&idn.siplock); - return (DDI_FAILURE); - } - idn_deinit_autolink(); - /* - * Remove our sigblock SSP interrupt handler. - */ - (void) sgnblk_poll_unregister(idn_sigbhandler); - mutex_enter(&idn.sigbintr.sb_mutex); - idn_sigbhandler_kill(); - idn.sigbintr.sb_cpuid = (uchar_t)-1; - idn.sigbintr.sb_busy = IDNSIGB_NOTREADY; - mutex_exit(&idn.sigbintr.sb_mutex); - /* - * Remove our reference to the sigblock area. - */ - sgnblk_poll_unreference(idn_sigb_setup); - idn_gkstat_deinit(); - } - - ddi_remove_minor_node(dip, NULL); - - /* - * Remove this instance from our linked list. - */ - IDN_SET_INST2SIP(instance, NULL); - if ((hsip = tsip = idn.sip) == sip) { - idn.sip = sip->si_nextp; - } else { - for (; hsip && (sip != hsip); tsip = hsip, - hsip = hsip->si_nextp) - ; - if (hsip) - tsip->si_nextp = hsip->si_nextp; - } - mutex_exit(&idn.siplock); - if (sip->si_ksp) - kstat_delete(sip->si_ksp); - - ddi_set_driver_private(dip, NULL); - - FREESTRUCT(sip, struct idn, 1); - - return (DDI_SUCCESS); -} - -/* - * ---------------------------------------------- - */ -static idn_gprops_t -idn_check_conf(dev_info_t *dip, processorid_t *cpuid) -{ - static idn_gprops_t global_props = IDN_GPROPS_UNCHECKED; - - if (global_props == IDN_GPROPS_UNCHECKED) { - int p; - - global_props = IDN_GPROPS_OKAY; - - for (p = 0; idn_global_props[p].p_string; p++) { - char *str; - int *var; - int val, v_min, v_max, v_def; - - str = idn_global_props[p].p_string; - var = (int *)idn_global_props[p].p_var; - v_min = idn_global_props[p].p_min; - v_max = idn_global_props[p].p_max; - v_def = idn_global_props[p].p_def; - ASSERT(str && var); - - val = ddi_prop_get_int(DDI_DEV_T_ANY, dip, - DDI_PROP_DONTPASS | - DDI_PROP_NOTPROM, - str, v_def); - if ((v_min != v_max) && - ((val < v_min) || (val > v_max))) { - cmn_err(CE_WARN, - "IDN: 105: driver parameter " - "(%s) specified (%d) out of " - "range [%d - %d]", - str, val, v_min, v_max); - global_props = IDN_GPROPS_ERROR; - } else { - *var = val; - } - } - } - - *cpuid = ddi_prop_get_int(DDI_DEV_T_ANY, dip, - DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, - "bind_cpu", -1); - - return (global_props); -} - -static int -idn_size_check() -{ - int i, cnt; - int rv = 0; - ulong_t mboxareasize; - int max_num_slabs; - procname_t proc = "idn_size_check"; - - if (IDN_NWR_SIZE == 0) - IDN_NWR_SIZE = IDN_SMR_SIZE; - - if (IDN_NWR_SIZE > IDN_SMR_SIZE) { - cmn_err(CE_WARN, - "IDN: 106: idn_nwr_size(%d) > idn_smr_size(%d)" - " - Limiting to %d MB", - IDN_NWR_SIZE, IDN_SMR_SIZE, IDN_SMR_SIZE); - IDN_NWR_SIZE = IDN_SMR_SIZE; - } - - if (MB2B(IDN_NWR_SIZE) < IDN_SLAB_SIZE) { - cmn_err(CE_WARN, - "IDN: 107: memory region(%lu) < slab size(%u)", - MB2B(IDN_NWR_SIZE), IDN_SLAB_SIZE); - rv = -1; - } - - if (IDN_LOWAT >= IDN_HIWAT) { - cmn_err(CE_WARN, - "IDN: 108: idn_lowat(%d) >= idn_hiwat(%d)", - IDN_LOWAT, IDN_HIWAT); - rv = -1; - } - - mboxareasize = (ulong_t)(IDN_MBOXAREA_SIZE + (IDN_SMR_BUFSIZE - 1)); - mboxareasize &= ~((ulong_t)IDN_SMR_BUFSIZE - 1); -#ifdef DEBUG - if ((ulong_t)IDN_SLAB_SIZE < mboxareasize) { - PR_DRV("%s: slab size(%d) < mailbox area(%ld)", - proc, IDN_SLAB_SIZE, mboxareasize); - /* not fatal */ - } -#endif /* DEBUG */ - - if ((mboxareasize + (ulong_t)IDN_SLAB_SIZE) > MB2B(IDN_NWR_SIZE)) { - cmn_err(CE_WARN, - "IDN: 109: mailbox area(%lu) + slab size(%u) " - "> nwr region(%lu)", - mboxareasize, IDN_SLAB_SIZE, - MB2B(IDN_NWR_SIZE)); - rv = -1; - } - - max_num_slabs = (int)((MB2B(IDN_NWR_SIZE) - mboxareasize) / - (ulong_t)IDN_SLAB_SIZE); - if (max_num_slabs < IDN_SLAB_MINTOTAL) { - cmn_err(CE_WARN, - "IDN: 110: maximum number of slabs(%d) < " - "minimum required(%d)", - max_num_slabs, IDN_SLAB_MINTOTAL); - rv = -1; - } else { - IDN_SLAB_MAXPERDOMAIN = max_num_slabs / IDN_SLAB_MINTOTAL; - } - -#if 0 - if ((IDN_MTU + sizeof (struct ether_header)) > IDN_DATA_SIZE) { - cmn_err(CE_WARN, - "IDN: (IDN_MTU(%d) + ether_header(%d)) " - "> IDN_DATA_SIZE(%lu)", - IDN_MTU, sizeof (struct ether_header), - IDN_DATA_SIZE); - rv = -1; - } -#endif /* 0 */ - - if (IDN_SMR_BUFSIZE & (IDN_ALIGNSIZE - 1)) { - cmn_err(CE_WARN, - "IDN: 111: idn_smr_bufsize(%d) not on a " - "64 byte boundary", IDN_SMR_BUFSIZE); - rv = -1; - } - - for (i = cnt = 0; - (cnt <= 1) && (((ulong_t)1 << i) < MB2B(IDN_NWR_SIZE)); - i++) - if ((1 << i) & IDN_SMR_BUFSIZE) - cnt++; - if ((i > 0) && (!cnt || (cnt > 1))) { - cmn_err(CE_WARN, - "IDN: 112: idn_smr_bufsize(%d) not a power of 2", - IDN_SMR_BUFSIZE); - rv = -1; - } - - if ((IDN_MBOX_PER_NET & 1) == 0) { - cmn_err(CE_WARN, - "IDN: 113: idn_mbox_per_net(%d) must be an " - "odd number", IDN_MBOX_PER_NET); - rv = -1; - } - - if (idn.nchannels > 0) - IDN_WINDOW_EMAX = IDN_WINDOW_MAX + - ((idn.nchannels - 1) * IDN_WINDOW_INCR); - - if (IDN_NETSVR_WAIT_MIN > IDN_NETSVR_WAIT_MAX) { - cmn_err(CE_WARN, - "IDN: 115: idn_netsvr_wait_min(%d) cannot be " - "greater than idn_netsvr_wait_max(%d)", - IDN_NETSVR_WAIT_MIN, - IDN_NETSVR_WAIT_MAX); - rv = -1; - } - - return (rv); -} - -static int -idn_init_smr() -{ - uint64_t obp_paddr; - uint64_t obp_size; /* in Bytes */ - uint_t smr_size; /* in MBytes */ - pgcnt_t npages; - procname_t proc = "idn_init_smr"; - - if (idn.smr.ready) - return (0); - - if (idn_prom_getsmr(&smr_size, &obp_paddr, &obp_size) < 0) - return (-1); - - PR_PROTO("%s: smr_size = %d, obp_paddr = 0x%lx, obp_size = 0x%lx\n", - proc, smr_size, obp_paddr, obp_size); - - if (IDN_SMR_SIZE) - smr_size = MIN(smr_size, IDN_SMR_SIZE); - - npages = btopr(MB2B(smr_size)); - - idn.smr.prom_paddr = obp_paddr; - idn.smr.prom_size = obp_size; - idn.smr.vaddr = vmem_alloc(heap_arena, ptob(npages), VM_SLEEP); - ASSERT(((ulong_t)idn.smr.vaddr & MMU_PAGEOFFSET) == 0); - idn.smr.locpfn = (pfn_t)(obp_paddr >> MMU_PAGESHIFT); - idn.smr.rempfn = idn.smr.rempfnlim = PFN_INVALID; - IDN_SMR_SIZE = smr_size; - - PR_PROTO("%s: smr vaddr = %p\n", proc, (void *)idn.smr.vaddr); - - smr_remap(&kas, idn.smr.vaddr, idn.smr.locpfn, IDN_SMR_SIZE); - - idn.localid = PADDR_TO_DOMAINID(obp_paddr); - - idn.smr.ready = 1; - - return (0); -} - -static void -idn_deinit_smr() -{ - pgcnt_t npages; - - if (idn.smr.ready == 0) - return; - - smr_remap(&kas, idn.smr.vaddr, PFN_INVALID, IDN_SMR_SIZE); - - npages = btopr(MB2B(IDN_SMR_SIZE)); - - vmem_free(heap_arena, idn.smr.vaddr, ptob(npages)); - - idn.localid = IDN_NIL_DOMID; - - IDN_SMR_SIZE = 0; - - idn.smr.ready = 0; -} - -/*ARGSUSED1*/ -static void -idn_sigb_setup(cpu_sgnblk_t *sigbp, void *arg) -{ - procname_t proc = "idn_sigb_setup"; - - PR_PROTO("%s: Setting sigb to %p\n", proc, (void *)sigbp); - - mutex_enter(&idn.idnsb_mutex); - if (sigbp == NULL) { - idn.idnsb = NULL; - idn.idnsb_eventp = NULL; - mutex_exit(&idn.idnsb_mutex); - return; - } - idn.idnsb_eventp = (idnsb_event_t *)sigbp->sigb_idn; - idn.idnsb = (idnsb_t *)&idn.idnsb_eventp->idn_reserved1; - mutex_exit(&idn.idnsb_mutex); -} - -static int -idn_init(dev_info_t *dip) -{ - struct hwconfig local_hw; - procname_t proc = "idn_init"; - - - ASSERT(MUTEX_HELD(&idn.siplock)); - - if (!idn.enabled) { - cmn_err(CE_WARN, - "IDN: 117: IDN not enabled"); - return (-1); - } - - if (idn.dip != NULL) { - PR_DRV("%s: already initialized (dip = 0x%p)\n", - proc, (void *)idn.dip); - return (0); - } - - /* - * Determine our local domain's hardware configuration. - */ - if (get_hw_config(&local_hw)) { - cmn_err(CE_WARN, - "IDN: 118: hardware config not appropriate"); - return (-1); - } - - PR_DRV("%s: locpfn = 0x%lx\n", proc, idn.smr.locpfn); - PR_DRV("%s: rempfn = 0x%lx\n", proc, idn.smr.rempfn); - PR_DRV("%s: smrsize = %d MB\n", proc, IDN_SMR_SIZE); - - rw_init(&idn.grwlock, NULL, RW_DEFAULT, NULL); - rw_init(&idn.struprwlock, NULL, RW_DEFAULT, NULL); - mutex_init(&idn.sync.sz_mutex, NULL, MUTEX_DEFAULT, NULL); - mutex_init(&idn.sipwenlock, NULL, MUTEX_DEFAULT, NULL); - - /* - * 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", - proc, idn.bframe_shift, IDN_SMR_BUFSIZE_MIN); - - ASSERT((uint_t)IDN_OFFSET2BFRAME(MB2B(idn_smr_size)) < - (1 << 24)); - } - - idn_xmit_monitor_init(); - - /* - * Initialize the domain op (dopers) stuff. - */ - idn_dopers_init(); - - /* - * Initialize the timer (kmem) cache used for timeout - * structures. - */ - idn_timercache_init(); - - /* - * Initialize the slab waiting areas. - */ - (void) smr_slabwaiter_init(); - - /* - * Initialize retryjob kmem cache. - */ - idn_retrytask_init(); - - idn_init_msg_waittime(); - idn_init_msg_retrytime(); - - /* - * Initialize idn_domains[] and local domains information - * include idn_global information. - */ - idn_domains_init(&local_hw); - - /* - * Start up IDN protocol servers. - */ - if (idn_protocol_init(idn_protocol_nservers) <= 0) { - cmn_err(CE_WARN, - "IDN: 119: failed to initialize %d protocol servers", - idn_protocol_nservers); - idn_domains_deinit(); - idn_retrytask_deinit(); - smr_slabwaiter_deinit(); - idn_timercache_deinit(); - idn_dopers_deinit(); - idn_xmit_monitor_deinit(); - mutex_destroy(&idn.sipwenlock); - mutex_destroy(&idn.sync.sz_mutex); - rw_destroy(&idn.grwlock); - rw_destroy(&idn.struprwlock); - 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.dip = dip; - IDN_GLOCK_EXCL(); - IDN_GSTATE_TRANSITION(IDNGS_OFFLINE); - IDN_GUNLOCK(); - - return (0); -} - -static int -idn_deinit() -{ - procname_t proc = "idn_deinit"; - - ASSERT(MUTEX_HELD(&idn.siplock)); - - IDN_GLOCK_EXCL(); - - if (idn.state != IDNGS_OFFLINE) { - int d; - - cmn_err(CE_WARN, - "IDN: 120: cannot deinit while active " - "(state = %s)", idngs_str[idn.state]); - - for (d = 0; d < MAX_DOMAINS; d++) { - idn_domain_t *dp; - - dp = &idn_domain[d]; - if (dp->dcpu < 0) - continue; - - cmn_err(CE_CONT, - "IDN: 121: domain %d (CPU %d, " - "name \"%s\", state %s)\n", - d, dp->dcpu, dp->dname, - idnds_str[dp->dstate]); - } - IDN_GUNLOCK(); - return (-1); - } - - if (idn.dip == NULL) { - PR_DRV("%s: already deinitialized\n", proc); - IDN_GUNLOCK(); - return (0); - } - - IDN_GSTATE_TRANSITION(IDNGS_IGNORE); - - IDN_GUNLOCK(); - - idn_xmit_monitor_deinit(); - - idn_deinit_handler(); - - idn_chanservers_deinit(); - - idn.nchannels = 0; - ASSERT(idn.chan_servers == NULL); - - smr_slabpool_deinit(); - - idn_protocol_deinit(); - - idn_domains_deinit(); - - smr_slabwaiter_deinit(); - - idn_retrytask_deinit(); - - idn_timercache_deinit(); - - idn_dopers_deinit(); - - ASSERT(idn.localid == IDN_NIL_DOMID); - - IDN_SET_MASTERID(IDN_NIL_DOMID); - - idn_deinit_smr(); - - mutex_destroy(&idn.sipwenlock); - mutex_destroy(&idn.sync.sz_mutex); - rw_destroy(&idn.grwlock); - rw_destroy(&idn.struprwlock); - - idn.dip = NULL; - - return (0); -} - -static void -idn_xmit_monitor_init() -{ - mutex_init(&idn.xmit_lock, NULL, MUTEX_DEFAULT, NULL); - idn.xmit_tid = (timeout_id_t)NULL; - CHANSET_ZERO(idn.xmit_chanset_wanted); -} - -static void -idn_xmit_monitor_deinit() -{ - timeout_id_t tid; - - mutex_enter(&idn.xmit_lock); - CHANSET_ZERO(idn.xmit_chanset_wanted); - if ((tid = idn.xmit_tid) != (timeout_id_t)NULL) { - idn.xmit_tid = (timeout_id_t)NULL; - mutex_exit(&idn.xmit_lock); - (void) untimeout(tid); - } else { - mutex_exit(&idn.xmit_lock); - } - mutex_destroy(&idn.xmit_lock); -} - -static void -idn_init_msg_waittime() -{ - idn_msg_waittime[IDNP_NULL] = -1; - idn_msg_waittime[IDNP_NEGO] = idn_msgwait_nego * hz; - idn_msg_waittime[IDNP_CFG] = idn_msgwait_cfg * hz; - idn_msg_waittime[IDNP_CON] = idn_msgwait_con * hz; - idn_msg_waittime[IDNP_FIN] = idn_msgwait_fin * hz; - idn_msg_waittime[IDNP_CMD] = idn_msgwait_cmd * hz; - idn_msg_waittime[IDNP_DATA] = idn_msgwait_data * hz; -} - -static void -idn_init_msg_retrytime() -{ - idn_msg_retrytime[(int)IDNRETRY_NIL] = -1; - idn_msg_retrytime[(int)IDNRETRY_NEGO] = idn_retryfreq_nego * hz; - idn_msg_retrytime[(int)IDNRETRY_CON] = idn_retryfreq_con * hz; - idn_msg_retrytime[(int)IDNRETRY_CONQ] = idn_retryfreq_con * hz; - idn_msg_retrytime[(int)IDNRETRY_FIN] = idn_retryfreq_fin * hz; - idn_msg_retrytime[(int)IDNRETRY_FINQ] = idn_retryfreq_fin * hz; -} - -/* - * ---------------------------------------------- - */ -/*ARGSUSED*/ -static int -idnopen(register queue_t *rq, dev_t *devp, int flag, int sflag, cred_t *crp) -{ - register int err = 0; - int minordev; - struct idnstr *stp, **pstp; - procname_t proc = "idnopen"; - - ASSERT(sflag != MODOPEN); - - IDN_GLOCK_EXCL(); - - rw_enter(&idn.struprwlock, RW_WRITER); - mutex_enter(&idn.sipwenlock); - pstp = &idn.strup; - - if (idn.enabled == 0) { - PR_DRV("%s: Driver disabled (check OBP:idn-smr-size)\n", - proc); - mutex_exit(&idn.sipwenlock); - rw_exit(&idn.struprwlock); - IDN_GUNLOCK(); - return (EACCES); - } - - if (!idn_ndlist && - idn_param_register(idn_param_arr, A_CNT(idn_param_arr))) { - PR_DRV("%s: failed to register ndd parameters\n", proc); - mutex_exit(&idn.sipwenlock); - rw_exit(&idn.struprwlock); - IDN_GUNLOCK(); - return (ENOMEM); - } - IDN_GUNLOCK(); - - if (sflag == CLONEOPEN) { - minordev = 0; - for (stp = *pstp; stp; pstp = &stp->ss_nextp, stp = *pstp) { - if (minordev < stp->ss_minor) - break; - minordev++; - } - *devp = makedevice(getmajor(*devp), minordev); - } else { - minordev = getminor(*devp); - } - if (rq->q_ptr) - goto done; - - stp = GETSTRUCT(struct idnstr, 1); - stp->ss_rq = rq; - stp->ss_minor = minordev; - rw_init(&stp->ss_rwlock, NULL, RW_DEFAULT, NULL); - /* - * DLPI stuff - */ - stp->ss_sip = NULL; - stp->ss_state = DL_UNATTACHED; - stp->ss_sap = 0; - stp->ss_flags = 0; - stp->ss_mccount = 0; - stp->ss_mctab = NULL; - - /* - * Link new entry into list of actives. - */ - stp->ss_nextp = *pstp; - *pstp = stp; - - WR(rq)->q_ptr = rq->q_ptr = (void *)stp; - /* - * Disable automatic enabling of our write service - * procedure. We control this explicitly. - */ - noenable(WR(rq)); - - /* - * Set our STREAMs queue maximum packet size that - * we'll accept and our high/low water marks. - */ - (void) strqset(WR(rq), QMAXPSZ, 0, IDN_DATA_SIZE); - (void) strqset(WR(rq), QLOWAT, 0, IDN_LOWAT); - (void) strqset(WR(rq), QHIWAT, 0, IDN_HIWAT); - (void) strqset(rq, QMAXPSZ, 0, IDN_DATA_SIZE); - (void) strqset(rq, QLOWAT, 0, IDN_LOWAT); - (void) strqset(rq, QHIWAT, 0, IDN_HIWAT); - -done: - mutex_exit(&idn.sipwenlock); - rw_exit(&idn.struprwlock); - - (void) qassociate(rq, -1); - qprocson(rq); - - return (err); -} - -/* - * ---------------------------------------------- - */ -/*ARGSUSED1*/ -static int -idnclose(queue_t *rq, int flag, cred_t *crp) -{ - struct idnstr *stp, **pstp; - - ASSERT(rq->q_ptr); - - qprocsoff(rq); - /* - * Guaranteed to be single threaded with respect - * to this stream at this point. - */ - - stp = (struct idnstr *)rq->q_ptr; - - if (stp->ss_sip) - idndl_dodetach(stp); - - rw_enter(&idn.struprwlock, RW_WRITER); - mutex_enter(&idn.sipwenlock); - pstp = &idn.strup; - for (stp = *pstp; stp; pstp = &stp->ss_nextp, stp = *pstp) - if (stp == (struct idnstr *)rq->q_ptr) - break; - ASSERT(stp); - ASSERT(stp->ss_rq == rq); - *pstp = stp->ss_nextp; - - rw_destroy(&stp->ss_rwlock); - FREESTRUCT(stp, struct idnstr, 1); - - WR(rq)->q_ptr = rq->q_ptr = NULL; - mutex_exit(&idn.sipwenlock); - rw_exit(&idn.struprwlock); - - idn_param_cleanup(); - (void) qassociate(rq, -1); - - return (0); -} - -/* - * ---------------------------------------------- - */ -static int -idnwput(register queue_t *wq, register mblk_t *mp) -{ - register struct idnstr *stp; - struct idn *sip; - procname_t proc = "idnwput"; - - stp = (struct idnstr *)wq->q_ptr; - sip = stp->ss_sip; - - switch (DB_TYPE(mp)) { - case M_IOCTL: - idnioctl(wq, mp); - break; - - case M_DATA: - if (((stp->ss_flags & (IDNSFAST|IDNSRAW)) == 0) || - (stp->ss_state != DL_IDLE) || - (sip == NULL)) { - PR_DLPI("%s: fl=0x%x, st=0x%x, ret(EPROTO)\n", - proc, stp->ss_flags, stp->ss_state); - merror(wq, mp, EPROTO); - - } else if (wq->q_first) { - if (putq(wq, mp) == 0) - freemsg(mp); - /* - * We're only holding the reader lock, - * but that's okay since this field - * is just a soft-flag. - */ - sip->si_wantw = 1; - qenable(wq); - - } else if (sip->si_flags & IDNPROMISC) { - if (putq(wq, mp) == 0) { - PR_DLPI("%s: putq failed\n", proc); - freemsg(mp); - } else { - PR_DLPI("%s: putq succeeded\n", proc); - } - qenable(wq); - - } else { - PR_DLPI("%s: idndl_start(sip=0x%p)\n", - proc, (void *)sip); - rw_enter(&stp->ss_rwlock, RW_READER); - (void) idndl_start(wq, mp, sip); - rw_exit(&stp->ss_rwlock); - } - 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. - */ - if (putq(wq, mp) == 0) - freemsg(mp); - qenable(wq); - break; - - case M_FLUSH: - PR_STR("%s: M_FLUSH request (flush = %d)\n", - proc, (int)*mp->b_rptr); - if (*mp->b_rptr & FLUSHW) { - flushq(wq, FLUSHALL); - *mp->b_rptr &= ~FLUSHW; - } - if (*mp->b_rptr & FLUSHR) - qreply(wq, mp); - else - freemsg(mp); - break; - - default: - PR_STR("%s: unexpected DB_TYPE 0x%x\n", - proc, DB_TYPE(mp)); - freemsg(mp); - break; - } - - return (0); -} - -/* - * ---------------------------------------------- - */ -static int -idnwsrv(queue_t *wq) -{ - mblk_t *mp; - int err = 0; - struct idnstr *stp; - struct idn *sip; - procname_t proc = "idnwsrv"; - - stp = (struct idnstr *)wq->q_ptr; - sip = stp->ss_sip; - - while (mp = getq(wq)) { - switch (DB_TYPE(mp)) { - case M_DATA: - if (sip) { - PR_DLPI("%s: idndl_start(sip=0x%p)\n", - proc, (void *)sip); - rw_enter(&stp->ss_rwlock, RW_READER); - err = idndl_start(wq, mp, sip); - rw_exit(&stp->ss_rwlock); - if (err) - goto done; - } else { - PR_DLPI("%s: NO sip to start msg\n", proc); - freemsg(mp); - } - break; - - case M_PROTO: - case M_PCPROTO: - idndl_proto(wq, mp); - break; - - default: - ASSERT(0); - PR_STR("%s: unexpected db_type (%d)\n", - proc, DB_TYPE(mp)); - freemsg(mp); - break; - } - } -done: - return (0); -} - -/* - * ---------------------------------------------- - */ -static int -idnrput(register queue_t *rq, register mblk_t *mp) -{ - register int err = 0; - procname_t proc = "idnrput"; - - switch (DB_TYPE(mp)) { - case M_DATA: - /* - * Should not reach here with data packets - * if running DLPI. - */ - cmn_err(CE_WARN, - "IDN: 123: unexpected M_DATA packets for " - "q_stream 0x%p", (void *)rq->q_stream); - freemsg(mp); - err = ENXIO; - break; - - case M_FLUSH: - PR_STR("%s: M_FLUSH request (flush = %d)\n", - proc, (int)*mp->b_rptr); - if (*mp->b_rptr & FLUSHR) - flushq(rq, FLUSHALL); - (void) putnext(rq, mp); - break; - - case M_ERROR: - PR_STR("%s: M_ERROR (error = %d) coming through\n", - proc, (int)*mp->b_rptr); - (void) putnext(rq, mp); - break; - default: - PR_STR("%s: unexpected DB_TYPE 0x%x\n", - proc, DB_TYPE(mp)); - freemsg(mp); - err = ENXIO; - break; - } - - return (err); -} - -/* - * ---------------------------------------------- - * Not allowed to enqueue messages! Only M_DATA messages - * can be enqueued on the write stream. - * ---------------------------------------------- - */ -static void -idnioctl(register queue_t *wq, register mblk_t *mp) -{ - register struct iocblk *iocp; - register int cmd; - idnop_t *idnop = NULL; - int error = 0; - int argsize; - procname_t proc = "idnioctl"; - - iocp = (struct iocblk *)mp->b_rptr; - cmd = iocp->ioc_cmd; - - /* - * Intercept DLPI ioctl's. - */ - if (VALID_DLPIOP(cmd)) { - PR_STR("%s: DLPI ioctl(%d)\n", proc, cmd); - error = idnioc_dlpi(wq, mp, &argsize); - goto done; - } - - /* - * Validate expected arguments. - */ - if (!VALID_IDNIOCTL(cmd)) { - PR_STR("%s: invalid cmd (0x%x)\n", proc, cmd); - error = EINVAL; - goto done; - - } else if (!VALID_NDOP(cmd)) { - error = miocpullup(mp, sizeof (idnop_t)); - if (error != 0) { - PR_STR("%s: idnioc(cmd = 0x%x) miocpullup " - "failed (%d)\n", proc, cmd, error); - goto done; - } - } - - argsize = mp->b_cont->b_wptr - mp->b_cont->b_rptr; - idnop = (idnop_t *)mp->b_cont->b_rptr; - - switch (cmd) { - case IDNIOC_LINK: - error = idnioc_link(idnop); - break; - - case IDNIOC_UNLINK: - error = idnioc_unlink(idnop); - break; - - case IDNIOC_MEM_RW: - error = idn_rw_mem(idnop); - break; - - case IDNIOC_PING: - error = idn_send_ping(idnop); - break; - - case ND_SET: - IDN_GLOCK_EXCL(); - if (!nd_getset(wq, idn_ndlist, mp)) { - IDN_GUNLOCK(); - error = ENOENT; - break; - } - IDN_GUNLOCK(); - qreply(wq, mp); - return; - - case ND_GET: - IDN_GLOCK_SHARED(); - if (!nd_getset(wq, idn_ndlist, mp)) { - IDN_GUNLOCK(); - error = ENOENT; - break; - } - IDN_GUNLOCK(); - qreply(wq, mp); - return; - - default: - PR_STR("%s: invalid cmd 0x%x\n", proc, cmd); - error = EINVAL; - break; - } - -done: - if (error == 0) - miocack(wq, mp, argsize, 0); - else - miocnak(wq, mp, 0, error); -} - -/* - * This thread actually services the SSI_LINK/UNLINK calls - * 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 -idn_sigbhandler_thread(struct sigbintr **sbpp) -{ - int d, pri, rv; - struct sigbintr *sbp; - sigbmbox_t *mbp; - idn_fin_t fintype; - idnsb_data_t *sdp; - idnsb_info_t *sfp; - idnsb_error_t *sep; - idn_domain_t *dp; - procname_t proc = "idn_sigbhandler_thread"; - - - sbp = *sbpp; - - PR_PROTO("%s: KICKED OFF (sigbintr pointer = 0x%p)\n", - proc, (void *)sbp); - - ASSERT(sbp == &idn.sigbintr); - - mutex_enter(&idn.sigbintr.sb_mutex); - - while (sbp->sb_busy != IDNSIGB_DIE) { - cpu_sgnblk_t *sigbp; - - while ((sbp->sb_busy != IDNSIGB_ACTIVE) && - (sbp->sb_busy != IDNSIGB_DIE)) { - cv_wait(&sbp->sb_cv, &idn.sigbintr.sb_mutex); - PR_PROTO("%s: AWAKENED (busy = %d)\n", - proc, (int)sbp->sb_busy); - } - if (sbp->sb_busy == IDNSIGB_DIE) { - PR_PROTO("%s: DIE REQUESTED\n", proc); - break; - } - - if ((sigbp = cpu_sgnblkp[sbp->sb_cpuid]) == NULL) { - cmn_err(CE_WARN, - "IDN: 124: sigblk for CPU ID %d " - "is NULL", sbp->sb_cpuid); - sbp->sb_busy = IDNSIGB_INACTIVE; - continue; - } - - mbp = &sigbp->sigb_host_mbox; - - if (mbp->flag != SIGB_MBOX_BUSY) { - PR_PROTO("%s: sigblk mbox flag (%d) != BUSY (%d)\n", - proc, mbp->flag, SIGB_MBOX_BUSY); - sbp->sb_busy = IDNSIGB_INACTIVE; - 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. - */ - mutex_exit(&idn.sigbintr.sb_mutex); - - sdp = (idnsb_data_t *)mbp->data; - sep = (idnsb_error_t *)&sdp->ssb_error; - INIT_IDNKERR(sep); - - if (mbp->len != sizeof (idnsb_data_t)) { - PR_PROTO("%s: sigblk mbox length (%d) != " - "expected (%lu)\n", proc, mbp->len, - sizeof (idnsb_data_t)); - SET_IDNKERR_ERRNO(sep, EINVAL); - SET_IDNKERR_IDNERR(sep, IDNKERR_DATA_LEN); - SET_IDNKERR_PARAM0(sep, sizeof (idnsb_data_t)); - - goto sberr; - - } - if (idn.enabled == 0) { -#ifdef DEBUG - cmn_err(CE_NOTE, - "IDN: 102: driver disabled " - "- check OBP environment " - "(idn-smr-size)"); -#else /* DEBUG */ - cmn_err(CE_NOTE, - "!IDN: 102: driver disabled " - "- check OBP environment " - "(idn-smr-size)"); -#endif /* DEBUG */ - SET_IDNKERR_ERRNO(sep, EACCES); - SET_IDNKERR_IDNERR(sep, IDNKERR_DRV_DISABLED); - - goto sberr; - - } - - switch (mbp->cmd) { - - case SSI_LINK: - { - idnsb_link_t slp; - - bcopy(&sdp->ssb_link, &slp, sizeof (slp)); - - if (slp.master_pri < 0) { - pri = IDNVOTE_MINPRI; - } 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 = IDNVOTE_MAXPRI; - IDN_GLOCK_SHARED(); - if (idn.ndomains <= 1) - pri--; - IDN_GUNLOCK(); - } else { - pri = IDNVOTE_DEFPRI; - } - - PR_PROTO("%s: SSI_LINK(cpuid = %d, domid = %d, " - "pri = %d (req = %d), t/o = %d)\n", - proc, slp.cpuid, slp.domid, pri, - slp.master_pri, slp.timeout); - - rv = idn_link(slp.domid, slp.cpuid, pri, - slp.timeout, sep); - SET_IDNKERR_ERRNO(sep, rv); - (void) idn_info(&sdp->ssb_info); - break; - } - - case SSI_UNLINK: - { - idnsb_unlink_t sup; - idn_domain_t *xdp; - domainset_t domset; - - bcopy(&sdp->ssb_unlink, &sup, sizeof (sup)); - - PR_PROTO("%s: SSI_UNLINK(c = %d, d = %d, bs = 0x%x, " - "f = %d, is = 0x%x, t/o = %d)\n", - proc, sup.cpuid, sup.domid, sup.boardset, - sup.force, sup.idnset, sup.timeout); - - domset = idn.domset.ds_trans_on | - idn.domset.ds_connected | - idn.domset.ds_trans_off | - idn.domset.ds_awol | - idn.domset.ds_relink; - - if (VALID_DOMAINID(sup.domid)) { - dp = &idn_domain[sup.domid]; - } else if (VALID_CPUID(sup.cpuid)) { - for (d = 0; d < MAX_DOMAINS; d++) { - xdp = &idn_domain[d]; - - if ((xdp->dcpu == IDN_NIL_DCPU) && - !DOMAIN_IN_SET(domset, d)) - continue; - - if (CPU_IN_SET(xdp->dcpuset, - sup.cpuid)) - break; - } - dp = (d == MAX_DOMAINS) ? NULL : xdp; - } - if ((dp == NULL) && sup.boardset) { - for (d = 0; d < MAX_DOMAINS; d++) { - xdp = &idn_domain[d]; - - if ((xdp->dcpu == IDN_NIL_DCPU) && - !DOMAIN_IN_SET(domset, d)) - continue; - - if (xdp->dhw.dh_boardset & - sup.boardset) - break; - } - dp = (d == MAX_DOMAINS) ? NULL : xdp; - } - if (dp == NULL) { - SET_IDNKERR_ERRNO(sep, EINVAL); - SET_IDNKERR_IDNERR(sep, IDNKERR_INVALID_DOMAIN); - SET_IDNKERR_PARAM0(sep, sup.domid); - SET_IDNKERR_PARAM1(sep, sup.cpuid); - (void) idn_info(&sdp->ssb_info); - goto sberr; - } else { - sup.domid = dp->domid; - } - - switch (sup.force) { - case SSIFORCE_OFF: - fintype = IDNFIN_NORMAL; - break; - - case SSIFORCE_SOFT: - fintype = IDNFIN_FORCE_SOFT; - break; - - case SSIFORCE_HARD: - fintype = IDNFIN_FORCE_HARD; - break; - default: - SET_IDNKERR_ERRNO(sep, EINVAL); - SET_IDNKERR_IDNERR(sep, IDNKERR_INVALID_FORCE); - SET_IDNKERR_PARAM0(sep, sup.force); - (void) idn_info(&sdp->ssb_info); - goto sberr; - } - - rv = idn_unlink(sup.domid, sup.idnset, fintype, - IDNFIN_OPT_UNLINK, sup.timeout, sep); - SET_IDNKERR_ERRNO(sep, rv); - (void) idn_info(&sdp->ssb_info); - break; - } - - case SSI_INFO: - sfp = &sdp->ssb_info; - - PR_PROTO("%s: SSI_INFO\n", proc); - - rv = idn_info(sfp); - SET_IDNKERR_ERRNO(sep, rv); - if (rv != 0) { - SET_IDNKERR_IDNERR(sep, IDNKERR_INFO_FAILED); - } - break; - - default: - ASSERT(0); - SET_IDNKERR_ERRNO(sep, EINVAL); - SET_IDNKERR_IDNERR(sep, IDNKERR_INVALID_CMD); - SET_IDNKERR_PARAM0(sep, mbp->cmd); - break; - } - -sberr: - - if (GET_IDNKERR_ERRNO(sep) != 0) { - cmn_err(CE_WARN, -#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 */ - (mbp->cmd == SSI_LINK) ? "LINK" : - (mbp->cmd == SSI_UNLINK) ? "UNLINK" : - (mbp->cmd == SSI_INFO) ? - "INFO" : "UNKNOWN", - GET_IDNKERR_ERRNO(sep), - GET_IDNKERR_IDNERR(sep), - GET_IDNKERR_PARAM0(sep), - GET_IDNKERR_PARAM1(sep), - GET_IDNKERR_PARAM2(sep)); - } - - PR_PROTO("%s: returning errno = %d, idnerr = %d, " - "params = [%d, %d, %d]\n", - proc, GET_IDNKERR_ERRNO(sep), GET_IDNKERR_IDNERR(sep), - GET_IDNKERR_PARAM0(sep), GET_IDNKERR_PARAM1(sep), - GET_IDNKERR_PARAM2(sep)); - - mutex_enter(&idn.sigbintr.sb_mutex); - ASSERT((sbp->sb_busy == IDNSIGB_ACTIVE) || - (sbp->sb_busy == IDNSIGB_DIE)); - mbp->cmd |= SSI_ACK; - if (sbp->sb_busy == IDNSIGB_ACTIVE) - sbp->sb_busy = IDNSIGB_INACTIVE; - /* - * Set flag which kicks off response to SSP. - */ - membar_stst_ldst(); - mbp->flag = HOST_TO_CBS; - } - - /* - * Wake up the dude that killed us! - */ - idn.sigb_threadp = NULL; - cv_signal(&sbp->sb_cv); - mutex_exit(&idn.sigbintr.sb_mutex); - thread_exit(); -} - -/* - * Create the thread that will service sigb interrupts. - */ -static void -idn_sigbhandler_create() -{ - struct sigbintr *sbp; - - if (idn.sigb_threadp) { - cmn_err(CE_WARN, - "IDN: 126: sigbhandler thread already " - "exists (0x%p)", (void *)idn.sigb_threadp); - return; - } - cv_init(&idn.sigbintr.sb_cv, NULL, CV_DEFAULT, NULL); - sbp = &idn.sigbintr; - sbp->sb_busy = IDNSIGB_INACTIVE; - idn.sigb_threadp = thread_create(NULL, 0, - idn_sigbhandler_thread, &sbp, sizeof (sbp), &p0, - TS_RUN, minclsyspri); - sbp->sb_inum = add_softintr((uint_t)idn_sigbpil, - idn_sigbhandler_wakeup, 0, SOFTINT_ST); -} - -static void -idn_sigbhandler_kill() -{ - if (idn.sigb_threadp) { - struct sigbintr *sbp; - - sbp = &idn.sigbintr; - if (sbp->sb_inum != 0) - (void) rem_softintr(sbp->sb_inum); - sbp->sb_inum = 0; - sbp->sb_busy = IDNSIGB_DIE; - cv_signal(&sbp->sb_cv); - while (idn.sigb_threadp != NULL) - cv_wait(&sbp->sb_cv, &idn.sigbintr.sb_mutex); - sbp->sb_busy = IDNSIGB_INACTIVE; - cv_destroy(&sbp->sb_cv); - } -} - -/*ARGSUSED0*/ -static uint_t -idn_sigbhandler_wakeup(caddr_t arg1, caddr_t arg2) -{ - mutex_enter(&idn.sigbintr.sb_mutex); - if (idn.sigbintr.sb_busy == IDNSIGB_STARTED) { - idn.sigbintr.sb_busy = IDNSIGB_ACTIVE; - cv_signal(&idn.sigbintr.sb_cv); - } - mutex_exit(&idn.sigbintr.sb_mutex); - - return (DDI_INTR_CLAIMED); -} - -static void -idn_sigbhandler(processorid_t cpuid, cpu_sgnblk_t *sgnblkp) -{ - struct sigbintr *sbp = &idn.sigbintr; - sigbmbox_t *mbp; - idnsb_data_t *sdp; - idnsb_error_t *sep; - uint32_t cmd; - int sigb_lock = 0; - - ASSERT(sgnblkp); - - mbp = &sgnblkp->sigb_host_mbox; - sdp = (idnsb_data_t *)mbp->data; - sep = &sdp->ssb_error; - cmd = mbp->cmd; - - if ((mbp->flag != CBS_TO_HOST) || !VALID_IDNSIGBCMD(cmd)) { - /* - * Not a valid IDN command. Just bail out. - */ - return; - } - - mbp->flag = SIGB_MBOX_BUSY; - SET_IDNKERR_ERRNO(sep, 0); - - if (cmd & SSI_ACK) { - /* - * Hmmm...weird, the ACK bit is set. - */ - SET_IDNKERR_ERRNO(sep, EPROTO); - SET_IDNKERR_IDNERR(sep, IDNKERR_INVALID_CMD); - SET_IDNKERR_PARAM0(sep, cmd); - goto sigb_done; - } - - if (!mutex_tryenter(&idn.sigbintr.sb_mutex)) { - /* - * 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. - */ - cmd |= SSI_ACK; - SET_IDNKERR_ERRNO(sep, EBUSY); - SET_IDNKERR_IDNERR(sep, IDNKERR_SIGBINTR_LOCKED); - goto sigb_done; - } - sigb_lock = 1; - - if ((idn.sigb_threadp == NULL) || - (sbp->sb_busy == IDNSIGB_NOTREADY)) { - cmd |= SSI_ACK; - SET_IDNKERR_ERRNO(sep, EAGAIN); - SET_IDNKERR_IDNERR(sep, IDNKERR_SIGBINTR_NOTRDY); - goto sigb_done; - } - - if (sbp->sb_busy != IDNSIGB_INACTIVE) { - cmd |= SSI_ACK; - SET_IDNKERR_ERRNO(sep, EBUSY); - SET_IDNKERR_IDNERR(sep, IDNKERR_SIGBINTR_BUSY); - goto sigb_done; - } - - sbp->sb_cpuid = (uchar_t)cpuid & 0xff; - membar_stst_ldst(); - sbp->sb_busy = IDNSIGB_STARTED; - /* - * 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. - */ - setsoftint(sbp->sb_inum); - -sigb_done: - - if (GET_IDNKERR_ERRNO(sep) != 0) { - mbp->len = sizeof (idnsb_data_t); - mbp->cmd = cmd; - membar_stst_ldst(); - mbp->flag = HOST_TO_CBS; - } - - if (sigb_lock) - mutex_exit(&idn.sigbintr.sb_mutex); -} - -static int -idn_info(idnsb_info_t *sfp) -{ - int count, d; - idn_domain_t *dp; - idnsb_info_t sinfo; - int local_id, master_id; - procname_t proc = "idn_info"; - - bzero(&sinfo, sizeof (sinfo)); - sinfo.master_index = (uchar_t)-1; - sinfo.master_cpuid = (uchar_t)-1; - sinfo.local_index = (uchar_t)-1; - sinfo.local_cpuid = (uchar_t)-1; - - IDN_GLOCK_SHARED(); - - sinfo.idn_state = (uchar_t)idn.state; - - switch (idn.state) { - case IDNGS_OFFLINE: - sinfo.idn_active = SSISTATE_INACTIVE; - PR_PROTO("%s: idn_state (%s) = INACTIVE\n", - proc, idngs_str[idn.state]); - break; - - case IDNGS_IGNORE: - PR_PROTO("%s: IGNORING IDN_INFO call...\n", proc); - IDN_GUNLOCK(); - return (EIO); - - default: - sinfo.idn_active = SSISTATE_ACTIVE; - PR_PROTO("%s: idn_state (%s) = ACTIVE\n", - proc, idngs_str[idn.state]); - break; - } - master_id = IDN_GET_MASTERID(); - local_id = idn.localid; - - /* - * Need to drop idn.grwlock before acquiring domain locks. - */ - IDN_GUNLOCK(); - - IDN_SYNC_LOCK(); - - sinfo.awol_domset = (ushort_t)idn.domset.ds_awol; - sinfo.conn_domset = (ushort_t)(idn.domset.ds_connected & - ~idn.domset.ds_trans_on); - DOMAINSET_ADD(sinfo.conn_domset, idn.localid); - - count = 0; - for (d = 0; d < MAX_DOMAINS; d++) { - dp = &idn_domain[d]; - - if (dp->dcpu == IDN_NIL_DCPU) - continue; - - IDN_DLOCK_SHARED(d); - if ((dp->dcpu == IDN_NIL_DCPU) || - (dp->dstate == IDNDS_CLOSED)) { - IDN_DUNLOCK(d); - continue; - } - - count++; - if (d == local_id) { - sinfo.local_index = (uchar_t)d; - sinfo.local_cpuid = (uchar_t)dp->dcpu; - PR_PROTO("%s: domid %d is LOCAL (cpuid = %d)\n", - proc, d, dp->dcpu); - } - if (d == master_id) { - sinfo.master_index = (uchar_t)d; - sinfo.master_cpuid = (uchar_t)dp->dcpu; - PR_PROTO("%s: domid %d is MASTER (cpuid = %d)\n", - proc, d, dp->dcpu); - } - - sinfo.domain_boardset[d] = (ushort_t)dp->dhw.dh_boardset; - - IDN_DUNLOCK(d); - } - - IDN_SYNC_UNLOCK(); - - bcopy(&sinfo, sfp, sizeof (*sfp)); - - PR_PROTO("%s: Found %d domains within IDNnet\n", proc, count); - - return (0); -} - -/* - * ---------------------------------------------- - * ndd param support routines. - * - Borrowed from tcp. - * ---------------------------------------------- - */ -static void -idn_param_cleanup() -{ - IDN_GLOCK_EXCL(); - if (!idn.strup && idn_ndlist) - nd_free(&idn_ndlist); - IDN_GUNLOCK(); -} - -/*ARGSUSED*/ -static int -idn_param_get(queue_t *q, mblk_t *mp, caddr_t cp, cred_t *cr) -{ - idnparam_t *idnpa = (idnparam_t *)cp; - - /* - * lock grabbed before calling nd_getset. - */ - ASSERT(IDN_GLOCK_IS_HELD()); - - (void) mi_mpprintf(mp, "%ld", idnpa->sp_val); - - return (0); -} - -/*ARGSUSED*/ -static int -idn_param_set(queue_t *q, mblk_t *mp, char *value, caddr_t cp, cred_t *cr) -{ - char *end; - ulong_t new_value; - idnparam_t *idnpa = (idnparam_t *)cp; - - /* - * lock grabbed before calling nd_getset. - */ - ASSERT(IDN_GLOCK_IS_EXCL()); - - new_value = (ulong_t)mi_strtol(value, &end, 10); - - if ((end == value) || - (new_value < idnpa->sp_min) || - (new_value > idnpa->sp_max)) - return (EINVAL); - - if (idn.enabled == 0) { -#ifdef DEBUG - cmn_err(CE_NOTE, - "IDN: 102: driver disabled " - "- check OBP environment " - "(idn-smr-size)"); -#else /* DEBUG */ - cmn_err(CE_NOTE, - "!IDN: 102: driver disabled " - "- check OBP environment " - "(idn-smr-size)"); -#endif /* DEBUG */ - return (EACCES); - } - - idnpa->sp_val = new_value; - - return (0); -} - -static int -idn_param_register(register idnparam_t *idnpa, int count) -{ - ASSERT(IDN_GLOCK_IS_EXCL()); - - for (; count > 0; count--, idnpa++) { - if (idnpa->sp_name && idnpa->sp_name[0]) { - register int i; - ndsetf_t set_func; - char *p; - /* - * Don't advertise in non-DEBUG parameters. - */ - for (i = 0; idn_param_debug_only[i]; i++) { - p = idn_param_debug_only[i]; - if (strcmp(idnpa->sp_name, p) == 0) - 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]; - if (strcmp(idnpa->sp_name, p) == 0) - break; - } - if (idn_param_read_only[i]) - set_func = NULL; - else - set_func = idn_param_set; - - if (!nd_load(&idn_ndlist, idnpa->sp_name, - idn_param_get, set_func, - (caddr_t)idnpa)) { - nd_free(&idn_ndlist); - return (-1); - } - } - } - if (!nd_load(&idn_ndlist, "idn_slabpool", idn_slabpool_report, - NULL, NULL)) { - nd_free(&idn_ndlist); - return (-1); - } - if (!nd_load(&idn_ndlist, "idn_buffers", idn_buffer_report, - NULL, NULL)) { - nd_free(&idn_ndlist); - return (-1); - } - if (!nd_load(&idn_ndlist, "idn_mboxtbl", idn_mboxtbl_report, - NULL, MBXTBL_PART_REPORT)) { - nd_free(&idn_ndlist); - return (-1); - } - if (!nd_load(&idn_ndlist, "idn_mboxtbl_all", idn_mboxtbl_report, - NULL, MBXTBL_FULL_REPORT)) { - nd_free(&idn_ndlist); - return (-1); - } - if (!nd_load(&idn_ndlist, "idn_mainmbox", idn_mainmbox_report, - NULL, NULL)) { - nd_free(&idn_ndlist); - return (-1); - } - if (!nd_load(&idn_ndlist, "idn_global", idn_global_report, - NULL, NULL)) { - nd_free(&idn_ndlist); - return (-1); - } - if (!nd_load(&idn_ndlist, "idn_domain", idn_domain_report, - NULL, (caddr_t)0)) { - nd_free(&idn_ndlist); - return (-1); - } - if (!nd_load(&idn_ndlist, "idn_domain_all", idn_domain_report, - NULL, (caddr_t)1)) { - nd_free(&idn_ndlist); - return (-1); - } - if (!nd_load(&idn_ndlist, "idn_bind_net", idn_get_net_binding, - idn_set_net_binding, NULL)) { - nd_free(&idn_ndlist); - return (-1); - } - - return (0); -} - -/*ARGSUSED*/ -static int -idn_set_net_binding(queue_t *q, mblk_t *mp, char *value, caddr_t cp, cred_t *cr) -{ - char *end, *cpup; - long net; - processorid_t cpuid; - - /* - * lock grabbed before calling nd_getset. - */ - ASSERT(IDN_GLOCK_IS_EXCL()); - - if ((cpup = strchr(value, '=')) == NULL) - return (EINVAL); - - *cpup++ = '\0'; - - net = mi_strtol(value, &end, 10); - if ((end == value) || (net < 0) || (net >= IDN_MAX_NETS) || - !CHAN_IN_SET(idn.chanset, net)) - return (EINVAL); - - cpuid = (processorid_t)mi_strtol(cpup, &end, 10); - if ((end == cpup) || ((cpuid != -1) && - (!VALID_CPUID(cpuid) || - !CPU_IN_SET(cpu_ready_set, cpuid)))) - return (EINVAL); - - idn_chanserver_bind(net, cpuid); - - return (0); -} - -/*ARGSUSED*/ -static int -idn_get_net_binding(queue_t *q, mblk_t *mp, caddr_t cp, cred_t *cr) -{ - int c; - - /* - * lock grabbed before calling nd_getset. - */ - ASSERT(IDN_GLOCK_IS_HELD()); - - (void) mi_mpprintf(mp, - "IDN network interfaces/channels active = %d", - idn.nchannels); - - if (idn.nchannels == 0) - return (0); - - (void) mi_mpprintf(mp, "Net Cpu"); - - for (c = 0; c < IDN_MAX_NETS; c++) { - int bc; - idn_chansvr_t *csp; - - if (!CHAN_IN_SET(idn.chanset, c)) - continue; - - csp = &idn.chan_servers[c]; - - if ((bc = csp->ch_bound_cpuid) == -1) - bc = csp->ch_bound_cpuid_pending; - - if (c < 10) - (void) mi_mpprintf(mp, " %d %d", c, bc); - else - (void) mi_mpprintf(mp, " %d %d", c, bc); - } - - return (0); -} - -static int -idnioc_link(idnop_t *idnop) -{ - int rv; - int pri; - idnsb_error_t err; - procname_t proc = "idnioc_link"; - - if (idnop->link.master < 0) - pri = IDNVOTE_MINPRI; - else if (idnop->link.master > 0) - pri = IDNVOTE_MAXPRI; - else - pri = IDNVOTE_DEFPRI; - - PR_DRV("%s: domid = %d, cpuid = %d, pri = %d\n", - proc, idnop->link.domid, idnop->link.cpuid, pri); - - rv = idn_link(idnop->link.domid, idnop->link.cpuid, - pri, idnop->link.wait, &err); - - return (rv); -} - -static int -idnioc_unlink(idnop_t *idnop) -{ - int d, cpuid, domid, rv; - boardset_t idnset; - idn_fin_t fintype; - idn_domain_t *dp, *xdp; - idnsb_error_t err; - procname_t proc = "idnioc_unlink"; - - PR_DRV("%s: domid = %d, cpuid = %d, force = %d\n", - proc, idnop->unlink.domid, idnop->unlink.cpuid, - idnop->unlink.force); - - idnset = BOARDSET_ALL; - domid = idnop->unlink.domid; - cpuid = idnop->unlink.cpuid; - dp = NULL; - - if (domid == IDN_NIL_DOMID) - domid = idn.localid; - - if (VALID_DOMAINID(domid)) { - dp = &idn_domain[domid]; - if (VALID_CPUID(cpuid) && (dp->dcpu != IDN_NIL_DCPU) && - !CPU_IN_SET(dp->dcpuset, cpuid)) { - dp = NULL; - PR_PROTO("%s: ERROR: invalid cpuid " - "(%d) for domain (%d) [cset = 0x%x.x%x]\n", - proc, cpuid, domid, - UPPER32_CPUMASK(dp->dcpuset), - LOWER32_CPUMASK(dp->dcpuset)); - } - } else if (VALID_CPUID(cpuid)) { - for (d = 0; d < MAX_DOMAINS; d++) { - xdp = &idn_domain[d]; - - if (xdp->dcpu == IDN_NIL_DCPU) - continue; - - if (CPU_IN_SET(xdp->dcpuset, cpuid)) - break; - } - dp = (d == MAX_DOMAINS) ? NULL : xdp; - } - - if ((dp == NULL) || (dp->dcpu == IDN_NIL_DCPU)) - return (0); - - domid = dp->domid; - - switch (idnop->unlink.force) { - case SSIFORCE_OFF: - fintype = IDNFIN_NORMAL; - break; - - case SSIFORCE_SOFT: - fintype = IDNFIN_FORCE_SOFT; - break; - - case SSIFORCE_HARD: - fintype = IDNFIN_FORCE_HARD; - break; - default: - PR_PROTO("%s: invalid force parameter \"%d\"", - proc, idnop->unlink.force); - return (EINVAL); - } - - rv = idn_unlink(domid, idnset, fintype, IDNFIN_OPT_UNLINK, - idnop->unlink.wait, &err); - - return (rv); -} - -static int -idn_send_ping(idnop_t *idnop) -{ - int domid = idnop->ping.domid; - int cpuid = idnop->ping.cpuid; - int ocpuid; - idn_domain_t *dp; - idn_msgtype_t mt; - procname_t proc = "idn_send_ping"; - - if ((domid == IDN_NIL_DOMID) && (cpuid == IDN_NIL_DCPU)) { - cmn_err(CE_WARN, - "IDN: %s: no valid domain ID or CPU ID given", - proc); - return (EINVAL); - } - if (domid == IDN_NIL_DOMID) - domid = MAX_DOMAINS - 1; - - dp = &idn_domain[domid]; - IDN_DLOCK_EXCL(domid); - if ((dp->dcpu == IDN_NIL_DCPU) && (cpuid == IDN_NIL_DCPU)) { - cmn_err(CE_WARN, - "IDN: %s: no valid target CPU specified", - proc); - IDN_DUNLOCK(domid); - return (EINVAL); - } - if (cpuid == IDN_NIL_DCPU) - cpuid = dp->dcpu; - - ocpuid = dp->dcpu; - dp->dcpu = cpuid; - - /* - * XXX - Need a special PING IDN command. - */ - mt.mt_mtype = IDNP_DATA | IDNP_ACK; - mt.mt_atype = 0; - - (void) IDNXDC(domid, &mt, 0x100, 0x200, 0x300, 0x400); - - dp->dcpu = ocpuid; - IDN_DUNLOCK(domid); - - return (0); -} - -/* - * ---------------------------------------------- - */ -static void -idn_dopers_init() -{ - int i; - dop_waitlist_t *dwl; - - if (idn.dopers) - return; - - idn.dopers = GETSTRUCT(struct dopers, 1); - - bzero(idn.dopers, sizeof (struct dopers)); - - dwl = &idn.dopers->_dop_wcache[0]; - for (i = 0; i < (IDNOP_CACHE_SIZE-1); i++) - dwl[i].dw_next = &dwl[i+1]; - dwl[i].dw_next = NULL; - - idn.dopers->dop_freelist = &idn.dopers->_dop_wcache[0]; - idn.dopers->dop_waitcount = 0; - idn.dopers->dop_domset = 0; - idn.dopers->dop_waitlist = NULL; - - cv_init(&idn.dopers->dop_cv, NULL, CV_DEFAULT, NULL); - mutex_init(&idn.dopers->dop_mutex, NULL, MUTEX_DEFAULT, NULL); -} - -static void -idn_dopers_deinit() -{ - dop_waitlist_t *dwl, *next_dwl; - - - if (idn.dopers == NULL) - return; - - for (dwl = idn.dopers->dop_waitlist; dwl; dwl = next_dwl) { - next_dwl = dwl->dw_next; - if (!IDNOP_IN_CACHE(dwl)) - FREESTRUCT(dwl, dop_waitlist_t, 1); - } - - cv_destroy(&idn.dopers->dop_cv); - mutex_destroy(&idn.dopers->dop_mutex); - - FREESTRUCT(idn.dopers, struct dopers, 1); - idn.dopers = NULL; -} - -/* - * Reset the dop_errset field in preparation for an - * IDN operation attempt. This is only called from - * idn_link() and idn_unlink(). - */ -void * -idn_init_op(idn_opflag_t opflag, domainset_t domset, idnsb_error_t *sep) -{ - dop_waitlist_t *dwl; - /* - * Clear any outstanding error ops in preparation - * for an IDN (link/unlink) operation. - */ - mutex_enter(&idn.dopers->dop_mutex); - if ((dwl = idn.dopers->dop_freelist) == NULL) { - dwl = GETSTRUCT(dop_waitlist_t, 1); - } else { - idn.dopers->dop_freelist = dwl->dw_next; - bzero(dwl, sizeof (*dwl)); - } - dwl->dw_op = opflag; - dwl->dw_reqset = domset; - dwl->dw_idnerr = sep; - dwl->dw_next = idn.dopers->dop_waitlist; - - idn.dopers->dop_waitlist = dwl; - idn.dopers->dop_waitcount++; - idn.dopers->dop_domset |= domset; - mutex_exit(&idn.dopers->dop_mutex); - - 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 -idn_add_op(idn_opflag_t opflag, domainset_t domset) -{ - dop_waitlist_t *dwl; - - mutex_enter(&idn.dopers->dop_mutex); - if ((idn.dopers->dop_waitcount == 0) || - ((idn.dopers->dop_domset & domset) == 0)) { - mutex_exit(&idn.dopers->dop_mutex); - return; - } - for (dwl = idn.dopers->dop_waitlist; dwl; dwl = dwl->dw_next) - if ((dwl->dw_op == opflag) && (dwl->dw_reqset & domset)) - dwl->dw_reqset |= domset; - mutex_exit(&idn.dopers->dop_mutex); -} - -/* - * Mechanism to wakeup any potential users which may be waiting - * for a link/unlink operation to complete. If an error occurred - * don't update dop_errset unless there was no previous error. - */ -void -idn_update_op(idn_opflag_t opflag, domainset_t domset, idnsb_error_t *sep) -{ - int do_wakeup = 0; - dop_waitlist_t *dw; - procname_t proc = "idn_update_op"; - - mutex_enter(&idn.dopers->dop_mutex); - /* - * If there are no waiters, or nobody is waiting for - * the particular domainset in question, then - * just bail. - */ - if ((idn.dopers->dop_waitcount == 0) || - ((idn.dopers->dop_domset & domset) == 0)) { - mutex_exit(&idn.dopers->dop_mutex); - PR_PROTO("%s: NO waiters exist (domset=0x%x)\n", - proc, domset); - return; - } - - for (dw = idn.dopers->dop_waitlist; dw; dw = dw->dw_next) { - int d; - domainset_t dset, rset; - - if ((dset = dw->dw_reqset & domset) == 0) - continue; - - if (opflag == IDNOP_ERROR) { - dw->dw_errset |= dset; - if (sep) { - for (d = 0; d < MAX_DOMAINS; d++) { - if (!DOMAIN_IN_SET(dset, d)) - continue; - - dw->dw_errors[d] = - (short)GET_IDNKERR_ERRNO(sep); - } - bcopy(sep, dw->dw_idnerr, sizeof (*sep)); - } - } else if (opflag == dw->dw_op) { - dw->dw_domset |= dset; - } - - /* - * 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. - */ - rset = (dw->dw_errset | dw->dw_domset) & dw->dw_reqset; - if (rset == dw->dw_reqset) - do_wakeup++; - } - - PR_PROTO("%s: found %d waiters ready for wakeup\n", proc, do_wakeup); - - if (do_wakeup > 0) - cv_broadcast(&idn.dopers->dop_cv); - - mutex_exit(&idn.dopers->dop_mutex); -} - -void -idn_deinit_op(void *cookie) -{ - domainset_t domset; - dop_waitlist_t *hw, *tw; - dop_waitlist_t *dwl = (dop_waitlist_t *)cookie; - - mutex_enter(&idn.dopers->dop_mutex); - - ASSERT(idn.dopers->dop_waitlist); - - if (dwl == idn.dopers->dop_waitlist) { - idn.dopers->dop_waitlist = dwl->dw_next; - if (IDNOP_IN_CACHE(dwl)) { - dwl->dw_next = idn.dopers->dop_freelist; - idn.dopers->dop_freelist = dwl; - } else { - FREESTRUCT(dwl, dop_waitlist_t, 1); - } - } else { - for (tw = idn.dopers->dop_waitlist, hw = tw->dw_next; - hw; - tw = hw, hw = hw->dw_next) { - if (dwl == hw) - break; - } - ASSERT(hw); - - tw->dw_next = hw->dw_next; - } - - /* - * 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. - */ - for (hw = idn.dopers->dop_waitlist, domset = 0; hw; hw = hw->dw_next) - domset |= hw->dw_reqset; - - idn.dopers->dop_waitcount--; - idn.dopers->dop_domset = domset; - - mutex_exit(&idn.dopers->dop_mutex); -} - -/* - * Wait until the specified operation succeeds or fails with - * respect to the given domains. Note the function terminates - * if at least one error occurs. - * This process is necessary since link/unlink operations occur - * 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 -idn_wait_op(void *cookie, domainset_t *domsetp, int wait_timeout) -{ - int d, rv, err = 0; - dop_waitlist_t *dwl; - - - dwl = (dop_waitlist_t *)cookie; - - ASSERT(wait_timeout > 0); - ASSERT((dwl->dw_op == IDNOP_CONNECTED) || - (dwl->dw_op == IDNOP_DISCONNECTED)); - - mutex_enter(&idn.dopers->dop_mutex); - - while (((dwl->dw_domset | dwl->dw_errset) != dwl->dw_reqset) && !err) { - rv = cv_reltimedwait_sig(&idn.dopers->dop_cv, - &idn.dopers->dop_mutex, (wait_timeout * hz), TR_CLOCK_TICK); - - if ((dwl->dw_domset | dwl->dw_errset) == dwl->dw_reqset) - break; - - switch (rv) { - case -1: - /* - * timed out - */ - cmn_err(CE_WARN, - "!IDN: 129: %s operation timed out", - (dwl->dw_op == IDNOP_CONNECTED) ? "LINK" : - (dwl->dw_op == IDNOP_DISCONNECTED) ? "UNLINK" : - "UNKNOWN"); - /*FALLTHROUGH*/ - case 0: - /* - * signal, e.g. kill(2) - */ - err = 1; - break; - - default: - break; - } - } - - if (dwl->dw_domset == dwl->dw_reqset) { - rv = 0; - } else { - /* - * Op failed for some domains or we were awakened. - */ - for (d = rv = 0; (d < MAX_DOMAINS) && !rv; d++) - rv = dwl->dw_errors[d]; - } - *domsetp = dwl->dw_domset; - - mutex_exit(&idn.dopers->dop_mutex); - - idn_deinit_op(cookie); - - return (rv); -} - -/* - * -------------------------------------------------- - * Return any valid (& ready) cpuid for the given board based on - * the given cpuset. - * -------------------------------------------------- - */ -int -board_to_ready_cpu(int board, cpuset_t cpuset) -{ - int base_cpuid; - int ncpu_board = MAX_CPU_PER_BRD; - - board *= ncpu_board; - for (base_cpuid = board; - base_cpuid < (board + ncpu_board); - base_cpuid++) - if (CPU_IN_SET(cpuset, base_cpuid)) - return (base_cpuid); - - return (-1); -} - -void -idn_domain_resetentry(idn_domain_t *dp) -{ - register int i; - procname_t proc = "idn_domain_resetentry"; - - ASSERT(dp); - ASSERT(dp->dstate == IDNDS_CLOSED); - ASSERT(IDN_DLOCK_IS_EXCL(dp->domid)); - ASSERT(IDN_GLOCK_IS_EXCL()); - - ASSERT(dp->domid == (dp - &idn_domain[0])); - - IDN_FSTATE_TRANSITION(dp, IDNFIN_OFF); - dp->dname[0] = '\0'; - dp->dnetid = (ushort_t)-1; - dp->dmtu = 0; - dp->dbufsize = 0; - dp->dslabsize = 0; - dp->dnwrsize = 0; - dp->dncpus = 0; - dp->dcpuindex = 0; - CPUSET_ZERO(dp->dcpuset); - dp->dcpu = dp->dcpu_last = dp->dcpu_save = IDN_NIL_DCPU; - dp->dvote.ticket = 0; - dp->dslab = NULL; - dp->dslab_state = DSLAB_STATE_UNKNOWN; - dp->dnslabs = 0; - dp->dio = 0; - dp->dioerr = 0; - lock_clear(&dp->diowanted); - bzero(&dp->dhw, sizeof (dp->dhw)); - dp->dxp = NULL; - IDN_XSTATE_TRANSITION(dp, IDNXS_NIL); - dp->dsync.s_cmd = IDNSYNC_NIL; - dp->dfin_sync = IDNFIN_SYNC_OFF; - IDN_RESET_COOKIES(dp->domid); - dp->dcookie_err = 0; - bzero(&dp->dawol, sizeof (dp->dawol)); - dp->dtmp = -1; - - if (dp->dtimerq.tq_queue != NULL) { - PR_PROTO("%s: WARNING: MSG timerq not empty (count = %d)\n", - proc, dp->dtimerq.tq_count); - IDN_MSGTIMER_STOP(dp->domid, 0, 0); - } - - for (i = 0; i < NCPU; i++) - dp->dcpumap[i] = (uchar_t)-1; -} - -int -idn_open_domain(int domid, int cpuid, uint_t ticket) -{ - int c, new_cpuid; - idn_domain_t *dp, *ldp; - procname_t proc = "idn_open_domain"; - - ASSERT(IDN_SYNC_IS_LOCKED()); - ASSERT(IDN_DLOCK_IS_EXCL(domid)); - - if (!VALID_DOMAINID(domid)) { - PR_PROTO("%s: INVALID domainid (%d) " - "[cpuid = %d, ticket = 0x%x]\n", - proc, domid, cpuid, ticket); - return (-1); - } - - dp = &idn_domain[domid]; - ldp = &idn_domain[idn.localid]; - - if (dp->dcpu >= 0) { - PR_PROTO("%s:%d: domain already OPEN (state = %s)\n", - proc, domid, idnds_str[dp->dstate]); - return (1); - } - - if (DOMAIN_IN_SET(idn.domset.ds_relink, domid)) { - if (dp->dcpu_save == IDN_NIL_DCPU) - new_cpuid = cpuid; - else - new_cpuid = dp->dcpu_save; - } else { - new_cpuid = cpuid; - } - - if (new_cpuid == IDN_NIL_DCPU) { - PR_PROTO("%s:%d: WARNING: invalid cpuid (%d) specified\n", - proc, domid, new_cpuid); - return (-1); - } - - IDN_GLOCK_EXCL(); - - idn_domain_resetentry(dp); - - PR_STATE("%s:%d: requested cpuid %d, assigning cpuid %d\n", - proc, domid, cpuid, new_cpuid); - - idn_assign_cookie(domid); - - dp->dcpu = dp->dcpu_save = new_cpuid; - dp->dvote.ticket = ticket; - CPUSET_ADD(dp->dcpuset, new_cpuid); - dp->dncpus = 1; - for (c = 0; c < NCPU; c++) - dp->dcpumap[c] = (uchar_t)new_cpuid; - dp->dhw.dh_nboards = 1; - dp->dhw.dh_boardset = BOARDSET(CPUID_TO_BOARDID(new_cpuid)); - - if (domid != idn.localid) - IDN_DLOCK_EXCL(idn.localid); - - if (idn.ndomains == 1) { - struct hwconfig local_hw; - - /* - * 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. - */ - PR_PROTO("%s: RECHECKING local HW config.\n", proc); - if (get_hw_config(&local_hw)) { - dp->dcpu = IDN_NIL_DCPU; - cmn_err(CE_WARN, - "IDN: 118: hardware config not appropriate"); - if (domid != idn.localid) - IDN_DUNLOCK(idn.localid); - IDN_GUNLOCK(); - return (-1); - } - (void) update_local_hw_config(ldp, &local_hw); - } - - idn.ndomains++; - - if (domid != idn.localid) - IDN_DUNLOCK(idn.localid); - IDN_GUNLOCK(); - - IDN_MBOX_LOCK(domid); - dp->dmbox.m_tbl = NULL; - - if (domid != idn.localid) { - dp->dmbox.m_send = idn_mainmbox_init(domid, - IDNMMBOX_TYPE_SEND); - dp->dmbox.m_recv = idn_mainmbox_init(domid, - IDNMMBOX_TYPE_RECV); - } else { - /* - * The local domain does not need send/recv - * mailboxes in its idn_domain[] entry. - */ - dp->dmbox.m_send = NULL; - dp->dmbox.m_recv = NULL; - } - IDN_MBOX_UNLOCK(domid); - - PR_PROTO("%s:%d: new domain (cpu = %d, vote = 0x%x)\n", - proc, domid, dp->dcpu, dp->dvote.ticket); - - 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 -idn_close_domain(int domid) -{ - uint_t token; - idn_domain_t *dp; - procname_t proc = "idn_close_domain"; - - ASSERT(IDN_SYNC_IS_LOCKED()); - ASSERT(IDN_DLOCK_IS_EXCL(domid)); - - dp = &idn_domain[domid]; - - ASSERT(dp->dstate == IDNDS_CLOSED); - - if (dp->dcpu == IDN_NIL_DCPU) { - PR_PROTO("%s:%d: DOMAIN ALREADY CLOSED!\n", - proc, domid); - return; - } - - token = IDN_RETRY_TOKEN(domid, IDN_RETRY_TYPEALL); - - (void) idn_retry_terminate(token); - - DOMAINSET_DEL(idn.domset.ds_trans_on, domid); - DOMAINSET_DEL(idn.domset.ds_ready_on, domid); - DOMAINSET_DEL(idn.domset.ds_connected, domid); - DOMAINSET_DEL(idn.domset.ds_trans_off, domid); - DOMAINSET_DEL(idn.domset.ds_ready_off, domid); - DOMAINSET_DEL(idn.domset.ds_hwlinked, domid); - DOMAINSET_DEL(idn.domset.ds_flush, domid); - - idn_sync_exit(domid, IDNSYNC_CONNECT); - idn_sync_exit(domid, IDNSYNC_DISCONNECT); - - IDN_GLOCK_EXCL(); - - if (DOMAIN_IN_SET(idn.domset.ds_awol, domid)) - idn_clear_awol(domid); - - idn.ndomains--; - - IDN_GUNLOCK(); - - IDN_MBOX_LOCK(domid); - dp->dmbox.m_tbl = NULL; - - if (dp->dmbox.m_send) { - idn_mainmbox_deinit(domid, dp->dmbox.m_send); - dp->dmbox.m_send = NULL; - } - - if (dp->dmbox.m_recv) { - idn_mainmbox_deinit(domid, dp->dmbox.m_recv); - dp->dmbox.m_recv = NULL; - } - - IDN_MBOX_UNLOCK(domid); - - cmn_err(CE_NOTE, - "!IDN: 142: link (domain %d, CPU %d) disconnected", - dp->domid, dp->dcpu); - - dp->dcpu = IDN_NIL_DCPU; /* ultimate demise */ - - IDN_RESET_COOKIES(domid); - - ASSERT(dp->dio <= 0); - ASSERT(dp->dioerr == 0); - ASSERT(dp->dslab == NULL); - ASSERT(dp->dnslabs == 0); - - IDN_GKSTAT_GLOBAL_EVENT(gk_unlinks, gk_unlink_last); -} - - -/* - * ----------------------------------------------------------------------- - */ -static void -idn_domains_init(struct hwconfig *local_hw) -{ - register int i, d; - idn_domain_t *ldp; - uchar_t *cpumap; - - ASSERT(local_hw != NULL); - - cpumap = GETSTRUCT(uchar_t, NCPU * MAX_DOMAINS); - - for (d = 0; d < MAX_DOMAINS; d++) { - register idn_domain_t *dp; - - dp = &idn_domain[d]; - - dp->domid = d; - - rw_init(&dp->drwlock, NULL, RW_DEFAULT, NULL); - - IDN_TIMERQ_INIT(&dp->dtimerq); - - dp->dstate = IDNDS_CLOSED; - - mutex_init(&dp->dmbox.m_mutex, NULL, MUTEX_DEFAULT, NULL); - - dp->dcpumap = cpumap; - - rw_init(&dp->dslab_rwlock, NULL, RW_DEFAULT, NULL); - - IDN_DLOCK_EXCL(d); - IDN_GLOCK_EXCL(); - - idn_domain_resetentry(dp); - - IDN_GUNLOCK(); - - IDNSB_DOMAIN_UPDATE(dp); - - IDN_DUNLOCK(d); - - cpumap += NCPU; - } - - IDN_SYNC_LOCK(); - - /* - * Update local domain information. - */ - ASSERT(idn.smr.locpfn); - ASSERT(local_hw->dh_nboards && local_hw->dh_boardset); - - idn.ndomains = 0; /* note that open_domain will get us to 1 */ - - IDN_DLOCK_EXCL(idn.localid); - d = idn_open_domain(idn.localid, (int)CPU->cpu_id, 0); - ASSERT(d == 0); - IDN_GLOCK_EXCL(); - IDN_SET_MASTERID(IDN_NIL_DOMID); - IDN_SET_NEW_MASTERID(IDN_NIL_DOMID); - - ldp = &idn_domain[idn.localid]; - - (void) strncpy(ldp->dname, utsname.nodename, MAXDNAME - 1); - ldp->dname[MAXDNAME-1] = '\0'; - bcopy(local_hw, &ldp->dhw, sizeof (ldp->dhw)); - ASSERT(idn.ndomains == 1); - ASSERT((ldp->dhw.dh_nboards > 0) && - (ldp->dhw.dh_nboards <= MAX_BOARDS)); - ldp->dnetid = IDN_DOMID2NETID(ldp->domid); - ldp->dmtu = IDN_MTU; - ldp->dbufsize = IDN_SMR_BUFSIZE; - ldp->dslabsize = (short)IDN_SLAB_BUFCOUNT; - ldp->dnwrsize = (short)IDN_NWR_SIZE; - ldp->dcpuset = cpu_ready_set; - ldp->dncpus = (short)ncpus; - ldp->dvote.ticket = IDNVOTE_INITIAL_TICKET; - ldp->dvote.v.master = 0; - ldp->dvote.v.nmembrds = ldp->dhw.dh_nmcadr - 1; - ldp->dvote.v.ncpus = (int)ldp->dncpus - 1; - ldp->dvote.v.board = CPUID_TO_BOARDID(ldp->dcpu); - i = -1; - for (d = 0; d < NCPU; d++) { - BUMP_INDEX(ldp->dcpuset, i); - ldp->dcpumap[d] = (uchar_t)i; - } - - CPUSET_ZERO(idn.dc_cpuset); - CPUSET_OR(idn.dc_cpuset, ldp->dcpuset); - idn.dc_boardset = ldp->dhw.dh_boardset; - - /* - * 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_DSTATE_TRANSITION(ldp, IDNDS_CONNECTED); - - IDN_GUNLOCK(); - IDN_DUNLOCK(idn.localid); - IDN_SYNC_UNLOCK(); -} - -static void -idn_domains_deinit() -{ - register int d; - - IDN_SYNC_LOCK(); - IDN_DLOCK_EXCL(idn.localid); - IDN_DSTATE_TRANSITION(&idn_domain[idn.localid], IDNDS_CLOSED); - idn_close_domain(idn.localid); - IDN_DUNLOCK(idn.localid); - IDN_SYNC_UNLOCK(); - idn.localid = IDN_NIL_DOMID; - - FREESTRUCT(idn_domain[0].dcpumap, uchar_t, NCPU * MAX_DOMAINS); - - for (d = 0; d < MAX_DOMAINS; d++) { - idn_domain_t *dp; - - dp = &idn_domain[d]; - - rw_destroy(&dp->dslab_rwlock); - mutex_destroy(&dp->dmbox.m_mutex); - rw_destroy(&dp->drwlock); - IDN_TIMERQ_DEINIT(&dp->dtimerq); - dp->dcpumap = NULL; - } -} - -/* - * ----------------------------------------------------------------------- - */ -static void -idn_retrytask_init() -{ - ASSERT(idn.retryqueue.rq_cache == NULL); - - mutex_init(&idn.retryqueue.rq_mutex, NULL, MUTEX_DEFAULT, NULL); - idn.retryqueue.rq_cache = kmem_cache_create("idn_retryjob_cache", - sizeof (idn_retry_job_t), - 0, NULL, NULL, NULL, - NULL, NULL, 0); -} - -static void -idn_retrytask_deinit() -{ - if (idn.retryqueue.rq_cache == NULL) - return; - - kmem_cache_destroy(idn.retryqueue.rq_cache); - mutex_destroy(&idn.retryqueue.rq_mutex); - - bzero(&idn.retryqueue, sizeof (idn.retryqueue)); -} - -/* - * ----------------------------------------------------------------------- - */ -static void -idn_timercache_init() -{ - ASSERT(idn.timer_cache == NULL); - - idn.timer_cache = kmem_cache_create("idn_timer_cache", - sizeof (idn_timer_t), - 0, NULL, NULL, NULL, - NULL, NULL, 0); -} - -static void -idn_timercache_deinit() -{ - if (idn.timer_cache == NULL) - return; - - kmem_cache_destroy(idn.timer_cache); - idn.timer_cache = NULL; -} - -idn_timer_t * -idn_timer_alloc() -{ - idn_timer_t *tp; - - tp = kmem_cache_alloc(idn.timer_cache, KM_SLEEP); - bzero(tp, sizeof (*tp)); - tp->t_forw = tp->t_back = tp; - - return (tp); -} - -void -idn_timer_free(idn_timer_t *tp) -{ - if (tp == NULL) - return; - kmem_cache_free(idn.timer_cache, tp); -} - -void -idn_timerq_init(idn_timerq_t *tq) -{ - mutex_init(&tq->tq_mutex, NULL, MUTEX_DEFAULT, NULL); - tq->tq_count = 0; - tq->tq_queue = NULL; -} - -void -idn_timerq_deinit(idn_timerq_t *tq) -{ - ASSERT(tq->tq_queue == NULL); - mutex_destroy(&tq->tq_mutex); -} - -/* - * Dequeue all the timers of the given subtype from the - * given timerQ. If subtype is 0, then dequeue all the - * timers. - */ -idn_timer_t * -idn_timer_get(idn_timerq_t *tq, int type, ushort_t tcookie) -{ - register idn_timer_t *tp, *tphead; - - ASSERT(IDN_TIMERQ_IS_LOCKED(tq)); - - if ((tp = tq->tq_queue) == NULL) - return (NULL); - - if (!type) { - tq->tq_queue = NULL; - tq->tq_count = 0; - tphead = tp; - } else { - int count; - idn_timer_t *tpnext; - - tphead = NULL; - count = tq->tq_count; - do { - tpnext = tp->t_forw; - if ((tp->t_type == type) && - (!tcookie || (tp->t_cookie == tcookie))) { - tp->t_forw->t_back = tp->t_back; - tp->t_back->t_forw = tp->t_forw; - if (tphead == NULL) { - tp->t_forw = tp->t_back = tp; - } else { - tp->t_forw = tphead; - tp->t_back = tphead->t_back; - tp->t_back->t_forw = tp; - tphead->t_back = tp; - } - tphead = tp; - if (--(tq->tq_count) == 0) - tq->tq_queue = NULL; - else if (tq->tq_queue == tp) - tq->tq_queue = tpnext; - } - tp = tpnext; - } while (--count > 0); - } - - if (tphead) { - tphead->t_back->t_forw = NULL; - - for (tp = tphead; tp; tp = tp->t_forw) - tp->t_onq = 0; - } - - return (tphead); -} - -ushort_t -idn_timer_start(idn_timerq_t *tq, idn_timer_t *tp, clock_t tval) -{ - idn_timer_t *otp; - ushort_t tcookie; - procname_t proc = "idn_timer_start"; - STRING(str); - - ASSERT(tq && tp && (tval > 0)); - ASSERT((tp->t_forw == tp) && (tp->t_back == tp)); - ASSERT(tp->t_type != 0); - - IDN_TIMERQ_LOCK(tq); - /* - * Assign a unique non-zero 8-bit cookie to this timer - * if the caller hasn't already preassigned one. - */ - while ((tcookie = tp->t_cookie) == 0) { - tp->t_cookie = (tp->t_type & 0xf) | - ((++tq->tq_cookie & 0xf) << 4); - /* - * Calculated cookie must never conflict - * with the public timer cookie. - */ - ASSERT(tp->t_cookie != IDN_TIMER_PUBLIC_COOKIE); - } - - /* - * First have to remove old timers of the - * same type and cookie, and get rid of them. - */ - otp = idn_timer_get(tq, tp->t_type, tcookie); - - tq->tq_count++; - - if (tq->tq_queue == NULL) { - tq->tq_queue = tp; - ASSERT((tp->t_forw == tp) && (tp->t_back == tp)); - } else { - /* - * Put me at the end of the list. - */ - tp->t_forw = tq->tq_queue; - tp->t_back = tq->tq_queue->t_back; - tp->t_back->t_forw = tp; - tp->t_forw->t_back = tp; - } - - tp->t_onq = 1; - tp->t_q = tq; - tp->t_id = timeout(idn_timer_expired, (caddr_t)tp, tval); - - - INUM2STR(tp->t_type, str); - PR_TIMER("%s: started %s timer (domain = %d, cookie = 0x%x)\n", - proc, str, tp->t_domid, tcookie); - - IDN_TIMERQ_UNLOCK(tq); - - 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 -idn_timer_stop(idn_timerq_t *tq, int type, ushort_t tcookie) -{ - idn_timer_t *tphead; - procname_t proc = "idn_timer_stop"; - STRING(str); - - ASSERT(tq); - - INUM2STR(type, str); - - IDN_TIMERQ_LOCK(tq); - - if (tq->tq_count == 0) { - PR_TIMER("%s: found no %s timers (count=0)\n", proc, str); - IDN_TIMERQ_UNLOCK(tq); - return; - } - tphead = idn_timer_get(tq, type, tcookie); -#ifdef DEBUG - if (tphead == NULL) - PR_TIMER("%s: found no %s (cookie = 0x%x) " - "timers (count=%d)!!\n", - proc, str, tcookie, tq->tq_count); -#endif /* DEBUG */ - IDN_TIMERQ_UNLOCK(tq); - - if (tphead) - (void) idn_timer_stopall(tphead); -} - -int -idn_timer_stopall(idn_timer_t *tp) -{ - int count = 0; - int nonactive; - uint_t type; - idn_timer_t *ntp; - procname_t proc = "idn_timer_stopall"; - STRING(str); - - nonactive = 0; - - if (tp) { - /* - * Circle should have been broken. - */ - ASSERT(tp->t_back->t_forw == NULL); - type = tp->t_type; - INUM2STR(type, str); - } - - for (; tp; tp = ntp) { - ntp = tp->t_forw; - count++; - ASSERT(tp->t_id != (timeout_id_t)0); - if (untimeout(tp->t_id) < 0) { - nonactive++; - PR_TIMER("%s: bad %s untimeout (domain=%d)\n", - proc, str, tp->t_domid); - } else { - PR_TIMER("%s: good %s untimeout (domain=%d)\n", - proc, str, tp->t_domid); - } - /* - * 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. It - * probably just fired off. - */ - idn_timer_free(tp); - } - PR_TIMER("%s: stopped %d of %d %s timers\n", - proc, count - nonactive, count, str); - - return (count); -} - -void -idn_timer_dequeue(idn_timerq_t *tq, idn_timer_t *tp) -{ - ASSERT(tq && tp); - ASSERT(IDN_TIMERQ_IS_LOCKED(tq)); - - ASSERT(tp->t_q == tq); - - if (tp->t_onq == 0) { - /* - * We've already been dequeued. - */ - ASSERT(tp == tp->t_forw); - ASSERT(tp == tp->t_back); - } else { - /* - * We're still in the queue, get out. - */ - if (tq->tq_queue == tp) - tq->tq_queue = tp->t_forw; - tp->t_forw->t_back = tp->t_back; - tp->t_back->t_forw = tp->t_forw; - tp->t_onq = 0; - if (--(tq->tq_count) == 0) { - ASSERT(tq->tq_queue == tp); - tq->tq_queue = NULL; - } - tp->t_forw = tp->t_back = tp; - } -} - -/* - * ----------------------------------------------------------------------- - */ -/*ARGSUSED*/ -static int -idn_slabpool_report(queue_t *wq, mblk_t *mp, caddr_t cp, cred_t *cr) -{ - register int p, nfree; - char dsetstr[128]; - - ASSERT(IDN_GLOCK_IS_HELD()); - - if (idn.slabpool == NULL) { - (void) mi_mpprintf(mp, - "IDN slabpool not initialized (masterid = %d)", - IDN_GET_MASTERID()); - return (0); - } - - for (p = nfree = 0; p < idn.slabpool->npools; p++) - nfree += idn.slabpool->pool[p].nfree; - - (void) mi_mpprintf(mp, - "IDN slabpool (ntotal_slabs = %d, nalloc = %d, " - "npools = %d)", - idn.slabpool->ntotslabs, - idn.slabpool->ntotslabs - nfree, - idn.slabpool->npools); - - (void) mi_mpprintf(mp, "pool nslabs nfree domains"); - - for (p = 0; p < idn.slabpool->npools; p++) { - register int d, s; - uint_t domset; - - domset = 0; - for (s = 0; s < idn.slabpool->pool[p].nslabs; s++) { - short dd; - - dd = idn.slabpool->pool[p].sarray[s].sl_domid; - if (dd != (short)IDN_NIL_DOMID) - DOMAINSET_ADD(domset, dd); - } - dsetstr[0] = '\0'; - if (domset) { - for (d = 0; d < MAX_DOMAINS; d++) { - if (!DOMAIN_IN_SET(domset, d)) - continue; - - if (dsetstr[0] == '\0') - (void) sprintf(dsetstr, "%d", d); - else - (void) sprintf(dsetstr, "%s %d", - dsetstr, d); - } - } - - if (p < 10) - (void) mi_mpprintf(mp, " %d %d %d %s", - p, idn.slabpool->pool[p].nslabs, - idn.slabpool->pool[p].nfree, - dsetstr); - else - (void) mi_mpprintf(mp, " %d %d %d %s", - p, idn.slabpool->pool[p].nslabs, - idn.slabpool->pool[p].nfree, - dsetstr); - } - return (0); -} - -/*ARGSUSED*/ -static int -idn_buffer_report(queue_t *wq, mblk_t *mp, caddr_t cp, cred_t *cr) -{ - smr_slab_t *sp; - register int d, cnt; - int bufcount[MAX_DOMAINS]; - int spl; - - ASSERT(IDN_GLOCK_IS_HELD()); - - if (idn.localid == IDN_NIL_DOMID) { - (void) mi_mpprintf(mp, "IDN not initialized (localid = %d)", - idn.localid); - return (0); - } - - (void) mi_mpprintf(mp, "Local domain has %d slabs allocated.", - idn_domain[idn.localid].dnslabs); - - DSLAB_LOCK_SHARED(idn.localid); - if ((sp = idn_domain[idn.localid].dslab) == NULL) { - DSLAB_UNLOCK(idn.localid); - return (0); - } - - bzero(bufcount, sizeof (bufcount)); - cnt = 0; - - spl = splhi(); - for (; sp; sp = sp->sl_next) { - smr_slabbuf_t *bp; - - while (!lock_try(&sp->sl_lock)) - ; - for (bp = sp->sl_inuse; bp; bp = bp->sb_next) { - bufcount[bp->sb_domid]++; - cnt++; - } - lock_clear(&sp->sl_lock); - } - splx(spl); - - DSLAB_UNLOCK(idn.localid); - - (void) mi_mpprintf(mp, "Local domain has %d buffers outstanding.", cnt); - if (cnt == 0) - return (0); - - (void) mi_mpprintf(mp, "Domain nbufs"); - for (d = 0; d < MAX_DOMAINS; d++) - if (bufcount[d]) { - if (d < 10) - (void) mi_mpprintf(mp, " %d %d", - d, bufcount[d]); - else - (void) mi_mpprintf(mp, " %d %d", - 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 * -_hexspace(uint64_t v, int sz, int width, int padding) -{ - int maxnbl = 16; - int diff; - uchar_t *np; - - diff = sizeof (uint64_t) - sz; - np = (uchar_t *)&v + diff; - maxnbl -= diff << 1; - while (sz-- > 0) { - if ((*np & 0xf0) && (width >= maxnbl)) - return (_get_spaces(width, padding, maxnbl)); - maxnbl--; - if ((*np & 0x0f) && (width >= maxnbl)) - return (_get_spaces(width, padding, maxnbl)); - maxnbl--; - np++; - } - return (_get_spaces(width, padding, 1)); -} - -#define HEXSPACE(v, t, w, s) _hexspace((uint64_t)(v), sizeof (t), (w), (s)) - -#define DECSPACE(n, w, s) \ - (_SSS((uint_t)(n) >= 10000000, 8, (w), (s)) : \ - _SSS((uint_t)(n) >= 1000000, 7, (w), (s)) : \ - _SSS((uint_t)(n) >= 100000, 6, (w), (s)) : \ - _SSS((uint_t)(n) >= 10000, 5, (w), (s)) : \ - _SSS((uint_t)(n) >= 1000, 4, (w), (s)) : \ - _SSS((uint_t)(n) >= 100, 3, (w), (s)) : \ - _SSS((uint_t)(n) >= 10, 2, (w), (s)) : \ - _get_spaces((w), (s), 1)) - -#define DECSPACE16(n, w, s) \ - (_SSS((n) >= 10000, 5, (w), (s)) : \ - _SSS((n) >= 1000, 4, (w), (s)) : \ - _SSS((n) >= 100, 3, (w), (s)) : \ - _SSS((n) >= 10, 2, (w), (s)) : \ - _get_spaces((w), (s), 1)) - -#define MBXINFO(mtp) \ - (void *)&mtp->mt_header, \ - HEXSPACE(&mtp->mt_header, &mtp->mt_header, 16, 2), \ - mtp->mt_header.mh_svr_ready_ptr, \ - HEXSPACE(mtp->mt_header.mh_svr_ready_ptr, \ - mtp->mt_header.mh_svr_ready_ptr, 8, 1), \ - mtp->mt_header.mh_svr_active_ptr, \ - HEXSPACE(mtp->mt_header.mh_svr_active_ptr, \ - mtp->mt_header.mh_svr_active_ptr, 8, 2), \ - *(ushort_t *)(IDN_OFFSET2ADDR(mtp->mt_header.mh_svr_ready_ptr)), \ - DECSPACE16(*(ushort_t *) \ - (IDN_OFFSET2ADDR(mtp->mt_header.mh_svr_ready_ptr)), \ - 1, 1), \ - *(ushort_t *)(IDN_OFFSET2ADDR(mtp->mt_header.mh_svr_active_ptr)), \ - DECSPACE16(*(ushort_t *) \ - (IDN_OFFSET2ADDR(mtp->mt_header.mh_svr_active_ptr)), \ - 1, 5), \ - mtp->mt_header.mh_cookie, \ - HEXSPACE(mtp->mt_header.mh_cookie, \ - mtp->mt_header.mh_cookie, 8, 2), \ - (void *)&mtp->mt_queue[0], \ - HEXSPACE(&mtp->mt_queue[0], &mtp->mt_queue[0], 16, 2) - -/*ARGSUSED*/ -static int -idn_mboxtbl_report(queue_t *wq, mblk_t *mp, caddr_t cp, cred_t *cr) -{ - register int c, n, domid, subdomid; - register idn_mboxtbl_t *mtp; - register idn_mboxmsg_t *msp; - idn_mboxtbl_t *map, *mtbasep; - - - ASSERT((cp == MBXTBL_PART_REPORT) || (cp == MBXTBL_FULL_REPORT)); - - if (IDN_GLOCK_TRY_SHARED() == 0) { - (void) mi_mpprintf(mp, "Local domain busy, try again."); - return (0); - } - - if ((map = idn.mboxarea) == NULL) { - (void) mi_mpprintf(mp, - "WARNING: Local domain is not master, " - "ASSUMING idn.smr.vaddr."); - map = (idn_mboxtbl_t *)idn.smr.vaddr; - } - - if (map) { - (void) mi_mpprintf(mp, "Mailbox Area starts @ 0x%p", - (void *)map); - } else { - (void) mi_mpprintf(mp, "Mailbox Area not found."); - goto repdone; - } - - if (!idn.nchannels) { - (void) mi_mpprintf(mp, "No OPEN channels found"); - goto repdone; - } - - for (c = 0; c < IDN_MAX_NETS; c++) { - - IDN_CHAN_LOCK_GLOBAL(&idn.chan_servers[c]); - if (!IDN_CHANNEL_IS_ATTACHED(&idn.chan_servers[c])) { - IDN_CHAN_UNLOCK_GLOBAL(&idn.chan_servers[c]); - continue; - } - - (void) mi_mpprintf(mp, - "Channel %d ---------------------------" - "--------------------------" - "-----------------------------", c); - (void) mi_mpprintf(mp, - " Domain Header " - "Ready/Active Ptrs " - "rdy/actv cookie Queue " - "busy"); - - for (domid = 0; domid < MAX_DOMAINS; domid++) { - register int busy_count; - - if ((cp == MBXTBL_PART_REPORT) && - (idn_domain[domid].dcpu == IDN_NIL_DCPU)) - continue; - - mtbasep = IDN_MBOXAREA_BASE(map, domid); - - for (subdomid = 0; subdomid < MAX_DOMAINS; - subdomid++) { - mtp = IDN_MBOXTBL_PTR(mtbasep, subdomid); - mtp = IDN_MBOXTBL_PTR_CHAN(mtp, c); - - if (subdomid == domid) { - if (subdomid == 0) - (void) mi_mpprintf(mp, - " %x.%x-%d%s%s", - domid, subdomid, c, - /*CONSTCOND*/ - DECSPACE(c, 2, 2), - "-- unused --"); - else - (void) mi_mpprintf(mp, - " .%x-%d%s%s", - subdomid, c, - /*CONSTCOND*/ - DECSPACE(c, 2, 2), - "-- unused --"); - continue; - } - busy_count = 0; - msp = &mtp->mt_queue[0]; - for (n = 0; n < IDN_MMBOX_NUMENTRIES; n++) { - if (msp[n].ms_owner) - 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", - domid, subdomid, c, - /*CONSTCOND*/ - DECSPACE(c, 2, 2), - MBXINFO(mtp), busy_count, - busy_count ? " <<<<<":""); - } 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*/ - DECSPACE(c, 2, 2), - MBXINFO(mtp), busy_count, - busy_count ? " <<<<<":""); - } - } - } - IDN_CHAN_UNLOCK_GLOBAL(&idn.chan_servers[c]); - } - -repdone: - IDN_GUNLOCK(); - - return (0); -} - -/*ARGSUSED*/ -static void -idn_mainmbox_domain_report(queue_t *wq, mblk_t *mp, int domid, - idn_mainmbox_t *mmp, char *mbxtype) -{ - register int c; - - if (mmp == NULL) { - (void) mi_mpprintf(mp, " %x.%s -- none --", domid, mbxtype); - return; - } - - for (c = 0; c < IDN_MAX_NETS; mmp++, c++) { - int mm_count; - - IDN_CHAN_LOCK_GLOBAL(&idn.chan_servers[c]); - if (IDN_CHANNEL_IS_DETACHED(&idn.chan_servers[c])) { - (void) mi_mpprintf(mp, " %x.%s %u -- not open --", - domid, mbxtype, (int)mmp->mm_channel); - IDN_CHAN_UNLOCK_GLOBAL(&idn.chan_servers[c]); - continue; - } - - mm_count = ((mmp->mm_count < 0) ? 0 : mmp->mm_count) / 1000; - - (void) mi_mpprintf(mp, " %x.%s %d%s%d%s%d%s%p%s%p%s%p%s%d/%d", - domid, mbxtype, - (int)mmp->mm_channel, - /*CONSTCOND*/ - DECSPACE((int)mmp->mm_channel, 5, 2), - mm_count, DECSPACE(mm_count, 8, 2), - mmp->mm_dropped, - DECSPACE(mmp->mm_dropped, 8, 2), - (void *)mmp->mm_smr_mboxp, - HEXSPACE(mmp->mm_smr_mboxp, - mmp->mm_smr_mboxp, 16, 2), - (void *)mmp->mm_smr_readyp, - HEXSPACE(mmp->mm_smr_readyp, - mmp->mm_smr_readyp, 16, 2), - (void *)mmp->mm_smr_activep, - HEXSPACE(mmp->mm_smr_activep, - mmp->mm_smr_activep, 16, 2), - mmp->mm_qiget, mmp->mm_qiput); - IDN_CHAN_UNLOCK_GLOBAL(&idn.chan_servers[c]); - } -} - -/*ARGSUSED2*/ -static int -idn_mainmbox_report(queue_t *wq, mblk_t *mp, caddr_t cp, cred_t *cr) -{ - int domid; - int header = 0; - - /* - * Domain 0 never has a send/recv mainmbox so - * don't bother printing it. - */ - for (domid = 1; domid < MAX_DOMAINS; domid++) { - idn_domain_t *dp; - - dp = &idn_domain[domid]; - - if (dp->dcpu == IDN_NIL_DCPU) - continue; - IDN_DLOCK_SHARED(domid); - if (dp->dcpu == IDN_NIL_DCPU) { - IDN_DUNLOCK(domid); - continue; - } - if (!header) { - (void) mi_mpprintf(mp, - "Domain Chan PktCntK " - "PktDrop SMRMbox " - "ReadyPtr " - "ActvPtr Miget/Miput"); - header = 1; - } - - mutex_enter(&dp->dmbox.m_mutex); - idn_mainmbox_domain_report(wq, mp, domid, - idn_domain[domid].dmbox.m_send, - "snd"); - idn_mainmbox_domain_report(wq, mp, domid, - idn_domain[domid].dmbox.m_recv, - "rcv"); - mutex_exit(&dp->dmbox.m_mutex); - - IDN_DUNLOCK(domid); - - (void) mi_mpprintf(mp, - " ---------------------------------------" - "------------------------" - "----------------------------"); - } - - if (!header) - (void) mi_mpprintf(mp, "No ACTIVE domain connections exist"); - - return (0); -} - -/*ARGSUSED*/ -static int -idn_global_report(queue_t *wq, mblk_t *mp, caddr_t cp, cred_t *cr) -{ - int i, nactive, masterid, nretry; - uint_t locpfn_upper, locpfn_lower, - rempfn_upper, rempfn_lower; - uint_t marea_upper, marea_lower, - iarea_upper, iarea_lower; - char alt_dbuffer[64]; - idn_retry_job_t *rp; - domainset_t retryset; - domainset_t connected; - idn_synczone_t *zp; - idn_syncop_t *sp; - idn_domain_t *dp; - char *dbp, *dbuffer; - - if (IDN_SYNC_TRYLOCK() == 0) { - (void) mi_mpprintf(mp, "Sync lock busy, try again."); - return (0); - } - - if (IDN_GLOCK_TRY_SHARED() == 0) { - (void) mi_mpprintf(mp, "Local domain busy, try again."); - IDN_SYNC_UNLOCK(); - return (0); - } - if ((dbp = dbuffer = ALLOC_DISPSTRING()) == NULL) - dbp = alt_dbuffer; - - (void) mi_mpprintf(mp, "IDN\n Global State = %s (%d)", - idngs_str[idn.state], idn.state); - - (void) mi_mpprintf(mp, "SMR"); - (void) mi_mpprintf(mp, " vaddr "); - (void) mi_mpprintf(mp, " 0x%p", (void *)idn.smr.vaddr); - - (void) mi_mpprintf(mp, " paddr-local paddr-remote"); - masterid = IDN_GET_MASTERID(); - locpfn_upper = (uint_t)(idn.smr.locpfn >> (32 - PAGESHIFT)); - locpfn_lower = (uint_t)(idn.smr.locpfn << PAGESHIFT); - if (idn.smr.rempfn == PFN_INVALID) { - rempfn_upper = rempfn_lower = 0; - } else { - rempfn_upper = (uint_t)(idn.smr.rempfn >> (32 - PAGESHIFT)); - rempfn_lower = (uint_t)(idn.smr.rempfn << PAGESHIFT); - } - (void) mi_mpprintf(mp, " 0x%x.%x%s0x%x.%x", - locpfn_upper, locpfn_lower, - HEXSPACE(locpfn_lower, locpfn_lower, 8, - (locpfn_upper < 0x10) ? 4 : 3), - rempfn_upper, rempfn_lower); - - (void) mi_mpprintf(mp, " SMR length = %d MBytes", IDN_SMR_SIZE); - (void) mi_mpprintf(mp, " SMR bufsize = %d Bytes", IDN_SMR_BUFSIZE); - (void) mi_mpprintf(mp, " NWR length = %d MBytes", IDN_NWR_SIZE); - marea_upper = (uint_t)((uint64_t)IDN_MBOXAREA_SIZE >> 32); - marea_lower = (uint_t)((uint64_t)IDN_MBOXAREA_SIZE & 0xffffffff); - iarea_upper = (uint_t)((uint64_t)(MB2B(IDN_NWR_SIZE) - - (size_t)IDN_MBOXAREA_SIZE) >> 32); - iarea_lower = (uint_t)((MB2B(IDN_NWR_SIZE) - - (size_t)IDN_MBOXAREA_SIZE) & 0xffffffff); - (void) mi_mpprintf(mp, - " [ mbox area = 0x%x.%x Bytes, " - "iobuf area = 0x%x.%x Bytes ]", - marea_upper, marea_lower, iarea_upper, iarea_lower); - - (void) mi_mpprintf(mp, - "\nIDNnet (local domain [id:%d] [name:%s] is %s)", - idn.localid, - idn_domain[idn.localid].dname, - (masterid == IDN_NIL_DOMID) ? "IDLE" : - (idn.localid == masterid) ? "MASTER" : - "SLAVE"); - nactive = 0; - for (i = 0; i < IDN_MAX_NETS; i++) { - IDN_CHAN_LOCK_GLOBAL(&idn.chan_servers[i]); - if (IDN_CHANNEL_IS_ACTIVE(&idn.chan_servers[i])) - nactive++; - IDN_CHAN_UNLOCK_GLOBAL(&idn.chan_servers[i]); - } - (void) mi_mpprintf(mp, " I/O Networks: (Open = %d, " - "Active = %d, Max = %d)", - idn.nchannels, nactive, IDN_MAX_NETS); - (void) mi_mpprintf(mp, " Number of Domains = %d", idn.ndomains); - (void) mi_mpprintf(mp, " Number of AWOLs = %d", idn.nawols); - /* - * 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. - */ - connected = idn.domset.ds_connected & ~idn.domset.ds_trans_on; - DOMAINSET_ADD(connected, idn.localid); - boardset2str(connected, dbp); - (void) mi_mpprintf(mp, " Connected Domains = %s", dbp); - domainset2str(idn.domset.ds_trans_on, dbp); - (void) mi_mpprintf(mp, " Pending Domain Links = %s", - idn.domset.ds_trans_on ? dbp : "<>"); - domainset2str(idn.domset.ds_trans_off, dbp); - (void) mi_mpprintf(mp, " Pending Domain Unlinks = %s", - idn.domset.ds_trans_off ? dbp : "<>"); - mutex_enter(&idn.retryqueue.rq_mutex); - nretry = idn.retryqueue.rq_count; - retryset = 0; - for (i = 0, rp = idn.retryqueue.rq_jobs; i < nretry; i++, - rp = rp->rj_next) { - int domid; - - domid = IDN_RETRY_TOKEN2DOMID(rp->rj_token); - if (VALID_DOMAINID(domid)) { - DOMAINSET_ADD(retryset, domid); - } - } - mutex_exit(&idn.retryqueue.rq_mutex); - domainset2str(retryset, dbp); - (void) mi_mpprintf(mp, " Retry Jobs:Domains = %d:%s", - nretry, retryset ? dbp : "<>"); - domainset2str(idn.domset.ds_hitlist, dbp); - (void) mi_mpprintf(mp, " Hitlist Domains = %s", - idn.domset.ds_hitlist ? dbp : "<>"); - domainset2str(idn.domset.ds_relink, dbp); - (void) mi_mpprintf(mp, " Reconfig Domains = %s", - idn.domset.ds_relink ? dbp : "<>"); - if (idn.domset.ds_relink) - (void) mi_mpprintf(mp, " new master id = %d", - IDN_GET_NEW_MASTERID()); - if (masterid == IDN_NIL_DOMID) { - (void) mi_mpprintf(mp, " Master Domain: no master"); - } else { - idn_domain_t *mdp; - - mdp = &idn_domain[masterid]; - - (void) mi_mpprintf(mp, - " Master Domain (id:name/brds - state):"); - - if (strlen(mdp->dname) > 0) - (void) strcpy(dbp, mdp->dname); - else - boardset2str(mdp->dhw.dh_boardset, dbp); - if (masterid < 10) - (void) mi_mpprintf(mp, " %d: %s - %s", - masterid, dbp, - idnds_str[mdp->dstate]); - else - (void) mi_mpprintf(mp, " %d: %s - %s", - masterid, dbp, - idnds_str[mdp->dstate]); - } - if (idn.ndomains <= 1) { - (void) mi_mpprintf(mp, " Slave Domains: none"); - } else { - int d; - - (void) mi_mpprintf(mp, - " Slave Domains (id:name/brds - state):"); - for (d = 0; d < MAX_DOMAINS; d++) { - dp = &idn_domain[d]; - - if ((dp->dcpu == IDN_NIL_DCPU) || (d == masterid)) - continue; - - if (strlen(dp->dname) > 0) - (void) strcpy(dbp, dp->dname); - else - boardset2str(dp->dhw.dh_boardset, dbp); - if (d < 10) - (void) mi_mpprintf(mp, " %d: %s - %s", - d, dbp, - idnds_str[dp->dstate]); - else - (void) mi_mpprintf(mp, " %d: %s - %s", - d, dbp, - idnds_str[dp->dstate]); - } - } - - if (idn.nawols == 0) { - (void) mi_mpprintf(mp, " AWOL Domains: none"); - } else { - int d; - - (void) mi_mpprintf(mp, " AWOL Domains (id:name/brds):"); - for (d = 0; d < MAX_DOMAINS; d++) { - dp = &idn_domain[d]; - - if (!DOMAIN_IN_SET(idn.domset.ds_awol, d) || - (dp->dcpu == IDN_NIL_DCPU)) - continue; - - if (strlen(dp->dname) > 0) - (void) strcpy(dbp, dp->dname); - else - boardset2str(dp->dhw.dh_boardset, dbp); - if (d < 10) - (void) mi_mpprintf(mp, " %d: %s", - d, dbp); - else - (void) mi_mpprintf(mp, " %d: %s", - d, dbp); - } - } - - /*CONSTCOND*/ - i = IDN_SYNC_GETZONE(IDNSYNC_CONNECT); - zp = &idn.sync.sz_zone[i]; - if (zp->sc_cnt == 0) { - (void) mi_mpprintf(mp, " Sync Zone (con): [empty]"); - } else { - (void) mi_mpprintf(mp, " Sync Zone (con): [%d domains]", - zp->sc_cnt); - sp = zp->sc_op; - for (i = 0; (i < zp->sc_cnt) && sp; i++) { - (void) mi_mpprintf(mp, - " " - "%x: x_set =%s0x%x, r_set =%s0x%x", - sp->s_domid, - HEXSPACE(sp->s_set_exp, - sp->s_set_exp, 4, 1), - sp->s_set_exp, - HEXSPACE(sp->s_set_rdy, - sp->s_set_rdy, 4, 1), - sp->s_set_rdy); - sp = sp->s_next; - } - } - /*CONSTCOND*/ - i = IDN_SYNC_GETZONE(IDNSYNC_DISCONNECT); - zp = &idn.sync.sz_zone[i]; - if (zp->sc_cnt == 0) { - (void) mi_mpprintf(mp, " Sync Zone (dis): [empty]"); - } else { - (void) mi_mpprintf(mp, " Sync Zone (dis): [%d domains]", - zp->sc_cnt); - sp = zp->sc_op; - for (i = 0; (i < zp->sc_cnt) && sp; i++) { - (void) mi_mpprintf(mp, - " " - "%x: x_set =%s0x%x, r_set =%s0x%x", - sp->s_domid, - HEXSPACE(sp->s_set_exp, - sp->s_set_exp, 4, 1), - sp->s_set_exp, - HEXSPACE(sp->s_set_rdy, - sp->s_set_rdy, 4, 1), - sp->s_set_rdy); - sp = sp->s_next; - } - } - - IDN_GUNLOCK(); - IDN_SYNC_UNLOCK(); - - if (dbuffer) { - FREE_DISPSTRING(dbuffer); - } - - return (0); -} - -/*ARGSUSED*/ -static int -idn_domain_report(queue_t *wq, mblk_t *mp, caddr_t cp, cred_t *cr) -{ - int d, nchan; - uint_t domset; - idn_chanset_t chanset; - idn_domain_t *dp; - uint_t pset_upper, pset_lower; - char *dbuffer, *dbp; - char alt_dbuffer[64]; - - - if (IDN_SYNC_TRYLOCK() == 0) { - (void) mi_mpprintf(mp, "Sync lock busy, try again."); - return (0); - } - - if (IDN_GLOCK_TRY_SHARED() == 0) { - (void) mi_mpprintf(mp, "Local domain busy, try again."); - IDN_SYNC_UNLOCK(); - return (0); - } - - if ((dbp = dbuffer = ALLOC_DISPSTRING()) == NULL) - dbp = alt_dbuffer; - - if (cp == NULL) - domset = DOMAINSET(idn.localid); - else - domset = DOMAINSET_ALL; - - for (d = 0; d < MAX_DOMAINS; d++) { - - if (DOMAIN_IN_SET(domset, d) == 0) - continue; - - dp = &idn_domain[d]; - - if (dp->dcpu == IDN_NIL_DCPU) - 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; - } - if (dp->dcpu == IDN_NIL_DCPU) { - IDN_DUNLOCK(d); - continue; - } - if (d < 10) - (void) mi_mpprintf(mp, "%sDomain %d (0x%p)", - (d && (idn.ndomains > 1)) ? "\n" : "", - d, (void *)dp); - else - (void) mi_mpprintf(mp, "%sDomain %d (0x%p)", - (d && (idn.ndomains > 1)) ? "\n" : "", - d, (void *)dp); - - if (d == idn.localid) - (void) mi_mpprintf(mp, " (local) State = %s (%d)", - idnds_str[dp->dstate], dp->dstate); - else - (void) mi_mpprintf(mp, " State = %s (%d)", - idnds_str[dp->dstate], dp->dstate); - (void) mi_mpprintf(mp, " Name = %s, Netid = %d", - (strlen(dp->dname) > 0) ? dp->dname : "<>", - (int)dp->dnetid); - - CHANSET_ZERO(chanset); - nchan = idn_domain_is_registered(d, -1, &chanset); - if (dbuffer) - mask2str(chanset, dbp, 32); - else - (void) sprintf(dbp, "0x%x", chanset); - (void) mi_mpprintf(mp, " Nchans = %d, Chanset = %s", - nchan, nchan ? dbp : "<>"); - pset_upper = UPPER32_CPUMASK(dp->dcpuset); - pset_lower = LOWER32_CPUMASK(dp->dcpuset); - if (dbuffer) - boardset2str(dp->dhw.dh_boardset, dbp); - else - (void) sprintf(dbp, "0x%x", dp->dhw.dh_boardset); - - (void) mi_mpprintf(mp, " Nboards = %d, Brdset = %s", - dp->dhw.dh_nboards, - dp->dhw.dh_nboards ? dbp : "<>"); - (void) sprintf(dbp, "0x%x.%x", pset_upper, pset_lower); - (void) mi_mpprintf(mp, " Ncpus = %d, Cpuset = %s", - dp->dncpus, dp->dncpus ? dbp : "<>"); - (void) mi_mpprintf(mp, " Nmcadr = %d", - dp->dhw.dh_nmcadr); - (void) mi_mpprintf(mp, - " MsgTimer = %s (cnt = %d)", - (dp->dtimerq.tq_count > 0) - ? "active" : "idle", - dp->dtimerq.tq_count); - (void) mi_mpprintf(mp, " Dcpu = %d " - "(lastcpu = %d, cpuindex = %d)", - dp->dcpu, dp->dcpu_last, dp->dcpuindex); - (void) mi_mpprintf(mp, " Dio = %d " - "(ioerr = %d, iochk = %d, iowanted = %d)", - dp->dio, dp->dioerr, dp->diocheck ? 1 : 0, - dp->diowanted ? 1 : 0); - if (dp->dsync.s_cmd == IDNSYNC_NIL) { - (void) mi_mpprintf(mp, " Dsync = %s", - idnsync_str[IDNSYNC_NIL]); - } else { - (void) mi_mpprintf(mp, - " Dsync = %s " - "(x_set = 0x%x, r_set = 0x%x)", - idnsync_str[dp->dsync.s_cmd], - (uint_t)dp->dsync.s_set_exp, - (uint_t)dp->dsync.s_set_rdy); - } - (void) mi_mpprintf(mp, " Dvote = 0x%x", - dp->dvote.ticket); - (void) mi_mpprintf(mp, " Dfin = %s (Sync = %s)", - idnfin_str[dp->dfin], - (dp->dfin_sync == IDNFIN_SYNC_OFF) ? "OFF" : - (dp->dfin_sync == IDNFIN_SYNC_YES) ? "YES" : - "NO"); - (void) mi_mpprintf(mp, " Dcookie_err = %s (cnt = %d)", - dp->dcookie_err ? "YES" : "NO", - dp->dcookie_errcnt); - IDN_DUNLOCK(d); - } - - IDN_GUNLOCK(); - - if (dbuffer) { - FREE_DISPSTRING(dbuffer); - } - - IDN_SYNC_UNLOCK(); - - return (0); -} - -#define SNOOP_ENTRIES 2048 /* power of 2 */ - -struct snoop_buffer { -/* 0 */ char io; -/* 1 */ char board; -/* 2 */ char trans[14]; - -/* 10 */ uint_t xargs[4]; -} *snoop_data, snoop_buffer[SNOOP_ENTRIES+1]; - - -int snoop_index; -kmutex_t snoop_mutex; -static char _bd2hexascii[] = { - '0', '1', '2', '3', '4', '5', '6', '7', - '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' -}; - -#define SNOOP_IDN(in, tr, bd, arg1, arg2, arg3, arg4) \ -{ \ - if (idn_snoop) { \ - mutex_enter(&snoop_mutex); \ - if (snoop_data == NULL) { \ - snoop_data = (struct snoop_buffer *) \ - (((uint_t)(uintptr_t)snoop_buffer + 0xf) & \ - ~0xf); \ - } \ - snoop_data[snoop_index].io = ((in) == 0) ? 'o' : 'i'; \ - snoop_data[snoop_index].board = \ - ((bd) == -1) ? 'X' : _bd2hexascii[bd]; \ - (void) strncpy(snoop_data[snoop_index].trans, (tr), 14); \ - snoop_data[snoop_index].xargs[0] = (arg1); \ - snoop_data[snoop_index].xargs[1] = (arg2); \ - snoop_data[snoop_index].xargs[2] = (arg3); \ - snoop_data[snoop_index].xargs[3] = (arg4); \ - snoop_index++; \ - snoop_index &= SNOOP_ENTRIES - 1; \ - mutex_exit(&snoop_mutex); \ - } \ -} - -/* - * Allocate the circular buffers to be used for - * DMV interrupt processing. - */ -static int -idn_init_handler() -{ - int i, c; - size_t len; - idn_dmv_msg_t *basep, *ivp; - uint32_t ivp_offset; - procname_t proc = "idn_init_handler"; - - if (idn.intr.dmv_data != NULL) { - cmn_err(CE_WARN, - "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); - len = roundup(len, sizeof (uint64_t)); - len += NCPU * idn_dmv_pending_max * sizeof (idn_dmv_msg_t); - len = roundup(len, PAGESIZE); - - PR_PROTO("%s: sizeof (idn_dmv_data_t) = %lu\n", - proc, sizeof (idn_dmv_data_t)); - PR_PROTO("%s: allocating %lu bytes for dmv data area\n", proc, len); - - idn.intr.dmv_data_len = len; - idn.intr.dmv_data = kmem_zalloc(len, KM_SLEEP); - - PR_PROTO("%s: DMV data area = %p\n", proc, (void *)idn.intr.dmv_data); - - idn_dmv_data = (idn_dmv_data_t *)idn.intr.dmv_data; - basep = (idn_dmv_msg_t *)roundup((size_t)idn.intr.dmv_data + - sizeof (idn_dmv_data_t), - sizeof (uint64_t)); - idn_dmv_data->idn_dmv_qbase = (uint64_t)basep; - - ivp = basep; - ivp_offset = 0; - /* - * The buffer queues are allocated per-cpu. - */ - for (c = 0, ivp = basep; c < NCPU; ivp++, c++) { - idn_dmv_data->idn_dmv_cpu[c].idn_dmv_current = ivp_offset; - idn_iv_queue[c] = ivp; - ivp_offset += sizeof (idn_dmv_msg_t); - for (i = 1; i < idn_dmv_pending_max; ivp++, i++) { - ivp->iv_next = ivp_offset; - ivp->iv_ready = 0; - lock_set(&ivp->iv_ready); - ivp_offset += sizeof (idn_dmv_msg_t); - } - ivp->iv_next = idn_dmv_data->idn_dmv_cpu[c].idn_dmv_current; - ivp->iv_ready = 0; - lock_set(&ivp->iv_ready); - } - - idn.intr.dmv_inum = STARFIRE_DMV_IDN_BASE; - idn.intr.soft_inum = add_softintr((uint_t)idn_pil, idn_handler, 0, - SOFTINT_ST); - idn_dmv_data->idn_soft_inum = idn.intr.soft_inum; - /* - * Make sure everything is out there before - * we effectively set it free for use. - */ - membar_stld_stst(); - - if (dmv_add_intr(idn.intr.dmv_inum, idn_dmv_handler, - (caddr_t)idn_dmv_data)) { - idn_deinit_handler(); - cmn_err(CE_WARN, "IDN: 132: failed to add IDN DMV handler"); - return (-1); - } - - return (0); -} - -static void -idn_deinit_handler() -{ - if (idn.intr.dmv_data == NULL) - return; - - (void) dmv_rem_intr(idn.intr.dmv_inum); - (void) rem_softintr(idn.intr.soft_inum); - kmem_free(idn.intr.dmv_data, idn.intr.dmv_data_len); - idn.intr.dmv_data = NULL; -} - -/* - * High-level (soft interrupt) handler for DMV interrupts - */ -/*ARGSUSED0*/ -static uint_t -idn_handler(caddr_t unused, caddr_t unused2) -{ -#ifdef DEBUG - int count = 0; -#endif /* DEBUG */ - int cpuid = (int)CPU->cpu_id; - ushort_t mtype, atype; - idn_dmv_msg_t *xp, *xplimit; - procname_t proc = "idn_handler"; - - ASSERT(getpil() >= idn_pil); - flush_windows(); - - /* - * 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. - */ - lock_clear(&idn_dmv_data->idn_dmv_cpu[cpuid].idn_dmv_active); - - xp = idn_iv_queue[cpuid]; - xplimit = xp + idn_dmv_pending_max; - xp += idn_intr_index[cpuid]; - /* - * As long as there's stuff that's READY in the - * queue, keep processing. - */ - while (lock_try(&xp->iv_ready)) { - - ASSERT(lock_try(&xp->iv_inuse) == 0); - - mtype = (ushort_t)xp->iv_mtype; - mtype &= IDNP_MSGTYPE_MASK | IDNP_ACKNACK_MASK; - atype = (ushort_t)xp->iv_atype; - - if (((int)xp->iv_ver == idn.version) && mtype) { - idn_protojob_t *jp; -#ifdef DEBUG - STRING(mstr); - STRING(astr); - - INUM2STR(mtype, mstr); - if ((mtype & IDNP_MSGTYPE_MASK) == 0) { - INUM2STR(atype, astr); - (void) strcat(mstr, "/"); - (void) strcat(mstr, astr); - } - - count++; - - PR_XDC("%s:%d:%d RECV: scpu = %d, msg = 0x%x(%s)\n", - proc, (int)xp->iv_domid, count, - (int)xp->iv_cpuid, mtype, mstr); - PR_XDC("%s:%d:%d R-DATA: a0 = 0x%x, a1 = 0x%x\n", - proc, (int)xp->iv_domid, count, - xp->iv_xargs0, xp->iv_xargs1); - PR_XDC("%s:%d:%d R-DATA: a2 = 0x%x, a3 = 0x%x\n", - proc, (int)xp->iv_domid, count, - xp->iv_xargs2, xp->iv_xargs3); -#endif /* DEBUG */ - - if (mtype == IDNP_DATA) { - jp = NULL; - /* - * 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. - */ - idn_signal_data_server((int)xp->iv_domid, - (ushort_t)xp->iv_xargs0); - } else { - jp = idn_protojob_alloc(KM_NOSLEEP); - /* - * 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) { - jp->j_msg.m_domid = (int)xp->iv_domid; - jp->j_msg.m_cpuid = (int)xp->iv_cpuid; - jp->j_msg.m_msgtype = mtype; - jp->j_msg.m_acktype = atype; - jp->j_msg.m_cookie = xp->iv_cookie; - SET_XARGS(jp->j_msg.m_xargs, - xp->iv_xargs0, xp->iv_xargs1, - xp->iv_xargs2, xp->iv_xargs3); - } - - } - membar_ldst_stst(); - - lock_clear(&xp->iv_inuse); - - if (jp) - idn_protojob_submit(jp->j_msg.m_domid, jp); - } else { - membar_ldst_stst(); - IDN_GKSTAT_INC(gk_dropped_intrs); - lock_clear(&xp->iv_inuse); - } - - if (++xp == xplimit) - xp = idn_iv_queue[cpuid]; - } - - idn_intr_index[cpuid] = xp - idn_iv_queue[cpuid]; - - return (DDI_INTR_CLAIMED); -} - -void -idn_awol_event_set(boardset_t boardset) -{ - idnsb_event_t *sbp; - procname_t proc = "idn_awol_event_set"; - - ASSERT(IDN_GLOCK_IS_EXCL()); - - mutex_enter(&idn.idnsb_mutex); - sbp = idn.idnsb_eventp; - if (sbp == NULL) { - cmn_err(CE_WARN, "IDN: 133: sigblock event area missing"); - cmn_err(CE_CONT, - "IDN: 134: unable to mark boardset (0x%x) AWOL\n", - boardset); - mutex_exit(&idn.idnsb_mutex); - return; - } - - if (boardset == 0) { - PR_PROTO("%s: AWOL BOARDSET is 0, NO EVENT <<<<<<<<<<<<<<<\n", - proc); - mutex_exit(&idn.idnsb_mutex); - return; - } else { - PR_PROTO("%s: MARKING BOARDSET (0x%x) AWOL\n", proc, boardset); - } - SSIEVENT_ADD(sbp, SSIEVENT_AWOL, boardset); - mutex_exit(&idn.idnsb_mutex); -} - -void -idn_awol_event_clear(boardset_t boardset) -{ - idnsb_event_t *sbp; - procname_t proc = "idn_awol_event_clear"; - - ASSERT(IDN_GLOCK_IS_EXCL()); - - mutex_enter(&idn.idnsb_mutex); - sbp = idn.idnsb_eventp; - if (sbp == NULL) { - cmn_err(CE_WARN, "IDN: 133: sigblock event area missing"); - cmn_err(CE_CONT, - "IDN: 134: unable to mark boardset (0x%x) AWOL\n", - boardset); - mutex_exit(&idn.idnsb_mutex); - return; - } - - if (boardset == 0) { - PR_PROTO("%s: AWOL BOARDSET is 0, NO EVENT <<<<<<<<<<<<<<<\n", - proc); - mutex_exit(&idn.idnsb_mutex); - return; - } else { - PR_PROTO("%s: CLEARING BOARDSET (0x%x) AWOL\n", proc, boardset); - } - SSIEVENT_DEL(sbp, SSIEVENT_AWOL, boardset); - mutex_exit(&idn.idnsb_mutex); -} - -static void -idn_gkstat_init() -{ - struct kstat *ksp; - struct idn_gkstat_named *sgkp; - -#ifdef kstat - if ((ksp = kstat_create(IDNNAME, ddi_get_instance(idn.dip), - IDNNAME, "net", KSTAT_TYPE_NAMED, - sizeof (struct idn_gkstat_named) / sizeof (kstat_named_t), - KSTAT_FLAG_PERSISTENT)) == NULL) { -#else - if ((ksp = kstat_create(IDNNAME, ddi_get_instance(idn.dip), - IDNNAME, "net", KSTAT_TYPE_NAMED, - sizeof (struct idn_gkstat_named) / - sizeof (kstat_named_t), 0)) == NULL) { -#endif /* kstat */ - cmn_err(CE_CONT, "IDN: 135: %s: %s\n", - IDNNAME, "kstat_create failed"); - return; - } - - idn.ksp = ksp; - sgkp = (struct idn_gkstat_named *)(ksp->ks_data); - kstat_named_init(&sgkp->sk_curtime, "curtime", - KSTAT_DATA_ULONG); - kstat_named_init(&sgkp->sk_reconfigs, "reconfigs", - KSTAT_DATA_ULONG); - kstat_named_init(&sgkp->sk_reconfig_last, "reconfig_last", - KSTAT_DATA_ULONG); - kstat_named_init(&sgkp->sk_reaps, "reaps", - KSTAT_DATA_ULONG); - kstat_named_init(&sgkp->sk_reap_last, "reap_last", - KSTAT_DATA_ULONG); - kstat_named_init(&sgkp->sk_links, "links", - KSTAT_DATA_ULONG); - kstat_named_init(&sgkp->sk_link_last, "link_last", - KSTAT_DATA_ULONG); - kstat_named_init(&sgkp->sk_unlinks, "unlinks", - KSTAT_DATA_ULONG); - kstat_named_init(&sgkp->sk_unlink_last, "unlink_last", - KSTAT_DATA_ULONG); - kstat_named_init(&sgkp->sk_buffail, "buf_fail", - KSTAT_DATA_ULONG); - kstat_named_init(&sgkp->sk_buffail_last, "buf_fail_last", - KSTAT_DATA_ULONG); - kstat_named_init(&sgkp->sk_slabfail, "slab_fail", - KSTAT_DATA_ULONG); - kstat_named_init(&sgkp->sk_slabfail_last, "slab_fail_last", - KSTAT_DATA_ULONG); - kstat_named_init(&sgkp->sk_slabfail_last, "slab_fail_last", - KSTAT_DATA_ULONG); - kstat_named_init(&sgkp->sk_reap_count, "reap_count", - KSTAT_DATA_ULONG); - kstat_named_init(&sgkp->sk_dropped_intrs, "dropped_intrs", - KSTAT_DATA_ULONG); - ksp->ks_update = idn_gkstat_update; - ksp->ks_private = (void *)NULL; - kstat_install(ksp); -} - -static void -idn_gkstat_deinit() -{ - if (idn.ksp) - kstat_delete(idn.ksp); - idn.ksp = NULL; -} - -static int -idn_gkstat_update(kstat_t *ksp, int rw) -{ - struct idn_gkstat_named *sgkp; - - sgkp = (struct idn_gkstat_named *)ksp->ks_data; - - if (rw == KSTAT_WRITE) { - sg_kstat.gk_reconfigs = sgkp->sk_reconfigs.value.ul; - sg_kstat.gk_reconfig_last = sgkp->sk_reconfig_last.value.ul; - sg_kstat.gk_reaps = sgkp->sk_reaps.value.ul; - sg_kstat.gk_reap_last = sgkp->sk_reap_last.value.ul; - sg_kstat.gk_links = sgkp->sk_links.value.ul; - sg_kstat.gk_link_last = sgkp->sk_link_last.value.ul; - sg_kstat.gk_unlinks = sgkp->sk_unlinks.value.ul; - sg_kstat.gk_unlink_last = sgkp->sk_unlink_last.value.ul; - sg_kstat.gk_buffail = sgkp->sk_buffail.value.ul; - sg_kstat.gk_buffail_last = sgkp->sk_buffail_last.value.ul; - sg_kstat.gk_slabfail = sgkp->sk_slabfail.value.ul; - sg_kstat.gk_slabfail_last = sgkp->sk_slabfail_last.value.ul; - sg_kstat.gk_reap_count = sgkp->sk_reap_count.value.ul; - sg_kstat.gk_dropped_intrs = sgkp->sk_dropped_intrs.value.ul; - } else { - sgkp->sk_curtime.value.ul = ddi_get_lbolt(); - sgkp->sk_reconfigs.value.ul = sg_kstat.gk_reconfigs; - sgkp->sk_reconfig_last.value.ul = sg_kstat.gk_reconfig_last; - sgkp->sk_reaps.value.ul = sg_kstat.gk_reaps; - sgkp->sk_reap_last.value.ul = sg_kstat.gk_reap_last; - sgkp->sk_links.value.ul = sg_kstat.gk_links; - sgkp->sk_link_last.value.ul = sg_kstat.gk_link_last; - sgkp->sk_unlinks.value.ul = sg_kstat.gk_unlinks; - sgkp->sk_unlink_last.value.ul = sg_kstat.gk_unlink_last; - sgkp->sk_buffail.value.ul = sg_kstat.gk_buffail; - sgkp->sk_buffail_last.value.ul = sg_kstat.gk_buffail_last; - sgkp->sk_slabfail.value.ul = sg_kstat.gk_slabfail; - sgkp->sk_slabfail_last.value.ul = sg_kstat.gk_slabfail_last; - sgkp->sk_reap_count.value.ul = sg_kstat.gk_reap_count; - sgkp->sk_dropped_intrs.value.ul = sg_kstat.gk_dropped_intrs; - } - - return (0); -} - -#ifdef DEBUG -#define RW_HISTORY 100 -static uint_t rw_history[NCPU][RW_HISTORY]; -static int rw_index[NCPU]; -#endif /* DEBUG */ - -static int -idn_rw_mem(idnop_t *idnop) -{ - uint_t lo_off, hi_off; - int rw, blksize, num; - int cpuid; - register int n, idx; - char *ibuf, *obuf; - char *smraddr; - struct seg *segp; - ulong_t randx; - kmutex_t slock; - kcondvar_t scv; - static int orig_gstate = IDNGS_IGNORE; - extern struct seg ktextseg; - -#define RANDOM_INIT() (randx = ddi_get_lbolt()) -#define RANDOM(a, b) \ - (((a) >= (b)) ? \ - (a) : (((randx = randx * 1103515245L + 12345) % ((b)-(a))) + (a))) - - RANDOM_INIT(); - - lo_off = idnop->rwmem.lo_off; - hi_off = idnop->rwmem.hi_off; - blksize = idnop->rwmem.blksize; - num = idnop->rwmem.num; - rw = idnop->rwmem.rw; /* 0 = rd, 1 = wr, 2 = rd/wr */ - - if (((hi_off > (uint_t)MB2B(IDN_SMR_SIZE)) || (lo_off >= hi_off) || - (blksize <= 0) || (blksize > (hi_off - lo_off)) || (num <= 0)) && - (idnop->rwmem.goawol == -1)) { - return (EINVAL); - } - - if (idnop->rwmem.goawol && (orig_gstate == IDNGS_IGNORE)) { - IDN_GLOCK_EXCL(); - cmn_err(CE_WARN, "IDN: Local domain going into IGNORE MODE!!"); - orig_gstate = idn.state; - IDN_GSTATE_TRANSITION(IDNGS_IGNORE); - IDN_GUNLOCK(); - - } else if (!idnop->rwmem.goawol && (orig_gstate != IDNGS_IGNORE)) { - IDN_GLOCK_EXCL(); - cmn_err(CE_WARN, - "IDN: Local domain restoring original state %s(%d)", - idngs_str[orig_gstate], (int)orig_gstate); - IDN_GSTATE_TRANSITION(orig_gstate); - orig_gstate = IDNGS_IGNORE; - IDN_GUNLOCK(); - } - /* - * Just requested AWOL. - */ - if (num == 0) - return (0); - /* - * Default READ only. - */ - ibuf = (char *)kmem_alloc(blksize, KM_SLEEP); - if (rw == 1) { - /* - * WRITE only. - */ - obuf = ibuf; - ibuf = NULL; - } else if (rw == 2) { - /* - * READ/WRITE. - */ - obuf = (char *)kmem_alloc(blksize, KM_SLEEP); - for (segp = &ktextseg; segp; segp = AS_SEGNEXT(&kas, segp)) { - if (segp->s_size >= blksize) - break; - } - if (segp == NULL) { - cmn_err(CE_WARN, - "IDN: blksize (%d) too large", blksize); - return (EINVAL); - } - bcopy(segp->s_base, obuf, blksize); - } - - mutex_init(&slock, NULL, MUTEX_DEFAULT, NULL); - cv_init(&scv, NULL, CV_DEFAULT, NULL); - - cmn_err(CE_NOTE, - "IDN: starting %s of %d blocks of %d bytes each...", - (rw == 1) ? "W-ONLY" : (rw == 2) ? "RW" : "R-ONLY", - num, blksize); - - for (n = 0; n < num; n++) { - uint_t rpos; - - if ((hi_off - lo_off) > blksize) - rpos = RANDOM(lo_off, (hi_off - blksize)); - else - rpos = lo_off; - smraddr = IDN_OFFSET2ADDR(rpos); - - cpuid = (int)CPU->cpu_id; -#ifdef DEBUG - idx = rw_index[cpuid]++ % RW_HISTORY; - rw_history[cpuid][idx] = rpos; -#endif /* DEBUG */ - - switch (rw) { - case 0: - bcopy(smraddr, ibuf, blksize); - break; - case 1: - bcopy(obuf, smraddr, blksize); - break; - case 2: - if (n & 1) - bcopy(obuf, smraddr, blksize); - else - bcopy(smraddr, ibuf, blksize); - break; - default: - break; - } - if (!(n % 1000)) { - int rv; - - mutex_enter(&slock); - rv = cv_reltimedwait_sig(&scv, &slock, hz, - TR_CLOCK_TICK); - mutex_exit(&slock); - if (rv == 0) - break; - } - } - - cv_destroy(&scv); - mutex_destroy(&slock); - - if (ibuf) - kmem_free(ibuf, blksize); - if (obuf) - kmem_free(obuf, blksize); - - return (0); -} - -void -inum2str(uint_t inum, char str[]) -{ - uint_t acknack; - - str[0] = '\0'; - - acknack = (inum & IDNP_ACKNACK_MASK); - inum &= ~IDNP_ACKNACK_MASK; - - if (!inum && !acknack) { - (void) strcpy(str, idnm_str[0]); - return; - } - - if (inum == 0) { - (void) strcpy(str, (acknack & IDNP_ACK) ? "ack" : "nack"); - } else { - if (inum < IDN_NUM_MSGTYPES) - (void) strcpy(str, idnm_str[inum]); - else - (void) sprintf(str, "0x%x?", inum); - if (acknack) { - if (acknack & IDNP_ACK) - (void) strcat(str, "+ack"); - else - (void) strcat(str, "+nack"); - } - } -} - -boardset_t -cpuset2boardset(cpuset_t portset) -{ - register int c; - register boardset_t bset; - - bset = 0; - for (c = 0; c < NCPU; ) - if (CPU_IN_SET(portset, c)) { - BOARDSET_ADD(bset, CPUID_TO_BOARDID(c)); - c = (c + 4) & ~3; - } else { - c++; - } - - return (bset); -} - -void -cpuset2str(cpuset_t cset, char buffer[]) -{ - register int c, n; - - buffer[0] = '\0'; - for (c = n = 0; c < NCPU; c++) { - if (!CPU_IN_SET(cset, c)) - continue; -#ifdef DEBUG - if (strlen(buffer) >= _DSTRLEN) { - PR_PROTO("************* WARNING WARNING WARNING\n"); - PR_PROTO("cpuset2str(cpu = %d) buffer " - "OVERFLOW <<<<<<\n", c); - PR_PROTO("*******************************\n"); - (void) sprintf(&buffer[_DSTRLEN-6], "*OVER"); - return; - } -#endif /* DEBUG */ - if (n == 0) - (void) sprintf(buffer, "%d", c); - else - (void) sprintf(buffer, "%s, %d", buffer, c); - n++; - } -} - -void -domainset2str(domainset_t dset, char buffer[]) -{ - /* - * Since domainset_t and boardset_t are the - * same (max = MAX_DOMAINS = MAX_BOARDS) we - * can just overload boardset2str(). - */ - mask2str((uint_t)dset, buffer, MAX_DOMAINS); -} - -void -boardset2str(boardset_t bset, char buffer[]) -{ - mask2str((uint_t)bset, buffer, MAX_BOARDS); -} - -void -mask2str(uint_t mask, char buffer[], int maxnum) -{ - int n, i; - - buffer[0] = '\0'; - for (i = n = 0; i < maxnum; i++) { - if ((mask & (1 << i)) == 0) - continue; - if (n == 0) - (void) sprintf(buffer, "%d", i); - else - (void) sprintf(buffer, "%s, %d", buffer, i); - n++; - } -} - -int -idnxdc(int domid, idn_msgtype_t *mtp, - uint_t arg1, uint_t arg2, - uint_t arg3, uint_t arg4) -{ - int rv, cpuid, tcpuid; - uint_t cookie; - uint64_t pdata; - uint64_t dmv_word0, dmv_word1, dmv_word2; - idn_domain_t *dp = &idn_domain[domid]; - extern kmutex_t xc_sys_mutex; - extern int xc_spl_enter[]; - procname_t proc = "idnxdc"; - - - if (idn_snoop) { - int bd; - STRING(str); - STRING(mstr); - STRING(astr); - - INUM2STR(mtp->mt_mtype, mstr); - if ((mtp->mt_mtype & IDNP_MSGTYPE_MASK) == 0) { - INUM2STR(arg1, astr); - (void) sprintf(str, "%s/%s", mstr, astr); - } else { - (void) strcpy(str, mstr); - } - if (dp->dcpu == IDN_NIL_DCPU) - bd = -1; - else - bd = CPUID_TO_BOARDID(dp->dcpu); - SNOOP_IDN(0, str, bd, arg1, arg2, arg3, arg4); - } - - /* - * 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). - */ - if ((mtp->mt_mtype & IDNP_MSGTYPE_MASK) == IDNP_NEGO) - cookie = IDN_MAKE_COOKIE(dp->dcookie_recv, mtp->mt_cookie); - else - cookie = IDN_MAKE_COOKIE(dp->dcookie_send, mtp->mt_cookie); - - pdata = IDN_MAKE_PDATA(mtp->mt_mtype, mtp->mt_atype, cookie); - - dmv_word0 = DMV_MAKE_DMV(idn.intr.dmv_inum, pdata); - dmv_word1 = ((uint64_t)arg1 << 32) | (uint64_t)arg2; - dmv_word2 = ((uint64_t)arg3 << 32) | (uint64_t)arg4; - - ASSERT((dp->dcpu != IDN_NIL_DCPU) || - (dp->dcpu_last != IDN_NIL_DCPU)); - - tcpuid = (dp->dcpu == IDN_NIL_DCPU) ? - dp->dcpu_last : dp->dcpu; - - if (tcpuid == IDN_NIL_DCPU) { - PR_PROTO("%s:%d: cpu/cpu_last == NIL_DCPU\n", - proc, domid); - return (-1); - } - - mutex_enter(&xc_sys_mutex); - cpuid = (int)CPU->cpu_id; - xc_spl_enter[cpuid] = 1; - - idnxf_init_mondo(dmv_word0, dmv_word1, dmv_word2); - - rv = idnxf_send_mondo(STARFIRE_UPAID2HWMID(tcpuid)); - - xc_spl_enter[cpuid] = 0; - mutex_exit(&xc_sys_mutex); - - return (rv); -} - -void -idnxdc_broadcast(domainset_t domset, idn_msgtype_t *mtp, - uint_t arg1, uint_t arg2, - uint_t arg3, uint_t arg4) -{ - int d; - - for (d = 0; d < MAX_DOMAINS; d++) { - idn_domain_t *dp; - - if (!DOMAIN_IN_SET(domset, d)) - continue; - - dp = &idn_domain[d]; - if (dp->dcpu == IDN_NIL_DCPU) - continue; - - (void) IDNXDC(d, mtp, arg1, arg2, arg3, arg4); - } -} - -#define PROM_SMRSIZE 0x1 -#define PROM_SMRADDR 0x2 -#define PROM_SMRPROPS (PROM_SMRSIZE | PROM_SMRADDR) -/* - * Locate the idn-smr-size property to determine the size of the SMR - * region for the SSI. Value inherently enables/disables SSI capability. - */ -static int -idn_prom_getsmr(uint_t *smrsz, uint64_t *paddrp, uint64_t *sizep) -{ - pnode_t nodeid; - int found = 0; - int len; - uint_t smrsize = 0; - uint64_t obpaddr, obpsize; - struct smraddr { - uint32_t hi_addr; - uint32_t lo_addr; - uint32_t hi_size; - uint32_t lo_size; - } smraddr; - procname_t proc = "idn_prom_getsmr"; - - bzero(&smraddr, sizeof (smraddr)); - /* - * idn-smr-size is a property of the "memory" node and - * is defined in megabytes. - */ - nodeid = prom_finddevice("/memory"); - - if (nodeid != OBP_NONODE) { - len = prom_getproplen(nodeid, IDN_PROP_SMRSIZE); - if (len == sizeof (smrsize)) { - (void) prom_getprop(nodeid, IDN_PROP_SMRSIZE, - (caddr_t)&smrsize); - found |= PROM_SMRSIZE; - } - len = prom_getproplen(nodeid, IDN_PROP_SMRADDR); - if (len == sizeof (smraddr)) { - (void) prom_getprop(nodeid, IDN_PROP_SMRADDR, - (caddr_t)&smraddr); - found |= PROM_SMRADDR; - } - } - - if (found != PROM_SMRPROPS) { - if ((found & PROM_SMRSIZE) == 0) - cmn_err(CE_WARN, - "IDN: 136: \"%s\" property not found, " - "disabling IDN", - IDN_PROP_SMRSIZE); - if (smrsize && ((found & PROM_SMRADDR) == 0)) - cmn_err(CE_WARN, - "IDN: 136: \"%s\" property not found, " - "disabling IDN", - IDN_PROP_SMRADDR); - return (-1); - } - - if (smrsize == 0) { - PR_SMR("%s: IDN DISABLED (idn_smr_size = 0)\n", proc); - cmn_err(CE_NOTE, "!IDN: 137: SMR size is 0, disabling IDN"); - - } else if (smrsize > IDN_SMR_MAXSIZE) { - PR_SMR("%s: IDN DISABLED (idn_smr_size too big %d > %d MB)\n", - proc, smrsize, IDN_SMR_MAXSIZE); - cmn_err(CE_WARN, - "!IDN: 138: SMR size (%dMB) is too big (max = %dMB), " - "disabling IDN", - smrsize, IDN_SMR_MAXSIZE); - smrsize = 0; - } else { - *smrsz = smrsize; - found &= ~PROM_SMRSIZE; - } - - obpaddr = ((uint64_t)smraddr.hi_addr << 32) | - (uint64_t)smraddr.lo_addr; - obpsize = ((uint64_t)smraddr.hi_size << 32) | - (uint64_t)smraddr.lo_size; - - if (obpsize == 0) { - if (smrsize > 0) { - cmn_err(CE_WARN, "!IDN: 139: OBP region for " - "SMR is 0 length"); - } - } else if (obpsize < (uint64_t)MB2B(smrsize)) { - cmn_err(CE_WARN, - "!IDN: 140: OBP region (%ld B) smaller " - "than requested size (%ld B)", - obpsize, MB2B(smrsize)); - } else if ((obpaddr & ((uint64_t)IDN_SMR_ALIGN - 1)) != 0) { - cmn_err(CE_WARN, - "!IDN: 141: OBP region (0x%lx) not on (0x%x) " - "boundary", obpaddr, IDN_SMR_ALIGN); - } else { - *sizep = obpsize; - *paddrp = obpaddr; - found &= ~PROM_SMRADDR; - } - - return (found ? -1 : 0); -} - -void -idn_init_autolink() -{ - idnsb_event_t *sbp; - procname_t proc = "idn_init_autolink"; - - mutex_enter(&idn.idnsb_mutex); - if ((sbp = idn.idnsb_eventp) == NULL) { - PR_PROTO("%s: IDN private sigb (event) area is NULL\n", proc); - mutex_exit(&idn.idnsb_mutex); - return; - } - - PR_PROTO("%s: marking domain IDN ready.\n", proc); - - bzero(sbp, sizeof (*sbp)); - - sbp->idn_version = (uchar_t)idn.version; - SSIEVENT_SET(sbp, SSIEVENT_BOOT, 0); - (void) strncpy(sbp->idn_cookie_str, SSIEVENT_COOKIE, - SSIEVENT_COOKIE_LEN); - mutex_exit(&idn.idnsb_mutex); -} - -void -idn_deinit_autolink() -{ - idnsb_event_t *sbp; - procname_t proc = "idn_deinit_autolink"; - - mutex_enter(&idn.idnsb_mutex); - if ((sbp = idn.idnsb_eventp) == NULL) { - PR_PROTO("%s: IDN private sigb (event) area is NULL\n", proc); - mutex_exit(&idn.idnsb_mutex); - return; - } - - PR_PROTO("%s: marking domain IDN unavailable.\n", proc); - - sbp->idn_version = (uchar_t)idn.version; - SSIEVENT_CLEAR(sbp, SSIEVENT_BOOT, 0); - (void) strncpy(sbp->idn_cookie_str, SSIEVENT_COOKIE, - SSIEVENT_COOKIE_LEN); - mutex_exit(&idn.idnsb_mutex); -} - -void -_make64cpumask(cpuset_t *csetp, uint_t upper, uint_t lower) -{ - int c; - - CPUSET_ZERO(*csetp); - - for (c = 0; c < 32; c++) { - if (lower & (1 << c)) { - CPUSET_ADD(*csetp, c); - } - if (upper & (1 << (c + 32))) { - CPUSET_ADD(*csetp, c + 32); - } - } -} - -uint_t -_lower32cpumask(cpuset_t cset) -{ - int c; - uint_t set = 0; - - for (c = 0; c < 32; c++) - if (CPU_IN_SET(cset, c)) - set |= 1 << c; - - return (set); -} - -uint_t -_upper32cpumask(cpuset_t cset) -{ - int c; - uint_t set = 0; - - for (c = 32; c < NCPU; c++) - if (CPU_IN_SET(cset, c)) - set |= 1 << (c - 32); - - return (set); -} - -#ifdef DEBUG -int -debug_idnxdc(char *f, int domid, idn_msgtype_t *mtp, - uint_t a1, uint_t a2, uint_t a3, uint_t a4) -{ - idn_domain_t *dp = &idn_domain[domid]; - int rv, cpuid, bd; - static int xx = 0; - STRING(str); - STRING(mstr); - STRING(astr); - - xx++; - INUM2STR(mtp->mt_mtype, mstr); - if ((mtp->mt_mtype & IDNP_MSGTYPE_MASK) == 0) { - INUM2STR(a1, astr); - (void) sprintf(str, "%s/%s", mstr, astr); - } else { - (void) strcpy(str, mstr); - } - - if ((cpuid = dp->dcpu) == IDN_NIL_DCPU) - bd = -1; - else - bd = CPUID_TO_BOARDID(cpuid); - - SNOOP_IDN(0, str, bd, a1, a2, a3, a4); - - PR_XDC("%s:%d:%d SENT: scpu = %d, msg = 0x%x(%s)\n", - f, domid, xx, cpuid, mtp->mt_mtype, str); - PR_XDC("%s:%d:%d S-DATA: a1 = 0x%x, a2 = 0x%x\n", - f, domid, xx, a1, a2); - PR_XDC("%s:%d:%d S-DATA: a3 = 0x%x, a4 = 0x%x\n", - f, domid, xx, a3, a4); - - rv = idnxdc(domid, mtp, a1, a2, a3, a4); - if (rv != 0) { - PR_XDC("%s:%d:%d: WARNING: idnxdc(cpu %d) FAILED\n", - f, domid, xx, cpuid); - } - - return (rv); -} - -caddr_t -_idn_getstruct(char *structname, int size) -{ - caddr_t ptr; - procname_t proc = "GETSTRUCT"; - - ptr = kmem_zalloc(size, KM_SLEEP); - - PR_ALLOC("%s: ptr 0x%p, struct(%s), size = %d\n", - proc, (void *)ptr, structname, size); - - return (ptr); -} - -void -_idn_freestruct(caddr_t ptr, char *structname, int size) -{ - procname_t proc = "FREESTRUCT"; - - PR_ALLOC("%s: ptr 0x%p, struct(%s), size = %d\n", - proc, (void *)ptr, structname, size); - - ASSERT(ptr != NULL); - kmem_free(ptr, size); -} -#endif /* DEBUG */ diff --git a/usr/src/uts/sun4u/starfire/io/idn.conf b/usr/src/uts/sun4u/starfire/io/idn.conf deleted file mode 100644 index 7bd23982b1..0000000000 --- a/usr/src/uts/sun4u/starfire/io/idn.conf +++ /dev/null @@ -1,35 +0,0 @@ -# -# 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 -# or http://www.opensolaris.org/os/licensing. -# 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 (c) 1998 by Sun Microsystems, Inc. -# All rights reserved. -# -#ident "%Z%%M% %I% %E% SMI" - -name="idn" parent="pseudo" instance=0; -name="idn" parent="pseudo" instance=1; -name="idn" parent="pseudo" instance=2; -name="idn" parent="pseudo" instance=3; -name="idn" parent="pseudo" instance=4; -name="idn" parent="pseudo" instance=5; -name="idn" parent="pseudo" instance=6; -name="idn" parent="pseudo" instance=7; diff --git a/usr/src/uts/sun4u/starfire/io/idn_dlpi.c b/usr/src/uts/sun4u/starfire/io/idn_dlpi.c deleted file mode 100644 index 693499c041..0000000000 --- a/usr/src/uts/sun4u/starfire/io/idn_dlpi.c +++ /dev/null @@ -1,2295 +0,0 @@ -/* - * 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 - * or http://www.opensolaris.org/os/licensing. - * 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. - */ - -/* - * IDN DLPI support (based on QE implementation). - */ -#include <sys/types.h> -#include <sys/debug.h> -#include <sys/stropts.h> -#include <sys/stream.h> -#include <sys/systm.h> -#include <sys/cmn_err.h> -#include <sys/errno.h> -#ifdef xxx_trace -#include <sys/vtrace.h> -#endif /* xxx_trace */ -#include <sys/kmem.h> -#include <sys/ddi.h> -#include <sys/sunddi.h> -#include <sys/strsun.h> -#include <sys/stat.h> -#include <sys/kstat.h> -#include <sys/dlpi.h> -#include <sys/time.h> -#include <sys/cpuvar.h> - -#include <sys/idn.h> - -#ifdef IPV6 -#define IS_ETHERTYPE_IPV4(x) ((x) == ETHERTYPE_IP) -#define IS_ETHERTYPE_IPV6(x) ((x) == ETHERTYPE_IPV6) -#define IS_ETHERTYPE_IP(x) (IS_ETHERTYPE_IPV4(x) || IS_ETHERTYPE_IPV6(x)) -#else -#define IS_ETHERTYPE_IPV4(x) ((x) == ETHERTYPE_IP) -#define IS_ETHERTYPE_IPV6(x) (0) -#define IS_ETHERTYPE_IP IS_ETHERTYPE_IPV4 -#endif /* IPV6 */ - -#ifdef IDN_TRACE -/* - * This stuff should go into <sys/vtrace.h> - */ -#define TR_FAC_IDN 100 -/* - * TR_FAC_IDN tags - */ -#define TR_IDN_OPEN 0 -#define TR_IDN_CLOSE 1 -#define TR_IDN_WPUT_START 2 -#define TR_IDN_WPUT_END 3 -#define TR_IDN_WSRV_START 4 -#define TR_IDN_WSRV_END 5 -#define TR_IDN_START_START 6 -#define TR_IDN_START_END 7 -#define TR_IDN_INTR_START 8 -#define TR_IDN_INTR_END 9 -#define TR_IDN_READ_START 10 -#define TR_IDN_READ_END 11 -#define TR_IDN_SENDUP_START 12 -#define TR_IDN_SENDUP_END 13 -#define TR_IDN_ADDUDIND_START 14 -#define TR_IDN_ADDUDIND_END 15 -#define TR_IDN_GETBUF_START 16 -#define TR_IDN_GETBUF_END 17 -#define TR_IDN_FREEBUF_START 18 -#define TR_IDN_FREEBUF_END 19 -#define TR_IDN_PROTO_START 20 -#define TR_IDN_PROTO_END 21 -#define TR_IDN_INIT_START 22 -#define TR_IDN_INIT_END 23 -#define TR_IDN_PROTO_IN 24 -#define TR_IDN_PROTO_OUT 25 - -#define IDNTRACE(fac, tag) (printf("idn.TRACE: ")) - -#define TRACE_0(fac, tag, name) \ - IDNTRACE((fac), (tag)); \ - printf(name); printf("\n"); - -#define TRACE_1(fac, tag, name, d1) \ - IDNTRACE((fac), (tag)); \ - printf(name, (d1)); printf("\n"); - -#define TRACE_2(fac, tag, name, d1, d2) \ - IDNTRACE((fac), (tag)); \ - printf(name, (d1), (d2)); printf("\n"); - -#define TRACE_3(fac, tag, name, d1, d2, d3) \ - IDNTRACE((fac), (tag)); \ - printf(name, (d1), (d2), (d3)); printf("\n"); - -#define TRACE_4(fac, tag, name, d1, d2, d3, d4) \ - IDNTRACE((fac), (tag)); \ - printf(name, (d1), (d2), (d3), (d4)); printf("\n"); - -#define TRACE_5(fac, tag, name, d1, d2, d3, d4, d5) \ - IDNTRACE((fac), (tag)); \ - printf(name, (d1), (d2), (d3), (d4), (d5)); printf("\n"); - -#else /* IDN_TRACE */ - -#define TRACE_0(fac, tag, name) {} -#define TRACE_1(fac, tag, name, d1) {} -#define TRACE_2(fac, tag, name, d1, d2) {} -#define TRACE_3(fac, tag, name, d1, d2, d3) {} -#define TRACE_4(fac, tag, name, d1, d2, d3, d4) {} -#define TRACE_5(fac, tag, name, d1, d2, d3, d4, d5) {} - -#endif /* IDN_TRACE */ - -#ifdef DEBUG -#define DLERRORACK(qq, mm, cc, ee, xx) \ -{ \ - PR_DLPI("dlpi: ERRORACK: 0x%x(%s), err = 0x%x(%s)\n", \ - (uint_t)(cc), dlprim2str(cc), \ - (uint_t)(ee), dlerr2str((int)(ee))); \ - dlerrorack((qq), (mm), (cc), (ee), (xx)); \ -} -#define DLOKACK(qq, mm, cc) \ -{ \ - PR_DLPI("dlpi: OKACK: 0x%x(%s)\n", (cc), dlprim2str(cc)); \ - dlokack((qq), (mm), (cc)); \ -} -#define DLBINDACK(qq, mm, ss, aa, ll, xx, yy) \ -{ \ - PR_DLPI("dlpi: BINDACK: eth=%x:%x:%x:%x:%x:%x, sap=0x%x, l=%d\n", \ - ((struct idndladdr *)(aa))->dl_phys.ether_addr_octet[0], \ - ((struct idndladdr *)(aa))->dl_phys.ether_addr_octet[1], \ - ((struct idndladdr *)(aa))->dl_phys.ether_addr_octet[2], \ - ((struct idndladdr *)(aa))->dl_phys.ether_addr_octet[3], \ - ((struct idndladdr *)(aa))->dl_phys.ether_addr_octet[4], \ - ((struct idndladdr *)(aa))->dl_phys.ether_addr_octet[5], \ - (uint_t)(ss), (int)(ll)); \ - dlbindack((qq), (mm), (ss), (aa), (ll), (xx), (yy)); \ -} -#define DLPHYSADDRACK(qq, mm, aa, ll) \ -{ \ - PR_DLPI("dlpi: PHYSACK: eth=%x:%x:%x:%x:%x:%x, l=%d\n", \ - ((struct idndladdr *)(aa))->dl_phys.ether_addr_octet[0], \ - ((struct idndladdr *)(aa))->dl_phys.ether_addr_octet[1], \ - ((struct idndladdr *)(aa))->dl_phys.ether_addr_octet[2], \ - ((struct idndladdr *)(aa))->dl_phys.ether_addr_octet[3], \ - ((struct idndladdr *)(aa))->dl_phys.ether_addr_octet[4], \ - ((struct idndladdr *)(aa))->dl_phys.ether_addr_octet[5], \ - (ll)); \ - dlphysaddrack((qq), (mm), (aa), (ll)); \ -} - -static char *dlerrstr[] = { - "DL_BADSAP", - "DL_BADADDR", - "DL_ACCESS", - "DL_OUTSTATE", - "DL_SYSERR", - "DL_BADCORR", - "DL_BADDATA", - "DL_UNSUPPORTED", - "DL_BADPPA", - "DL_BADPRIM", - "DL_BADQOSPARAM", - "DL_BADQOSTYPE", - "DL_BADTOKEN", - "DL_BOUND", - "DL_INITFAILED", - "DL_NOADDR", - "DL_NOTINIT", - "DL_UNDELIVERABLE", - "DL_NOTSUPPORTED", - "DL_TOOMANY", - "DL_NOTENAB", - "DL_BUSY", - "DL_NOAUTO", - "DL_NOXIDAUTO", - "DL_NOTESTAUTO", - "DL_XIDAUTO", - "DL_TESTAUTO", - "DL_PENDING" -}; -static int dlerrnum = (sizeof (dlerrstr) / sizeof (char *)); - -static char * -dlerr2str(int err) -{ - if ((err < 0) || (err >= dlerrnum)) - return ("unknown"); - else - return (dlerrstr[err]); -} - -static char * -dlprim2str(int prim) -{ - char *pstr; - - switch (prim) { - case DL_UNITDATA_REQ: pstr = "UNITDATA_REQ"; break; - case DL_ATTACH_REQ: pstr = "ATTACH_REQ"; break; - case DL_DETACH_REQ: pstr = "DETACH_REQ"; break; - case DL_BIND_REQ: pstr = "BIND_REQ"; break; - case DL_UNBIND_REQ: pstr = "UNBIND_REQ"; break; - case DL_INFO_REQ: pstr = "INFO_REQ"; break; - case DL_PROMISCON_REQ: pstr = "PROMISCON_REQ"; break; - case DL_PROMISCOFF_REQ: pstr = "PROMISCOFF_REQ"; break; - case DL_ENABMULTI_REQ: pstr = "ENABMULTI_REQ"; break; - case DL_DISABMULTI_REQ: pstr = "DISABMULTI_REQ"; break; - case DL_PHYS_ADDR_REQ: pstr = "PHYS_ADDR_REQ"; break; - case DL_SET_PHYS_ADDR_REQ: - pstr = "SET_PHYS_ADDR_REQ"; break; - default: pstr = "unsupported"; break; - } - return (pstr); -} -#else /* DEBUG */ -#define DLERRORACK(qq, mm, cc, ee, xx) \ - (dlerrorack((qq), (mm), (cc), (ee), (xx))) -#define DLOKACK(qq, mm, cc) \ - (dlokack((qq), (mm), (cc))) -#define DLBINDACK(qq, mm, ss, aa, ll, xx, yy) \ - (dlbindack((qq), (mm), (ss), (aa), (ll), (xx), (yy))) -#define DLPHYSADDRACK(qq, mm, aa, ll) \ - (dlphysaddrack((qq), (mm), (aa), (ll))) -#endif /* DEBUG */ - -#define IDNDL_ADDR_IS_MULTICAST(ap) (((ap)->ether_addr_octet[0] & 01) == 1) -/* - * MIB II broadcast/multicast packets - */ -#define IS_BROADCAST(ehp) \ - (ether_cmp(&(ehp)->ether_dhost, ðerbroadcastaddr) == 0) -#define IS_MULTICAST(ehp) \ - IDNDL_ADDR_IS_MULTICAST(&(ehp)->ether_dhost) -#define BUMP_InNUcast(sip, ehp) \ - if (IS_BROADCAST(ehp)) { \ - (sip)->si_kstat.si_brdcstrcv++; \ - } else if (IS_MULTICAST(ehp)) { \ - (sip)->si_kstat.si_multircv++; \ - } -#define BUMP_OutNUcast(sip, ehp) \ - if (IS_BROADCAST(ehp)) { \ - (sip)->si_kstat.si_brdcstxmt++; \ - } else if (IS_MULTICAST(ehp)) { \ - (sip)->si_kstat.si_multixmt++; \ - } - -/* - * Function prototypes. - */ -static int idndl_ioc_hdr_info(queue_t *, mblk_t *, int *); -static void idndl_areq(queue_t *, mblk_t *); -static void idndl_dreq(queue_t *, mblk_t *); -static void idndl_breq(queue_t *, mblk_t *); -static void idndl_ubreq(queue_t *, mblk_t *); -static void idndl_ireq(queue_t *, mblk_t *); -static void idndl_ponreq(queue_t *, mblk_t *); -static void idndl_poffreq(queue_t *, mblk_t *); -static void idndl_emreq(queue_t *, mblk_t *); -static void idndl_dmreq(queue_t *, mblk_t *); -static void idndl_pareq(queue_t *, mblk_t *); -#ifdef notdef -static void idndl_spareq(queue_t *, mblk_t *); -#endif /* notdef */ -static void idndl_udreq(queue_t *, mblk_t *); -static void serror(dev_info_t *dip, int idnerr, char *fmt, ...); -static mblk_t *idndl_addudind(struct idn *, mblk_t *, struct ether_addr *, - struct ether_addr *, int, ulong_t); -static void idndl_setipq(struct idn *); -static int idndl_mcmatch(struct idnstr *, struct ether_addr *); -static int idndl_stat_kstat_update(kstat_t *ksp, int rw); - -static int _idndl_ether2domain(struct ether_addr *eap); -static struct idn *_idndl_ether2sip(struct ether_addr *eap); - - -#define IDNSAPMATCH(sap, type, flags) ((sap == type)? 1 : \ - ((flags & IDNSALLSAP)? 1 : \ - ((sap <= ETHERMTU) && sap && (type <= ETHERMTU))? 1 : 0)) - -/* - * Our DL_INFO_ACK template. - */ -static dl_info_ack_t idninfoack = { - DL_INFO_ACK, /* dl_primitive */ - 0, /* dl_max_sdu (see idndl_dlpi_init()) */ - 0, /* dl_min_sdu */ - IDNADDRL, /* dl_addr_length */ - DL_ETHER, /* DL_OTHER, */ /* dl_mac_type */ - 0, /* dl_reserved */ - 0, /* dl_current_state */ - -2, /* dl_sap_length */ - DL_CLDLS, /* DL_CODLS? */ /* dl_service_mode */ - 0, /* dl_qos_length */ - 0, /* dl_qos_offset */ - 0, /* dl_range_length */ - 0, /* dl_range_offset */ - DL_STYLE2, /* dl_provider_style */ - sizeof (dl_info_ack_t), /* dl_addr_offset */ - DL_VERSION_2, /* dl_version */ - ETHERADDRL, /* dl_brdcst_addr_length */ - sizeof (dl_info_ack_t) + IDNADDRL, /* dl_brdcst_addr_offset */ - 0 /* dl_growth */ -}; - -/* - * Ethernet broadcast address definition. - */ -static struct ether_addr etherbroadcastaddr = { - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; - -/* - * -------------------------------------------------- - */ -void -idndl_localetheraddr(struct idn *sip, struct ether_addr *eap) -{ - int rv; - int instance; - procname_t proc = "idndl_localetheraddr"; - - ASSERT(sip && sip->si_dip && eap); - - instance = ddi_get_instance(sip->si_dip); - - PR_DLPI("%s: getting local etheraddr...\n", proc); - - rv = idndl_domain_etheraddr(idn.localid, instance, eap); - ASSERT(rv == 0); -} - -int -idndl_domain_etheraddr(int domid, int channel, struct ether_addr *eap) -{ - uchar_t netid; - procname_t proc = "idndl_domain_etheraddr"; - - if (idn_domain[domid].dcpu == IDN_NIL_DCPU) - return (-1); - - netid = (uchar_t)idn_domain[domid].dnetid; - - PR_DLPI("%s: dnetid = 0x%x, channel = 0x%x\n", - proc, (uint_t)netid, channel); - -#ifdef notdef - localetheraddr(NULL, eap); - - PR_DLPI("%s: localetheraddr = %x:%x:%x:%x:%x:%x\n", - proc, eap->ether_addr_octet[0], eap->ether_addr_octet[1], - eap->ether_addr_octet[2], eap->ether_addr_octet[3], - eap->ether_addr_octet[4], eap->ether_addr_octet[5]): -#endif /* notdef */ - - eap->ether_addr_octet[IDNETHER_ZERO] = 0; - eap->ether_addr_octet[IDNETHER_COOKIE1] = IDNETHER_COOKIE1_VAL; - eap->ether_addr_octet[IDNETHER_COOKIE2] = IDNETHER_COOKIE2_VAL; - eap->ether_addr_octet[IDNETHER_NETID] = netid; - eap->ether_addr_octet[IDNETHER_CHANNEL] = (uchar_t)channel; - eap->ether_addr_octet[IDNETHER_RESERVED] = IDNETHER_RESERVED_VAL; - - PR_DLPI("%s: domain %d: etheraddr = %x:%x:%x:%x:%x:%x\n", - proc, domid, - eap->ether_addr_octet[0], eap->ether_addr_octet[1], - eap->ether_addr_octet[2], eap->ether_addr_octet[3], - eap->ether_addr_octet[4], eap->ether_addr_octet[5]); - - return (0); -} - -#ifdef DEBUG -/* - */ -static int -_idndl_ether2domain(struct ether_addr *eap) -{ - uchar_t *eaop; - - eaop = eap->ether_addr_octet; - - ASSERT(IDNDL_ADDR_IS_MULTICAST(eap) || - ((eaop[IDNETHER_COOKIE1] == IDNETHER_COOKIE1_VAL) && - (eaop[IDNETHER_COOKIE2] == IDNETHER_COOKIE2_VAL)) || - ((eaop[IDNETHER_COOKIE1] == 0xff) && - (eaop[IDNETHER_COOKIE2] == 0xff))); - /* - * Note that (IDN_NIL_DOMID) will be returned if ether address is - * a broadcast 0xff. - */ - return (IDN_NETID2DOMID(eaop[IDNETHER_NETID])); -} - -/* - */ -static struct idn * -_idndl_ether2sip(struct ether_addr *eap) -{ - int instance; - struct idn *sip; - uchar_t *eaop; - procname_t proc = "_idndl_ether2sip"; - - eaop = eap->ether_addr_octet; - - if (!IDNDL_ADDR_IS_MULTICAST(eap) && - (((eaop[IDNETHER_COOKIE1] != IDNETHER_COOKIE1_VAL) || - (eaop[IDNETHER_COOKIE2] != IDNETHER_COOKIE2_VAL)) && - ((eaop[IDNETHER_COOKIE1] != 0xff) || - (eaop[IDNETHER_COOKIE2] != 0xff)))) { - - cmn_err(CE_WARN, - "IDN: 400: corrupted MAC header " - "(exp %x or 0xffff, act 0x%x)", - (IDNETHER_COOKIE1_VAL << 8) | - IDNETHER_COOKIE2_VAL, - (eaop[IDNETHER_COOKIE1] << 8) | - eaop[IDNETHER_COOKIE2]); - - return (NULL); - } - - if (IDNDL_ADDR_IS_MULTICAST(eap)) { - PR_DLPI("%s: MULTICAST ADDR *** ERROR ***\n", proc); - sip = NULL; - } else if (eaop[IDNETHER_CHANNEL] == 0xff) { - /* - * Received a broadcast. Need to manually - * find anybody the first running sip and use it. - * XXX - kind of kludgy - single threads broadcasts. - */ - PR_DLPI("%s: BROADCAST CHANNEL *** ERROR ***\n", proc); - sip = NULL; - } else { - instance = (int)eaop[IDNETHER_CHANNEL]; - - sip = IDN_INST2SIP(instance); - } - - return (sip); -} -#endif /* DEBUG */ - -void -idndl_dlpi_init() -{ - procname_t proc = "idndl_dlpi_init"; - - PR_DLPI("%s: setting dl_max_sdu to %ld (0x%lx) bytes\n", - proc, IDN_MTU, IDN_MTU); - /* - * This field is dynamic because the user may - * want to dynamically set it _before_ an IDNnet - * has been established via ndd(1M). - */ - idninfoack.dl_max_sdu = IDN_MTU; -} - -static int -idndl_stat_kstat_update(kstat_t *ksp, int rw) -{ - struct idn *sip; - struct idn_kstat_named *skp; - - sip = (struct idn *)ksp->ks_private; - skp = (struct idn_kstat_named *)ksp->ks_data; - - if (rw == KSTAT_WRITE) { -#if 0 - bzero(&sg_kstat.gk_kstat, sizeof (sg_kstat.gk_kstat)); -#endif /* 0 */ - bzero(&sip->si_kstat, sizeof (sip->si_kstat)); - - sip->si_kstat.si_ipackets = skp->sk_ipackets.value.ul; - sip->si_kstat.si_ierrors = skp->sk_ierrors.value.ul; - sip->si_kstat.si_opackets = skp->sk_opackets.value.ul; - sip->si_kstat.si_oerrors = skp->sk_oerrors.value.ul; - sip->si_kstat.si_txcoll = skp->sk_txcoll.value.ul; - sip->si_kstat.si_rxcoll = skp->sk_rxcoll.value.ul; - sip->si_kstat.si_crc = skp->sk_crc.value.ul; - sip->si_kstat.si_buff = skp->sk_buff.value.ul; - sip->si_kstat.si_nolink = skp->sk_nolink.value.ul; - sip->si_kstat.si_linkdown = skp->sk_linkdown.value.ul; - sip->si_kstat.si_inits = skp->sk_inits.value.ul; - sip->si_kstat.si_nocanput = skp->sk_nocanput.value.ul; - sip->si_kstat.si_allocbfail = skp->sk_allocbfail.value.ul; - sip->si_kstat.si_notbufs = skp->sk_notbufs.value.ul; - sip->si_kstat.si_reclaim = skp->sk_reclaim.value.ul; - sip->si_kstat.si_smraddr = skp->sk_smraddr.value.ul; - sip->si_kstat.si_txmax = skp->sk_txmax.value.ul; - sip->si_kstat.si_txfull = skp->sk_txfull.value.ul; - sip->si_kstat.si_xdcall = skp->sk_xdcall.value.ul; - sip->si_kstat.si_sigsvr = skp->sk_sigsvr.value.ul; - sip->si_kstat.si_mboxcrc = skp->sk_mboxcrc.value.ul; - /* - * MIB II kstat variables - */ - sip->si_kstat.si_rcvbytes = skp->sk_rcvbytes.value.ul; - sip->si_kstat.si_xmtbytes = skp->sk_xmtbytes.value.ul; - sip->si_kstat.si_multircv = skp->sk_multircv.value.ul; - sip->si_kstat.si_multixmt = skp->sk_multixmt.value.ul; - sip->si_kstat.si_brdcstrcv = skp->sk_brdcstrcv.value.ul; - sip->si_kstat.si_brdcstxmt = skp->sk_brdcstxmt.value.ul; - sip->si_kstat.si_norcvbuf = skp->sk_norcvbuf.value.ul; - sip->si_kstat.si_noxmtbuf = skp->sk_noxmtbuf.value.ul; - /* - * PSARC 1997/198 : 64bit kstats - */ - sip->si_kstat.si_ipackets64 = skp->sk_ipackets64.value.ull; - sip->si_kstat.si_opackets64 = skp->sk_opackets64.value.ull; - sip->si_kstat.si_rbytes64 = skp->sk_rbytes64.value.ull; - sip->si_kstat.si_obytes64 = skp->sk_obytes64.value.ull; - /* - * PSARC 1997/247 : RFC 1643 - */ - sip->si_kstat.si_fcs_errors = skp->sk_fcs_errors.value.ul; - sip->si_kstat.si_macxmt_errors = - skp->sk_macxmt_errors.value.ul; - sip->si_kstat.si_toolong_errors = - skp->sk_toolong_errors.value.ul; - sip->si_kstat.si_macrcv_errors = - skp->sk_macrcv_errors.value.ul; - - return (0); - } - - skp->sk_ipackets.value.ul = sip->si_kstat.si_ipackets; - skp->sk_ierrors.value.ul = sip->si_kstat.si_ierrors; - skp->sk_opackets.value.ul = sip->si_kstat.si_opackets; - skp->sk_oerrors.value.ul = sip->si_kstat.si_oerrors; - skp->sk_txcoll.value.ul = sip->si_kstat.si_txcoll; - skp->sk_rxcoll.value.ul = sip->si_kstat.si_rxcoll; - skp->sk_crc.value.ul = sip->si_kstat.si_crc; - skp->sk_buff.value.ul = sip->si_kstat.si_buff; - skp->sk_nolink.value.ul = sip->si_kstat.si_nolink; - skp->sk_linkdown.value.ul = sip->si_kstat.si_linkdown; - skp->sk_inits.value.ul = sip->si_kstat.si_inits; - skp->sk_nocanput.value.ul = sip->si_kstat.si_nocanput; - skp->sk_allocbfail.value.ul = sip->si_kstat.si_allocbfail; - skp->sk_notbufs.value.ul = sip->si_kstat.si_notbufs; - skp->sk_reclaim.value.ul = sip->si_kstat.si_reclaim; - skp->sk_smraddr.value.ul = sip->si_kstat.si_smraddr; - skp->sk_txfull.value.ul = sip->si_kstat.si_txfull; - skp->sk_txmax.value.ul = sip->si_kstat.si_txmax; - skp->sk_xdcall.value.ul = sip->si_kstat.si_xdcall; - skp->sk_sigsvr.value.ul = sip->si_kstat.si_sigsvr; - skp->sk_mboxcrc.value.ul = sip->si_kstat.si_mboxcrc; - /* - * MIB II kstat variables - */ - skp->sk_rcvbytes.value.ul = sip->si_kstat.si_rcvbytes; - skp->sk_xmtbytes.value.ul = sip->si_kstat.si_xmtbytes; - skp->sk_multircv.value.ul = sip->si_kstat.si_multircv; - skp->sk_multixmt.value.ul = sip->si_kstat.si_multixmt; - skp->sk_brdcstrcv.value.ul = sip->si_kstat.si_brdcstrcv; - skp->sk_brdcstxmt.value.ul = sip->si_kstat.si_brdcstxmt; - skp->sk_norcvbuf.value.ul = sip->si_kstat.si_norcvbuf; - skp->sk_noxmtbuf.value.ul = sip->si_kstat.si_noxmtbuf; - /* - * PSARC 1997/198 : 64bit kstats - */ - skp->sk_ipackets64.value.ull = sip->si_kstat.si_ipackets64; - skp->sk_opackets64.value.ull = sip->si_kstat.si_opackets64; - skp->sk_rbytes64.value.ull = sip->si_kstat.si_rbytes64; - skp->sk_obytes64.value.ull = sip->si_kstat.si_obytes64; - /* - * PSARC 1997/247 : RFC 1643 - */ - skp->sk_fcs_errors.value.ul = sip->si_kstat.si_fcs_errors; - skp->sk_macxmt_errors.value.ul = sip->si_kstat.si_macxmt_errors; - skp->sk_toolong_errors.value.ul = sip->si_kstat.si_toolong_errors; - skp->sk_macrcv_errors.value.ul = sip->si_kstat.si_macrcv_errors; - - return (0); -} - -void -idndl_statinit(struct idn *sip) -{ - struct kstat *ksp; - struct idn_kstat_named *skp; - -#ifdef kstat - if ((ksp = kstat_create(IDNNAME, ddi_get_instance(sip->si_dip), - NULL, "net", KSTAT_TYPE_NAMED, - sizeof (struct idn_kstat_named) / sizeof (kstat_named_t), - KSTAT_FLAG_PERSISTENT)) == NULL) { -#else - if ((ksp = kstat_create(IDNNAME, ddi_get_instance(sip->si_dip), - NULL, "net", KSTAT_TYPE_NAMED, - sizeof (struct idn_kstat_named) / - sizeof (kstat_named_t), 0)) == NULL) { -#endif /* kstat */ - serror(sip->si_dip, 450, "kstat_create failed"); - return; - } - - sip->si_ksp = ksp; - skp = (struct idn_kstat_named *)(ksp->ks_data); - kstat_named_init(&skp->sk_ipackets, "ipackets", - KSTAT_DATA_ULONG); - kstat_named_init(&skp->sk_ierrors, "ierrors", - KSTAT_DATA_ULONG); - kstat_named_init(&skp->sk_opackets, "opackets", - KSTAT_DATA_ULONG); - kstat_named_init(&skp->sk_oerrors, "oerrors", - KSTAT_DATA_ULONG); - kstat_named_init(&skp->sk_txcoll, "collisions", - KSTAT_DATA_ULONG); - kstat_named_init(&skp->sk_rxcoll, "rx_collisions", - KSTAT_DATA_ULONG); - kstat_named_init(&skp->sk_crc, "crc", - KSTAT_DATA_ULONG); - kstat_named_init(&skp->sk_buff, "buff", - KSTAT_DATA_ULONG); - kstat_named_init(&skp->sk_nolink, "nolink", - KSTAT_DATA_ULONG); - kstat_named_init(&skp->sk_linkdown, "linkdown", - KSTAT_DATA_ULONG); - kstat_named_init(&skp->sk_inits, "inits", - KSTAT_DATA_ULONG); - kstat_named_init(&skp->sk_nocanput, "nocanput", - KSTAT_DATA_ULONG); - kstat_named_init(&skp->sk_allocbfail, "allocbfail", - KSTAT_DATA_ULONG); - kstat_named_init(&skp->sk_notbufs, "notbufs", - KSTAT_DATA_ULONG); - kstat_named_init(&skp->sk_reclaim, "reclaim", - KSTAT_DATA_ULONG); - kstat_named_init(&skp->sk_smraddr, "smraddr", - KSTAT_DATA_ULONG); - kstat_named_init(&skp->sk_txmax, "txmax", - KSTAT_DATA_ULONG); - kstat_named_init(&skp->sk_txfull, "txfull", - KSTAT_DATA_ULONG); - kstat_named_init(&skp->sk_xdcall, "xdcall", - KSTAT_DATA_ULONG); - kstat_named_init(&skp->sk_sigsvr, "sigsvr", - KSTAT_DATA_ULONG); - kstat_named_init(&skp->sk_mboxcrc, "mboxcrc", - KSTAT_DATA_ULONG); - /* - * MIB II kstat variables - */ - kstat_named_init(&skp->sk_rcvbytes, "rbytes", - KSTAT_DATA_ULONG); - kstat_named_init(&skp->sk_xmtbytes, "obytes", - KSTAT_DATA_ULONG); - kstat_named_init(&skp->sk_multircv, "multircv", - KSTAT_DATA_ULONG); - kstat_named_init(&skp->sk_multixmt, "multixmt", - KSTAT_DATA_ULONG); - kstat_named_init(&skp->sk_brdcstrcv, "brdcstrcv", - KSTAT_DATA_ULONG); - kstat_named_init(&skp->sk_brdcstxmt, "brdcstxmt", - KSTAT_DATA_ULONG); - kstat_named_init(&skp->sk_norcvbuf, "norcvbuf", - KSTAT_DATA_ULONG); - kstat_named_init(&skp->sk_noxmtbuf, "noxmtbuf", - KSTAT_DATA_ULONG); - /* - * PSARC 1997/198 : 64bit kstats - */ - kstat_named_init(&skp->sk_ipackets64, "ipackets64", - KSTAT_DATA_ULONGLONG); - kstat_named_init(&skp->sk_opackets64, "opackets64", - KSTAT_DATA_ULONGLONG); - kstat_named_init(&skp->sk_rbytes64, "rbytes64", - KSTAT_DATA_ULONGLONG); - kstat_named_init(&skp->sk_obytes64, "obytes64", - KSTAT_DATA_ULONGLONG); - /* - * PSARC 1997/247 : RFC 1643 - */ - kstat_named_init(&skp->sk_fcs_errors, "fcs_errors", - KSTAT_DATA_ULONG); - kstat_named_init(&skp->sk_macxmt_errors, "macxmt_errors", - KSTAT_DATA_ULONG); - kstat_named_init(&skp->sk_toolong_errors, "toolong_errors", - KSTAT_DATA_ULONG); - kstat_named_init(&skp->sk_macrcv_errors, "macrcv_errors", - KSTAT_DATA_ULONG); - - ksp->ks_update = idndl_stat_kstat_update; - ksp->ks_private = (void *)sip; - kstat_install(ksp); -} - -void -idndl_proto(queue_t *wq, mblk_t *mp) -{ - union DL_primitives *dlp; - struct idnstr *stp; - t_uscalar_t prim; - procname_t proc = "idndl_proto"; - - stp = (struct idnstr *)wq->q_ptr; - if (MBLKL(mp) < sizeof (t_uscalar_t)) { - /* - * Gotta at least have enough room to hold - * the primitive! - */ - DLERRORACK(wq, mp, -1, DL_BADPRIM, 0); - return; - } - dlp = (union DL_primitives *)mp->b_rptr; - prim = dlp->dl_primitive; - - TRACE_2(TR_FAC_IDN, TR_IDN_PROTO_START, - "idndl_proto start: wq %p dlprim %X", wq, prim); - -#ifdef DEBUG - PR_DLPI("%s: stp = 0x%p, wq = 0x%p, dlprim = 0x%x(%s)\n", - proc, (void *)stp, (void *)wq, prim, dlprim2str(prim)); -#endif /* DEBUG */ - - rw_enter(&stp->ss_rwlock, RW_WRITER); - - switch (prim) { - case DL_UNITDATA_REQ: - idndl_udreq(wq, mp); - break; - - case DL_ATTACH_REQ: - idndl_areq(wq, mp); - break; - - case DL_DETACH_REQ: - idndl_dreq(wq, mp); - break; - - case DL_BIND_REQ: - idndl_breq(wq, mp); - break; - - case DL_UNBIND_REQ: - idndl_ubreq(wq, mp); - break; - - case DL_INFO_REQ: - idndl_ireq(wq, mp); - break; - - case DL_PROMISCON_REQ: - idndl_ponreq(wq, mp); - break; - - case DL_PROMISCOFF_REQ: - idndl_poffreq(wq, mp); - break; - - case DL_ENABMULTI_REQ: - idndl_emreq(wq, mp); - break; - - case DL_DISABMULTI_REQ: - idndl_dmreq(wq, mp); - break; - - case DL_PHYS_ADDR_REQ: - idndl_pareq(wq, mp); - break; - -#ifdef notdef - /* - * We cannot allow this in IDN-land because we - * rely on the ethernet (physical) address to determine - * where to target the message. Recall that unlike - * ethernet we simply cannot dump junk on the wire and - * expect it to automatically find its destination. - * In the IDN we need to target the destination. - * Note that if we used POINT-TO-POINT then we wouldn't - * have to worry about the physical address since each - * domain connection would have a separate queue. - * However, ptp then requires multiple interfaces at - * the appl level as opposed to a single one for all - * of idn. We opt for the simpler single interface (idn0). - */ - case DL_SET_PHYS_ADDR_REQ: - idndl_spareq(wq, mp); - break; -#endif /* notdef */ - - default: - DLERRORACK(wq, mp, prim, DL_UNSUPPORTED, 0); - break; - } - - TRACE_2(TR_FAC_IDN, TR_IDN_PROTO_END, - "idnproto end: wq %p dlprim %X", wq, prim); - - rw_exit(&stp->ss_rwlock); -} - -int -idnioc_dlpi(queue_t *wq, mblk_t *mp, int *argsizep) -{ - int rv = 0; - struct iocblk *iocp = (struct iocblk *)mp->b_rptr; - struct idnstr *stp = (struct idnstr *)wq->q_ptr; - procname_t proc = "idnioc_dlpi"; - - *argsizep = 0; - - switch (iocp->ioc_cmd) { - case DLIOCRAW: /* raw M_DATA mode */ - PR_DLPI("%s: cmd = DLIOCRAW\n", proc); - stp->ss_flags |= IDNSRAW; - break; - - case DL_IOC_HDR_INFO: /* M_DATA "fastpath" info request */ - PR_DLPI("%s: cmd = DL_IOC_HDR_INFO\n", proc); - rv = idndl_ioc_hdr_info(wq, mp, argsizep); - break; - - default: - PR_DLPI("%s: invalid cmd 0x%x\n", proc, iocp->ioc_cmd); - rv = EINVAL; - break; - } - return (rv); -} - -/* - * M_DATA "fastpath" info request. - * Following the M_IOCTL mblk should come a DL_UNITDATA_REQ mblk. - * We ack with an M_IOCACK pointing to the original DL_UNITDATA_REQ mblk - * followed by an mblk containing the raw ethernet header corresponding - * to the destination address. Subsequently, we may receive M_DATA - * msgs which start with this header and may send up - * up M_DATA msgs with b_rptr pointing to a (ulong) group address - * indicator followed by the network-layer data (IP packet header). - * This is all selectable on a per-Stream basis. - */ -static int -idndl_ioc_hdr_info(queue_t *wq, mblk_t *mp, int *argsizep) -{ - mblk_t *nmp; - struct idnstr *stp; - struct idndladdr *dlap; - dl_unitdata_req_t *dludp; - struct ether_header *headerp; - struct idn *sip; - int off, len; - int padding = 0; - int error; - procname_t proc = "idndl_ioc_hdr_info"; - - stp = (struct idnstr *)wq->q_ptr; - sip = stp->ss_sip; - if (sip == NULL) { - PR_DLPI("%s: NULL sip (ret EINVAL)\n", proc); - return (EINVAL); - } - - error = miocpullup(mp, sizeof (dl_unitdata_req_t) + IDNADDRL); - if (error != 0) { - PR_DLPI("%s: sanity error (ret %d)\n", proc, error); - return (error); - } - - /* - * Sanity check the DL_UNITDATA_REQ destination address - * offset and length values. - */ - dludp = (dl_unitdata_req_t *)mp->b_cont->b_rptr; - off = dludp->dl_dest_addr_offset; - len = dludp->dl_dest_addr_length; - if (dludp->dl_primitive != DL_UNITDATA_REQ || - !MBLKIN(mp->b_cont, off, len) || len != IDNADDRL) { - PR_DLPI("%s: off(0x%x)/len(%d) error (ret EINVAL)\n", - proc, off, len); - return (EINVAL); - } - - dlap = (struct idndladdr *)(mp->b_cont->b_rptr + off); - - /* - * Allocate a new mblk to hold the ether header. - */ - nmp = allocb(sizeof (struct ether_header) + padding, BPRI_MED); - if (nmp == NULL) { - IDN_KSTAT_INC(sip, si_allocbfail); - return (ENOMEM); - } - nmp->b_rptr += padding; - nmp->b_wptr = nmp->b_rptr + sizeof (struct ether_header); - - /* - * Fill in the ether header. - */ - headerp = (struct ether_header *)nmp->b_rptr; - ether_copy(&dlap->dl_phys, &headerp->ether_dhost); - ether_copy(&sip->si_ouraddr, &headerp->ether_shost); - headerp->ether_type = dlap->dl_sap; - - /* - * Link new mblk in after the "request" mblks. - */ - linkb(mp, nmp); - - stp->ss_flags |= IDNSFAST; - - /* - * XXX Don't bother calling idndl_setipq() here. - */ - - if (argsizep) - *argsizep = msgsize(mp->b_cont); - - return (0); -} - -static void -idndl_areq(queue_t *wq, mblk_t *mp) -{ - struct idnstr *stp; - union DL_primitives *dlp; - struct idn *sip; - int ppa; - procname_t proc = "idndl_areq"; - - stp = (struct idnstr *)wq->q_ptr; - dlp = (union DL_primitives *)mp->b_rptr; - - if (MBLKL(mp) < DL_ATTACH_REQ_SIZE) { - DLERRORACK(wq, mp, DL_ATTACH_REQ, DL_BADPRIM, 0); - return; - } - - if (stp->ss_state != DL_UNATTACHED) { - DLERRORACK(wq, mp, DL_ATTACH_REQ, DL_OUTSTATE, 0); - return; - } - - ppa = dlp->attach_req.dl_ppa; - - /* - * Valid ppa? - */ - if (ppa == -1 || qassociate(wq, ppa) != 0) { - PR_DLPI("%s: bad ppa %d\n", proc, ppa); - DLERRORACK(wq, mp, dlp->dl_primitive, DL_BADPPA, 0); - return; - } - mutex_enter(&idn.siplock); - for (sip = idn.sip; sip; sip = sip->si_nextp) { - if (ppa == ddi_get_instance(sip->si_dip)) - break; - } - mutex_exit(&idn.siplock); - ASSERT(sip != NULL); /* qassociate() succeeded */ - - /* - * Has device been initialized? Do so if necessary. - */ - if ((sip->si_flags & IDNRUNNING) == 0) { - if (idndl_init(sip)) { - DLERRORACK(wq, mp, dlp->dl_primitive, - DL_INITFAILED, 0); - (void) qassociate(wq, -1); - return; - } - } - - /* - * Set link to device and update our state. - */ - stp->ss_sip = sip; - stp->ss_state = DL_UNBOUND; - - DLOKACK(wq, mp, DL_ATTACH_REQ); -} - -static void -idndl_dreq(queue_t *wq, mblk_t *mp) -{ - struct idnstr *stp; - - stp = (struct idnstr *)wq->q_ptr; - - if (MBLKL(mp) < DL_DETACH_REQ_SIZE) { - DLERRORACK(wq, mp, DL_DETACH_REQ, DL_BADPRIM, 0); - return; - } - - if (stp->ss_state != DL_UNBOUND) { - DLERRORACK(wq, mp, DL_DETACH_REQ, DL_OUTSTATE, 0); - return; - } - - idndl_dodetach(stp); - (void) qassociate(wq, -1); - DLOKACK(wq, mp, DL_DETACH_REQ); -} - -/* - * Detach a Stream from an interface. - */ -void -idndl_dodetach(struct idnstr *stp) -{ - struct idnstr *tstp; - struct idn *sip; - int reinit = 0; - - ASSERT(stp->ss_sip); - - sip = stp->ss_sip; - stp->ss_sip = NULL; - - /* - * Disable promiscuous mode if on. - */ - if (stp->ss_flags & IDNSALLPHYS) { - stp->ss_flags &= ~IDNSALLPHYS; - reinit = 1; - } - - /* - * Disable ALLMULTI mode if on. - */ - if (stp->ss_flags & IDNSALLMULTI) { - stp->ss_flags &= ~IDNSALLMULTI; - reinit = 1; - } - - /* - * Disable any Multicast Addresses. - */ - stp->ss_mccount = 0; - if (stp->ss_mctab) { - kmem_free(stp->ss_mctab, IDNMCALLOC); - stp->ss_mctab = NULL; - reinit = 1; - } - - /* - * Detach from device structure. - * Uninit the device when no other streams are attached to it. - */ - rw_enter(&idn.struprwlock, RW_READER); - for (tstp = idn.strup; tstp; tstp = tstp->ss_nextp) - if (tstp->ss_sip == sip) - break; - rw_exit(&idn.struprwlock); - - if (tstp == NULL) - idndl_uninit(sip); - else if (reinit) - (void) idndl_init(sip); - - stp->ss_state = DL_UNATTACHED; - - idndl_setipq(sip); -} - -static void -idndl_breq(queue_t *wq, mblk_t *mp) -{ - struct idnstr *stp; - union DL_primitives *dlp; - struct idn *sip; - struct idndladdr idnaddr; - t_uscalar_t sap; - int xidtest; - procname_t proc = "idndl_breq"; - - stp = (struct idnstr *)wq->q_ptr; - - if (MBLKL(mp) < DL_BIND_REQ_SIZE) { - DLERRORACK(wq, mp, DL_BIND_REQ, DL_BADPRIM, 0); - return; - } - - if (stp->ss_state != DL_UNBOUND) { - DLERRORACK(wq, mp, DL_BIND_REQ, DL_OUTSTATE, 0); - return; - } - - dlp = (union DL_primitives *)mp->b_rptr; - - if (dlp->bind_req.dl_service_mode != idninfoack.dl_service_mode) { - DLERRORACK(wq, mp, DL_BIND_REQ, DL_UNSUPPORTED, 0); - return; - } - - sip = stp->ss_sip; - sap = dlp->bind_req.dl_sap; - xidtest = dlp->bind_req.dl_xidtest_flg; - - ASSERT(sip); - - if (xidtest) { - DLERRORACK(wq, mp, DL_BIND_REQ, DL_NOAUTO, 0); - return; - } - - if (sap > ETHERTYPE_MAX) { - DLERRORACK(wq, mp, dlp->dl_primitive, DL_BADSAP, 0); - return; - } - - /* - * Save SAP value for this Stream and change state. - */ - stp->ss_sap = sap; - stp->ss_state = DL_IDLE; - - idnaddr.dl_sap = sap; - ether_copy(&sip->si_ouraddr, &idnaddr.dl_phys); - - if (IS_ETHERTYPE_IP(sap)) { - int channel; - - channel = - (int)sip->si_ouraddr.ether_addr_octet[IDNETHER_CHANNEL]; - PR_DLPI("%s: IP SAP, opening channel %d\n", proc, channel); - if (idn_open_channel(channel)) { - PR_DLPI("%s: FAILED TO OPEN CHANNEL %d\n", - proc, channel); - DLERRORACK(wq, mp, dlp->dl_primitive, DL_NOADDR, 0); - return; - } - } - DLBINDACK(wq, mp, sap, &idnaddr, IDNADDRL, 0, 0); - - idndl_setipq(sip); -} - -static void -idndl_ubreq(queue_t *wq, mblk_t *mp) -{ - struct idnstr *stp; - procname_t proc = "idndl_ubreq"; - - stp = (struct idnstr *)wq->q_ptr; - - if (MBLKL(mp) < DL_UNBIND_REQ_SIZE) { - DLERRORACK(wq, mp, DL_UNBIND_REQ, DL_BADPRIM, 0); - return; - } - - if (stp->ss_state != DL_IDLE) { - DLERRORACK(wq, mp, DL_UNBIND_REQ, DL_OUTSTATE, 0); - return; - } - - stp->ss_state = DL_UNBOUND; - - if (IS_ETHERTYPE_IP(stp->ss_sap)) { - struct idn *sip; - int channel; - - sip = stp->ss_sip; - channel = - (int)sip->si_ouraddr.ether_addr_octet[IDNETHER_CHANNEL]; - PR_DLPI("%s: IP SAP, unbinding channel %d\n", proc, channel); - /* - * We need to do an "soft" close since there's a - * potential that we've been called by one of the - * IDN data server/dispatcher threads! We'll deadlock - * if we attempt a "hard" close of the channel from here. - */ - idn_close_channel(channel, IDNCHAN_SOFT_CLOSE); - } - - stp->ss_sap = 0; - - DLOKACK(wq, mp, DL_UNBIND_REQ); - - idndl_setipq(stp->ss_sip); -} - -static void -idndl_ireq(queue_t *wq, mblk_t *mp) -{ - struct idnstr *stp; - dl_info_ack_t *dlip; - struct idndladdr *dlap; - struct ether_addr *ep; - int size; - - stp = (struct idnstr *)wq->q_ptr; - - if (MBLKL(mp) < DL_INFO_REQ_SIZE) { - DLERRORACK(wq, mp, DL_INFO_REQ, DL_BADPRIM, 0); - return; - } - - /* - * Exchange current msg for a DL_INFO_ACK. - */ - size = sizeof (dl_info_ack_t) + IDNADDRL + ETHERADDRL; - if ((mp = mexchange(wq, mp, size, M_PCPROTO, DL_INFO_ACK)) == NULL) - return; - - /* - * Fill in the DL_INFO_ACK fields and reply. - */ - dlip = (dl_info_ack_t *)mp->b_rptr; - ASSERT(idninfoack.dl_max_sdu); - *dlip = idninfoack; - dlip->dl_current_state = stp->ss_state; - dlap = (struct idndladdr *)(mp->b_rptr + dlip->dl_addr_offset); - dlap->dl_sap = stp->ss_sap; - if (stp->ss_sip) { - ether_copy(&stp->ss_sip->si_ouraddr, &dlap->dl_phys); - } else { - bzero(&dlap->dl_phys, ETHERADDRL); - } - ep = (struct ether_addr *)(mp->b_rptr + dlip->dl_brdcst_addr_offset); - ether_copy(ðerbroadcastaddr, ep); - - qreply(wq, mp); -} - -static void -idndl_ponreq(queue_t *wq, mblk_t *mp) -{ - struct idnstr *stp; - - stp = (struct idnstr *)wq->q_ptr; - - if (MBLKL(mp) < DL_PROMISCON_REQ_SIZE) { - DLERRORACK(wq, mp, DL_PROMISCON_REQ, DL_BADPRIM, 0); - return; - } - - switch (((dl_promiscon_req_t *)mp->b_rptr)->dl_level) { - case DL_PROMISC_PHYS: - stp->ss_flags |= IDNSALLPHYS; - break; - - case DL_PROMISC_SAP: - stp->ss_flags |= IDNSALLSAP; - break; - - case DL_PROMISC_MULTI: - stp->ss_flags |= IDNSALLMULTI; - break; - - default: - DLERRORACK(wq, mp, DL_PROMISCON_REQ, DL_NOTSUPPORTED, 0); - return; - } - - if (stp->ss_sip) - (void) idndl_init(stp->ss_sip); - - if (stp->ss_sip) - idndl_setipq(stp->ss_sip); - - DLOKACK(wq, mp, DL_PROMISCON_REQ); -} - -static void -idndl_poffreq(queue_t *wq, mblk_t *mp) -{ - struct idnstr *stp; - int flag; - - stp = (struct idnstr *)wq->q_ptr; - - if (MBLKL(mp) < DL_PROMISCOFF_REQ_SIZE) { - DLERRORACK(wq, mp, DL_PROMISCOFF_REQ, DL_BADPRIM, 0); - return; - } - - switch (((dl_promiscoff_req_t *)mp->b_rptr)->dl_level) { - case DL_PROMISC_PHYS: - flag = IDNSALLPHYS; - break; - - case DL_PROMISC_SAP: - flag = IDNSALLSAP; - break; - - case DL_PROMISC_MULTI: - flag = IDNSALLMULTI; - break; - - default: - DLERRORACK(wq, mp, DL_PROMISCOFF_REQ, DL_NOTSUPPORTED, 0); - return; - } - - if ((stp->ss_flags & flag) == 0) { - DLERRORACK(wq, mp, DL_PROMISCOFF_REQ, DL_NOTENAB, 0); - return; - } - - stp->ss_flags &= ~flag; - - if (stp->ss_sip) - (void) idndl_init(stp->ss_sip); - - if (stp->ss_sip) - idndl_setipq(stp->ss_sip); - - DLOKACK(wq, mp, DL_PROMISCOFF_REQ); -} - -static void -idndl_emreq(queue_t *wq, mblk_t *mp) -{ - struct idnstr *stp; - union DL_primitives *dlp; - struct ether_addr *addrp; - int off; - int len; - int i; - - stp = (struct idnstr *)wq->q_ptr; - - if (MBLKL(mp) < DL_ENABMULTI_REQ_SIZE) { - DLERRORACK(wq, mp, DL_ENABMULTI_REQ, DL_BADPRIM, 0); - return; - } - - if (stp->ss_state == DL_UNATTACHED) { - DLERRORACK(wq, mp, DL_ENABMULTI_REQ, DL_OUTSTATE, 0); - return; - } - - dlp = (union DL_primitives *)mp->b_rptr; - len = dlp->enabmulti_req.dl_addr_length; - off = dlp->enabmulti_req.dl_addr_offset; - addrp = (struct ether_addr *)(mp->b_rptr + off); - - if ((len != ETHERADDRL) || - !MBLKIN(mp, off, len) || - !IDNDL_ADDR_IS_MULTICAST(addrp)) { - DLERRORACK(wq, mp, DL_ENABMULTI_REQ, DL_BADADDR, 0); - return; - } - - if ((stp->ss_mccount + 1) >= IDNMAXMC) { - DLERRORACK(wq, mp, DL_ENABMULTI_REQ, DL_TOOMANY, 0); - return; - } - - /* - * Allocate table on first request. - */ - if (stp->ss_mctab == NULL) - stp->ss_mctab = kmem_alloc(IDNMCALLOC, KM_SLEEP); - - /* - * Check to see if the address is already in the table. - * Bug 1209733: - * If present in the table, add the entry to the end of the table - * and return without initializing the hardware. - */ - for (i = 0; i < stp->ss_mccount; i++) { - if (ether_cmp(&stp->ss_mctab[i], addrp) == 0) { - stp->ss_mctab[stp->ss_mccount++] = *addrp; - DLOKACK(wq, mp, DL_ENABMULTI_REQ); - return; - } - } - - stp->ss_mctab[stp->ss_mccount++] = *addrp; - - (void) idndl_init(stp->ss_sip); - - DLOKACK(wq, mp, DL_ENABMULTI_REQ); -} - -static void -idndl_dmreq(queue_t *wq, mblk_t *mp) -{ - struct idnstr *stp; - union DL_primitives *dlp; - struct ether_addr *addrp; - int off; - int len; - int i; - - stp = (struct idnstr *)wq->q_ptr; - - if (MBLKL(mp) < DL_DISABMULTI_REQ_SIZE) { - DLERRORACK(wq, mp, DL_DISABMULTI_REQ, DL_BADPRIM, 0); - return; - } - - if (stp->ss_state == DL_UNATTACHED) { - DLERRORACK(wq, mp, DL_DISABMULTI_REQ, DL_OUTSTATE, 0); - return; - } - - dlp = (union DL_primitives *)mp->b_rptr; - len = dlp->disabmulti_req.dl_addr_length; - off = dlp->disabmulti_req.dl_addr_offset; - addrp = (struct ether_addr *)(mp->b_rptr + off); - - if ((len != ETHERADDRL) || !MBLKIN(mp, off, len)) { - DLERRORACK(wq, mp, DL_DISABMULTI_REQ, DL_BADADDR, 0); - return; - } - - /* - * Find the address in the multicast table for this Stream - * and delete it by shifting all subsequent multicast - * table entries over one. - */ - for (i = 0; i < stp->ss_mccount; i++) - if (ether_cmp(addrp, &stp->ss_mctab[i]) == 0) { - bcopy(&stp->ss_mctab[i+1], - &stp->ss_mctab[i], - ((stp->ss_mccount - i) * - sizeof (struct ether_addr))); - stp->ss_mccount--; - (void) idndl_init(stp->ss_sip); - DLOKACK(wq, mp, DL_DISABMULTI_REQ); - return; - } - DLERRORACK(wq, mp, DL_DISABMULTI_REQ, DL_NOTENAB, 0); -} - -static void -idndl_pareq(queue_t *wq, mblk_t *mp) -{ - struct idnstr *stp; - union DL_primitives *dlp; - int type; - struct idn *sip; - struct ether_addr addr; - - stp = (struct idnstr *)wq->q_ptr; - - if (MBLKL(mp) < DL_PHYS_ADDR_REQ_SIZE) { - DLERRORACK(wq, mp, DL_PHYS_ADDR_REQ, DL_BADPRIM, 0); - return; - } - - dlp = (union DL_primitives *)mp->b_rptr; - type = dlp->physaddr_req.dl_addr_type; - sip = stp->ss_sip; - - if (sip == NULL) { - DLERRORACK(wq, mp, DL_PHYS_ADDR_REQ, DL_OUTSTATE, 0); - return; - } - - switch (type) { - case DL_FACT_PHYS_ADDR: - idndl_localetheraddr(sip, &addr); - break; - - case DL_CURR_PHYS_ADDR: - ether_copy(&sip->si_ouraddr, &addr); - break; - - default: - DLERRORACK(wq, mp, DL_PHYS_ADDR_REQ, DL_NOTSUPPORTED, 0); - return; - } - - DLPHYSADDRACK(wq, mp, &addr, ETHERADDRL); -} - -#ifdef notdef -static void -idndl_spareq(queue_t *wq, mblk_t *mp) -{ - struct idnstr *stp; - union DL_primitives *dlp; - int off; - int len; - struct ether_addr *addrp; - struct idn *sip; - - stp = (struct idnstr *)wq->q_ptr; - - if (MBLKL(mp) < DL_SET_PHYS_ADDR_REQ_SIZE) { - DLERRORACK(wq, mp, DL_SET_PHYS_ADDR_REQ, DL_BADPRIM, 0); - return; - } - - dlp = (union DL_primitives *)mp->b_rptr; - len = dlp->set_physaddr_req.dl_addr_length; - off = dlp->set_physaddr_req.dl_addr_offset; - - if (!MBLKIN(mp, off, len)) { - DLERRORACK(wq, mp, DL_SET_PHYS_ADDR_REQ, DL_BADPRIM, 0); - return; - } - - addrp = (struct ether_addr *)(mp->b_rptr + off); - - /* - * Error if length of address isn't right or the address - * specified is a multicast or broadcast address. - */ - if ((len != ETHERADDRL) || - IDNDL_ADDR_IS_MULTICAST(addrp) || - (ether_cmp(addrp, ðerbroadcastaddr) == 0)) { - DLERRORACK(wq, mp, DL_SET_PHYS_ADDR_REQ, DL_BADADDR, 0); - return; - } - - /* - * Error if this stream is not attached to a device. - */ - if ((sip = stp->ss_sip) == NULL) { - DLERRORACK(wq, mp, DL_SET_PHYS_ADDR_REQ, DL_OUTSTATE, 0); - return; - } - - /* - * Set new interface local address and re-init device. - * This is destructive to any other streams attached - * to this device. - */ - ether_copy(addrp, &sip->si_ouraddr); - (void) idndl_init(stp->ss_sip); - - DLOKACK(wq, mp, DL_SET_PHYS_ADDR_REQ); -} -#endif /* notdef */ - -static void -idndl_udreq(queue_t *wq, mblk_t *mp) -{ - struct idnstr *stp; - register struct idn *sip; - register dl_unitdata_req_t *dludp; - mblk_t *nmp; - struct idndladdr *dlap; - struct ether_header *headerp; - t_uscalar_t off, len; - t_uscalar_t sap; - - stp = (struct idnstr *)wq->q_ptr; - sip = stp->ss_sip; - - if (stp->ss_state != DL_IDLE) { - DLERRORACK(wq, mp, DL_UNITDATA_REQ, DL_OUTSTATE, 0); - return; - } - - dludp = (dl_unitdata_req_t *)mp->b_rptr; - - off = dludp->dl_dest_addr_offset; - len = dludp->dl_dest_addr_length; - - /* - * Validate destination address format. - */ - if (!MBLKIN(mp, off, len) || (len != IDNADDRL)) { - dluderrorind(wq, mp, mp->b_rptr + off, len, DL_BADADDR, 0); - return; - } - - /* - * Error if no M_DATA follows. - */ - nmp = mp->b_cont; - if (nmp == NULL) { - dluderrorind(wq, mp, mp->b_rptr + off, len, DL_BADDATA, 0); - return; - } - - dlap = (struct idndladdr *)(mp->b_rptr + off); - - /* - * Create ethernet header by either prepending it onto the - * next mblk if potential, or reusing the M_PROTO block if not. - */ - if ((DB_REF(nmp) == 1) && - (MBLKHEAD(nmp) >= sizeof (struct ether_header)) && - (((ulong_t)nmp->b_rptr & 0x1) == 0)) { - nmp->b_rptr -= sizeof (struct ether_header); - headerp = (struct ether_header *)nmp->b_rptr; - ether_copy(&dlap->dl_phys, &headerp->ether_dhost); - ether_copy(&sip->si_ouraddr, &headerp->ether_shost); - sap = dlap->dl_sap; - freeb(mp); - mp = nmp; - } else { - DB_TYPE(mp) = M_DATA; - headerp = (struct ether_header *)mp->b_rptr; - mp->b_wptr = mp->b_rptr + sizeof (struct ether_header); - ether_copy(&dlap->dl_phys, &headerp->ether_dhost); - ether_copy(&sip->si_ouraddr, &headerp->ether_shost); - sap = dlap->dl_sap; - } - - /* - * For transmitting, the driver looks at the - * sap field of the DL_BIND_REQ being 0 in addition to the type - * field in the range [0-1500]. If either is true, then the driver - * computes the length of the message, not including initial M_PROTO - * mblk (message block), of all subsequent DL_UNITDATA_REQ messages and - * transmits 802.3 frames that have this value in the MAC frame header - * length field. - */ - if ((sap <= ETHERMTU) || (stp->ss_sap == 0)) - headerp->ether_type = (msgsize(mp) - - sizeof (struct ether_header)); - else - headerp->ether_type = sap; - - /* - * The data transfer code requires only READ access (idn_wput_data). - */ - rw_downgrade(&stp->ss_rwlock); - (void) idndl_start(wq, mp, sip); -} - -int -idndl_start(queue_t *wq, register mblk_t *mp, register struct idn *sip) -{ - int rv = 0; - int flags; - int broadcast = 0; - int goagain = 0; - int goqueue = 0; - int msgcount; - char channel; - mblk_t *nmp = NULL; - int domid; - domainset_t domset; - idn_netaddr_t netaddr; - struct idnstr *stp; - struct ether_header *ehp; - procname_t proc = "idndl_start"; - - ASSERT(DB_TYPE(mp) == M_DATA); - - stp = (struct idnstr *)wq->q_ptr; - ASSERT(sip == stp->ss_sip); - flags = sip->si_flags; - channel = (char)sip->si_ouraddr.ether_addr_octet[IDNETHER_CHANNEL]; - - ASSERT(RW_READ_HELD(&stp->ss_rwlock)); - - if ((flags & (IDNRUNNING|IDNPROMISC)) != IDNRUNNING) { - if (!(flags & IDNRUNNING)) - goto requeue; - } - - /* - * Translate an IDN ethernet address into a domainid - * and idnaddr. - */ - ehp = (struct ether_header *)mp->b_rptr; - domid = IDNDL_ETHER2DOMAIN(&ehp->ether_dhost); - - /* - * update MIB II statistics - */ - BUMP_OutNUcast(sip, ehp); - - PR_DLPI("%s: ether %x:%x:%x:%x:%x:%x (domid = %d)\n", - proc, ehp->ether_dhost.ether_addr_octet[0], - ehp->ether_dhost.ether_addr_octet[1], - ehp->ether_dhost.ether_addr_octet[2], - ehp->ether_dhost.ether_addr_octet[3], - ehp->ether_dhost.ether_addr_octet[4], - ehp->ether_dhost.ether_addr_octet[5], - domid); - - netaddr.net.chan = channel; - PR_DLPI("%s: source channel = %d\n", proc, (int)channel); - - if ((ether_cmp(&ehp->ether_dhost, ðerbroadcastaddr) == 0) || - IDNDL_ADDR_IS_MULTICAST(&ehp->ether_dhost)) { - /* - * Caller wants to broadcast! - * XXX - Send to everybody but ourself??? - */ - PR_DLPI("%s: broadcast/multicast requested!!!\n", proc); - domset = ~DOMAINSET(idn.localid); - broadcast = 1; - netaddr.net.netid = IDN_BROADCAST_ALLNETID; - if ((flags & IDNPROMISC) && - ((nmp = copymsg(mp)) == NULL)) { - IDN_KSTAT_INC(sip, si_allocbfail); - } - - } else if (domid != IDN_NIL_DOMID) { - domset = DOMAINSET(domid); - netaddr.net.netid = idn_domain[domid].dnetid; - if ((flags & IDNPROMISC) && - ((nmp = copymsg(mp)) == NULL)) { - IDN_KSTAT_INC(sip, si_allocbfail); - } - } else { -#ifdef DEBUG - int netid; - - netid = (int) - ehp->ether_dhost.ether_addr_octet[IDNETHER_NETID]; - PR_DLPI("%s: no domain found for netid 0x%x\n", - proc, netid); -#endif /* DEBUG */ - goto bad; - } - - PR_DLPI("%s: target domainset = 0x%x\n", proc, domset); - - if ((domset == 0) && (domid == IDN_NIL_DOMID)) { - PR_DLPI("%s: not connected to any domains!! Bailing\n", - proc); - goto bad; - } - /* - * XXX - Need to find a better way to handle broadcasting. - * Should be able to take advantage of the fact that - * we can broadcast XDC's (xdc_some). Need to use - * atomic counter (semaphore) instead of binary - * "owner" flag, or perhaps domain specific owner bytes. - * - * Transfer the data. - */ - msgcount = 0; - if (!broadcast) - goto noloop; - - for (domid = 0; domid < MAX_DOMAINS; domid++) { - if (!DOMAIN_IN_SET(domset, domid)) - continue; - -noloop: - - if (idn_domain[domid].dcpu == IDN_NIL_DCPU) { - if (broadcast) - continue; - else - break; - } - - rv = idn_send_data(domid, netaddr, wq, mp); - - switch (rv) { - case IDNXMIT_LOOP: /* handled in loopback */ - msgcount++; - break; - - case IDNXMIT_OKAY: /* handled, okay to free */ - msgcount++; - break; - - case IDNXMIT_RETRY: - if (!broadcast) - goto tryagain; - goagain++; - break; - - case IDNXMIT_REQUEUE: - if (!broadcast) - goto requeue; - goqueue++; - break; - - default: - if (!broadcast) - goto bad; - break; - } - if (!broadcast) - break; - } - - if (msgcount == 0) - if (goqueue) - goto requeue; - else if (goagain) - goto tryagain; - else - goto bad; - - if ((flags & IDNPROMISC) && nmp) - idndl_sendup(sip, nmp, idndl_paccept); - - freemsg(mp); - - PR_DLPI("%s: successful transmit to domainset 0x%x.\n", - proc, domset); - - return (0); - -bad: - PR_DLPI("%s: bad transmission to domainset 0x%x, dropping msg.\n", - proc, domset); - if (nmp) - freemsg(nmp); - freemsg(mp); - qenable(wq); - return (1); - -requeue: - PR_DLPI("%s: requeue for domainset 0x%x, no qenable\n", - proc, domset); - if (nmp) - freemsg(nmp); - if (putbq(wq, mp) == 0) - freemsg(mp); - return (1); - -tryagain: - PR_DLPI("%s: try again to domainset 0x%x, putbq.\n", - proc, domset); - if (nmp) - freemsg(nmp); - if (putbq(wq, mp) == 0) - freemsg(mp); - qenable(wq); - return (1); -} - -/* - * Called by: idnh_recv_data, idn_recv_mboxdata. - */ -void -idndl_read(struct idn *sip, mblk_t *mp) -{ - struct ether_header *ehp; - queue_t *ip4q; - queue_t *ip6q; - int pktlen; - procname_t proc = "idndl_read"; - - PR_DLPI("%s: incoming msgsize = %lu, msgdsize = %lu\n", - proc, msgsize(mp), msgdsize(mp)); - - ehp = (struct ether_header *)mp->b_rptr; - if (sip == NULL) - sip = IDNDL_ETHER2SIP(&ehp->ether_dhost); - if (sip == NULL) { - /* - * If the sip is NULL, then I don't have a connection - * for this network. No point in sending the message - * up. - */ - PR_DLPI("%s: no plumbing to send message through.\n", - proc); - freemsg(mp); - return; - } - IDN_KSTAT_INC(sip, si_ipackets); - IDN_KSTAT_INC(sip, si_ipackets64); - /* - * update MIB II statistics - */ - pktlen = mp->b_wptr - mp->b_rptr; - BUMP_InNUcast(sip, ehp); - IDN_KSTAT_ADD(sip, si_rcvbytes, pktlen); - IDN_KSTAT_ADD(sip, si_rbytes64, (uint64_t)pktlen); - - ip4q = sip->si_ip4q; - ip6q = sip->si_ip6q; - - if (IS_ETHERTYPE_IPV4(ehp->ether_type) && - !IDNDL_ADDR_IS_MULTICAST(&ehp->ether_dhost) && - ip4q && - canputnext(ip4q)) { - mp->b_rptr += sizeof (struct ether_header); - (void) putnext(ip4q, mp); - /*LINTED*/ - } else if (IS_ETHERTYPE_IPV6(ehp->ether_type) && - !IDNDL_ADDR_IS_MULTICAST(&ehp->ether_dhost) && - ip6q && - canputnext(ip6q)) { - mp->b_rptr += sizeof (struct ether_header); - (void) putnext(ip6q, mp); - } else { - /* - * Strip the PADs for 802.3 - */ - pktlen = ehp->ether_type + sizeof (struct ether_header); - PR_DLPI("%s: stripping PADs for 802.3 (pktlen=%d)\n", - proc, pktlen); - if (pktlen < ETHERMIN) - mp->b_wptr = mp->b_rptr + pktlen; - idndl_sendup(sip, mp, idndl_accept); - } -} - -int -idndl_init(struct idn *sip) -{ - struct idnstr *stp; - - if (sip->si_flags & IDNSUSPENDED) - (void) ddi_dev_is_needed(sip->si_dip, 0, 1); - - sip->si_flags = 0; - sip->si_wantw = 0; - - IDN_KSTAT_INC(sip, si_inits); - - rw_enter(&idn.struprwlock, RW_WRITER); - - for (stp = idn.strup; stp; stp = stp->ss_nextp) { - if ((stp->ss_sip == sip) && (stp->ss_flags & IDNSALLPHYS)) { - sip->si_flags |= IDNPROMISC; - break; - } - } - - sip->si_flags |= IDNRUNNING; - - mutex_enter(&idn.sipwenlock); - idndl_wenable(sip); - mutex_exit(&idn.sipwenlock); - - rw_exit(&idn.struprwlock); - - return (!(sip->si_flags & IDNRUNNING)); -} - -void -idndl_uninit(struct idn *sip) -{ - int channel; - procname_t proc = "idndl_uninit"; - - sip->si_flags &= ~IDNRUNNING; - - channel = (int)sip->si_ouraddr.ether_addr_octet[IDNETHER_CHANNEL]; - PR_DLPI("%s: IP SAP, uninit channel %d\n", proc, channel); - /* - * A uninit is a hard close of an interface. - */ - idn_close_channel(channel, IDNCHAN_HARD_CLOSE); -} - -/* - * Send packet upstream. - * Assume mp->b_rptr points to ether_header. - */ -void -idndl_sendup(struct idn *sip, mblk_t *mp, struct idnstr *(*acceptfunc)()) -{ - int type; - struct ether_addr *dhostp, *shostp; - struct idnstr *stp, *nstp; - mblk_t *nmp; - ulong_t isgroupaddr; - - TRACE_0(TR_FAC_IDN, TR_IDN_SENDUP_START, "idnsendup start"); - - dhostp = &((struct ether_header *)mp->b_rptr)->ether_dhost; - shostp = &((struct ether_header *)mp->b_rptr)->ether_shost; - type = ((struct ether_header *)mp->b_rptr)->ether_type; - - isgroupaddr = IDNDL_ADDR_IS_MULTICAST(dhostp); - - /* - * While holding a reader lock on the linked list of streams structures, - * attempt to match the address criteria for each stream - * and pass up the raw M_DATA ("fastpath") or a DL_UNITDATA_IND. - */ - - rw_enter(&idn.struprwlock, RW_READER); - - if ((stp = (*acceptfunc)(idn.strup, sip, type, dhostp)) == NULL) { - rw_exit(&idn.struprwlock); - freemsg(mp); - TRACE_0(TR_FAC_IDN, TR_IDN_SENDUP_END, "idnsendup end"); - return; - } - - /* - * Loop on matching open streams until (*acceptfunc)() returns NULL. - */ - for (; nstp = (*acceptfunc)(stp->ss_nextp, sip, type, dhostp); - stp = nstp) { - - if (canputnext(stp->ss_rq) == 0) { - IDN_KSTAT_INC(sip, si_nocanput); - continue; - } - if ((nmp = dupmsg(mp)) == NULL) - nmp = copymsg(mp); - if (nmp) { - if ((stp->ss_flags & IDNSFAST) && !isgroupaddr) { - nmp->b_rptr += sizeof (struct ether_header); - (void) putnext(stp->ss_rq, nmp); - } else if (stp->ss_flags & IDNSRAW) { - (void) putnext(stp->ss_rq, nmp); - } else if ((nmp = idndl_addudind(sip, nmp, shostp, - dhostp, type, isgroupaddr))) { - (void) putnext(stp->ss_rq, nmp); - } - } else { - IDN_KSTAT_INC(sip, si_allocbfail); - } - } - - - /* - * Do the last one. - */ - if (canputnext(stp->ss_rq)) { - if ((stp->ss_flags & IDNSFAST) && !isgroupaddr) { - mp->b_rptr += sizeof (struct ether_header); - (void) putnext(stp->ss_rq, mp); - } else if (stp->ss_flags & IDNSRAW) { - (void) putnext(stp->ss_rq, mp); - } else if ((mp = idndl_addudind(sip, mp, shostp, dhostp, - type, isgroupaddr))) { - (void) putnext(stp->ss_rq, mp); - } - } else { - freemsg(mp); - IDN_KSTAT_INC(sip, si_nocanput); - IDN_KSTAT_INC(sip, si_norcvbuf); /* MIB II */ - } - - rw_exit(&idn.struprwlock); - TRACE_0(TR_FAC_IDN, TR_IDN_SENDUP_END, "idnsendup end"); -} - -/* - * Test upstream destination sap and address match. - */ -struct idnstr * -idndl_accept(register struct idnstr *stp, register struct idn *sip, - int type, struct ether_addr *addrp) -{ - t_uscalar_t sap; - uint_t flags; - - for (; stp; stp = stp->ss_nextp) { - sap = stp->ss_sap; - flags = stp->ss_flags; - - if ((stp->ss_sip == sip) && IDNSAPMATCH(sap, type, flags)) - if ((ether_cmp(addrp, &sip->si_ouraddr) == 0) || - (ether_cmp(addrp, ðerbroadcastaddr) == 0) || - (flags & IDNSALLPHYS) || - idndl_mcmatch(stp, addrp)) - return (stp); - } - - return (NULL); -} - -/* - * Test upstream destination sap and address match for IDNSALLPHYS only. - */ -/* ARGSUSED3 */ -struct idnstr * -idndl_paccept(register struct idnstr *stp, register struct idn *sip, - int type, struct ether_addr *addrp) -{ - t_uscalar_t sap; - uint_t flags; - - for (; stp; stp = stp->ss_nextp) { - sap = stp->ss_sap; - flags = stp->ss_flags; - - if ((stp->ss_sip == sip) && - IDNSAPMATCH(sap, type, flags) && - (flags & IDNSALLPHYS)) - return (stp); - } - - return (NULL); -} - -/* - * Set or clear the device ipq pointer. - * Assumes IPv4 and IPv6 are IDNSFAST. - */ -static void -idndl_setipq(struct idn *sip) -{ - struct idnstr *stp; - int ok4 = 1; - int ok6 = 1; - queue_t *ip4q = NULL; - queue_t *ip6q = NULL; - - rw_enter(&idn.struprwlock, RW_READER); - - for (stp = idn.strup; stp; stp = stp->ss_nextp) { - if (stp->ss_sip == sip) { - if (stp->ss_flags & (IDNSALLPHYS|IDNSALLSAP)) { - ok4 = 0; - ok6 = 0; - break; - } - if (IS_ETHERTYPE_IPV4(stp->ss_sap)) { - if (ip4q == NULL) - ip4q = stp->ss_rq; - else - ok4 = 0; - /*LINTED*/ - } else if (IS_ETHERTYPE_IPV6(stp->ss_sap)) { - if (ip6q == NULL) - ip6q = stp->ss_rq; - else - ok6 = 0; - } - } - } - - rw_exit(&idn.struprwlock); - - if (ok4) - sip->si_ip4q = ip4q; - else - sip->si_ip4q = NULL; - if (ok6) - sip->si_ip6q = ip6q; - else - sip->si_ip6q = NULL; -} - -/* - * Prefix msg with a DL_UNITDATA_IND mblk and return the new msg. - */ -static mblk_t * -idndl_addudind(struct idn *sip, mblk_t *mp, - struct ether_addr *shostp, struct ether_addr *dhostp, - int type, ulong_t isgroupaddr) -{ - dl_unitdata_ind_t *dludindp; - struct idndladdr *dlap; - mblk_t *nmp; - int size; - - TRACE_0(TR_FAC_IDN, TR_IDN_ADDUDIND_START, "idndl_addudind start"); - - mp->b_rptr += sizeof (struct ether_header); - - /* - * Allocate an M_PROTO mblk for the DL_UNITDATA_IND. - */ - size = sizeof (dl_unitdata_ind_t) + IDNADDRL + IDNADDRL; - nmp = allocb(IDNROUNDUP(IDNHEADROOM + size, sizeof (double)), BPRI_LO); - if (nmp == NULL) { - IDN_KSTAT_INC(sip, si_allocbfail); - IDN_KSTAT_INC(sip, si_ierrors); - if (idn_debug) - serror(sip->si_dip, 451, "allocb failed"); - freemsg(mp); - TRACE_0(TR_FAC_IDN, TR_IDN_ADDUDIND_END, "idndl_addudind end"); - return (NULL); - } - DB_TYPE(nmp) = M_PROTO; - nmp->b_wptr = nmp->b_datap->db_lim; - nmp->b_rptr = nmp->b_wptr - size; - - /* - * Construct a DL_UNITDATA_IND primitive. - */ - dludindp = (dl_unitdata_ind_t *)nmp->b_rptr; - dludindp->dl_primitive = DL_UNITDATA_IND; - dludindp->dl_dest_addr_length = IDNADDRL; - dludindp->dl_dest_addr_offset = sizeof (dl_unitdata_ind_t); - dludindp->dl_src_addr_length = IDNADDRL; - dludindp->dl_src_addr_offset = sizeof (dl_unitdata_ind_t) + IDNADDRL; - dludindp->dl_group_address = isgroupaddr; - - dlap = (struct idndladdr *)(nmp->b_rptr + sizeof (dl_unitdata_ind_t)); - ether_copy(dhostp, &dlap->dl_phys); - dlap->dl_sap = (ushort_t)type; - - dlap = (struct idndladdr *)(nmp->b_rptr + sizeof (dl_unitdata_ind_t) - + IDNADDRL); - ether_copy(shostp, &dlap->dl_phys); - dlap->dl_sap = (ushort_t)type; - - /* - * Link the M_PROTO and M_DATA together. - */ - nmp->b_cont = mp; - TRACE_0(TR_FAC_IDN, TR_IDN_ADDUDIND_END, "idndl_addudind end"); - return (nmp); -} - -/* - * Return TRUE if the given multicast address is one - * of those that this particular Stream is interested in. - */ -static int -idndl_mcmatch(register struct idnstr *stp, register struct ether_addr *addrp) -{ - register struct ether_addr *mctab; - register int mccount; - register int i; - - /* - * Return FALSE if not a multicast address. - */ - if (!IDNDL_ADDR_IS_MULTICAST(addrp)) - return (0); - - /* - * Check if all multicasts have been enabled for this Stream - */ - if (stp->ss_flags & IDNSALLMULTI) - return (1); - - /* - * Return FALSE if no multicast addresses enabled for this Stream. - */ - if (stp->ss_mccount == 0) - return (0); - - /* - * Otherwise, find it in the table. - */ - - mccount = stp->ss_mccount; - mctab = stp->ss_mctab; - - for (i = 0; i < mccount; i++) - if (!ether_cmp(addrp, &mctab[i])) - return (1); - - return (0); -} - -/* - * Start xmit on any msgs previously enqueued on any write queues. - * If the caller passes NULL, then we need to check all - * our interfaces. - */ -void -idndl_wenable(struct idn *sip) -{ - struct idnstr *stp; - queue_t *wq; - - /* - * Order of wantw accesses is important. - */ - ASSERT((sip == NULL) ? RW_LOCK_HELD(&idn.struprwlock) : 1); - ASSERT(MUTEX_HELD(&idn.sipwenlock)); - - do { - if (sip) - sip->si_wantw = 0; - for (stp = idn.strup; stp; stp = stp->ss_nextp) { - if ((!sip || (stp->ss_sip == sip)) && - stp->ss_rq && ((wq = WR(stp->ss_rq))->q_first)) - qenable(wq); - } - } while (sip && sip->si_wantw); -} - -/*VARARGS*/ -static void -serror(dev_info_t *dip, int idnerr, char *fmt, ...) -{ - static long last; - static char *lastfmt; - char msg_buffer[255]; - va_list ap; - time_t now; - - /* - * Don't print same error message too often. - */ - now = gethrestime_sec(); - if ((last == (now & ~1)) && (lastfmt == fmt)) - return; - - last = now & ~1; - lastfmt = fmt; - - va_start(ap, fmt); - (void) vsprintf(msg_buffer, fmt, ap); - cmn_err(CE_CONT, "IDN: %d: %s%d: %s\n", - idnerr, ddi_get_name(dip), - ddi_get_instance(dip), msg_buffer); - va_end(ap); -} diff --git a/usr/src/uts/sun4u/starfire/io/idn_proto.c b/usr/src/uts/sun4u/starfire/io/idn_proto.c deleted file mode 100644 index cebcdb89f7..0000000000 --- a/usr/src/uts/sun4u/starfire/io/idn_proto.c +++ /dev/null @@ -1,12971 +0,0 @@ -/* - * 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 - * or http://www.opensolaris.org/os/licensing. - * 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. - * Copyright (c) 2016 by Delphix. All rights reserved. - */ - -/* - * Inter-Domain Network - * - * IDN Protocol functions to support domain link/unlink/reconfig. - */ - -#include <sys/types.h> -#include <sys/param.h> -#include <sys/machparam.h> -#include <sys/debug.h> -#include <sys/cpuvar.h> -#include <sys/kmem.h> -#include <sys/mutex.h> -#include <sys/rwlock.h> -#include <sys/systm.h> -#include <sys/stream.h> -#include <sys/strsun.h> -#include <sys/stropts.h> -#include <sys/sema_impl.h> -#include <sys/membar.h> -#include <sys/utsname.h> -#include <inet/common.h> -#include <inet/mi.h> -#include <netinet/ip6.h> -#include <inet/ip.h> -#include <netinet/in.h> -#include <sys/vm_machparam.h> -#include <sys/x_call.h> -#include <sys/ddi.h> -#include <sys/sunddi.h> -#include <sys/atomic.h> -#include <vm/as.h> /* kas decl */ - -#include <sys/idn.h> -#include <sys/idn_xf.h> - -#define IDNBUG_CPUPERBOARD - -extern pri_t maxclsyspri; -extern u_longlong_t gettick(); - -clock_t idn_xmit_monitor_freq = 50; - -static int idn_connect(int domid); -static int idn_disconnect(int domid, idn_fin_t fintype, - idn_finarg_t finarg, idn_finsync_t finsync); -static void idn_deconfig(int domid); -static void idn_unlink_domainset(domainset_t domset, idn_fin_t fintype, - idn_finarg_t finarg, idn_finopt_t finopt, - boardset_t idnset); -static void idn_retry_execute(void *arg); -static void idn_retry_submit(void (*func)(uint_t token, void *arg), - void *arg, uint_t token, clock_t ticks); -static void idn_shutdown_datapath(domainset_t domset, int force); -static mblk_t *idn_fill_buffer(caddr_t bufp, int size, mblk_t *mp, - uchar_t **data_rptrp); -static ushort_t idn_cksum(register ushort_t *hdrp, register int count); -static int idn_mark_awol(int domid, clock_t *atime); - -static void idn_recv_proto(idn_protomsg_t *hp); -static void idn_send_config(int domid, int phase); -static void idn_recv_config(int domid, idn_msgtype_t *mtp, - idn_xdcargs_t xargs); -static int idn_send_master_config(int domid, int phase); -static int idn_send_slave_config(int domid, int phase); -static uint_t idn_check_master_config(int domid, uint_t *exp, uint_t *act); -static uint_t idn_check_slave_config(int domid, uint_t *exp, uint_t *act); -static int idn_recv_config_done(int domid); -static void idn_nego_cleanup_check(int domid, int new_masterid, - int new_cpuid); -static void idn_recv_cmd(int domid, idn_msgtype_t *mtp, - idn_xdcargs_t xargs); -static int idn_recv_data(int domid, idn_msgtype_t *mtp, - idn_xdcargs_t xargs); -static int idn_send_data_loopback(idn_netaddr_t dst_netaddr, - queue_t *wq, mblk_t *mp); -static void idn_send_dataresp(int domid, idn_nack_t nacktype); -static int idn_send_mboxdata(int domid, struct idn *sip, int channel, - caddr_t bufp); -static int idn_recv_mboxdata(int channel, caddr_t bufp); -static int idn_program_hardware(int domid); -static int idn_deprogram_hardware(int domid); - -static void idn_send_cmd_nackresp(int domid, idn_msgtype_t *mtp, - idn_cmd_t cmdtype, idn_nack_t nacktype); -static void idn_local_cmd(idn_cmd_t cmdtype, uint_t arg1, - uint_t arg2, uint_t arg3); -static void idn_terminate_cmd(int domid, int serrno); -static void idn_mboxarea_init(idn_mboxtbl_t *mtp, register int ntbls); -static void idn_mainmbox_activate(int domid); -static void idn_mainmbox_deactivate(ushort_t domset); -static void idn_mainmbox_chan_register(int domid, - idn_mainmbox_t *send_mmp, - idn_mainmbox_t *recv_mmp, int channel); -static int idn_mainmbox_chan_unregister(ushort_t domset, int channel); -static int idn_mainmbox_flush(int domid, idn_mainmbox_t *mmp); -static void idn_mainmbox_reset(int domid, idn_mainmbox_t *cmp); -static int idn_activate_channel(idn_chanset_t chanset, - idn_chanop_t chanop); -static void idn_deactivate_channel(idn_chanset_t chanset, - idn_chanop_t chanop); -static int idn_deactivate_channel_services(int channel, - idn_chanop_t chanop); -static int idn_activate_channel_services(int channel); -static void idn_chan_server(idn_chansvr_t **cspp); -#if 0 -static void idn_chan_flush(idn_chansvr_t *csp); -#endif /* 0 */ -static void idn_chan_action(int channel, idn_chanaction_t chanaction, - int wait); -static void idn_chan_addmbox(int channel, ushort_t domset); -static void idn_chan_delmbox(int channel, ushort_t domset); -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); -static void idn_recv_slaballoc_req(int domid, idn_msgtype_t *mtp, - uint_t slab_size); -static void idn_send_slaballoc_resp(int domid, idn_msgtype_t *mtp, - uint_t slab_offset, uint_t slab_size, - int serrno); -static void idn_recv_slaballoc_resp(int domid, smr_offset_t slab_offset, - uint_t slab_size, int serrno); -static void idn_recv_slabreap_req(int domid, idn_msgtype_t *mtp, - int nslabs); -static void idn_recv_slabreap_resp(int domid, int nslabs, int serrno); -static void idn_send_slabreap_resp(int domid, idn_msgtype_t *mtp, - int nslabs, int serrno); -static void idn_recv_slabfree_req(int domid, idn_msgtype_t *mtp, - smr_offset_t slab_offset, uint_t slab_size); -static void idn_recv_slabfree_resp(int domid, uint_t slab_offset, - uint_t slab_size, int serrno); -static void idn_send_slabfree_resp(int domid, idn_msgtype_t *mtp, - uint_t slab_offset, uint_t slab_size, - int serrno); -static void idn_retry_nodename_req(void *arg); -static void idn_send_nodename_req(int domid); -static void idn_send_nodename_resp(int domid, idn_msgtype_t *mtp, - uint_t bufoffset, int serrno); -static void idn_recv_nodename_req(int domid, idn_msgtype_t *mtp, - uint_t bufoffset); -static void idn_recv_nodename_resp(int domid, uint_t bufoffset, - int serrno); - -static void idn_protocol_server(int *id); -static void idn_protocol_server_killall(); -static void idn_protojob_free(idn_protojob_t *jp); - -static int idn_xstate_transfunc(int domid, void *transarg); -static int idn_xphase_transition(int domid, idn_msgtype_t *mtp, - idn_xdcargs_t xargs); -static void idn_sync_enter(int domid, idn_synccmd_t cmd, - domainset_t xset, domainset_t rset, - int (*transfunc)(), void *transarg); -static domainset_t - idn_sync_register(int domid, idn_synccmd_t cmd, - domainset_t ready_set, idn_syncreg_t regtype); -static void idn_sync_register_awol(int domid); -static int idn_verify_config_mbox(int domid); -static int idn_select_master(int domid, int rmasterid, int rcpuid); - -static int valid_mtu(uint_t mtu); -static int valid_bufsize(uint_t bufsize); -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_send_acknack(int domid, idn_msgtype_t *mtp, - idn_xdcargs_t xargs); - -static int idn_send_nego(int domid, idn_msgtype_t *mtp, - domainset_t conset); -static void idn_retry_nego(uint_t token, void *arg); -static int idn_check_nego(int domid, idn_msgtype_t *mtp, - idn_xdcargs_t xargs); -static void idn_action_nego_pend(int domid, idn_msgtype_t *mtp, - idn_xdcargs_t xargs); -static void idn_error_nego(int domid, idn_msgtype_t *mtp, - idn_xdcargs_t xargs); -static void idn_action_nego_sent(int domid, idn_msgtype_t *mtp, - idn_xdcargs_t xargs); -static void idn_action_nego_rcvd(int domid, idn_msgtype_t *mtp, - idn_xdcargs_t xargs); -static void idn_final_nego(int domid); -static void idn_exit_nego(int domid, uint_t msgtype); - -static int idn_send_con(int domid, idn_msgtype_t *mtp, - idn_con_t contype, domainset_t conset); -static void idn_retry_con(uint_t token, void *arg); -static int idn_check_con(int domid, idn_msgtype_t *mtp, - idn_xdcargs_t xargs); -static void idn_action_con_pend(int domid, idn_msgtype_t *mtp, - idn_xdcargs_t xargs); -static void idn_error_con(int domid, idn_msgtype_t *mtp, - idn_xdcargs_t xargs); -static void idn_action_con_sent(int domid, idn_msgtype_t *mtp, - idn_xdcargs_t xargs); -static void idn_action_con_rcvd(int domid, idn_msgtype_t *mtp, - idn_xdcargs_t xargs); -static void idn_final_con(int domid); -static void idn_exit_con(int domid, uint_t msgtype); - -static int idn_send_fin(int domid, idn_msgtype_t *mtp, idn_fin_t fintype, - idn_finarg_t finarg, idn_finopt_t finopt, - domainset_t finset, uint_t finmaster); -static void idn_retry_fin(uint_t token, void *arg); -static int idn_check_fin_pend(int domid, idn_msgtype_t *mtp, - idn_xdcargs_t xargs); -static void idn_action_fin_pend(int domid, idn_msgtype_t *mtp, - idn_xdcargs_t xargs); -static void idn_error_fin_pend(int domid, idn_msgtype_t *mtp, - idn_xdcargs_t xargs); -static int idn_check_fin_sent(int domid, idn_msgtype_t *mtp, - idn_xdcargs_t xargs); -static void idn_action_fin_sent(int domid, idn_msgtype_t *mtp, - idn_xdcargs_t xargs); -static void idn_error_fin_sent(int domid, idn_msgtype_t *mtp, - idn_xdcargs_t xargs); -static void idn_action_fin_rcvd(int domid, idn_msgtype_t *mtp, - idn_xdcargs_t xargs); -static void idn_final_fin(int domid); -static void idn_exit_fin(int domid, uint_t msgtype); - -/* - * We keep a small cache of protojob structures just - * in case allocation within idn_handler comes back - * with nothing from the land of kmem. - */ -idn_protojob_t idn_protojob_cache[IDN_DMV_PENDING_MAX]; -idn_protojob_t *idn_protojob_cache_list; -kmutex_t idn_protojob_cache_lock; - -/* - * - 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 = { - IDNP_NEGO, - { - { IDNDS_NEGO_PEND, - idn_check_nego, - idn_action_nego_pend, - idn_error_nego}, - { IDNDS_NEGO_SENT, - idn_check_nego, - idn_action_nego_sent, - idn_error_nego}, - { IDNDS_NEGO_RCVD, - NULL, - idn_action_nego_rcvd, - NULL }, - { IDNDS_CONFIG, NULL, NULL, NULL }, - }, - idn_final_nego, - idn_exit_nego -}; - -static idn_xphase_t xphase_con = { - IDNP_CON, - { - { IDNDS_CON_PEND, - idn_check_con, - idn_action_con_pend, - idn_error_con}, - { IDNDS_CON_SENT, - idn_check_con, - idn_action_con_sent, - idn_error_con}, - { IDNDS_CON_RCVD, - NULL, - idn_action_con_rcvd, - NULL }, - { IDNDS_CON_READY, NULL, NULL, NULL }, - }, - idn_final_con, - idn_exit_con -}; - -static idn_xphase_t xphase_fin = { - IDNP_FIN, - { - { IDNDS_FIN_PEND, - idn_check_fin_pend, - idn_action_fin_pend, - idn_error_fin_pend }, - { IDNDS_FIN_SENT, - idn_check_fin_sent, - idn_action_fin_sent, - idn_error_fin_sent }, - { IDNDS_FIN_RCVD, - NULL, - idn_action_fin_rcvd, - NULL }, - { IDNDS_DMAP, NULL, NULL, NULL }, - }, - idn_final_fin, - idn_exit_fin -}; - -static int idnxs_state_table[4][5][2] = { - { /* IDNXS_PEND */ - { IDNXS_SENT, IDNXS_PEND }, /* 0 */ - { IDNXS_RCVD, IDNXS_PEND }, /* msg */ - { IDNXS_NIL, IDNXS_PEND }, /* msg+ack */ - { IDNXS_PEND, IDNXS_NIL }, /* ack */ - { IDNXS_PEND, IDNXS_NIL }, /* nack */ - }, - { /* IDNXS_SENT */ - { IDNXS_NIL, IDNXS_NIL }, /* 0 */ - { IDNXS_RCVD, IDNXS_PEND }, /* msg */ - { IDNXS_FINAL, IDNXS_PEND }, /* msg+ack */ - { IDNXS_NIL, IDNXS_NIL }, /* ack */ - { IDNXS_PEND, IDNXS_NIL }, /* nack */ - }, - { /* IDNXS_RCVD */ - { IDNXS_NIL, IDNXS_NIL }, /* 0 */ - { IDNXS_NIL, IDNXS_NIL }, /* msg */ - { IDNXS_FINAL, IDNXS_NIL }, /* msg+ack */ - { IDNXS_FINAL, IDNXS_NIL }, /* ack */ - { IDNXS_PEND, IDNXS_NIL }, /* nack */ - }, - { /* IDNXS_FINAL */ - { IDNXS_NIL, IDNXS_NIL }, /* 0 */ - { IDNXS_NIL, IDNXS_NIL }, /* msg */ - { IDNXS_NIL, IDNXS_NIL }, /* msg+ack */ - { IDNXS_NIL, IDNXS_NIL }, /* ack */ - { IDNXS_NIL, IDNXS_NIL }, /* nack */ - } -}; - -/* - * 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 theirs is different. - * ERROR An impossible condition. - * - * Index: - * 0 = Local - * 1 = Remote - */ -static idn_master_select_t master_select_table[4][4] = { - { /* 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) -{ - static ushort_t num = 0; - ushort_t cookie; - procname_t proc = "idn_assign_cookie"; - - if ((cookie = idn_domain[domid].dcookie_recv) != 0) - return; - - cookie = (ushort_t)(((uint64_t)&idn_domain[domid] >> 8) & 0xff); - while ((cookie ^= num++ & 0xff) == 0) - ; - - PR_PROTO("%s:%d: assigned RECV cookie 0x%x\n", proc, domid, cookie); - - idn_domain[domid].dcookie_recv = cookie; -} - -void -idn_update_priority(int domid, int pri) -{ - idn_domain_t *dp; - procname_t proc = "idn_update_priority"; - - ASSERT(IDN_DLOCK_IS_EXCL(domid)); - - dp = &idn_domain[domid]; - - if (pri >= IDNVOTE_MINPRI) { - dp->dvote.v.priority = pri & IDNVOTE_PRI_MASK; - - PR_PROTO("%s:%d: SETTING PRIORITY to req(%d) " - "(localpri = 0x%x)\n", - proc, domid, pri, IDNVOTE_PRIVALUE(dp->dvote)); - } else { - PR_PROTO("%s:%d: PRIORITIES UNCHANGED (pri = 0x%x)\n", - proc, domid, IDNVOTE_PRIVALUE(dp->dvote)); - } -} - -/* - * Initiate a link between the local domain and the remote domain - * containing the given cpuid. - */ -int -idn_link(int domid, int cpuid, int pri, int waittime, idnsb_error_t *sep) -{ - int rv; - idn_domain_t *dp; - void *opcookie; - procname_t proc = "idn_link"; - - if ((cpuid < 0) || (cpuid >= NCPU)) { - cmn_err(CE_WARN, - "IDN: 201: (LINK) invalid CPU ID (%d)", cpuid); - return (EINVAL); - } - if (waittime < 0) { - cmn_err(CE_WARN, - "IDN: 202: (LINK) invalid time-out value (%d)", - waittime); - return (EINVAL); - } - if (!VALID_DOMAINID(domid)) { - cmn_err(CE_WARN, - "IDN: 203: (LINK) invalid domain ID (%d)", - domid); - return (EINVAL); - } - if (domid == idn.localid) - return (0); - - IDN_SYNC_LOCK(); - IDN_DLOCK_EXCL(domid); - - dp = &idn_domain[domid]; - - switch (dp->dstate) { - case IDNDS_CLOSED: - break; - - case IDNDS_CONNECTED: -#ifdef DEBUG - cmn_err(CE_NOTE, - "!IDN: domain %d (CPU ID %d) already connected", - domid, cpuid); -#endif /* DEBUG */ - IDN_DUNLOCK(domid); - IDN_SYNC_UNLOCK(); - return (0); - - default: - cmn_err(CE_WARN, - "IDN: 204: domain %d state (%s) inappropriate", - domid, idnds_str[dp->dstate]); - IDN_DUNLOCK(domid); - IDN_SYNC_UNLOCK(); - return (EINVAL); - } - - rv = idn_open_domain(domid, cpuid, 0); - if (rv != 0) { - cmn_err(CE_WARN, - "IDN: 205: (%s) failed to open-domain(%d,%d)", - proc, domid, cpuid); - IDN_DUNLOCK(domid); - IDN_SYNC_UNLOCK(); - return (EIO); - } - - - IDN_DLOCK_EXCL(idn.localid); - idn_update_priority(idn.localid, pri); - IDN_DUNLOCK(idn.localid); - - if (waittime > 0) - opcookie = idn_init_op(IDNOP_CONNECTED, DOMAINSET(domid), sep); - - (void) idn_connect(domid); - - IDN_DUNLOCK(domid); - IDN_SYNC_UNLOCK(); - - PR_PROTO("%s:%d: ALLOCATED idn_link(%d)\n", proc, domid, cpuid); - - 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", - proc, domid, idnop_str[IDNOP_CONNECTED], - DOMAINSET(domid)); - - rv = idn_wait_op(opcookie, &domset, waittime); - } - -#ifdef DEBUG - if (rv == 0) { - if (waittime > 0) { - PR_PROTO("%s:%d: connect SUCCEEDED (cpu %d)\n", - proc, domid, cpuid); - } else { - PR_PROTO("%s:%d: connect KICKED OFF (cpu %d)\n", - proc, domid, cpuid); - } - } else { - PR_PROTO("%s:%d: connect FAILED (cpu %d)\n", - proc, domid, cpuid); - } -#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 -idn_unlink(int domid, boardset_t idnset, idn_fin_t fintype, - idn_finopt_t finopt, int waittime, idnsb_error_t *sep) -{ - int rv = 0; - domainset_t domset; - void *opcookie; - procname_t proc = "idn_unlink"; - - - if (waittime < 0) { - cmn_err(CE_WARN, - "IDN: 202: (UNLINK) invalid time-out value (%d)", - waittime); - SET_IDNKERR_IDNERR(sep, IDNKERR_INVALID_WTIME); - SET_IDNKERR_PARAM0(sep, waittime); - return (EINVAL); - } - if (!VALID_DOMAINID(domid)) { - cmn_err(CE_WARN, - "IDN: 203: (UNLINK) invalid domain ID (%d)", - domid); - SET_IDNKERR_IDNERR(sep, IDNKERR_INVALID_DOMAIN); - SET_IDNKERR_PARAM0(sep, domid); - SET_IDNKERR_PARAM1(sep, -1); - return (EINVAL); - } - if (idn.localid == IDN_NIL_DOMID) { -#ifdef DEBUG - cmn_err(CE_NOTE, - "!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. - */ - IDN_SYNC_LOCK(); - IDN_GLOCK_EXCL(); - domset = idn.domset.ds_trans_on | idn.domset.ds_trans_off; - if ((idn.state == IDNGS_OFFLINE) && !domset) { -#ifdef DEBUG - cmn_err(CE_WARN, - "!IDN: %s: local domain not connected to an IDNnet", - proc); -#endif /* DEBUG */ - IDN_GUNLOCK(); - IDN_SYNC_UNLOCK(); - return (0); - } - - if ((domid == IDN_NIL_DOMID) || (domid == idn.localid)) { - domid = idn.localid; - IDN_GSTATE_TRANSITION(IDNGS_DISCONNECT); - IDN_SET_NEW_MASTERID(IDN_NIL_DOMID); - domset = DOMAINSET_ALL; - DOMAINSET_DEL(domset, idn.localid); - } else { - domset = DOMAINSET(domid); - } - IDN_GUNLOCK(); - - if (waittime > 0) - opcookie = idn_init_op(IDNOP_DISCONNECTED, domset, sep); - - idn_unlink_domainset(domset, fintype, IDNFIN_ARG_NONE, finopt, idnset); - - IDN_SYNC_UNLOCK(); - - 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", - proc, domid, idnop_str[IDNOP_DISCONNECTED], - domset); - - rv = idn_wait_op(opcookie, &domset, waittime); - } - - if (rv == 0) { - if (waittime > 0) { - PR_PROTO("%s:%d: disconnect SUCCEEDED\n", - proc, domid); - } else { - PR_PROTO("%s:%d: disconnect KICKED OFF\n", - proc, domid); - } - } else { - PR_PROTO("%s:%d: disconnect FAILED\n", proc, domid); - } - - return (rv); -} - -static void -idn_unlink_domainset(domainset_t domset, idn_fin_t fintype, - idn_finarg_t finarg, idn_finopt_t finopt, - boardset_t idnset) -{ - int d; - domainset_t offset; - procname_t proc = "idn_unlink_domainset"; - - ASSERT(IDN_SYNC_IS_LOCKED()); - - /* - * Determine subset for which we have - * no active connections. - */ - offset = domset & ~(idn.domset.ds_trans_on | - idn.domset.ds_connected | - idn.domset.ds_trans_off | - idn.domset.ds_relink); - /* - * 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). - */ - domset &= ~offset; - - if (offset) - idn_update_op(IDNOP_DISCONNECTED, offset, NULL); - - IDN_GLOCK_EXCL(); - if ((finopt == IDNFIN_OPT_RELINK) && (idn.state != IDNGS_DISCONNECT)) { - /* - * 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 - if (idn.domset.ds_hitlist & domset) { - PR_HITLIST("%s: domset=%x, hitlist=%x, trans_off=%x " - "-> relink = %x -> %x\n", - proc, domset, idn.domset.ds_hitlist, - idn.domset.ds_relink, idn.domset.ds_trans_off, - idn.domset.ds_relink | - (domset & ~idn.domset.ds_trans_off)); - } -#endif /* DEBUG */ - - domset &= ~idn.domset.ds_trans_off; - idn.domset.ds_relink |= domset; - } else { - idn.domset.ds_relink &= ~domset; - } - /* - * Update the ds_trans_on/off so we don't waste - * time talking to these folks. - */ - idn.domset.ds_trans_on &= ~domset; - idn.domset.ds_trans_off |= domset; - - if (domset == 0) { - if ((idn.domset.ds_trans_on | - idn.domset.ds_connected | - idn.domset.ds_trans_off | - idn.domset.ds_relink) == 0) { - PR_HITLIST("%s:%x: HITLIST %x -> 0\n", - proc, domset, idn.domset.ds_hitlist); - idn.domset.ds_hitlist = 0; - IDN_GSTATE_TRANSITION(IDNGS_OFFLINE); - } - IDN_GUNLOCK(); - return; - } - IDN_GUNLOCK(); - - for (d = 0; d < MAX_DOMAINS; d++) { - idn_domain_t *dp; - idn_fin_t ftype; - - if (!DOMAIN_IN_SET(domset, d)) - continue; - - dp = &idn_domain[d]; - IDN_DLOCK_EXCL(d); - IDN_HISTORY_LOG(IDNH_RELINK, d, dp->dstate, - idn.domset.ds_relink); - ftype = fintype; - if ((dp->dcpu != IDN_NIL_DCPU) && dp->dhw.dh_boardset) { - /* - * 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. - */ - if ((idnset & dp->dhw.dh_boardset) == 0) { - PR_PROTO("%s:%d: boardset 0x%x " - "NOT in IDNSET 0x%x\n", - proc, d, dp->dhw.dh_boardset, - idnset); - if (ftype != IDNFIN_FORCE_HARD) - cmn_err(CE_NOTE, - "!IDN: 222: no IDN linkage " - "found (b=0x%x, i=0x%x) " - "upgrading unlink %s to %s", - dp->dhw.dh_boardset, - idnset, idnfin_str[ftype], - idnfin_str[IDNFIN_FORCE_HARD]); - - ftype = IDNFIN_FORCE_HARD; - } else { - PR_PROTO("%s:%d: boardset 0x%x " - "FOUND in IDNSET 0x%x\n", - proc, d, dp->dhw.dh_boardset, - idnset); - } - } - (void) idn_disconnect(d, ftype, finarg, IDNDS_SYNC_TYPE(dp)); - IDN_DUNLOCK(d); - } -} - -/* - * Return w/locks held. - */ -static int -idn_connect(int domid) -{ - idn_xdcargs_t xargs; - idn_domain_t *dp = &idn_domain[domid]; - procname_t proc = "idn_connect"; - - ASSERT(IDN_SYNC_IS_LOCKED()); - ASSERT(IDN_DLOCK_IS_EXCL(domid)); - - ASSERT(dp->dcpu != IDN_NIL_DCPU); - - if (dp->dstate != IDNDS_CLOSED) { - if (DOMAIN_IN_SET(idn.domset.ds_trans_on | - idn.domset.ds_connected, domid)) { - PR_PROTO("%s:%d: already connected or " - "in-progress\n", proc, domid); - } else { - PR_PROTO("%s:%d: current state (%s) != " - "CLOSED\n", proc, domid, - idnds_str[dp->dstate]); - } - return (-1); - } - - ASSERT(!DOMAIN_IN_SET(idn.domset.ds_connected, domid)); - ASSERT(!DOMAIN_IN_SET(idn.domset.ds_trans_off, domid)); - - dp->dxp = &xphase_nego; - IDN_XSTATE_TRANSITION(dp, IDNXS_PEND); - - (void) idn_xphase_transition(domid, NULL, xargs); - - return (0); -} - -/* - * Return w/locks held. - */ -static int -idn_disconnect(int domid, idn_fin_t fintype, idn_finarg_t finarg, - idn_finsync_t finsync) -{ - int new_masterid, new_cpuid = IDN_NIL_DCPU; - uint_t token; - uint_t finmaster; - idn_xdcargs_t xargs; - idn_finopt_t finopt; - idn_domain_t *dp = &idn_domain[domid]; - procname_t proc = "idn_disconnect"; - - ASSERT(IDN_SYNC_IS_LOCKED()); - ASSERT(IDN_DLOCK_IS_EXCL(domid)); - - if (dp->dstate == IDNDS_CLOSED) { - PR_PROTO("%s:%d: already CLOSED\n", proc, domid); - idn_update_op(IDNOP_DISCONNECTED, DOMAINSET(domid), NULL); - return (-1); - } - - /* - * Terminate any outstanding commands that were - * targeted towards this domain. - */ - idn_terminate_cmd(domid, ECANCELED); - - /* - * Terminate any and all retries that may have - * outstanding for this domain. - */ - token = IDN_RETRY_TOKEN(domid, IDN_RETRY_TYPEALL); - (void) idn_retry_terminate(token); - - /* - * Stop all outstanding message timers for - * this guy. - */ - IDN_MSGTIMER_STOP(domid, 0, 0); - - dp->dxp = &xphase_fin; - IDN_XSTATE_TRANSITION(dp, IDNXS_PEND); - if ((int)dp->dfin < (int)fintype) { - /* - * 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. - */ - IDN_FSTATE_TRANSITION(dp, fintype); - } - - dp->dfin_sync = finsync; - PR_PROTO("%s:%d: disconnect synchronously = %s\n", - proc, domid, (finsync == IDNFIN_SYNC_OFF) ? "OFF" : - (finsync == IDNFIN_SYNC_NO) ? "NO" : "YES"); - - IDN_GLOCK_SHARED(); - if (DOMAIN_IN_SET(idn.domset.ds_relink, domid) && - (idn.state != IDNGS_DISCONNECT)) { - finopt = IDNFIN_OPT_RELINK; - } else { - finopt = IDNFIN_OPT_UNLINK; - PR_HITLIST("%s:%d: HITLIST %x -> %x\n", - proc, domid, idn.domset.ds_hitlist, - idn.domset.ds_hitlist | DOMAINSET(domid)); - DOMAINSET_ADD(idn.domset.ds_hitlist, domid); - } - - CLR_XARGS(xargs); - SET_XARGS_FIN_TYPE(xargs, dp->dfin); - SET_XARGS_FIN_ARG(xargs, finarg); - SET_XARGS_FIN_OPT(xargs, finopt); - SET_XARGS_FIN_DOMSET(xargs, 0); /* unused when msg = 0 */ - new_masterid = IDN_GET_NEW_MASTERID(); - IDN_GUNLOCK(); - if (new_masterid != IDN_NIL_DOMID) - new_cpuid = idn_domain[new_masterid].dcpu; - finmaster = MAKE_FIN_MASTER(new_masterid, new_cpuid); - SET_XARGS_FIN_MASTER(xargs, finmaster); - - (void) idn_xphase_transition(domid, NULL, xargs); - - return (0); -} - -static int -idn_next_xstate(idn_xstate_t o_xstate, int err, uint_t msg) -{ - int index; - procname_t proc = "idn_next_xstate"; - - ASSERT(((int)o_xstate >= 0) && ((int)o_xstate <= 4)); - - if (!msg) - index = 0; - else if ((msg & IDNP_MSGTYPE_MASK) == 0) - index = (msg & IDNP_ACK) ? 3 : (msg & IDNP_NACK) ? 4 : -1; - else - index = (msg & IDNP_ACK) ? 2 : - !(msg & IDNP_ACKNACK_MASK) ? 1 : -1; - - if (index == -1) { - STRING(str); - - INUM2STR(msg, str); - PR_PROTO("%s: (msg = 0x%x(%s))\n", proc, msg, str); - 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. - */ - n_xstate = idnxs_state_table[(int)o_xstate][index][0]; - if (n_xstate != IDNXS_NIL) - return (n_xstate); - else - return (idnxs_state_table[(int)o_xstate][index][1]); - } else { - return (idnxs_state_table[(int)o_xstate][index][err ? 1 : 0]); - } -} - -static int -idn_select_candidate(domainset_t master_set) -{ - int d, best_id = IDN_NIL_DOMID; - uint_t best_vote = 0; - idn_domain_t *dp; - procname_t proc = "idn_select_candidate"; - - ASSERT(IDN_SYNC_IS_LOCKED()); - - if (master_set == 0) { - PR_PROTO("%s: %x -> %d\n", proc, master_set, IDN_NIL_DOMID); - return (IDN_NIL_DOMID); - } - - for (d = 0; d < MAX_DOMAINS; d++) { - uint_t vote; - idn_vote_t v; - - if (!DOMAIN_IN_SET(master_set, d)) - continue; - - dp = &idn_domain[d]; - - if ((dp->domid == IDN_NIL_DOMID) || - (dp->dcpu == IDN_NIL_DCPU) || - ((v.ticket = dp->dvote.ticket) == 0)) - continue; - - vote = IDNVOTE_ELECT(v); - - if (vote > best_vote) { - best_vote = vote; - best_id = d; - } - } - - PR_PROTO("%s: %x -> %d\n", proc, master_set, best_id); - - 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 -idn_select_master(int domid, int rmasterid, int rcpuid) -{ - char *sel; - int lmasterid, masterid; - int do_reconfig = 0; - int lindex, rindex; - idn_domain_t *ldp, *rdp; - uint_t rvote, lvote; - idn_master_select_t select; - procname_t proc = "idn_select_master"; - - ASSERT(IDN_SYNC_IS_LOCKED()); - ASSERT(IDN_GLOCK_IS_EXCL()); - ASSERT(IDN_DLOCK_IS_EXCL(domid)); - - PR_PROTO("%s:%d: lmasterid = %d, rmasterid = %d, rcpuid = %d\n", - proc, domid, IDN_GET_MASTERID(), rmasterid, rcpuid); - - IDN_DLOCK_EXCL(idn.localid); - - ldp = &idn_domain[idn.localid]; - rdp = &idn_domain[domid]; - - /* - * 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. - */ - lvote = IDNVOTE_ELECT(ldp->dvote); - rvote = IDNVOTE_ELECT(rdp->dvote); - - lmasterid = IDN_GET_MASTERID(); - - lindex = (lmasterid == IDN_NIL_DOMID) ? MASTER_IS_NONE : - (lmasterid == idn.localid) ? MASTER_IS_LOCAL : - (lmasterid == domid) ? MASTER_IS_REMOTE : - MASTER_IS_OTHER; - - rindex = (rmasterid == IDN_NIL_DOMID) ? MASTER_IS_NONE : - (rmasterid == domid) ? MASTER_IS_REMOTE : - (rmasterid == idn.localid) ? MASTER_IS_LOCAL : - MASTER_IS_OTHER; - - select = master_select_table[lindex][rindex]; - - masterid = IDN_NIL_DOMID; - - /* - * 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 (lvote > rvote) { - /* - * 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. - */ - masterid = idn.localid; - } else if (lvote < rvote) { - do_reconfig = 1; - /* - * GLOCK will get dropped once reconfig - * is kicked off. - */ - } else { - cmn_err(CE_WARN, - "IDN: 206: cannot link domains " - "with equal votes (L(%d),R(%d),0x%x)", - idn.localid, domid, rvote); - IDN_GUNLOCK(); - } - IDN_DUNLOCK(idn.localid); - break; - - case MASTER_SELECT_VOTE: - sel = "VOTE"; - if (lvote > rvote) { - masterid = idn.localid; - ldp->dvote.v.master = 1; - rdp->dvote.v.master = 0; - } else if (lvote < rvote) { - masterid = domid; - ldp->dvote.v.master = 0; - rdp->dvote.v.master = 1; - } else { - cmn_err(CE_WARN, - "IDN: 206: cannot link domains " - "with equal votes (L(%d),R(%d),0x%x)", - idn.localid, domid, rvote); - } - ASSERT(IDN_GET_MASTERID() == IDN_NIL_DOMID); - if (masterid != IDN_NIL_DOMID) { - IDN_SET_MASTERID(masterid); - IDN_SET_NEW_MASTERID(IDN_NIL_DOMID); - } else { - IDN_GUNLOCK(); - } - IDN_DUNLOCK(idn.localid); - break; - - case MASTER_SELECT_REMOTE: - sel = "REMOTE"; - masterid = domid; - if (IDN_GET_MASTERID() == IDN_NIL_DOMID) { - IDN_SET_MASTERID(masterid); - IDN_SET_NEW_MASTERID(IDN_NIL_DOMID); - ldp->dvote.v.master = 0; - rdp->dvote.v.master = 1; - } - ASSERT(IDN_GET_MASTERID() == domid); - IDN_DUNLOCK(idn.localid); - break; - - case MASTER_SELECT_LOCAL: - sel = "LOCAL"; - masterid = idn.localid; - if (IDN_GET_MASTERID() == IDN_NIL_DOMID) { - IDN_SET_MASTERID(masterid); - IDN_SET_NEW_MASTERID(IDN_NIL_DOMID); - ldp->dvote.v.master = 1; - rdp->dvote.v.master = 0; - } - ASSERT(IDN_GET_MASTERID() == idn.localid); - IDN_DUNLOCK(idn.localid); - break; - - case MASTER_SELECT_CONNECT: - sel = "CONNECT"; - if (rmasterid == lmasterid) { - /* - * Local and remote have same master, - * let him come onboard. - */ - masterid = lmasterid; - IDN_DUNLOCK(idn.localid); - - } else { - int rv; - - IDN_DUNLOCK(idn.localid); - IDN_GUNLOCK(); - IDN_DLOCK_EXCL(rmasterid); - PR_PROTO("%s:%d: attempting connect w/remote " - "master %d\n", - proc, domid, rmasterid); - rv = idn_open_domain(rmasterid, rcpuid, 0); - if (rv == 0) { - (void) idn_connect(rmasterid); - } else if (rv < 0) { - cmn_err(CE_WARN, - "IDN: 205: (%s) failed to " - "open-domain(%d,%d)", - proc, rmasterid, rcpuid); - } else { - /* - * Must already have a connection going. - */ - PR_PROTO("%s:%d: failed " - "idn_open_domain(%d,%d,0) " - "(rv = %d)\n", - proc, domid, rmasterid, - rcpuid, rv); - } - IDN_DUNLOCK(rmasterid); - } - 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. - */ - if (rmasterid == lmasterid) { - masterid = lmasterid; - } else { - IDN_GUNLOCK(); - } - IDN_DUNLOCK(idn.localid); - break; - - case MASTER_SELECT_ERROR: - sel = "ERROR"; - /* - * Hit impossible condition. - */ - cmn_err(CE_WARN, - "IDN: 207: local/remote master-id conflict " - "(%d.lmasterid = %d, %d.rmasterid = %d)", - idn.localid, lmasterid, domid, rmasterid); - IDN_GUNLOCK(); - IDN_DUNLOCK(idn.localid); - break; - - default: - cmn_err(CE_WARN, - "IDN: 208: %s: unknown case (%d)", - proc, (int)select); - IDN_GUNLOCK(); - IDN_DUNLOCK(idn.localid); - ASSERT(0); - break; - } - - if (masterid == IDN_NIL_DOMID) { - PR_PROTO("%s:%d: NO MASTER SELECTED (rmstr=%d) sel=%s\n", - proc, domid, rmasterid, sel); - } else { - PR_PROTO("%s:%d: MASTER SELECTED = %d (%s)\n", - proc, domid, masterid, - (masterid == idn.localid) ? "LOCAL" : - (masterid == domid) ? "REMOTE" : "OTHER"); - } - - if (do_reconfig) { - domainset_t dis_set; - - /* - * Local domain already has a master. - * Need to dismantle all connections - * and reestablish one with new master. - */ - IDN_GKSTAT_GLOBAL_EVENT(gk_reconfigs, gk_reconfig_last); - - PR_PROTO("%s:%d: RECONFIG new masterid = %d\n", - proc, domid, domid); - - IDN_GSTATE_TRANSITION(IDNGS_RECONFIG); - IDN_SET_NEW_MASTERID(domid); - IDN_GUNLOCK(); - - dis_set = idn.domset.ds_trans_on | idn.domset.ds_connected; - DOMAINSET_DEL(dis_set, domid); - - idn_unlink_domainset(dis_set, IDNFIN_NORMAL, IDNFIN_ARG_NONE, - IDNFIN_OPT_RELINK, BOARDSET_ALL); - } - - return ((masterid == IDN_NIL_DOMID) ? -1 : 0); -} - -/*ARGSUSED1*/ -static void -idn_retry_query(uint_t token, void *arg) -{ - idn_retry_t rtype = IDN_RETRY_TOKEN2TYPE(token); - int d, domid = IDN_RETRY_TOKEN2DOMID(token); - idn_domain_t *dp = &idn_domain[domid]; - idn_synccmd_t sync_cmd; - domainset_t query_set, my_ready_set; - procname_t proc = "idn_retry_query"; - - IDN_SYNC_LOCK(); - IDN_DLOCK_EXCL(domid); - - switch (rtype) { - case IDNRETRY_CONQ: - sync_cmd = IDNSYNC_CONNECT; - my_ready_set = idn.domset.ds_ready_on | idn.domset.ds_connected; - my_ready_set &= ~idn.domset.ds_trans_off; - DOMAINSET_ADD(my_ready_set, idn.localid); - break; - - case IDNRETRY_FINQ: - sync_cmd = IDNSYNC_DISCONNECT; - my_ready_set = idn.domset.ds_ready_off | - ~idn.domset.ds_connected; - break; - - default: - IDN_DUNLOCK(domid); - IDN_SYNC_UNLOCK(); - return; - } - - if (dp->dsync.s_cmd == sync_cmd) - my_ready_set |= dp->dsync.s_set_rdy; - - query_set = idn_sync_register(domid, sync_cmd, 0, IDNSYNC_REG_QUERY); - - PR_PROTO("%s:%d: query_set = 0x%x\n", proc, domid, query_set); - - if (query_set == 0) { - IDN_DUNLOCK(domid); - IDN_SYNC_UNLOCK(); - 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); - - if ((dp->dsync.s_cmd == sync_cmd) || - (!dp->dcookie_send && - (rtype == IDNRETRY_CONQ))) { - if (d != domid) - IDN_DUNLOCK(d); - continue; - } - - IDN_SYNC_QUERY_UPDATE(domid, d); - - if (rtype == IDNRETRY_CONQ) - (void) idn_send_con(d, NULL, IDNCON_QUERY, - my_ready_set); - else - (void) idn_send_fin(d, NULL, IDNFIN_QUERY, - IDNFIN_ARG_NONE, IDNFIN_OPT_NONE, my_ready_set, - NIL_FIN_MASTER); - if (d != domid) - IDN_DUNLOCK(d); - } - - IDN_DUNLOCK(domid); - IDN_SYNC_UNLOCK(); -} - -static int -idn_send_nego(int domid, idn_msgtype_t *mtp, domainset_t conset) -{ - idn_domain_t *ldp, *dp; - int d, masterid; - uint_t dmask; - uint_t acknack; - uint_t ticket; - idnneg_dset_t dset; - idn_msgtype_t mt; - procname_t proc = "idn_send_nego"; - - ASSERT(IDN_SYNC_IS_LOCKED()); - ASSERT(IDN_DLOCK_IS_EXCL(domid)); - - if (mtp) { - acknack = mtp->mt_mtype & IDNP_ACKNACK_MASK; - mt.mt_mtype = mtp->mt_mtype; - mt.mt_atype = mtp->mt_atype; - mt.mt_cookie = mtp->mt_cookie; - } else { - acknack = 0; - mt.mt_mtype = IDNP_NEGO; - mt.mt_atype = 0; - mt.mt_cookie = IDN_TIMER_PUBLIC_COOKIE; - } - - IDN_GLOCK_SHARED(); - - dp = &idn_domain[domid]; - ldp = &idn_domain[idn.localid]; - - if ((idn.state == IDNGS_RECONFIG) || - ((masterid = IDN_GET_MASTERID()) == IDN_NIL_DOMID)) { - masterid = IDN_GET_NEW_MASTERID(); - if ((masterid == idn.localid) || (masterid == domid)) { - /* - * 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. - */ - masterid = IDN_NIL_DOMID; - } - } - - DOMAINSET_DEL(conset, idn.localid); - DOMAINSET_DEL(conset, domid); - /* - * 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. - */ - conset &= ~idn.domset.ds_hitlist; - if ((masterid != IDN_NIL_DOMID) && - DOMAIN_IN_SET(idn.domset.ds_hitlist, masterid)) { - PR_PROTO("%s:%d: masterid(%d) on hitlist(0x%x) -> -1\n", - proc, domid, masterid, idn.domset.ds_hitlist); - /* - * Yikes, our chosen master is on the hitlist! - */ - masterid = IDN_NIL_DOMID; - } - - dmask = IDNNEG_DSET_MYMASK(); - IDNNEG_DSET_INIT(dset, dmask); - for (d = 0; d < MAX_DOMAINS; d++) { - int cpuid; - - if (!DOMAIN_IN_SET(conset, d)) - continue; - - if ((cpuid = idn_domain[d].dcpu) == IDN_NIL_DCPU) { - ASSERT(d != masterid); - continue; - } - - IDNNEG_DSET_SET(dset, d, cpuid, dmask); - } - IDNNEG_DSET_SET_MASTER(dset, domid, masterid); - ASSERT((masterid != IDN_NIL_DOMID) ? - (idn_domain[masterid].dcpu != IDN_NIL_DCPU) : 1); - IDN_GUNLOCK(); - - IDN_DLOCK_SHARED(idn.localid); - ticket = IDNVOTE_BASICS(ldp->dvote); - /* - * 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", - proc, domid, - (acknack & IDNP_ACK) ? "+ack " : - (acknack & IDNP_NACK) ? "+nack " : " ", - dp->dcpu, ticket, conset, masterid); - - IDN_MSGTIMER_START(domid, IDNP_NEGO, 0, - idn_msg_waittime[IDNP_NEGO], &mt.mt_cookie); - - IDNXDC(domid, &mt, ticket, dset[0], dset[1], dset[2]); - - IDN_DUNLOCK(idn.localid); - - return (0); -} - -static int -idn_recv_nego(int domid, idn_msgtype_t *mtp, idn_xdcargs_t xargs, - ushort_t dcookie) -{ - uint_t msg = mtp->mt_mtype; - idn_msgtype_t mt; - idn_domain_t *dp = &idn_domain[domid]; - idn_xdcargs_t nargs; - procname_t proc = "idn_recv_nego"; - - ASSERT(IDN_SYNC_IS_LOCKED()); - ASSERT(IDN_DLOCK_IS_EXCL(domid)); - - mt.mt_cookie = mtp->mt_cookie; - -#ifdef DEBUG - if (DOMAIN_IN_SET(idn.domset.ds_hitlist, domid)) { - PR_HITLIST("%s:%d: dcpu=%d, dstate=%s, msg=%x, " - "hitlist=%x\n", - proc, domid, dp->dcpu, idnds_str[dp->dstate], - msg, idn.domset.ds_hitlist); - } -#endif /* DEBUG */ - - if (dp->dcpu == IDN_NIL_DCPU) { - int cpuid; - uint_t ticket; - /* - * Brandnew link. Need to open a new domain entry. - */ - ticket = GET_XARGS_NEGO_TICKET(xargs); - cpuid = dp->dcpu_last; - ASSERT(VALID_CPUID(cpuid)); - - if (idn_open_domain(domid, cpuid, ticket) != 0) { - PR_PROTO("%s:%d: FAILED to open doamin " - "(ticket = 0x%x)\n", - proc, domid, ticket); - return (-1); - } - } - - if ((msg & IDNP_MSGTYPE_MASK) == IDNP_NEGO) { - PR_PROTO("%s:%d: assigned SEND cookie 0x%x\n", - proc, domid, dcookie); - dp->dcookie_send = dcookie; - } - - if ((dp->dxp == NULL) && IDNDS_IS_CLOSED(dp)) { - dp->dxp = &xphase_nego; - IDN_XSTATE_TRANSITION(dp, IDNXS_PEND); - } else if (dp->dxp != &xphase_nego) { - 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. - */ - if (dp->dstate == IDNDS_CONNECTED) { - DOMAINSET_ADD(idn.domset.ds_relink, domid); - IDN_HISTORY_LOG(IDNH_RELINK, domid, - dp->dstate, idn.domset.ds_relink); - (void) idn_disconnect(domid, IDNFIN_NORMAL, - IDNFIN_ARG_NONE, IDNFIN_SYNC_YES); - } else { - mt.mt_mtype = IDNP_NACK; - mt.mt_atype = msg; - - CLR_XARGS(nargs); - - if (DOMAIN_IN_SET(idn.domset.ds_hitlist, - domid)) { - SET_XARGS_NACK_TYPE(nargs, - IDNNACK_EXIT); - } else { - int new_masterid; - int new_cpuid = IDN_NIL_DCPU; - - SET_XARGS_NACK_TYPE(nargs, - IDNNACK_RETRY); - IDN_GLOCK_SHARED(); - new_masterid = IDN_GET_NEW_MASTERID(); - if (new_masterid == IDN_NIL_DOMID) - new_masterid = - IDN_GET_MASTERID(); - if (new_masterid != IDN_NIL_DOMID) { - idn_domain_t *mdp; - - mdp = &idn_domain[new_masterid]; - new_cpuid = mdp->dcpu; - } - SET_XARGS_NACK_ARG1(nargs, - new_masterid); - SET_XARGS_NACK_ARG2(nargs, new_cpuid); - IDN_GUNLOCK(); - } - idn_send_acknack(domid, &mt, nargs); - } - } - return (0); - } - - (void) idn_xphase_transition(domid, mtp, xargs); - - return (0); -} - -/*ARGSUSED1*/ -static void -idn_retry_nego(uint_t token, void *arg) -{ - int domid = IDN_RETRY_TOKEN2DOMID(token); - int new_masterid; - idn_domain_t *dp = &idn_domain[domid]; - idn_xdcargs_t xargs; - procname_t proc = "idn_retry_nego"; - - ASSERT(IDN_RETRY_TOKEN2TYPE(token) == IDNRETRY_NEGO); - - IDN_SYNC_LOCK(); - IDN_DLOCK_EXCL(domid); - - if (dp->dxp != &xphase_nego) { - STRING(str); - -#ifdef DEBUG - if (dp->dxp) { - INUM2STR(dp->dxp->xt_msgtype, str); - } -#endif /* DEBUG */ - - PR_PROTO("%s:%d: dxp(%s) != NEGO...bailing...\n", - proc, domid, dp->dxp ? str : "NULL"); - IDN_DUNLOCK(domid); - IDN_SYNC_UNLOCK(); - return; - } - - if (dp->dxstate != IDNXS_PEND) { - PR_PROTO("%s:%d: xstate(%s) != %s...bailing\n", - proc, domid, idnxs_str[dp->dxstate], - idnxs_str[IDNXS_PEND]); - IDN_DUNLOCK(domid); - IDN_SYNC_UNLOCK(); - return; - } - - IDN_GLOCK_SHARED(); - if (idn.state == IDNGS_RECONFIG) { - /* - * Have to try again later after - * reconfig has completed. - */ - PR_PROTO("%s:%d: reconfig in-progress...try later\n", - proc, domid); - idn_retry_submit(idn_retry_nego, NULL, token, - idn_msg_retrytime[IDNP_NEGO]); - IDN_GUNLOCK(); - IDN_DUNLOCK(domid); - IDN_SYNC_UNLOCK(); - return; - } - new_masterid = IDN_GET_NEW_MASTERID(); - if ((idn.state == IDNGS_CONNECT) && - (new_masterid != IDN_NIL_DOMID) && - (domid != new_masterid) && - (idn.localid != 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", - proc, domid, IDN_GET_NEW_MASTERID()); - idn_retry_submit(idn_retry_nego, NULL, token, - idn_msg_retrytime[IDNP_NEGO]); - IDN_GUNLOCK(); - IDN_DUNLOCK(domid); - IDN_SYNC_UNLOCK(); - return; - } - IDN_GUNLOCK(); - - (void) idn_xphase_transition(domid, NULL, xargs); - - IDN_DUNLOCK(domid); - IDN_SYNC_UNLOCK(); -} - -static int -idn_check_nego(int domid, idn_msgtype_t *mtp, idn_xdcargs_t xargs) -{ - int d, new_masterid, masterid; - int cpuid, m_cpuid = -1; - uint_t dmask; - uint_t msg = mtp ? mtp->mt_mtype : 0; - idn_domain_t *dp, *ldp; - domainset_t con_set, pending_set; - idnneg_dset_t dset; - procname_t proc = "idn_check_nego"; - - ASSERT(IDN_SYNC_IS_LOCKED()); - ASSERT(IDN_DLOCK_IS_EXCL(domid)); - - dp = &idn_domain[domid]; - ldp = &idn_domain[idn.localid]; - - if (msg & IDNP_NACK) { - if (GET_XARGS_NACK_TYPE(xargs) == IDNNACK_EXIT) { - PR_HITLIST("%s:%d(%s): (msg=%x) EXIT received, " - "adding to hitlist %x -> %x\n", - proc, domid, idnds_str[dp->dstate], msg, - idn.domset.ds_hitlist, - idn.domset.ds_hitlist | DOMAINSET(domid)); - - DOMAINSET_ADD(idn.domset.ds_hitlist, domid); - return (-1); - } else { - return (0); - } - } - - if (DOMAIN_IN_SET(idn.domset.ds_hitlist, domid)) { - PR_HITLIST("%s:%d(%s): (msg=%x) domain in hitlist (%x) - " - "exiting phase\n", - proc, domid, idnds_str[dp->dstate], msg, - idn.domset.ds_hitlist); - return (-1); - } - - if ((dp->dstate == IDNDS_NEGO_PEND) && (msg & IDNP_MSGTYPE_MASK) && - (msg & IDNP_ACK)) /* nego+ack */ - return (1); - - dmask = (uint_t)-1; - - IDN_GLOCK_EXCL(); - if (idn.state == IDNGS_DISCONNECT) { - PR_PROTO("%s:%d: DISCONNECT in-progress >>> EXIT\n", - proc, domid); - IDN_GUNLOCK(); - return (-1); - } else if (idn.state == IDNGS_OFFLINE) { - IDN_GSTATE_TRANSITION(IDNGS_CONNECT); - IDN_PREP_HWINIT(); - IDN_DLOCK_EXCL(idn.localid); - ldp->dvote.v.connected = 0; - IDN_DUNLOCK(idn.localid); - } - - if (!DOMAIN_IN_SET(idn.domset.ds_trans_on, domid)) { - DOMAINSET_ADD(idn.domset.ds_trans_on, domid); - IDN_HISTORY_LOG(IDNH_NEGO, domid, - idn.domset.ds_trans_on, - idn.domset.ds_connected); - } - - switch (idn.state) { - case IDNGS_RECONFIG: - PR_PROTO("%s:%d: RECONFIG in-progress >>> RETRY\n", - proc, domid); - IDN_GUNLOCK(); - return (1); - - case IDNGS_CONNECT: - new_masterid = IDN_GET_NEW_MASTERID(); - if ((new_masterid != IDN_NIL_DOMID) && - (domid != new_masterid) && - (idn.localid != new_masterid)) { - PR_PROTO("%s:%d: waiting for connect to " - "new master %d\n", - proc, domid, IDN_GET_NEW_MASTERID()); - IDN_GUNLOCK(); - return (1); - } - break; - - default: - break; - } - - ASSERT((idn.state == IDNGS_CONNECT) || (idn.state == IDNGS_ONLINE)); - - con_set = 0; - - if (msg) { - idn_domain_t *mdp; - idn_vote_t vote; - - vote.ticket = GET_XARGS_NEGO_TICKET(xargs); - /* - * Sender should note have set master bit, - * but just in case clear it so local domain - * doesn't get confused. - */ - vote.v.master = 0; - dp->dvote.ticket = vote.ticket; - GET_XARGS_NEGO_DSET(xargs, dset); - /*LINTED*/ - IDNNEG_DSET_GET_MASK(dset, domid, dmask); - IDNNEG_DSET_GET_MASTER(dset, new_masterid); - if (new_masterid == IDNNEG_NO_MASTER) { - new_masterid = IDN_NIL_DOMID; - } else { - /* - * Remote domain has a master. Find - * his cpuid in the dset. We may need - * it to initiate a connection. - */ - if (new_masterid == domid) { - m_cpuid = dp->dcpu; - } else { - IDNNEG_DSET_GET(dset, new_masterid, m_cpuid, - dmask); - if (m_cpuid == -1) { - /* - * Something is bogus if remote domain - * is reporting a valid masterid, but - * doesn't have the cpuid for it. - */ - cmn_err(CE_WARN, - "IDN: 209: remote domain (ID " - "%d, CPU %d) reporting master " - "(ID %d) without CPU ID", - domid, dp->dcpu, new_masterid); - DOMAINSET_ADD(idn.domset.ds_hitlist, - domid); - IDN_GUNLOCK(); - return (-1); - } - } - } - - for (d = 0; d < MAX_DOMAINS; d++) { - if ((d == idn.localid) || (d == domid)) - continue; - IDNNEG_DSET_GET(dset, d, cpuid, dmask); - if (cpuid != -1) { - DOMAINSET_ADD(con_set, d); - } - } - -#ifdef DEBUG - if (idn.domset.ds_hitlist) { - PR_HITLIST("%s:%d: con_set %x -> %x (hitlist = %x)\n", - proc, domid, con_set, - con_set & ~idn.domset.ds_hitlist, - idn.domset.ds_hitlist); - } -#endif /* DEBUG */ - - con_set &= ~idn.domset.ds_hitlist; - - ASSERT(!DOMAIN_IN_SET(con_set, idn.localid)); - ASSERT(!DOMAIN_IN_SET(con_set, domid)); - - if ((new_masterid != IDN_NIL_DOMID) && - DOMAIN_IN_SET(idn.domset.ds_hitlist, new_masterid)) { - PR_HITLIST("%s:%d: new_mstr %d -> -1 (hitlist = %x)\n", - proc, domid, new_masterid, - idn.domset.ds_hitlist); - IDN_GUNLOCK(); - return (1); - } - - if (idn_select_master(domid, new_masterid, m_cpuid) < 0) { - /* - * Returns w/GLOCK dropped if error. - */ - return (1); - } - - masterid = IDN_GET_MASTERID(); - ASSERT(masterid != IDN_NIL_DOMID); - - if (idn.state == IDNGS_CONNECT) { - /* - * This is the initial connection for - * the local domain. - */ - IDN_DLOCK_EXCL(idn.localid); - - if (masterid == idn.localid) { - if (idn_master_init() < 0) { - cmn_err(CE_WARN, - "IDN: 210: failed to init " - "MASTER context"); - ldp->dvote.v.master = 0; - IDN_DUNLOCK(idn.localid); - IDN_GSTATE_TRANSITION(IDNGS_DISCONNECT); - IDN_SET_MASTERID(IDN_NIL_DOMID); - IDN_GUNLOCK(); - return (-1); - } - DSLAB_LOCK_EXCL(idn.localid); - ldp->dslab_state = DSLAB_STATE_LOCAL; - DSLAB_UNLOCK(idn.localid); - ldp->dvote.v.connected = 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. - */ - if (masterid != domid) { - IDN_DUNLOCK(idn.localid); - IDN_GUNLOCK(); - return (1); - } - DSLAB_LOCK_EXCL(idn.localid); - ldp->dslab_state = DSLAB_STATE_REMOTE; - DSLAB_UNLOCK(idn.localid); - } - IDN_DUNLOCK(idn.localid); - /* - * We've sync'd up with the new master. - */ - IDN_GSTATE_TRANSITION(IDNGS_ONLINE); - } - - mdp = &idn_domain[masterid]; - - if ((masterid != domid) && !IDNDS_CONFIG_DONE(mdp)) { - /* - * 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 " - "w/master(%d)\n", proc, domid, masterid); - IDN_GUNLOCK(); - return (1); - } - - DSLAB_LOCK_EXCL(domid); - dp->dslab_state = ldp->dslab_state; - DSLAB_UNLOCK(domid); - if (idn.state != IDNGS_ONLINE) { - IDN_GSTATE_TRANSITION(IDNGS_ONLINE); - } - } - - IDN_GUNLOCK(); - - pending_set = con_set; - pending_set &= ~(idn.domset.ds_trans_on | idn.domset.ds_connected); - idn.domset.ds_trans_on |= pending_set; - - con_set |= idn.domset.ds_trans_on | idn.domset.ds_connected; - con_set &= ~idn.domset.ds_trans_off; - DOMAINSET_ADD(con_set, idn.localid); - - if (dp->dsync.s_cmd != IDNSYNC_CONNECT) { - idn_sync_exit(domid, IDNSYNC_DISCONNECT); - idn_sync_enter(domid, IDNSYNC_CONNECT, - con_set, DOMAINSET(idn.localid), idn_xstate_transfunc, - (void *)IDNP_CON); - } - - /* - * Get this domain registered as an expected domain on - * the remaining domains in the CONNECT synchronization. - */ - (void) idn_sync_register(domid, IDNSYNC_CONNECT, 0, IDNSYNC_REG_NEW); - - /* - * 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. - */ - ASSERT(pending_set ? (dmask != (uint_t)-1) : 1); - - for (d = 0; d < MAX_DOMAINS; d++) { - int rv; - - if (!DOMAIN_IN_SET(pending_set, d)) - continue; - - ASSERT((d != idn.localid) && (d != domid)); - - dp = &idn_domain[d]; - - IDNNEG_DSET_GET(dset, d, cpuid, dmask); - if (cpuid == -1) { - PR_PROTO("%s:%d: failed to get cpuid from dset " - "for domain %d (pset = 0x%x)\n", - proc, domid, d, pending_set); - DOMAINSET_DEL(idn.domset.ds_trans_on, d); - continue; - } - - IDN_DLOCK_EXCL(d); - if ((rv = idn_open_domain(d, cpuid, 0)) != 0) { - PR_PROTO("%s:%d: failed " - "idn_open_domain(%d,%d,0) (rv = %d)\n", - proc, domid, d, cpuid, rv); - if (rv < 0) { - cmn_err(CE_WARN, - "IDN: 205: (%s) failed to " - "open-domain(%d,%d)", - proc, d, cpuid); - DOMAINSET_DEL(idn.domset.ds_trans_on, d); - } else if (DOMAIN_IN_SET(idn.domset.ds_trans_off, d)) { - /* - * We've requested to connect to a domain - * from which we're disconnecting. We - * better mark this guy for relinking. - */ - DOMAINSET_ADD(idn.domset.ds_relink, d); - IDN_HISTORY_LOG(IDNH_RELINK, d, dp->dstate, - idn.domset.ds_relink); - } - IDN_DUNLOCK(d); - continue; - } - - (void) idn_connect(d); - - IDN_DUNLOCK(d); - } - - return (0); -} - -/*ARGSUSED*/ -static void -idn_action_nego_pend(int domid, idn_msgtype_t *mtp, idn_xdcargs_t xargs) -{ - uint_t msg = mtp ? mtp->mt_mtype : 0; - idn_msgtype_t mt; - domainset_t con_set; - - ASSERT(IDN_SYNC_IS_LOCKED()); - ASSERT(IDN_DLOCK_IS_EXCL(domid)); - - con_set = idn.domset.ds_trans_on | idn.domset.ds_connected; - con_set &= ~idn.domset.ds_trans_off; - - if (!msg) { - (void) idn_send_nego(domid, NULL, con_set); - } else { - mt.mt_mtype = IDNP_NEGO | IDNP_ACK; - mt.mt_atype = 0; - mt.mt_cookie = mtp->mt_cookie; - (void) idn_send_nego(domid, &mt, con_set); - } -} - -/*ARGSUSED*/ -static void -idn_error_nego(int domid, idn_msgtype_t *mtp, idn_xdcargs_t xargs) -{ - int new_masterid, new_cpuid; - int retry = 1; - uint_t msg = mtp ? mtp->mt_mtype : 0; - uint_t token; - - ASSERT(IDN_SYNC_IS_LOCKED()); - ASSERT(IDN_DLOCK_IS_EXCL(domid)); - - if (msg & IDNP_NACK) { - idn_nack_t nack; - - nack = GET_XARGS_NACK_TYPE(xargs); - switch (nack) { - case IDNNACK_RETRY: - new_masterid = (int)GET_XARGS_NACK_ARG1(xargs); - new_cpuid = (int)GET_XARGS_NACK_ARG2(xargs); - break; - - case IDNNACK_EXIT: - retry = 0; - /*FALLTHROUGH*/ - - default: - new_masterid = IDN_NIL_DOMID; - new_cpuid = IDN_NIL_DCPU; - break; - } - idn_nego_cleanup_check(domid, new_masterid, new_cpuid); - } - - if (msg & IDNP_MSGTYPE_MASK) { - idn_msgtype_t mt; - idn_xdcargs_t nargs; - - mt.mt_mtype = IDNP_NACK; - mt.mt_atype = msg; - mt.mt_cookie = mtp->mt_cookie; - CLR_XARGS(nargs); - SET_XARGS_NACK_TYPE(nargs, IDNNACK_RETRY); - IDN_GLOCK_SHARED(); - new_masterid = IDN_GET_NEW_MASTERID(); - if (new_masterid == IDN_NIL_DOMID) - new_masterid = IDN_GET_MASTERID(); - if (new_masterid != IDN_NIL_DOMID) - new_cpuid = idn_domain[new_masterid].dcpu; - else - new_cpuid = IDN_NIL_DCPU; - SET_XARGS_NACK_ARG1(nargs, new_masterid); - SET_XARGS_NACK_ARG2(nargs, new_cpuid); - IDN_GUNLOCK(); - idn_send_acknack(domid, &mt, nargs); - } - - if (retry) { - token = IDN_RETRY_TOKEN(domid, IDNRETRY_NEGO); - idn_retry_submit(idn_retry_nego, NULL, token, - idn_msg_retrytime[(int)IDNRETRY_NEGO]); - } else { - DOMAINSET_DEL(idn.domset.ds_relink, domid); - IDN_RESET_COOKIES(domid); - (void) idn_disconnect(domid, IDNFIN_NORMAL, IDNFIN_ARG_NONE, - IDNDS_SYNC_TYPE(&idn_domain[domid])); - } -} - -/*ARGSUSED*/ -static void -idn_action_nego_sent(int domid, idn_msgtype_t *mtp, idn_xdcargs_t xargs) -{ - uint_t msg = mtp ? mtp->mt_mtype : 0; - domainset_t conset; - idn_msgtype_t mt; - - ASSERT(IDN_SYNC_IS_LOCKED()); - ASSERT(IDN_DLOCK_IS_EXCL(domid)); - - mt.mt_cookie = mtp ? mtp->mt_cookie : 0; - - conset = idn.domset.ds_trans_on | idn.domset.ds_connected; - conset &= ~idn.domset.ds_trans_off; - - if ((msg & IDNP_ACKNACK_MASK) == 0) { - /* - * nego - */ - mt.mt_mtype = IDNP_NEGO | IDNP_ACK; - mt.mt_atype = 0; - (void) idn_send_nego(domid, &mt, conset); - } else if (msg & IDNP_MSGTYPE_MASK) { - int d; - idn_xdcargs_t nargs; - idnneg_dset_t dset; - uint_t dmask; - idn_vote_t vote; - - mt.mt_mtype = IDNP_ACK; - mt.mt_atype = msg; - DOMAINSET_DEL(conset, idn.localid); - DOMAINSET_DEL(conset, domid); - - dmask = IDNNEG_DSET_MYMASK(); - IDNNEG_DSET_INIT(dset, dmask); - for (d = 0; d < MAX_DOMAINS; d++) { - int cpuid; - - if (!DOMAIN_IN_SET(conset, d)) - continue; - - if ((cpuid = idn_domain[d].dcpu) == IDN_NIL_DCPU) - continue; - - IDNNEG_DSET_SET(dset, d, cpuid, dmask); - } - IDNNEG_DSET_SET_MASTER(dset, domid, IDN_GET_MASTERID()); - ASSERT((IDN_GET_MASTERID() != IDN_NIL_DOMID) ? - (idn_domain[IDN_GET_MASTERID()].dcpu != IDN_NIL_DCPU) : 1); - vote.ticket = idn_domain[idn.localid].dvote.ticket; - vote.v.master = 0; - CLR_XARGS(nargs); - SET_XARGS_NEGO_TICKET(nargs, vote.ticket); - SET_XARGS_NEGO_DSET(nargs, dset); - /* - * nego+ack - */ - idn_send_acknack(domid, &mt, nargs); - } else { - uint_t token; - int new_masterid, new_cpuid; - int retry = 1; - idn_nack_t nack; - /* - * 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. - */ - nack = GET_XARGS_NACK_TYPE(xargs); - switch (nack) { - case IDNNACK_RETRY: - new_masterid = (int)GET_XARGS_NACK_ARG1(xargs); - new_cpuid = (int)GET_XARGS_NACK_ARG2(xargs); - break; - - case IDNNACK_EXIT: - retry = 0; - /*FALLTHROUGH*/ - - default: - new_masterid = IDN_NIL_DOMID; - new_cpuid = IDN_NIL_DCPU; - break; - } - - idn_nego_cleanup_check(domid, new_masterid, new_cpuid); - - if (retry) { - token = IDN_RETRY_TOKEN(domid, IDNRETRY_NEGO); - idn_retry_submit(idn_retry_nego, NULL, token, - idn_msg_retrytime[(int)IDNRETRY_NEGO]); - } else { - DOMAINSET_DEL(idn.domset.ds_relink, domid); - IDN_RESET_COOKIES(domid); - (void) idn_disconnect(domid, IDNFIN_NORMAL, - IDNFIN_ARG_NONE, - IDNDS_SYNC_TYPE(&idn_domain[domid])); - } - } -} - -/*ARGSUSED*/ -static void -idn_action_nego_rcvd(int domid, idn_msgtype_t *mtp, idn_xdcargs_t xargs) -{ - uint_t msg = mtp ? mtp->mt_mtype : 0; - - ASSERT(IDN_SYNC_IS_LOCKED()); - ASSERT(IDN_DLOCK_IS_EXCL(domid)); - - if (msg & IDNP_NACK) { - uint_t token; - int new_masterid, new_cpuid; - int retry = 1; - idn_nack_t nack; - /* - * 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. - */ - nack = GET_XARGS_NACK_TYPE(xargs); - switch (nack) { - case IDNNACK_RETRY: - new_masterid = (int)GET_XARGS_NACK_ARG1(xargs); - new_cpuid = (int)GET_XARGS_NACK_ARG2(xargs); - break; - - case IDNNACK_EXIT: - retry = 0; - /*FALLTHROUGH*/ - - default: - new_masterid = IDN_NIL_DOMID; - new_cpuid = IDN_NIL_DCPU; - break; - } - - idn_nego_cleanup_check(domid, new_masterid, new_cpuid); - - if (retry) { - token = IDN_RETRY_TOKEN(domid, IDNRETRY_NEGO); - idn_retry_submit(idn_retry_nego, NULL, token, - idn_msg_retrytime[(int)IDNRETRY_NEGO]); - } else { - DOMAINSET_DEL(idn.domset.ds_relink, domid); - IDN_RESET_COOKIES(domid); - (void) idn_disconnect(domid, IDNFIN_NORMAL, - IDNFIN_ARG_NONE, - IDNDS_SYNC_TYPE(&idn_domain[domid])); - } - } -} - -static void -idn_final_nego(int domid) -{ - idn_domain_t *dp = &idn_domain[domid]; - - ASSERT(IDN_SYNC_IS_LOCKED()); - ASSERT(IDN_DLOCK_IS_EXCL(domid)); - - (void) idn_retry_terminate(IDN_RETRY_TOKEN(domid, IDNRETRY_NEGO)); - - ASSERT(dp->dstate == IDNDS_CONFIG); - - dp->dxp = NULL; - IDN_XSTATE_TRANSITION(dp, IDNXS_NIL); - - idn_send_config(domid, 1); -} - -/* - */ -/*ARGSUSED1*/ -static void -idn_exit_nego(int domid, uint_t msgtype) -{ - idn_domain_t *dp; - idn_fin_t fintype; - - ASSERT(IDN_SYNC_IS_LOCKED()); - ASSERT(IDN_DLOCK_IS_EXCL(domid)); - - dp = &idn_domain[domid]; - - fintype = msgtype ? IDNFIN_NORMAL : IDNFIN_FORCE_HARD; - - (void) idn_retry_terminate(IDN_RETRY_TOKEN(domid, IDNRETRY_NEGO)); - - ASSERT(!DOMAIN_IN_SET(idn.domset.ds_connected, domid)); - ASSERT(!DOMAIN_IN_SET(idn.domset.ds_ready_on, domid)); - ASSERT(dp->dxp == &xphase_nego); - - idn_nego_cleanup_check(domid, IDN_NIL_DOMID, IDN_NIL_DCPU); - - IDN_GLOCK_SHARED(); - if ((idn.state != IDNGS_DISCONNECT) && - !DOMAIN_IN_SET(idn.domset.ds_hitlist, domid)) { - DOMAINSET_ADD(idn.domset.ds_relink, domid); - IDN_HISTORY_LOG(IDNH_RELINK, domid, dp->dstate, - idn.domset.ds_relink); - } else { - idn_update_op(IDNOP_ERROR, DOMAINSET(domid), NULL); - DOMAINSET_DEL(idn.domset.ds_relink, domid); - } - 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. - */ - IDN_RESET_COOKIES(domid); - (void) idn_disconnect(domid, fintype, IDNFIN_ARG_NONE, - IDNDS_SYNC_TYPE(dp)); -} - -static void -idn_nego_cleanup_check(int domid, int new_masterid, int new_cpuid) -{ - idn_domain_t *ldp, *dp; - procname_t proc = "idn_nego_cleanup_check"; - - ASSERT(IDN_SYNC_IS_LOCKED()); - ASSERT(IDN_DLOCK_IS_EXCL(domid)); - - dp = &idn_domain[domid]; - ldp = &idn_domain[idn.localid]; - - IDN_GLOCK_EXCL(); - - if (((idn.state == IDNGS_ONLINE) && !idn.domset.ds_connected) || - (idn.state == IDNGS_CONNECT)) { - domainset_t trans_on; - int masterid; - int retry_domid = IDN_NIL_DOMID; - int rv; - - IDN_DLOCK_EXCL(idn.localid); - masterid = (idn.state == IDNGS_ONLINE) ? - IDN_GET_MASTERID() : IDN_GET_NEW_MASTERID(); - trans_on = idn.domset.ds_trans_on; - DOMAINSET_DEL(trans_on, domid); - if (trans_on == 0) { - int d; - domainset_t relink = idn.domset.ds_relink; - /* - * This was the only guy we were trying - * to connect with. - */ - ASSERT((idn.state == IDNGS_ONLINE) ? - ((idn.localid == masterid) || - (domid == masterid)) : 1); - if (idn.localid == masterid) - idn_master_deinit(); - ldp->dvote.v.connected = 0; - ldp->dvote.v.master = 0; - dp->dvote.v.master = 0; - IDN_SET_MASTERID(IDN_NIL_DOMID); - IDN_SET_NEW_MASTERID(new_masterid); - IDN_GSTATE_TRANSITION(IDNGS_CONNECT); - IDN_PREP_HWINIT(); - IDN_DUNLOCK(idn.localid); - 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 != idn.localid) && - (new_masterid != domid)) { - IDN_DLOCK_EXCL(new_masterid); - rv = idn_open_domain(new_masterid, - new_cpuid, 0); - if (rv < 0) { - cmn_err(CE_WARN, - "IDN: 205: (%s) failed to " - "open-domain(%d,%d)", - proc, new_masterid, new_cpuid); - IDN_GLOCK_EXCL(); - IDN_SET_NEW_MASTERID(IDN_NIL_DOMID); - IDN_GUNLOCK(); - } else { - relink = DOMAINSET(new_masterid); - } - IDN_DUNLOCK(new_masterid); - } - DOMAINSET_DEL(relink, domid); - if (relink) - for (d = 0; d < MAX_DOMAINS; d++) { - if (!DOMAIN_IN_SET(relink, d)) - continue; - retry_domid = d; - break; - } - } else if (domid == masterid) { - /* - * 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_DUNLOCK(idn.localid); - dp->dvote.v.master = 0; - IDN_SET_MASTERID(IDN_NIL_DOMID); - IDN_SET_NEW_MASTERID(new_masterid); - - if (idn.state == IDNGS_ONLINE) { - IDN_GKSTAT_GLOBAL_EVENT(gk_reconfigs, - gk_reconfig_last); - IDN_GSTATE_TRANSITION(IDNGS_RECONFIG); - IDN_GUNLOCK(); - idn_unlink_domainset(trans_on, IDNFIN_NORMAL, - IDNFIN_ARG_NONE, - IDNFIN_OPT_RELINK, - BOARDSET_ALL); - } else if ((new_masterid != IDN_NIL_DOMID) && - (new_masterid != idn.localid) && - (new_masterid != domid) && - !DOMAIN_IN_SET(trans_on, new_masterid)) { - IDN_GUNLOCK(); - IDN_DLOCK_EXCL(new_masterid); - rv = idn_open_domain(new_masterid, - new_cpuid, 0); - IDN_GLOCK_EXCL(); - IDN_DUNLOCK(new_masterid); - if (rv < 0) { - cmn_err(CE_WARN, - "IDN: 205: (%s) failed to " - "open-domain(%d,%d)", - proc, new_masterid, - new_cpuid); - IDN_SET_NEW_MASTERID(IDN_NIL_DOMID); - new_masterid = IDN_NIL_DOMID; - } else { - retry_domid = new_masterid; - } - IDN_GUNLOCK(); - } else { - IDN_GUNLOCK(); - } - } else { - IDN_DUNLOCK(idn.localid); - IDN_GUNLOCK(); - } - if (retry_domid != IDN_NIL_DOMID) { - uint_t token; - idn_domain_t *rdp = &idn_domain[retry_domid]; - - IDN_DLOCK_EXCL(retry_domid); - rdp->dxp = &xphase_nego; - IDN_XSTATE_TRANSITION(rdp, IDNXS_PEND); - IDN_DUNLOCK(retry_domid); - token = IDN_RETRY_TOKEN(retry_domid, IDNRETRY_NEGO); - idn_retry_submit(idn_retry_nego, NULL, token, - idn_msg_retrytime[(int)IDNRETRY_NEGO]); - } - } else { - IDN_GUNLOCK(); - } -} - -static int -idn_send_con(int domid, idn_msgtype_t *mtp, idn_con_t contype, domainset_t - conset) -{ - idn_msgtype_t mt; - uint_t acknack; - procname_t proc = "idn_send_con"; - - ASSERT(IDN_SYNC_IS_LOCKED()); - ASSERT(IDN_DLOCK_IS_EXCL(domid)); - - if (mtp) { - acknack = mtp->mt_mtype & IDNP_ACKNACK_MASK; - mt.mt_mtype = mtp->mt_mtype; - mt.mt_atype = mtp->mt_atype; - mt.mt_cookie = mtp->mt_cookie; - } else { - acknack = 0; - mt.mt_mtype = IDNP_CON; - mt.mt_atype = 0; - /* - * For simple CON queries we want a unique - * timer assigned. For others, they - * effectively share one. - */ - if (contype == IDNCON_QUERY) - mt.mt_cookie = 0; - else - mt.mt_cookie = IDN_TIMER_PUBLIC_COOKIE; - } - - ASSERT((contype == IDNCON_QUERY) ? idn_domain[domid].dcookie_send : 1); - - PR_PROTO("%s:%d: sending con%sto (cpu %d) [ct=%s, cs=0x%x]\n", - proc, domid, - (acknack & IDNP_ACK) ? "+ack " : - (acknack & IDNP_NACK) ? "+nack " : " ", - idn_domain[domid].dcpu, - idncon_str[contype], conset); - - IDN_MSGTIMER_START(domid, IDNP_CON, (ushort_t)contype, - idn_msg_waittime[IDNP_CON], &mt.mt_cookie); - - IDNXDC(domid, &mt, (uint_t)contype, (uint_t)conset, 0, 0); - - return (0); -} - -/* - * Must leave w/DLOCK dropped and SYNC_LOCK held. - */ -static int -idn_recv_con(int domid, idn_msgtype_t *mtp, idn_xdcargs_t xargs) -{ - uint_t msg = mtp ? mtp->mt_mtype : 0; - uint_t msgarg = mtp ? mtp->mt_atype : 0; - idn_con_t contype; - domainset_t my_ready_set, ready_set; - idn_msgtype_t mt; - idn_domain_t *dp = &idn_domain[domid]; - idn_xdcargs_t aargs; - procname_t proc = "idn_recv_con"; - - ASSERT(IDN_SYNC_IS_LOCKED()); - ASSERT(IDN_DLOCK_IS_EXCL(domid)); - - mt.mt_cookie = mtp ? mtp->mt_cookie : 0; - - contype = GET_XARGS_CON_TYPE(xargs); - ready_set = GET_XARGS_CON_DOMSET(xargs); - - CLR_XARGS(aargs); - - if (!(msg & IDNP_NACK) && (contype == IDNCON_QUERY)) { - domainset_t query_set; - - query_set = idn_sync_register(domid, IDNSYNC_CONNECT, - ready_set, IDNSYNC_REG_REG); - - my_ready_set = idn.domset.ds_connected | idn.domset.ds_ready_on; - my_ready_set &= ~idn.domset.ds_trans_off; - DOMAINSET_ADD(my_ready_set, idn.localid); - - if (msg & IDNP_MSGTYPE_MASK) { - mt.mt_mtype = IDNP_ACK; - mt.mt_atype = IDNP_CON; - SET_XARGS_CON_TYPE(aargs, contype); - SET_XARGS_CON_DOMSET(aargs, my_ready_set); - idn_send_acknack(domid, &mt, aargs); - } - - if (query_set) { - uint_t token; - - token = IDN_RETRY_TOKEN(domid, IDNRETRY_CONQ); - idn_retry_submit(idn_retry_query, NULL, token, - idn_msg_retrytime[(int)IDNRETRY_CONQ]); - } - - return (0); - } - - if (dp->dxp == NULL) { - STRING(mstr); - STRING(lstr); - /* - * Must have received an inappropriate error - * message as we should already be registered - * by the time we reach here. - */ - INUM2STR(msg, mstr); - INUM2STR(msgarg, lstr); - - PR_PROTO("%s:%d: ERROR: NOT YET REGISTERED (%s/%s)\n", - proc, domid, mstr, lstr); - - if (msg & IDNP_MSGTYPE_MASK) { - mt.mt_mtype = IDNP_NACK; - mt.mt_atype = msg; - SET_XARGS_NACK_TYPE(aargs, IDNNACK_RETRY); - idn_send_acknack(domid, &mt, aargs); - } - - return (-1); - } - - (void) idn_xphase_transition(domid, mtp, xargs); - - return (0); -} - -/*ARGSUSED1*/ -static void -idn_retry_con(uint_t token, void *arg) -{ - int domid = IDN_RETRY_TOKEN2DOMID(token); - idn_domain_t *dp = &idn_domain[domid]; - idn_xdcargs_t xargs; - procname_t proc = "idn_retry_con"; - - ASSERT(IDN_RETRY_TOKEN2TYPE(token) == IDNRETRY_CON); - - IDN_SYNC_LOCK(); - IDN_DLOCK_EXCL(domid); - - if (dp->dxp != &xphase_con) { - STRING(str); - -#ifdef DEBUG - if (dp->dxp) { - INUM2STR(dp->dxp->xt_msgtype, str); - } -#endif /* DEBUG */ - - PR_PROTO("%s:%d: dxp(%s) != CON...bailing...\n", - proc, domid, dp->dxp ? str : "NULL"); - IDN_DUNLOCK(domid); - IDN_SYNC_UNLOCK(); - return; - } - - if ((dp->dsync.s_cmd != IDNSYNC_CONNECT) || - (dp->dxstate != IDNXS_PEND)) { - PR_PROTO("%s:%d: cmd (%s) and/or xstate (%s) not " - "expected (%s/%s)\n", - proc, domid, idnsync_str[dp->dsync.s_cmd], - idnxs_str[dp->dxstate], idnsync_str[IDNSYNC_CONNECT], - idnxs_str[IDNXS_PEND]); - IDN_DUNLOCK(domid); - IDN_SYNC_UNLOCK(); - return; - } - - (void) idn_xphase_transition(domid, NULL, xargs); - - IDN_DUNLOCK(domid); - IDN_SYNC_UNLOCK(); -} - -static int -idn_check_con(int domid, idn_msgtype_t *mtp, idn_xdcargs_t xargs) -{ - int ready; - uint_t msg = mtp ? mtp->mt_mtype : 0; - idn_domain_t *dp = &idn_domain[domid]; - domainset_t ready_set, my_ready_set, query_set; - - ASSERT(IDN_SYNC_IS_LOCKED()); - ASSERT(IDN_DLOCK_IS_EXCL(domid)); - - if (msg & IDNP_NACK) - return (0); - - if ((dp->dstate == IDNDS_CON_PEND) && - (msg & IDNP_MSGTYPE_MASK) && (msg & IDNP_ACK)) /* con+ack */ - return (1); - - if (msg == 0) { - ready_set = idn.domset.ds_connected & - ~idn.domset.ds_trans_off; - } else { - ready_set = GET_XARGS_CON_DOMSET(xargs); - DOMAINSET_ADD(idn.domset.ds_ready_on, domid); - } - - DOMAINSET_ADD(ready_set, idn.localid); - - query_set = idn_sync_register(domid, IDNSYNC_CONNECT, - ready_set, IDNSYNC_REG_REG); - /* - * No need to query this domain as he's already - * in the CON sequence. - */ - DOMAINSET_DEL(query_set, domid); - - ready = (dp->dsync.s_set_exp == dp->dsync.s_set_rdy) ? 1 : 0; - if (ready) { - DOMAINSET_DEL(idn.domset.ds_ready_on, domid); - DOMAINSET_ADD(idn.domset.ds_connected, domid); - } - - if (query_set) { - int d; - - my_ready_set = idn.domset.ds_ready_on | - idn.domset.ds_connected; - my_ready_set &= ~idn.domset.ds_trans_off; - DOMAINSET_ADD(my_ready_set, idn.localid); - - for (d = 0; d < MAX_DOMAINS; d++) { - if (!DOMAIN_IN_SET(query_set, d)) - continue; - - dp = &idn_domain[d]; - - IDN_DLOCK_EXCL(d); - if ((dp->dsync.s_cmd == IDNSYNC_CONNECT) || - !dp->dcookie_send) { - IDN_DUNLOCK(d); - continue; - } - - IDN_SYNC_QUERY_UPDATE(domid, d); - - (void) idn_send_con(d, NULL, IDNCON_QUERY, - my_ready_set); - IDN_DUNLOCK(d); - } - } - - return (!msg ? 0 : (ready ? 0 : 1)); -} - -/*ARGSUSED2*/ -static void -idn_error_con(int domid, idn_msgtype_t *mtp, idn_xdcargs_t xargs) -{ - uint_t token; - uint_t msg = mtp ? mtp->mt_mtype : 0; - - ASSERT(IDN_SYNC_IS_LOCKED()); - ASSERT(IDN_DLOCK_IS_EXCL(domid)); - - if (msg & IDNP_MSGTYPE_MASK) { - idn_msgtype_t mt; - idn_xdcargs_t nargs; - - mt.mt_mtype = IDNP_NACK; - mt.mt_atype = msg; - mt.mt_cookie = mtp->mt_cookie; - CLR_XARGS(nargs); - SET_XARGS_NACK_TYPE(nargs, IDNNACK_RETRY); - idn_send_acknack(domid, &mt, nargs); - } - - token = IDN_RETRY_TOKEN(domid, IDNRETRY_CON); - idn_retry_submit(idn_retry_con, NULL, token, - idn_msg_retrytime[(int)IDNRETRY_CON]); -} - -/*ARGSUSED*/ -static void -idn_action_con_pend(int domid, idn_msgtype_t *mtp, idn_xdcargs_t xargs) -{ - uint_t msg = mtp ? mtp->mt_mtype : 0; - idn_domain_t *dp = &idn_domain[domid]; - idn_msgtype_t mt; - domainset_t my_ready_set; - - ASSERT(IDN_SYNC_IS_LOCKED()); - ASSERT(IDN_DLOCK_IS_EXCL(domid)); - - my_ready_set = dp->dsync.s_set_rdy | idn.domset.ds_ready_on | - idn.domset.ds_connected; - my_ready_set &= ~idn.domset.ds_trans_off; - DOMAINSET_ADD(my_ready_set, idn.localid); - - if (!msg) { - (void) idn_send_con(domid, NULL, IDNCON_NORMAL, my_ready_set); - } else { - mt.mt_mtype = IDNP_CON | IDNP_ACK; - mt.mt_atype = 0; - mt.mt_cookie = mtp->mt_cookie; - (void) idn_send_con(domid, &mt, IDNCON_NORMAL, my_ready_set); - } -} - -static void -idn_action_con_sent(int domid, idn_msgtype_t *mtp, idn_xdcargs_t xargs) -{ - uint_t msg = mtp ? mtp->mt_mtype : 0; - idn_domain_t *dp = &idn_domain[domid]; - idn_con_t contype; - domainset_t my_ready_set; - idn_msgtype_t mt; - - ASSERT(IDN_SYNC_IS_LOCKED()); - ASSERT(IDN_DLOCK_IS_EXCL(domid)); - - mt.mt_cookie = mtp ? mtp->mt_cookie : 0; - - my_ready_set = dp->dsync.s_set_rdy | idn.domset.ds_ready_on | - idn.domset.ds_connected; - my_ready_set &= ~idn.domset.ds_trans_off; - DOMAINSET_ADD(my_ready_set, idn.localid); - - contype = GET_XARGS_CON_TYPE(xargs); - - if ((msg & IDNP_ACKNACK_MASK) == 0) { - /* - * con - */ - mt.mt_mtype = IDNP_CON | IDNP_ACK; - mt.mt_atype = 0; - (void) idn_send_con(domid, &mt, contype, my_ready_set); - } else if (msg & IDNP_MSGTYPE_MASK) { - idn_xdcargs_t cargs; - - mt.mt_mtype = IDNP_ACK; - mt.mt_atype = msg; - CLR_XARGS(cargs); - SET_XARGS_CON_TYPE(cargs, contype); - SET_XARGS_CON_DOMSET(cargs, my_ready_set); - /* - * con+ack - */ - idn_send_acknack(domid, &mt, cargs); - } else { - uint_t token; - /* - * nack - retry - */ - token = IDN_RETRY_TOKEN(domid, IDNRETRY_CON); - idn_retry_submit(idn_retry_con, NULL, token, - idn_msg_retrytime[(int)IDNRETRY_CON]); - } -} - -/*ARGSUSED*/ -static void -idn_action_con_rcvd(int domid, idn_msgtype_t *mtp, idn_xdcargs_t xargs) -{ - uint_t msg = mtp ? mtp->mt_mtype : 0; - - ASSERT(IDN_SYNC_IS_LOCKED()); - ASSERT(IDN_DLOCK_IS_EXCL(domid)); - - if (msg & IDNP_NACK) { - uint_t token; - /* - * nack - retry - */ - token = IDN_RETRY_TOKEN(domid, IDNRETRY_CON); - idn_retry_submit(idn_retry_con, NULL, token, - idn_msg_retrytime[(int)IDNRETRY_CON]); - } -} - -static void -idn_final_con(int domid) -{ - uint_t targ; - uint_t token = IDN_RETRY_TOKEN(domid, IDNRETRY_CON); - idn_domain_t *dp = &idn_domain[domid]; - procname_t proc = "idn_final_con"; - - ASSERT(IDN_SYNC_IS_LOCKED()); - ASSERT(IDN_DLOCK_IS_EXCL(domid)); - - (void) idn_retry_terminate(token); - - dp->dxp = NULL; - IDN_XSTATE_TRANSITION(dp, IDNXS_NIL); - - idn_sync_exit(domid, IDNSYNC_CONNECT); - - CHECKPOINT_OPENED(IDNSB_CHKPT_LINK, dp->dhw.dh_boardset, 1); - - DOMAINSET_DEL(idn.domset.ds_trans_on, domid); - DOMAINSET_DEL(idn.domset.ds_relink, domid); - IDN_FSTATE_TRANSITION(dp, IDNFIN_OFF); - - PR_PROTO("%s:%d: CONNECTED\n", proc, domid); - - if (idn.domset.ds_trans_on == 0) { - if ((idn.domset.ds_trans_off | idn.domset.ds_relink) == 0) { - PR_HITLIST("%s:%d: HITLIST %x -> 0\n", - proc, domid, idn.domset.ds_hitlist); - idn.domset.ds_hitlist = 0; - } - PR_PROTO("%s:%d: ALL CONNECTED ************ " - "(0x%x + 0x%x) = 0x%x\n", proc, domid, - DOMAINSET(idn.localid), idn.domset.ds_connected, - DOMAINSET(idn.localid) | idn.domset.ds_connected); - } else { - PR_PROTO("%s:%d: >>> ds_trans_on = 0x%x, ds_ready_on = 0x%x\n", - proc, domid, - idn.domset.ds_trans_on, idn.domset.ds_ready_on); - } - - if (idn_verify_config_mbox(domid)) { - idnsb_error_t idnerr; - /* - * Mailbox is not cool. Need to disconnect. - */ - INIT_IDNKERR(&idnerr); - SET_IDNKERR_ERRNO(&idnerr, EPROTO); - SET_IDNKERR_IDNERR(&idnerr, IDNKERR_SMR_CORRUPTED); - SET_IDNKERR_PARAM0(&idnerr, domid); - idn_update_op(IDNOP_ERROR, DOMAINSET(domid), &idnerr); - /* - * 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. - */ - (void) idn_disconnect(domid, IDNFIN_NORMAL, IDNFIN_ARG_SMRBAD, - IDNFIN_SYNC_YES); - - return; - } - - if (lock_try(&idn.first_swlink)) { - /* - * This is our first connection. Need to - * kick some stuff into gear. - */ - idndl_dlpi_init(); - (void) idn_activate_channel(CHANSET_ALL, IDNCHAN_ONLINE); - - targ = 0xf0; - } else { - targ = 0; - } - - idn_mainmbox_activate(domid); - - idn_update_op(IDNOP_CONNECTED, DOMAINSET(domid), NULL); - - IDN_GKSTAT_GLOBAL_EVENT(gk_links, gk_link_last); - - membar_stst_ldst(); - - IDN_DSTATE_TRANSITION(dp, IDNDS_CONNECTED); - /* - * 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. - */ - targ |= domid & 0x0f; - (void) timeout(idn_link_established, (void *)(uintptr_t)targ, 50); - - cmn_err(CE_NOTE, - "!IDN: 200: link (domain %d, CPU %d) connected", - dp->domid, dp->dcpu); -} - -static void -idn_exit_con(int domid, uint_t msgtype) -{ - idn_domain_t *dp = &idn_domain[domid]; - idn_fin_t fintype; - procname_t proc = "idn_exit_con"; - STRING(str); - - ASSERT(IDN_SYNC_IS_LOCKED()); - ASSERT(IDN_DLOCK_IS_EXCL(domid)); - - INUM2STR(msgtype, str); - PR_PROTO("%s:%d: msgtype = 0x%x(%s)\n", proc, domid, msgtype, str); - - fintype = msgtype ? IDNFIN_NORMAL : IDNFIN_FORCE_HARD; - - IDN_GLOCK_SHARED(); - if (idn.state != IDNGS_DISCONNECT) { - DOMAINSET_ADD(idn.domset.ds_relink, domid); - IDN_HISTORY_LOG(IDNH_RELINK, domid, dp->dstate, - idn.domset.ds_relink); - } else { - DOMAINSET_DEL(idn.domset.ds_relink, domid); - } - IDN_GUNLOCK(); - - (void) idn_disconnect(domid, fintype, IDNFIN_ARG_NONE, - IDNDS_SYNC_TYPE(dp)); -} - -static int -idn_send_fin(int domid, idn_msgtype_t *mtp, idn_fin_t fintype, idn_finarg_t - finarg, idn_finopt_t finopt, domainset_t finset, uint_t finmaster) -{ - int need_timer = 1; - uint_t acknack; - uint_t fintypearg = 0; - idn_msgtype_t mt; - idn_domain_t *dp = &idn_domain[domid]; - procname_t proc = "idn_send_fin"; - - ASSERT(IDN_SYNC_IS_LOCKED()); - ASSERT(IDN_DLOCK_IS_HELD(domid)); - - ASSERT((fintype != IDNFIN_QUERY) ? (finopt != IDNFIN_OPT_NONE) : 1); - - if (mtp) { - acknack = mtp->mt_mtype & IDNP_ACKNACK_MASK; - mt.mt_mtype = mtp->mt_mtype; - mt.mt_atype = mtp->mt_atype; - mt.mt_cookie = mtp->mt_cookie; - } else { - acknack = 0; - mt.mt_mtype = IDNP_FIN; - mt.mt_atype = 0; - /* - * For simple FIN queries we want a unique - * timer assigned. For others, they - * effectively share one. - */ - if (fintype == IDNFIN_QUERY) - mt.mt_cookie = 0; - else - mt.mt_cookie = IDN_TIMER_PUBLIC_COOKIE; - } - - PR_PROTO("%s:%d: sending fin%sto (cpu %d) " - "[ft=%s, fa=%s, fs=0x%x, fo=%s, fm=(%d,%d)]\n", - proc, domid, - (acknack & IDNP_ACK) ? "+ack " : - (acknack & IDNP_NACK) ? "+nack " : " ", - dp->dcpu, idnfin_str[fintype], idnfinarg_str[finarg], - (int)finset, idnfinopt_str[finopt], - FIN_MASTER_DOMID(finmaster), FIN_MASTER_CPUID(finmaster)); - - if (need_timer) { - IDN_MSGTIMER_START(domid, IDNP_FIN, (ushort_t)fintype, - idn_msg_waittime[IDNP_FIN], &mt.mt_cookie); - } - - SET_FIN_TYPE(fintypearg, fintype); - SET_FIN_ARG(fintypearg, finarg); - - IDNXDC(domid, &mt, fintypearg, (uint_t)finset, (uint_t)finopt, - finmaster); - - return (0); -} - -/* - * Must leave w/DLOCK dropped and SYNC_LOCK held. - */ -static int -idn_recv_fin(int domid, idn_msgtype_t *mtp, idn_xdcargs_t xargs) -{ - uint_t msg = mtp ? mtp->mt_mtype : 0; - idn_fin_t fintype; - idn_finarg_t finarg; - idn_finopt_t finopt; - domainset_t my_ready_set, ready_set; - idn_msgtype_t mt; - idn_domain_t *dp = &idn_domain[domid]; - idn_xdcargs_t aargs; - procname_t proc = "idn_recv_fin"; - - ASSERT(IDN_SYNC_IS_LOCKED()); - ASSERT(IDN_DLOCK_IS_EXCL(domid)); - - mt.mt_cookie = mtp ? mtp->mt_cookie : 0; - - fintype = GET_XARGS_FIN_TYPE(xargs); - finarg = GET_XARGS_FIN_ARG(xargs); - ready_set = GET_XARGS_FIN_DOMSET(xargs); - finopt = GET_XARGS_FIN_OPT(xargs); - - CLR_XARGS(aargs); - - if (msg & IDNP_NACK) { - PR_PROTO("%s:%d: received NACK (type = %s)\n", - proc, domid, idnnack_str[xargs[0]]); - } else { - PR_PROTO("%s:%d: fintype = %s, finopt = %s, " - "finarg = %s, ready_set = 0x%x\n", - proc, domid, idnfin_str[fintype], - idnfinopt_str[finopt], - idnfinarg_str[finarg], ready_set); - } - - if (!(msg & IDNP_NACK) && (fintype == IDNFIN_QUERY)) { - domainset_t query_set; - - query_set = idn_sync_register(domid, IDNSYNC_DISCONNECT, - ready_set, IDNSYNC_REG_REG); - - my_ready_set = ~idn.domset.ds_connected | - idn.domset.ds_ready_off; - - if (msg & IDNP_MSGTYPE_MASK) { - mt.mt_mtype = IDNP_ACK; - mt.mt_atype = IDNP_FIN; - SET_XARGS_FIN_TYPE(aargs, fintype); - SET_XARGS_FIN_ARG(aargs, finarg); - SET_XARGS_FIN_DOMSET(aargs, my_ready_set); - SET_XARGS_FIN_OPT(aargs, IDNFIN_OPT_NONE); - SET_XARGS_FIN_MASTER(aargs, NIL_FIN_MASTER); - idn_send_acknack(domid, &mt, aargs); - } - - if (query_set) { - uint_t token; - - token = IDN_RETRY_TOKEN(domid, IDNRETRY_FINQ); - idn_retry_submit(idn_retry_query, NULL, token, - idn_msg_retrytime[(int)IDNRETRY_FINQ]); - } - - return (0); - } - - if (dp->dxp != &xphase_fin) { - uint_t token; - - if (IDNDS_IS_CLOSED(dp)) { - PR_PROTO("%s:%d: domain already closed (%s)\n", - proc, domid, idnds_str[dp->dstate]); - if (msg & IDNP_MSGTYPE_MASK) { - /* - * fin or fin+ack. - */ - mt.mt_mtype = IDNP_NACK; - mt.mt_atype = msg; - SET_XARGS_NACK_TYPE(aargs, IDNNACK_NOCONN); - idn_send_acknack(domid, &mt, aargs); - } - return (0); - } - dp->dfin_sync = IDNDS_SYNC_TYPE(dp); - - /* - * Need to do some clean-up ala idn_disconnect(). - * - * Terminate any outstanding commands that were - * targeted towards this domain. - */ - idn_terminate_cmd(domid, ECANCELED); - - /* - * Terminate any and all retries that may have - * outstanding for this domain. - */ - token = IDN_RETRY_TOKEN(domid, IDN_RETRY_TYPEALL); - (void) idn_retry_terminate(token); - - /* - * Stop all outstanding message timers for - * this guy. - */ - IDN_MSGTIMER_STOP(domid, 0, 0); - - dp->dxp = &xphase_fin; - IDN_XSTATE_TRANSITION(dp, IDNXS_PEND); - } - - if (msg & IDNP_NACK) { - idn_nack_t nack; - - nack = GET_XARGS_NACK_TYPE(xargs); - if (nack == IDNNACK_NOCONN) { - /* - * We're trying to FIN with somebody we're - * already disconnected from. Need to - * speed this guy through. - */ - DOMAINSET_ADD(idn.domset.ds_ready_off, domid); - (void) idn_sync_register(domid, IDNSYNC_DISCONNECT, - DOMAINSET_ALL, IDNSYNC_REG_REG); - ready_set = (uint_t)DOMAINSET_ALL; - /* - * Need to transform message to allow us to - * pass this guy right through and not waste time - * talking to him. - */ - IDN_FSTATE_TRANSITION(dp, IDNFIN_FORCE_HARD); - - switch (dp->dstate) { - case IDNDS_FIN_PEND: - mtp->mt_mtype = 0; - mtp->mt_atype = 0; - break; - - case IDNDS_FIN_SENT: - mtp->mt_mtype = IDNP_FIN | IDNP_ACK; - mtp->mt_atype = 0; - break; - - case IDNDS_FIN_RCVD: - mtp->mt_mtype = IDNP_ACK; - mtp->mt_atype = IDNP_FIN | IDNP_ACK; - break; - - default: -#ifdef DEBUG - cmn_err(CE_PANIC, - "%s:%d: UNEXPECTED state = %s", - proc, domid, - idnds_str[dp->dstate]); -#endif /* DEBUG */ - break; - } - } - fintype = (uint_t)dp->dfin; - finopt = DOMAIN_IN_SET(idn.domset.ds_relink, domid) ? - IDNFIN_OPT_RELINK : IDNFIN_OPT_UNLINK; - - CLR_XARGS(xargs); - SET_XARGS_FIN_TYPE(xargs, fintype); - SET_XARGS_FIN_ARG(xargs, finarg); - SET_XARGS_FIN_DOMSET(xargs, ready_set); - SET_XARGS_FIN_OPT(xargs, finopt); - SET_XARGS_FIN_MASTER(xargs, NIL_FIN_MASTER); - } - - (void) idn_xphase_transition(domid, mtp, xargs); - - return (0); -} - -/*ARGSUSED1*/ -static void -idn_retry_fin(uint_t token, void *arg) -{ - int domid = IDN_RETRY_TOKEN2DOMID(token); - int new_masterid, new_cpuid = IDN_NIL_DCPU; - uint_t finmaster; - idn_domain_t *dp = &idn_domain[domid]; - idn_xdcargs_t xargs; - idn_finopt_t finopt; - procname_t proc = "idn_retry_fin"; - - ASSERT(IDN_RETRY_TOKEN2TYPE(token) == IDNRETRY_FIN); - - IDN_SYNC_LOCK(); - IDN_DLOCK_EXCL(domid); - - if (dp->dxp != &xphase_fin) { - PR_PROTO("%s:%d: dxp(0x%p) != xstate_fin(0x%p)...bailing\n", - proc, domid, (void *)dp->dxp, (void *)&xphase_fin); - IDN_DUNLOCK(domid); - IDN_SYNC_UNLOCK(); - return; - } - - if (dp->dxstate != IDNXS_PEND) { - PR_PROTO("%s:%d: xstate(%s) != %s...bailing\n", - proc, domid, idnxs_str[dp->dxstate], - idnxs_str[IDNXS_PEND]); - IDN_DUNLOCK(domid); - IDN_SYNC_UNLOCK(); - return; - } - - finopt = DOMAIN_IN_SET(idn.domset.ds_relink, domid) ? - IDNFIN_OPT_RELINK : IDNFIN_OPT_UNLINK; - - CLR_XARGS(xargs); - SET_XARGS_FIN_TYPE(xargs, dp->dfin); - /*LINTED*/ - SET_XARGS_FIN_ARG(xargs, IDNFIN_ARG_NONE); - SET_XARGS_FIN_OPT(xargs, finopt); - SET_XARGS_FIN_DOMSET(xargs, 0); /* unused when msg == 0 */ - IDN_GLOCK_SHARED(); - new_masterid = IDN_GET_NEW_MASTERID(); - IDN_GUNLOCK(); - if (new_masterid != IDN_NIL_DOMID) - new_cpuid = idn_domain[new_masterid].dcpu; - finmaster = MAKE_FIN_MASTER(new_masterid, new_cpuid); - SET_XARGS_FIN_MASTER(xargs, finmaster); - - (void) idn_xphase_transition(domid, NULL, xargs); - - IDN_DUNLOCK(domid); - IDN_SYNC_UNLOCK(); -} - -static int -idn_check_fin_pend(int domid, idn_msgtype_t *mtp, idn_xdcargs_t xargs) -{ - idn_domain_t *dp = &idn_domain[domid]; - idn_fin_t fintype; - idn_finopt_t finopt; - idn_finarg_t finarg; - int ready; - int finmasterid; - int fincpuid; - uint_t finmaster; - uint_t msg = mtp ? mtp->mt_mtype : 0; - domainset_t query_set, ready_set, conn_set; - domainset_t my_ready_set, shutdown_set; - procname_t proc = "idn_check_fin_pend"; - - ASSERT(IDN_SYNC_IS_LOCKED()); - ASSERT(IDN_DLOCK_IS_EXCL(domid)); - - if (msg & IDNP_NACK) - return (0); - - if ((dp->dstate == IDNDS_FIN_PEND) && (msg & IDNP_MSGTYPE_MASK) && - (msg & IDNP_ACK)) /* fin+ack */ - return (1); - - query_set = 0; - - if (!DOMAIN_IN_SET(idn.domset.ds_trans_off, domid)) { - /* - * Can't remove domain from ds_connected yet, - * since he's still officially connected until - * we get an ACK from him. - */ - DOMAINSET_DEL(idn.domset.ds_trans_on, domid); - DOMAINSET_ADD(idn.domset.ds_trans_off, domid); - } - - IDN_GLOCK_SHARED(); - conn_set = (idn.domset.ds_connected | idn.domset.ds_trans_on) & - ~idn.domset.ds_trans_off; - if ((idn.state == IDNGS_DISCONNECT) || - (idn.state == IDNGS_RECONFIG) || - (domid == IDN_GET_MASTERID()) || !conn_set) { - /* - * If we're disconnecting, reconfiguring, - * unlinking from the master, or unlinking - * the last of our connections, then we need - * to shutdown all the channels. - */ - shutdown_set = DOMAINSET_ALL; - } else { - shutdown_set = DOMAINSET(domid); - } - IDN_GUNLOCK(); - - idn_shutdown_datapath(shutdown_set, (dp->dfin == IDNFIN_FORCE_HARD)); - - IDN_GLOCK_EXCL(); - /* - * 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. - */ - if ((domid == IDN_GET_MASTERID()) && (idn.smr.rempfn != PFN_INVALID)) { - PR_PROTO("%s:%d: deconfiging CURRENT MASTER - SMR remap\n", - proc, domid); - IDN_DLOCK_EXCL(idn.localid); - /* - * We're going to remap the SMR, - * so gotta blow away our local - * pointer to the mbox table. - */ - idn_domain[idn.localid].dmbox.m_tbl = NULL; - IDN_DUNLOCK(idn.localid); - - idn.smr.rempfn = PFN_INVALID; - idn.smr.rempfnlim = PFN_INVALID; - - smr_remap(&kas, idn.smr.vaddr, idn.smr.locpfn, IDN_SMR_SIZE); - } - IDN_GUNLOCK(); - - if (DOMAIN_IN_SET(idn.domset.ds_flush, domid)) { - idnxf_flushall_ecache(); - CHECKPOINT_CLOSED(IDNSB_CHKPT_CACHE, dp->dhw.dh_boardset, 2); - DOMAINSET_DEL(idn.domset.ds_flush, domid); - } - - fintype = GET_XARGS_FIN_TYPE(xargs); - finarg = GET_XARGS_FIN_ARG(xargs); - ready_set = GET_XARGS_FIN_DOMSET(xargs); - finopt = GET_XARGS_FIN_OPT(xargs); - - ASSERT(fintype != IDNFIN_QUERY); - if (!VALID_FIN(fintype)) { - /* - * 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", - proc, domid, (int)fintype, - idnfin_str[IDNFIN_NORMAL], (int)IDNFIN_NORMAL); - fintype = IDNFIN_NORMAL; - } - - if (!VALID_FINOPT(finopt)) { - PR_PROTO("%s:%d: WARNING invalid finopt (%d) -> %s(%d)\n", - proc, domid, (int)finopt, - idnfinopt_str[IDNFIN_OPT_UNLINK], - (int)IDNFIN_OPT_UNLINK); - finopt = IDNFIN_OPT_UNLINK; - } - - finmaster = GET_XARGS_FIN_MASTER(xargs); - finmasterid = FIN_MASTER_DOMID(finmaster); - fincpuid = FIN_MASTER_CPUID(finmaster); - - if ((finarg != IDNFIN_ARG_NONE) && - !DOMAIN_IN_SET(idn.domset.ds_hitlist, domid)) { - idnsb_error_t idnerr; - - INIT_IDNKERR(&idnerr); - SET_IDNKERR_ERRNO(&idnerr, EPROTO); - SET_IDNKERR_IDNERR(&idnerr, FINARG2IDNKERR(finarg)); - SET_IDNKERR_PARAM0(&idnerr, domid); - - if (IDNFIN_ARG_IS_FATAL(finarg)) { - finopt = IDNFIN_OPT_UNLINK; - DOMAINSET_DEL(idn.domset.ds_relink, domid); - DOMAINSET_ADD(idn.domset.ds_hitlist, domid); - - if (idn.domset.ds_connected == 0) { - domainset_t domset; - - IDN_GLOCK_EXCL(); - domset = ~idn.domset.ds_relink; - if (idn.domset.ds_relink == 0) { - IDN_GSTATE_TRANSITION(IDNGS_DISCONNECT); - } - domset &= ~idn.domset.ds_hitlist; - /* - * 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_SET_NEW_MASTERID(IDN_NIL_DOMID); - IDN_GUNLOCK(); - IDN_DUNLOCK(domid); - - DOMAINSET_DEL(domset, idn.localid); - DOMAINSET_DEL(domset, domid); - - idn_update_op(IDNOP_ERROR, DOMAINSET_ALL, - &idnerr); - - PR_HITLIST("%s:%d: unlink_domainset(%x) " - "due to CFG error (relink=%x, " - "hitlist=%x)\n", proc, domid, domset, - idn.domset.ds_relink, - idn.domset.ds_hitlist); - - idn_unlink_domainset(domset, IDNFIN_NORMAL, - finarg, IDNFIN_OPT_UNLINK, BOARDSET_ALL); - IDN_DLOCK_EXCL(domid); - } - PR_HITLIST("%s:%d: CFG error, (conn=%x, relink=%x, " - "hitlist=%x)\n", - proc, domid, idn.domset.ds_connected, - idn.domset.ds_relink, idn.domset.ds_hitlist); - } - idn_update_op(IDNOP_ERROR, DOMAINSET(domid), &idnerr); - } - - if ((finmasterid != IDN_NIL_DOMID) && (!VALID_DOMAINID(finmasterid) || - DOMAIN_IN_SET(idn.domset.ds_hitlist, domid))) { - PR_HITLIST("%s:%d: finmasterid = %d -> -1, relink=%x, " - "hitlist=%x\n", - proc, domid, finmasterid, idn.domset.ds_relink, - idn.domset.ds_hitlist); - PR_PROTO("%s:%d: WARNING invalid finmasterid (%d) -> -1\n", - proc, domid, finmasterid); - finmasterid = IDN_NIL_DOMID; - } - - IDN_GLOCK_EXCL(); - - if ((finopt == IDNFIN_OPT_RELINK) && (idn.state != IDNGS_DISCONNECT)) { - DOMAINSET_ADD(idn.domset.ds_relink, domid); - IDN_HISTORY_LOG(IDNH_RELINK, domid, dp->dstate, - idn.domset.ds_relink); - } else { - DOMAINSET_DEL(idn.domset.ds_relink, domid); - DOMAINSET_ADD(idn.domset.ds_hitlist, domid); - } - - if ((domid == IDN_GET_NEW_MASTERID()) && - !DOMAIN_IN_SET(idn.domset.ds_relink, domid)) { - IDN_SET_NEW_MASTERID(IDN_NIL_DOMID); - } - - if ((idn.state != IDNGS_DISCONNECT) && (idn.state != IDNGS_RECONFIG) && - (domid == IDN_GET_MASTERID())) { - domainset_t dis_set, master_candidates; - - IDN_GKSTAT_GLOBAL_EVENT(gk_reconfigs, gk_reconfig_last); - - IDN_GSTATE_TRANSITION(IDNGS_RECONFIG); - IDN_GUNLOCK(); - - if ((finmasterid != IDN_NIL_DOMID) && - (finmasterid != idn.localid)) { - if (finmasterid != domid) - IDN_DLOCK_EXCL(finmasterid); - if (idn_open_domain(finmasterid, fincpuid, 0) < 0) { - cmn_err(CE_WARN, - "IDN: 205: (%s) failed to " - "open-domain(%d,%d)", - proc, finmasterid, fincpuid); - if (finmasterid != domid) - IDN_DUNLOCK(finmasterid); - finmasterid = IDN_NIL_DOMID; - } - if (finmasterid != domid) - IDN_DUNLOCK(finmasterid); - } - - IDN_GLOCK_EXCL(); - if (finmasterid == IDN_NIL_DOMID) { - int m; - - master_candidates = idn.domset.ds_trans_on | - idn.domset.ds_connected | - idn.domset.ds_relink; - master_candidates &= ~(idn.domset.ds_trans_off & - ~idn.domset.ds_relink); - DOMAINSET_DEL(master_candidates, domid); - /* - * Local domain gets to participate also. - */ - DOMAINSET_ADD(master_candidates, idn.localid); - - m = idn_select_candidate(master_candidates); - IDN_SET_NEW_MASTERID(m); - } else { - IDN_SET_NEW_MASTERID(finmasterid); - } - IDN_GUNLOCK(); - - dis_set = idn.domset.ds_trans_on | idn.domset.ds_connected; - DOMAINSET_DEL(dis_set, domid); - - idn_unlink_domainset(dis_set, IDNFIN_NORMAL, IDNFIN_ARG_NONE, - IDNFIN_OPT_RELINK, BOARDSET_ALL); - } else { - IDN_GUNLOCK(); - } - - /* - * My local ready-set are those domains from which I - * have confirmed no datapaths exist. - */ - my_ready_set = ~idn.domset.ds_connected; - - switch (dp->dfin) { - case IDNFIN_NORMAL: - case IDNFIN_FORCE_SOFT: - case IDNFIN_FORCE_HARD: - if (fintype < dp->dfin) { - /* - * 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: - IDN_FSTATE_TRANSITION(dp, fintype); - break; - } - - ASSERT(dp->dfin_sync != IDNFIN_SYNC_OFF); - - 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. - */ - ready_set = my_ready_set; - } 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. - */ - DOMAINSET_ADD(ready_set, idn.localid); - /* - * Since we know both sides of the connection - * have ceased, this remote domain is effectively - * considered disconnected. - */ - DOMAINSET_ADD(idn.domset.ds_ready_off, domid); - } - - if (dp->dfin == IDNFIN_FORCE_HARD) { - /* - * 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. - */ - DOMAINSET_ADD(my_ready_set, domid); - my_ready_set |= idn.domset.ds_awol; - ready_set = DOMAINSET_ALL; - - } else if (dp->dfin_sync == IDNFIN_SYNC_NO) { - /* - * If we're not fin'ing this domain - * synchronously then the only - * expected domain set is himself. - */ - ready_set |= ~DOMAINSET(domid); - my_ready_set |= ~DOMAINSET(domid); - } - - if (dp->dsync.s_cmd != IDNSYNC_DISCONNECT) { - idn_sync_exit(domid, IDNSYNC_CONNECT); - idn_sync_enter(domid, IDNSYNC_DISCONNECT, DOMAINSET_ALL, - my_ready_set, idn_xstate_transfunc, (void *)IDNP_FIN); - } - - query_set = idn_sync_register(domid, IDNSYNC_DISCONNECT, ready_set, - IDNSYNC_REG_REG); - - /* - * No need to query this domain as he's already - * in the FIN sequence. - */ - DOMAINSET_DEL(query_set, domid); - - ready = (dp->dsync.s_set_exp == dp->dsync.s_set_rdy) ? 1 : 0; - if (ready) { - DOMAINSET_DEL(idn.domset.ds_ready_off, domid); - DOMAINSET_DEL(idn.domset.ds_connected, domid); - } - - if (query_set) { - int d; - - my_ready_set = idn.domset.ds_ready_off | - ~idn.domset.ds_connected; - - for (d = 0; d < MAX_DOMAINS; d++) { - if (!DOMAIN_IN_SET(query_set, d)) - continue; - - dp = &idn_domain[d]; - - IDN_DLOCK_EXCL(d); - - if (dp->dsync.s_cmd == IDNSYNC_DISCONNECT) { - IDN_DUNLOCK(d); - continue; - } - - IDN_SYNC_QUERY_UPDATE(domid, d); - - (void) idn_send_fin(d, NULL, IDNFIN_QUERY, - IDNFIN_ARG_NONE, IDNFIN_OPT_NONE, my_ready_set, - NIL_FIN_MASTER); - IDN_DUNLOCK(d); - } - } - - return (!msg ? 0 : (ready ? 0 : 1)); -} - -/*ARGSUSED*/ -static void -idn_error_fin_pend(int domid, idn_msgtype_t *mtp, idn_xdcargs_t xargs) -{ - uint_t msg = mtp ? mtp->mt_mtype : 0; - uint_t token; - - ASSERT(IDN_SYNC_IS_LOCKED()); - ASSERT(IDN_DLOCK_IS_HELD(domid)); - - /* - * Don't communicate with domains that - * we're forcing a hard disconnect. - */ - if ((idn_domain[domid].dfin != IDNFIN_FORCE_HARD) && - (msg & IDNP_MSGTYPE_MASK)) { - idn_msgtype_t mt; - idn_xdcargs_t nargs; - - mt.mt_mtype = IDNP_NACK; - mt.mt_atype = msg; - mt.mt_cookie = mtp->mt_cookie; - CLR_XARGS(nargs); - SET_XARGS_NACK_TYPE(nargs, IDNNACK_RETRY); - idn_send_acknack(domid, &mt, nargs); - } - - token = IDN_RETRY_TOKEN(domid, IDNRETRY_FIN); - idn_retry_submit(idn_retry_fin, NULL, token, - idn_msg_retrytime[(int)IDNRETRY_FIN]); -} - -static void -idn_action_fin_pend(int domid, idn_msgtype_t *mtp, idn_xdcargs_t xargs) -{ - idn_domain_t *dp = &idn_domain[domid]; - domainset_t my_ready_set; - idn_finopt_t finopt; - idn_finarg_t finarg; - uint_t finmaster; - int new_masterid, new_cpuid = IDN_NIL_DCPU; - uint_t msg = mtp ? mtp->mt_mtype : 0; - idn_msgtype_t mt; - - ASSERT(IDN_SYNC_IS_LOCKED()); - ASSERT(IDN_DLOCK_IS_HELD(domid)); - - my_ready_set = dp->dsync.s_set_rdy | idn.domset.ds_ready_off | - ~idn.domset.ds_connected; - - ASSERT(xargs[0] != (uint_t)IDNFIN_QUERY); - - finarg = GET_XARGS_FIN_ARG(xargs); - finopt = DOMAIN_IN_SET(idn.domset.ds_relink, domid) ? - IDNFIN_OPT_RELINK : IDNFIN_OPT_UNLINK; - - mt.mt_cookie = mtp ? mtp->mt_cookie : 0; - - IDN_GLOCK_SHARED(); - new_masterid = IDN_GET_NEW_MASTERID(); - IDN_GUNLOCK(); - if (new_masterid != IDN_NIL_DOMID) - new_cpuid = idn_domain[new_masterid].dcpu; - finmaster = MAKE_FIN_MASTER(new_masterid, new_cpuid); - - if (dp->dfin == IDNFIN_FORCE_HARD) { - ASSERT(IDN_DLOCK_IS_EXCL(domid)); - - if (!msg) { - mt.mt_mtype = IDNP_FIN | IDNP_ACK; - mt.mt_atype = 0; - } else { - mt.mt_mtype = IDNP_ACK; - mt.mt_atype = IDNP_FIN | IDNP_ACK; - } - (void) idn_xphase_transition(domid, &mt, xargs); - } else if (!msg) { - (void) idn_send_fin(domid, NULL, dp->dfin, finarg, - finopt, my_ready_set, finmaster); - } else if ((msg & IDNP_ACKNACK_MASK) == 0) { - /* - * fin - */ - mt.mt_mtype = IDNP_FIN | IDNP_ACK; - mt.mt_atype = 0; - (void) idn_send_fin(domid, &mt, dp->dfin, finarg, - finopt, my_ready_set, finmaster); - } else { - uint_t token; - /* - * nack - retry - */ - token = IDN_RETRY_TOKEN(domid, IDNRETRY_FIN); - idn_retry_submit(idn_retry_fin, NULL, token, - idn_msg_retrytime[(int)IDNRETRY_FIN]); - } -} - -static int -idn_check_fin_sent(int domid, idn_msgtype_t *mtp, idn_xdcargs_t xargs) -{ - int ready; - uint_t msg = mtp ? mtp->mt_mtype : 0; - idn_fin_t fintype; - idn_finopt_t finopt; - idn_domain_t *dp = &idn_domain[domid]; - domainset_t query_set, ready_set; - - ASSERT(IDN_SYNC_IS_LOCKED()); - ASSERT(IDN_DLOCK_IS_EXCL(domid)); - - if (msg & IDNP_NACK) - return (0); - - fintype = GET_XARGS_FIN_TYPE(xargs); - ready_set = GET_XARGS_FIN_DOMSET(xargs); - finopt = GET_XARGS_FIN_OPT(xargs); - - ASSERT(fintype != IDNFIN_QUERY); - if (!VALID_FIN(fintype)) { - /* - * If for some reason remote domain - * sent us an invalid FIN type, - * override it to a NORMAL fin. - */ - fintype = IDNFIN_NORMAL; - } - - if (!VALID_FINOPT(finopt)) { - finopt = IDNFIN_OPT_UNLINK; - } - IDN_GLOCK_SHARED(); - if ((finopt == IDNFIN_OPT_RELINK) && (idn.state != IDNGS_DISCONNECT)) { - DOMAINSET_ADD(idn.domset.ds_relink, domid); - IDN_HISTORY_LOG(IDNH_RELINK, domid, dp->dstate, - idn.domset.ds_relink); - } else { - DOMAINSET_DEL(idn.domset.ds_relink, domid); - } - IDN_GUNLOCK(); - - switch (dp->dfin) { - case IDNFIN_NORMAL: - case IDNFIN_FORCE_SOFT: - case IDNFIN_FORCE_HARD: - if (fintype < dp->dfin) { - /* - * 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: - IDN_FSTATE_TRANSITION(dp, fintype); - break; - } - - if (dp->dfin == IDNFIN_FORCE_HARD) { - /* - * 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. - */ - ready_set = DOMAINSET_ALL; - } else { - DOMAINSET_ADD(ready_set, idn.localid); - } - - DOMAINSET_ADD(idn.domset.ds_ready_off, domid); - - query_set = idn_sync_register(domid, IDNSYNC_DISCONNECT, - ready_set, IDNSYNC_REG_REG); - /* - * No need to query this domain as he's already - * in the FIN sequence. - */ - DOMAINSET_DEL(query_set, domid); - - ready = (dp->dsync.s_set_exp == dp->dsync.s_set_rdy) ? 1 : 0; - if (ready) { - DOMAINSET_DEL(idn.domset.ds_ready_off, domid); - DOMAINSET_DEL(idn.domset.ds_connected, domid); - } - - if (query_set) { - int d; - domainset_t my_ready_set; - - my_ready_set = idn.domset.ds_ready_off | - ~idn.domset.ds_connected; - - for (d = 0; d < MAX_DOMAINS; d++) { - if (!DOMAIN_IN_SET(query_set, d)) - continue; - - dp = &idn_domain[d]; - - IDN_DLOCK_EXCL(d); - - if (dp->dsync.s_cmd == IDNSYNC_DISCONNECT) { - IDN_DUNLOCK(d); - continue; - } - - IDN_SYNC_QUERY_UPDATE(domid, d); - - (void) idn_send_fin(d, NULL, IDNFIN_QUERY, - IDNFIN_ARG_NONE, IDNFIN_OPT_NONE, my_ready_set, - NIL_FIN_MASTER); - IDN_DUNLOCK(d); - } - } - - return ((ready > 0) ? 0 : 1); -} - -/*ARGSUSED*/ -static void -idn_error_fin_sent(int domid, idn_msgtype_t *mtp, idn_xdcargs_t xargs) -{ - uint_t msg = mtp ? mtp->mt_mtype : 0; - uint_t token; - - ASSERT(IDN_SYNC_IS_LOCKED()); - ASSERT(IDN_DLOCK_IS_EXCL(domid)); - - /* - * Don't communicate with domains that - * we're forcing a hard disconnect. - */ - if ((idn_domain[domid].dfin != IDNFIN_FORCE_HARD) && - (msg & IDNP_MSGTYPE_MASK)) { - idn_msgtype_t mt; - idn_xdcargs_t nargs; - - mt.mt_mtype = IDNP_NACK; - mt.mt_atype = msg; - mt.mt_cookie = mtp->mt_cookie; - CLR_XARGS(nargs); - SET_XARGS_NACK_TYPE(nargs, IDNNACK_RETRY); - idn_send_acknack(domid, &mt, nargs); - } - - token = IDN_RETRY_TOKEN(domid, IDNRETRY_FIN); - idn_retry_submit(idn_retry_fin, NULL, token, - idn_msg_retrytime[(int)IDNRETRY_FIN]); -} - -static void -idn_action_fin_sent(int domid, idn_msgtype_t *mtp, idn_xdcargs_t xargs) -{ - uint_t msg = mtp ? mtp->mt_mtype : 0; - int new_masterid, new_cpuid = IDN_NIL_DCPU; - uint_t finmaster; - idn_msgtype_t mt; - idn_finopt_t finopt; - idn_finarg_t finarg; - domainset_t my_ready_set; - idn_domain_t *dp = &idn_domain[domid]; - - ASSERT(IDN_SYNC_IS_LOCKED()); - ASSERT(IDN_DLOCK_IS_EXCL(domid)); - - mt.mt_cookie = mtp ? mtp->mt_cookie : 0; - - finopt = DOMAIN_IN_SET(idn.domset.ds_relink, domid) ? - IDNFIN_OPT_RELINK : IDNFIN_OPT_UNLINK; - - finarg = GET_XARGS_FIN_ARG(xargs); - - my_ready_set = dp->dsync.s_set_rdy | idn.domset.ds_ready_off | - ~idn.domset.ds_connected; - - IDN_GLOCK_SHARED(); - new_masterid = IDN_GET_NEW_MASTERID(); - IDN_GUNLOCK(); - if (new_masterid != IDN_NIL_DOMID) - new_cpuid = idn_domain[new_masterid].dcpu; - finmaster = MAKE_FIN_MASTER(new_masterid, new_cpuid); - - if ((msg & IDNP_ACKNACK_MASK) == 0) { - /* - * fin - */ - if (dp->dfin == IDNFIN_FORCE_HARD) { - mt.mt_mtype = IDNP_ACK; - mt.mt_atype = IDNP_FIN | IDNP_ACK; - (void) idn_xphase_transition(domid, &mt, xargs); - } else { - mt.mt_mtype = IDNP_FIN | IDNP_ACK; - mt.mt_atype = 0; - (void) idn_send_fin(domid, &mt, dp->dfin, finarg, - finopt, my_ready_set, finmaster); - } - } else if (msg & IDNP_MSGTYPE_MASK) { - /* - * fin+ack - */ - if (dp->dfin != IDNFIN_FORCE_HARD) { - idn_xdcargs_t fargs; - - mt.mt_mtype = IDNP_ACK; - mt.mt_atype = msg; - CLR_XARGS(fargs); - SET_XARGS_FIN_TYPE(fargs, dp->dfin); - SET_XARGS_FIN_ARG(fargs, finarg); - SET_XARGS_FIN_DOMSET(fargs, my_ready_set); - SET_XARGS_FIN_OPT(fargs, finopt); - SET_XARGS_FIN_MASTER(fargs, finmaster); - idn_send_acknack(domid, &mt, fargs); - } - } else { - uint_t token; - /* - * nack - retry - */ - token = IDN_RETRY_TOKEN(domid, IDNRETRY_FIN); - idn_retry_submit(idn_retry_fin, NULL, token, - idn_msg_retrytime[(int)IDNRETRY_FIN]); - } -} - -/*ARGSUSED*/ -static void -idn_action_fin_rcvd(int domid, idn_msgtype_t *mtp, idn_xdcargs_t xargs) -{ - uint_t msg = mtp ? mtp->mt_mtype : 0; - - ASSERT(IDN_SYNC_IS_LOCKED()); - ASSERT(IDN_DLOCK_IS_EXCL(domid)); - - if (msg & IDNP_NACK) { - uint_t token; - /* - * nack - retry. - */ - token = IDN_RETRY_TOKEN(domid, IDNRETRY_FIN); - idn_retry_submit(idn_retry_fin, NULL, token, - idn_msg_retrytime[(int)IDNRETRY_FIN]); - } -} - -static void -idn_final_fin(int domid) -{ - int do_relink; - int rv, d, new_masterid = IDN_NIL_DOMID; - idn_gstate_t next_gstate; - domainset_t relinkset; - uint_t token = IDN_RETRY_TOKEN(domid, IDNRETRY_FIN); - idn_domain_t *ldp, *dp = &idn_domain[domid]; - procname_t proc = "idn_final_fin"; - - ASSERT(IDN_SYNC_IS_LOCKED()); - ASSERT(IDN_DLOCK_IS_EXCL(domid)); - ASSERT(dp->dstate == IDNDS_DMAP); - - (void) idn_retry_terminate(token); - - dp->dxp = NULL; - IDN_XSTATE_TRANSITION(dp, IDNXS_NIL); - - idn_sync_exit(domid, IDNSYNC_DISCONNECT); - - DOMAINSET_DEL(idn.domset.ds_trans_off, domid); - - do_relink = DOMAIN_IN_SET(idn.domset.ds_relink, domid) ? 1 : 0; - - /* - * idn_deconfig will idn_close_domain. - */ - idn_deconfig(domid); - - PR_PROTO("%s:%d: DISCONNECTED\n", proc, domid); - - IDN_GLOCK_EXCL(); - /* - * 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 - * the SSI_LINK/UNLINK calls and when they complete - * (i.e. are awakened) they will immediately SSI_INFO - * and we don't want them to prematurely pick up stale - * information. - */ - idn_update_op(IDNOP_DISCONNECTED, DOMAINSET(domid), NULL); - - ASSERT(idn.state != IDNGS_OFFLINE); - ASSERT(!DOMAIN_IN_SET(idn.domset.ds_trans_on, domid)); - - if (domid == IDN_GET_MASTERID()) { - IDN_SET_MASTERID(IDN_NIL_DOMID); - dp->dvote.v.master = 0; - } - - if ((domid == IDN_GET_NEW_MASTERID()) && !do_relink) { - IDN_SET_NEW_MASTERID(IDN_NIL_DOMID); - } - - if (idn.state == IDNGS_RECONFIG) - new_masterid = IDN_GET_NEW_MASTERID(); - - if ((idn.domset.ds_trans_on | idn.domset.ds_trans_off | - idn.domset.ds_relink) == 0) { - PR_HITLIST("%s:%d: HITLIST %x -> 0\n", - proc, domid, idn.domset.ds_hitlist); - idn.domset.ds_hitlist = 0; - } - - if (idn.domset.ds_connected || idn.domset.ds_trans_off) { - PR_PROTO("%s:%d: ds_connected = 0x%x, ds_trans_off = 0x%x\n", - proc, domid, idn.domset.ds_connected, - idn.domset.ds_trans_off); - IDN_GUNLOCK(); - goto fin_done; - } - - IDN_DLOCK_EXCL(idn.localid); - ldp = &idn_domain[idn.localid]; - - if (idn.domset.ds_trans_on != 0) { - ASSERT((idn.state != IDNGS_DISCONNECT) && - (idn.state != IDNGS_OFFLINE)); - - switch (idn.state) { - case IDNGS_CONNECT: - if (idn.localid == IDN_GET_MASTERID()) { - idn_master_deinit(); - IDN_SET_MASTERID(IDN_NIL_DOMID); - ldp->dvote.v.master = 0; - } - /*FALLTHROUGH*/ - case IDNGS_ONLINE: - next_gstate = idn.state; - break; - - case IDNGS_RECONFIG: - if (idn.localid == IDN_GET_MASTERID()) { - idn_master_deinit(); - IDN_SET_MASTERID(IDN_NIL_DOMID); - ldp->dvote.v.master = 0; - } - ASSERT(IDN_GET_MASTERID() == IDN_NIL_DOMID); - next_gstate = IDNGS_CONNECT; - ldp->dvote.v.connected = 0; - /* - * 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. - */ - IDN_PREP_HWINIT(); - break; - - case IDNGS_DISCONNECT: - case IDNGS_OFFLINE: - cmn_err(CE_WARN, - "IDN: 211: disconnect domain %d, " - "unexpected Gstate (%s)", - domid, idngs_str[idn.state]); - IDN_DUNLOCK(idn.localid); - IDN_GUNLOCK(); - goto fin_done; - - default: - /* - * XXX - * Go into FATAL state? - */ - cmn_err(CE_PANIC, - "IDN: 212: disconnect domain %d, " - "bad Gstate (%d)", - domid, idn.state); - /* not reached */ - break; - } - } else { - if (idn.localid == IDN_GET_MASTERID()) { - idn_master_deinit(); - IDN_SET_MASTERID(IDN_NIL_DOMID); - ldp->dvote.v.master = 0; - } - next_gstate = IDNGS_OFFLINE; - if (idn.domset.ds_relink == 0) { - IDN_SET_NEW_MASTERID(IDN_NIL_DOMID); - } - } - IDN_DUNLOCK(idn.localid); - - /* - * If we reach here we've effectively disconnected all - * existing links, however new ones may be pending. - */ - PR_PROTO("%s:%d: ALL DISCONNECTED *****************\n", proc, domid); - - IDN_GSTATE_TRANSITION(next_gstate); - - ASSERT((idn.state == IDNGS_OFFLINE) ? - (IDN_GET_MASTERID() == IDN_NIL_DOMID) : 1); - - 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) && idn.domset.ds_relink) - new_masterid = idn.localid; - - 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. - */ - relinkset = (new_masterid == idn.localid) ? - idn.domset.ds_relink : DOMAINSET(new_masterid); - - DOMAINSET_DEL(relinkset, idn.localid); - - 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; - } - - rv = idn_open_domain(d, -1, 0); - 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); - cmn_err(CE_WARN, - "IDN: 205: (%s.1) failed to " - "open-domain(%d,%d)", - proc, domid, -1); - DOMAINSET_DEL(idn.domset.ds_relink, d); - } else { - if (lock_held) - IDN_DUNLOCK(d); - PR_PROTO("%s:%d: failed to " - "re-open domain %d " - "(cpu %d) [rv = %d]\n", - proc, domid, d, idn_domain[d].dcpu, - rv); - } - } - } - -fin_done: - if (do_relink) { - ASSERT(IDN_DLOCK_IS_EXCL(domid)); - - rv = idn_open_domain(domid, -1, 0); - if (rv == 0) { - (void) idn_connect(domid); - } else if (rv < 0) { - cmn_err(CE_WARN, - "IDN: 205: (%s.2) failed to " - "open-domain(%d,%d)", - proc, domid, -1); - DOMAINSET_DEL(idn.domset.ds_relink, domid); - } - } -} - -static void -idn_exit_fin(int domid, uint_t msgtype) -{ - idn_domain_t *dp = &idn_domain[domid]; - uint_t token; - procname_t proc = "idn_exit_fin"; - STRING(str); - - ASSERT(IDN_SYNC_IS_LOCKED()); - ASSERT(IDN_DLOCK_IS_EXCL(domid)); - - INUM2STR(msgtype, str); - PR_PROTO("%s:%d: msgtype = 0x%x(%s)\n", proc, domid, msgtype, str); - - token = IDN_RETRY_TOKEN(domid, IDNRETRY_FIN); - (void) idn_retry_terminate(token); - - DOMAINSET_DEL(idn.domset.ds_ready_off, domid); - - dp->dxp = &xphase_fin; - IDN_XSTATE_TRANSITION(dp, IDNXS_PEND); - - idn_retry_submit(idn_retry_fin, NULL, token, - idn_msg_retrytime[(int)IDNRETRY_FIN]); -} - -/* - * Must return w/locks held. - */ -static int -idn_xphase_transition(int domid, idn_msgtype_t *mtp, idn_xdcargs_t xargs) -{ - uint_t msg = mtp ? mtp->mt_mtype : 0; - uint_t msgarg = mtp ? mtp->mt_atype : 0; - idn_xphase_t *xp; - idn_domain_t *dp; - int (*cfunc)(int, idn_msgtype_t *, idn_xdcargs_t); - void (*ffunc)(int); - void (*afunc)(int, idn_msgtype_t *, idn_xdcargs_t); - void (*efunc)(int, idn_msgtype_t *, idn_xdcargs_t); - void (*xfunc)(int, uint_t); - int err = 0; - uint_t msgtype; - idn_xstate_t o_xstate, n_xstate; - procname_t proc = "idn_xphase_transition"; - STRING(mstr); - STRING(astr); - - ASSERT(IDN_SYNC_IS_LOCKED()); - ASSERT(IDN_DLOCK_IS_EXCL(domid)); - - INUM2STR(msg, mstr); - INUM2STR(msgarg, astr); - - dp = &idn_domain[domid]; - if ((xp = dp->dxp) == NULL) { - PR_PROTO("%s:%d: WARNING: domain xsp is NULL (msg = %s, " - "msgarg = %s) <<<<<<<<<<<<\n", - proc, domid, mstr, astr); - return (-1); - } - o_xstate = dp->dxstate; - - xfunc = xp->xt_exit; - - if ((msgtype = (msg & IDNP_MSGTYPE_MASK)) == 0) - msgtype = msgarg & IDNP_MSGTYPE_MASK; - - if ((o_xstate == IDNXS_PEND) && msg && - ((msg & IDNP_ACKNACK_MASK) == msg)) { - PR_PROTO("%s:%d: unwanted acknack received (o_xstate = %s, " - "msg = %s/%s - dropping message\n", - proc, domid, idnxs_str[(int)o_xstate], mstr, astr); - return (0); - } - - /* - * Validate that message received is following - * the expected protocol for the current state. - */ - if (idn_next_xstate(o_xstate, -1, msg) == IDNXS_NIL) { - PR_PROTO("%s:%d: WARNING: o_xstate = %s, msg = %s -> NIL " - "<<<<<<<<<\n", - proc, domid, idnxs_str[(int)o_xstate], mstr); - if (xfunc) - (*xfunc)(domid, msgtype); - return (-1); - } - - if (msg || msgarg) { - /* - * Verify that message type is correct for - * the given xstate. - */ - if (msgtype != xp->xt_msgtype) { - STRING(xstr); - STRING(tstr); - - INUM2STR(xp->xt_msgtype, xstr); - INUM2STR(msgtype, tstr); - PR_PROTO("%s:%d: WARNING: msg expected %s(0x%x), " - "actual %s(0x%x) [msg=%s(0x%x), " - "msgarg=%s(0x%x)]\n", - proc, domid, xstr, xp->xt_msgtype, - tstr, msgtype, mstr, msg, astr, msgarg); - if (xfunc) - (*xfunc)(domid, msgtype); - return (-1); - } - } - - cfunc = xp->xt_trans[(int)o_xstate].t_check; - - if (cfunc && ((err = (*cfunc)(domid, mtp, xargs)) < 0)) { - if (o_xstate != IDNXS_PEND) { - IDN_XSTATE_TRANSITION(dp, IDNXS_PEND); - } - if (xfunc) - (*xfunc)(domid, msgtype); - return (-1); - } - - n_xstate = idn_next_xstate(o_xstate, err, msg); - - if (n_xstate == IDNXS_NIL) { - PR_PROTO("%s:%d: WARNING: n_xstate = %s, msg = %s -> NIL " - "<<<<<<<<<\n", - proc, domid, idnxs_str[(int)n_xstate], mstr); - if (xfunc) - (*xfunc)(domid, msgtype); - return (-1); - } - - if (n_xstate != o_xstate) { - IDN_XSTATE_TRANSITION(dp, n_xstate); - } - - if (err) { - if ((efunc = xp->xt_trans[(int)o_xstate].t_error) != NULL) - (*efunc)(domid, mtp, xargs); - } else if ((afunc = xp->xt_trans[(int)o_xstate].t_action) != NULL) { - (*afunc)(domid, mtp, xargs); - } - - if ((n_xstate == IDNXS_FINAL) && ((ffunc = xp->xt_final) != NULL)) - (*ffunc)(domid); - - return (0); -} - -/* - * Entered and returns w/DLOCK & SYNC_LOCK held. - */ -static int -idn_xstate_transfunc(int domid, void *transarg) -{ - uint_t msg = (uint_t)(uintptr_t)transarg; - uint_t token; - procname_t proc = "idn_xstate_transfunc"; - - ASSERT(IDN_SYNC_IS_LOCKED()); - - switch (msg) { - case IDNP_CON: - DOMAINSET_ADD(idn.domset.ds_connected, domid); - break; - - case IDNP_FIN: - DOMAINSET_DEL(idn.domset.ds_connected, domid); - break; - - default: - PR_PROTO("%s:%d: ERROR: unknown msg (0x%x) <<<<<<<<\n", - proc, domid, msg); - return (0); - } - - token = IDN_RETRY_TOKEN(domid, (msg == IDNP_CON) ? - IDNRETRY_CON : IDNRETRY_FIN); - if (msg == IDNP_CON) - idn_retry_submit(idn_retry_con, NULL, token, - idn_msg_retrytime[(int)IDNRETRY_CON]); - else - idn_retry_submit(idn_retry_fin, NULL, token, - idn_msg_retrytime[(int)IDNRETRY_FIN]); - - return (1); -} - -/* - * Entered and returns w/DLOCK & SYNC_LOCK held. - */ -static void -idn_sync_enter(int domid, idn_synccmd_t cmd, domainset_t xset, - domainset_t rset, int (*transfunc)(), void *transarg) -{ - int z; - idn_syncop_t *sp; - idn_synczone_t *zp; - procname_t proc = "idn_sync_enter"; - - ASSERT(IDN_SYNC_IS_LOCKED()); - ASSERT(IDN_DLOCK_IS_EXCL(domid)); - - z = IDN_SYNC_GETZONE(cmd); - ASSERT(z >= 0); - zp = &idn.sync.sz_zone[z]; - - PR_SYNC("%s:%d: cmd=%s(%d), z=%d, xs=0x%x, rx=0x%x, cnt=%d\n", - proc, domid, idnsync_str[cmd], cmd, z, xset, rset, zp->sc_cnt); - - sp = &idn_domain[domid].dsync; - - sp->s_domid = domid; - sp->s_cmd = cmd; - sp->s_msg = 0; - sp->s_set_exp = xset; - sp->s_set_rdy = rset; - sp->s_transfunc = transfunc; - sp->s_transarg = transarg; - IDN_SYNC_QUERY_INIT(domid); - - sp->s_next = zp->sc_op; - zp->sc_op = sp; - zp->sc_cnt++; -} - -/* - * Entered and returns w/DLOCK & SYNC_LOCK held. - */ -void -idn_sync_exit(int domid, idn_synccmd_t cmd) -{ - int d, z, zone, tot_queries, tot_domains; - idn_syncop_t *sp; - idn_synczone_t *zp = NULL; - procname_t proc = "idn_sync_exit"; - - ASSERT(IDN_SYNC_IS_LOCKED()); - ASSERT(IDN_DLOCK_IS_EXCL(domid)); - - sp = &idn_domain[domid].dsync; - - z = IDN_SYNC_GETZONE(sp->s_cmd); - - zone = IDN_SYNC_GETZONE(cmd); - - PR_SYNC("%s:%d: cmd=%s(%d) (z=%d, zone=%d)\n", - proc, domid, idnsync_str[cmd], cmd, z, zone); - -#ifdef DEBUG - if (z != -1) { - tot_queries = tot_domains = 0; - - for (d = 0; d < MAX_DOMAINS; d++) { - int qv; - - if ((qv = sp->s_query[d]) > 0) { - tot_queries += qv; - tot_domains++; - PR_SYNC("%s:%d: query_count = %d\n", - proc, domid, qv); - } - } - PR_SYNC("%s:%d: tot_queries = %d, tot_domaines = %d\n", - proc, domid, tot_queries, tot_domains); - } -#endif /* DEBUG */ - - zp = (z != -1) ? &idn.sync.sz_zone[z] : NULL; - - if (zp) { - idn_syncop_t **spp; - - for (spp = &zp->sc_op; *spp; spp = &((*spp)->s_next)) { - if (*spp == sp) { - *spp = sp->s_next; - sp->s_next = NULL; - zp->sc_cnt--; - break; - } - } - } - - sp->s_cmd = IDNSYNC_NIL; - - for (z = 0; z < IDN_SYNC_NUMZONE; z++) { - idn_syncop_t **spp, **nspp; - - if ((zone != -1) && (z != zone)) - continue; - - zp = &idn.sync.sz_zone[z]; - - for (spp = &zp->sc_op; *spp; spp = nspp) { - sp = *spp; - nspp = &sp->s_next; - - if (!DOMAIN_IN_SET(sp->s_set_exp, domid)) - continue; - - DOMAINSET_DEL(sp->s_set_exp, domid); - DOMAINSET_DEL(sp->s_set_rdy, domid); - - if ((sp->s_set_exp == sp->s_set_rdy) && - sp->s_transfunc) { - int delok; - - ASSERT(sp->s_domid != domid); - - PR_SYNC("%s:%d invoking transfunc " - "for domain %d\n", - proc, domid, sp->s_domid); - delok = (*sp->s_transfunc)(sp->s_domid, - sp->s_transarg); - if (delok) { - *spp = sp->s_next; - sp->s_next = NULL; - zp->sc_cnt--; - nspp = spp; - } - } - } - } -} - -/* - * Entered and returns w/DLOCK & SYNC_LOCK held. - */ -static domainset_t -idn_sync_register(int domid, idn_synccmd_t cmd, domainset_t ready_set, - idn_syncreg_t regtype) -{ - int z; - idn_synczone_t *zp; - idn_syncop_t *sp, **spp, **nspp; - domainset_t query_set = 0, trans_set; - procname_t proc = "idn_sync_register"; - - ASSERT(IDN_SYNC_IS_LOCKED()); - ASSERT(IDN_DLOCK_IS_EXCL(domid)); - - if ((z = IDN_SYNC_GETZONE(cmd)) == -1) { - PR_SYNC("%s:%d: ERROR: unexpected sync cmd(%d)\n", - proc, domid, cmd); - return (0); - } - - /* - * Find out what domains are in transition with respect - * to given command. There will be no need to query - * these folks. - */ - trans_set = IDN_SYNC_GETTRANS(cmd); - - zp = &idn.sync.sz_zone[z]; - - PR_SYNC("%s:%d: cmd=%s(%d), z=%d, rset=0x%x, " - "regtype=%s(%d), sc_op=%s\n", - proc, domid, idnsync_str[cmd], cmd, z, ready_set, - idnreg_str[regtype], regtype, - zp->sc_op ? idnsync_str[zp->sc_op->s_cmd] : "NULL"); - - for (spp = &zp->sc_op; *spp; spp = nspp) { - sp = *spp; - nspp = &sp->s_next; - - if (regtype == IDNSYNC_REG_NEW) { - DOMAINSET_ADD(sp->s_set_exp, domid); - PR_SYNC("%s:%d: adding new to %d (exp=0x%x)\n", - proc, domid, sp->s_domid, sp->s_set_exp); - } else if (regtype == IDNSYNC_REG_QUERY) { - query_set |= ~sp->s_set_rdy & sp->s_set_exp; - continue; - } - - if (!DOMAIN_IN_SET(sp->s_set_exp, domid)) - continue; - - if (!DOMAIN_IN_SET(ready_set, sp->s_domid)) { - /* - * Given domid doesn't have a desired - * domain in his ready-set. We'll need - * to query him again. - */ - DOMAINSET_ADD(query_set, domid); - 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). - */ - DOMAINSET_ADD(sp->s_set_rdy, domid); - - PR_SYNC("%s:%d: mark READY for domain %d " - "(r=0x%x, x=0x%x)\n", - proc, domid, sp->s_domid, - sp->s_set_rdy, sp->s_set_exp); - - query_set |= ~sp->s_set_rdy & sp->s_set_exp; - - if (sp->s_set_exp == sp->s_set_rdy) { -#ifdef DEBUG - if (sp->s_msg == 0) { - sp->s_msg = 1; - PR_SYNC("%s:%d: >>>>>>>>>>> DOMAIN %d " - "ALL CHECKED IN (0x%x)\n", - proc, domid, sp->s_domid, - sp->s_set_exp); - } -#endif /* DEBUG */ - - if ((sp->s_domid != domid) && sp->s_transfunc) { - int delok; - - PR_SYNC("%s:%d invoking transfunc " - "for domain %d\n", - proc, domid, sp->s_domid); - delok = (*sp->s_transfunc)(sp->s_domid, - sp->s_transarg); - if (delok) { - *spp = sp->s_next; - sp->s_next = NULL; - zp->sc_cnt--; - nspp = spp; - } - } - } - } - - PR_SYNC("%s:%d: trans_set = 0x%x, query_set = 0x%x -> 0x%x\n", - proc, domid, trans_set, query_set, query_set & ~trans_set); - - query_set &= ~trans_set; - - return (query_set); -} - -static void -idn_sync_register_awol(int domid) -{ - int z; - idn_synccmd_t cmd = IDNSYNC_DISCONNECT; - idn_synczone_t *zp; - idn_syncop_t *sp; - procname_t proc = "idn_sync_register_awol"; - - ASSERT(IDN_SYNC_IS_LOCKED()); - - if ((z = IDN_SYNC_GETZONE(cmd)) == -1) { - PR_SYNC("%s:%d: ERROR: unexpected sync cmd(%d)\n", - proc, domid, cmd); - return; - } - - zp = &idn.sync.sz_zone[z]; - - PR_SYNC("%s:%d: cmd=%s(%d), z=%d (domain %d = AWOL)\n", - proc, domid, idnsync_str[cmd], cmd, z, domid); - - for (sp = zp->sc_op; sp; sp = sp->s_next) { - idn_domain_t *dp; - - dp = &idn_domain[sp->s_domid]; - if (dp->dfin == IDNFIN_FORCE_HARD) { - DOMAINSET_ADD(sp->s_set_rdy, domid); - PR_SYNC("%s:%d: adding new to %d (rdy=0x%x)\n", - proc, domid, sp->s_domid, sp->s_set_rdy); - } - } -} - -static void -idn_link_established(void *arg) -{ - int first_link; - int domid, masterid; - uint_t info = (uint_t)(uintptr_t)arg; - - first_link = (int)(info & 0xf0); - domid = (int)(info & 0x0f); - - IDN_GLOCK_SHARED(); - masterid = IDN_GET_MASTERID(); - if ((masterid == IDN_NIL_DOMID) || - (idn_domain[masterid].dstate != IDNDS_CONNECTED)) { - /* - * No point in doing this unless we're connected - * to the master. - */ - if ((masterid != IDN_NIL_DOMID) && - (idn.state == IDNGS_ONLINE)) { - /* - * As long as we're still online keep - * trying. - */ - (void) timeout(idn_link_established, arg, 50); - } - IDN_GUNLOCK(); - return; - } - IDN_GUNLOCK(); - - if (first_link && IDN_SLAB_PREALLOC) - idn_prealloc_slab(IDN_SLAB_PREALLOC); - - /* - * No guarantee, but it might save a little - * time. - */ - if (idn_domain[domid].dstate == IDNDS_CONNECTED) { - /* - * Get the remote domain's dname. - */ - idn_send_nodename_req(domid); - } - - /* - * May have had some streams backed up waiting for - * this connection. Prod them. - */ - rw_enter(&idn.struprwlock, RW_READER); - mutex_enter(&idn.sipwenlock); - idndl_wenable(NULL); - mutex_exit(&idn.sipwenlock); - rw_exit(&idn.struprwlock); -} - -/* - * 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 -idn_send_data(int dst_domid, idn_netaddr_t dst_netaddr, queue_t *wq, mblk_t *mp) -{ - int pktcnt = 0; - int msglen; - int rv = IDNXMIT_OKAY; - int xfersize = 0; - caddr_t iobufp, iodatap; - uchar_t *data_rptr; - int cpuindex; - int serrno; - int channel; - int retry_reclaim; - idn_chansvr_t *csp = NULL; - uint_t netports = 0; - struct idnstr *stp; - struct idn *sip; - idn_domain_t *dp; - struct ether_header *ehp; - smr_pkthdr_t *hdrp; - idn_msgtype_t mt; - procname_t proc = "idn_send_data"; -#ifdef DEBUG - size_t orig_msglen = msgsize(mp); -#endif /* DEBUG */ - - ASSERT(DB_TYPE(mp) == M_DATA); - - mt.mt_mtype = IDNP_DATA; - mt.mt_atype = 0; - mt.mt_cookie = 0; - - channel = (int)dst_netaddr.net.chan; - - msglen = msgdsize(mp); - PR_DATA("%s:%d: (netaddr 0x%x) msgsize=%ld, msgdsize=%d\n", - proc, dst_domid, dst_netaddr.netaddr, msgsize(mp), msglen); - - ASSERT(wq->q_ptr); - - stp = (struct idnstr *)wq->q_ptr; - sip = stp->ss_sip; - ASSERT(sip); - - if (msglen < 0) { - /* - * No data to send. That was easy! - */ - PR_DATA("%s:%d: BAD msg length (%d) (netaddr 0x%x)\n", - proc, dst_domid, msglen, dst_netaddr.netaddr); - return (IDNXMIT_DROP); - } - - ASSERT(RW_READ_HELD(&stp->ss_rwlock)); - - if (dst_domid == IDN_NIL_DOMID) { - cmn_err(CE_WARN, - "IDN: 213: no destination specified " - "(d=%d, c=%d, n=0x%x)", - dst_domid, dst_netaddr.net.chan, - dst_netaddr.net.netid); - IDN_KSTAT_INC(sip, si_nolink); - IDN_KSTAT_INC(sip, si_macxmt_errors); - rv = IDNXMIT_DROP; - goto nocando; - } - - ehp = (struct ether_header *)mp->b_rptr; - PR_DATA("%s:%d: destination channel = %d\n", proc, dst_domid, channel); - -#ifdef DEBUG - { - uchar_t echn; - - echn = (uchar_t) - ehp->ether_shost.ether_addr_octet[IDNETHER_CHANNEL]; - ASSERT((uchar_t)channel == echn); - } -#endif /* DEBUG */ - ASSERT(msglen <= IDN_DATA_SIZE); - - dp = &idn_domain[dst_domid]; - /* - * 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. - */ - if ((dp->dstate != IDNDS_CONNECTED) || (idn.state != IDNGS_ONLINE)) { - IDN_KSTAT_INC(sip, si_linkdown); - if (idn.state != IDNGS_ONLINE) { - rv = IDNXMIT_REQUEUE; - } else { - IDN_KSTAT_INC(sip, si_macxmt_errors); - rv = IDNXMIT_DROP; - } - goto nocando; - } - - if (idn.chan_servers[channel].ch_send.c_checkin) { - /* - * Gotta bail, somethin' s'up. - */ - rv = IDNXMIT_REQUEUE; - goto nocando; - } - - csp = &idn.chan_servers[channel]; - IDN_CHAN_LOCK_SEND(csp); - - if (dst_netaddr.net.netid == IDN_BROADCAST_ALLNETID) { - /* - * 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. - */ - dst_netaddr.net.netid = dp->dnetid; - - (void) idndl_domain_etheraddr(dst_domid, channel, - &ehp->ether_dhost); - - if (dst_domid == idn.localid) { - mblk_t *nmp; - /* - * 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", - proc, dst_domid); - if ((nmp = copymsg(mp)) == NULL) { - /* - * Couldn't get a duplicate copy. - */ - IDN_CHAN_UNLOCK_SEND(csp); - csp = NULL; - IDN_KSTAT_INC(sip, si_allocbfail); - IDN_KSTAT_INC(sip, si_noxmtbuf); - rv = IDNXMIT_DROP; - goto nocando; - } - mp = nmp; - } - } - - if (dp->dnetid != dst_netaddr.net.netid) { - PR_DATA("%s:%d: dest netid (0x%x) != expected (0x%x)\n", - proc, dst_domid, (uint_t)dst_netaddr.net.netid, - (uint_t)dp->dnetid); - IDN_CHAN_UNLOCK_SEND(csp); - csp = NULL; - IDN_KSTAT_INC(sip, si_nolink); - IDN_KSTAT_INC(sip, si_macxmt_errors); - rv = IDNXMIT_DROP; - goto nocando; - } - - if (dst_domid == idn.localid) { - 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. - */ - IDN_CHAN_UNLOCK_SEND(csp); - rw_exit(&stp->ss_rwlock); - lbrv = idn_send_data_loopback(dst_netaddr, wq, mp); - rw_enter(&stp->ss_rwlock, RW_READER); - if (lbrv == 0) { - return (IDNXMIT_LOOP); - } else { - IDN_KSTAT_INC(sip, si_macxmt_errors); - return (IDNXMIT_DROP); - } - } - - if (dp->dstate != IDNDS_CONNECTED) { - /* - * 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. - */ - IDN_CHAN_UNLOCK_SEND(csp); - csp = NULL; - IDN_KSTAT_INC(sip, si_linkdown); - IDN_KSTAT_INC(sip, si_macxmt_errors); - 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. - */ - IDN_CHAN_UNLOCK_SEND(csp); - not_active = idn_activate_channel(CHANSET(channel), - IDNCHAN_OPEN); - if (!not_active) { - /* - * Only grab the lock for a recheck if we were - * able to activate the channel. - */ - IDN_CHAN_LOCK_SEND(csp); - } - /* - * Verify channel still active now that we have the lock. - */ - if (not_active || !IDN_CHANNEL_IS_SEND_ACTIVE(csp)) { - if (!not_active) { - /* - * Only need to drop the lock if it was - * acquired while we thought we had - * activated the channel. - */ - IDN_CHAN_UNLOCK_SEND(csp); - } - ASSERT(!IDN_CHAN_SEND_IS_LOCKED(csp)); - /* - * 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. - */ - csp = NULL; - /* - * Channel is not active, should not be used. - */ - PR_DATA("%s:%d: dest channel %d NOT ACTIVE\n", - proc, dst_domid, channel); - IDN_KSTAT_INC(sip, si_linkdown); - rv = IDNXMIT_REQUEUE; - goto nocando; - } - ASSERT(IDN_CHAN_SEND_IS_LOCKED(csp)); - } - /* - * 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 (!IDN_CHAN_DOMAIN_IS_REGISTERED(csp, dst_domid)) { - /* - * 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", - proc, dst_domid, channel); - /* - * Set csp to NULL to prevent in-progress update below. - */ - IDN_CHAN_UNLOCK_SEND(csp); - csp = NULL; - IDN_KSTAT_INC(sip, si_linkdown); - IDN_KSTAT_INC(sip, si_macxmt_errors); - rv = IDNXMIT_DROP; - goto nocando; - } - - IDN_CHAN_SEND_INPROGRESS(csp); - IDN_CHAN_UNLOCK_SEND(csp); - - /* - * Find a target cpu to send interrupt to if - * it becomes necessary (i.e. remote channel - * server is idle). - */ - cpuindex = dp->dcpuindex; - - /* - * 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. - */ - if (cpuindex < NCPU) { - ATOMIC_INC(dp->dcpuindex); - } - if (dp->dcpuindex >= NCPU) - dp->dcpuindex = 0; - - IDN_ASSIGN_DCPU(dp, cpuindex); - -#ifdef XXX_DLPI_UNFRIENDLY - { - ushort_t dstport = (ushort_t)dp->dcpu; - - /* - * 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 - * TCP/IP port (socket). The (simple) alternative to - * 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. - */ - if (ehp->ether_type == ETHERTYPE_IP) { - ipha_t *ipha; - uchar_t *dstporta; - int hdr_length; - mblk_t *nmp = mp; - uchar_t *rptr = mp->b_rptr + - sizeof (struct ether_header); - if (nmp->b_wptr <= rptr) { - /* - * Only the ethernet header was contained - * in the first block. Check for the - * next packet. - */ - if ((nmp = mp->b_cont) != NULL) - rptr = nmp->b_rptr; - } - /* - * If we still haven't found the IP header packet - * then don't bother. Can't search forever. - */ - if (nmp && - ((nmp->b_wptr - rptr) >= IP_SIMPLE_HDR_LENGTH)) { - ipha = (ipha_t *)ALIGN32(rptr); - - ASSERT(DB_TYPE(mp) == M_DATA); - hdr_length = IPH_HDR_LENGTH(ipha); - - switch (ipha->ipha_protocol) { - case IPPROTO_UDP: - case IPPROTO_TCP: - /* - * TCP/UDP Protocol Header (1st word) - * 0 15,16 31 - * ----------------------- - * | src port | dst port | - * ----------------------- - */ - dstporta = (uchar_t *)ipha + hdr_length; - netports = *(uint_t *)dstporta; - dstporta += 2; - dstport = *(ushort_t *)dstporta; - break; - default: - break; - } - } - - } - IDN_ASSIGN_DCPU(dp, dstport); - - PR_DATA("%s:%d: (dstport %d) assigned %d\n", - proc, dst_domid, (int)dstport, dp->dcpu); - } -#endif /* XXX_DLPI_UNFRIENDLY */ - - data_rptr = mp->b_rptr; - - ASSERT(dp->dcpu != IDN_NIL_DCPU); - - ASSERT(idn_domain[dst_domid].dmbox.m_send); - - retry_reclaim = 1; -retry: - if ((dp->dio >= IDN_RECLAIM_MIN) || dp->diowanted) { - int reclaim_req; - /* - * Reclaim however many outstanding buffers - * there are up to IDN_RECLAIM_MAX if it's set. - */ - reclaim_req = dp->diowanted ? -1 : IDN_RECLAIM_MAX ? - MIN(dp->dio, IDN_RECLAIM_MAX) : dp->dio; - (void) idn_reclaim_mboxdata(dst_domid, channel, - reclaim_req); - } - - if (dp->dio >= IDN_WINDOW_EMAX) { - - if (lock_try(&dp->diocheck)) { - IDN_MSGTIMER_START(dst_domid, IDNP_DATA, 0, - idn_msg_waittime[IDNP_DATA], - &mt.mt_cookie); - /* - * 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). - */ - IDNXDC(dst_domid, &mt, - (uint_t)dst_netaddr.net.chan, 0, 0, 0); - } - - /* - * Yikes! We have exceeded the maximum window - * which means no more packets going to remote - * domain until he frees some up. - */ - IDN_KSTAT_INC(sip, si_txmax); - IDN_KSTAT_INC(sip, si_macxmt_errors); - 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. - */ - IDN_MSGTIMER_START(dst_domid, IDNP_DATA, 0, - idn_msg_waittime[IDNP_DATA], - &mt.mt_cookie); - IDNXDC(dst_domid, &mt, - (uint_t)dst_netaddr.net.chan, 0, 0, 0); - } - for (; (msglen > 0) && mp; msglen -= xfersize) { - int xrv; - smr_offset_t bufoffset; -#ifdef DEBUG - int n_xfersize; -#endif /* DEBUG */ - - ASSERT(msglen <= IDN_DATA_SIZE); - xfersize = msglen; - - serrno = smr_buf_alloc(dst_domid, xfersize, &iobufp); - if (serrno) { - PR_DATA("%s:%d: failed to alloc SMR I/O buffer " - "(serrno = %d)\n", - proc, dst_domid, serrno); - /* - * 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. - */ - - if (lock_try(&dp->diowanted) && retry_reclaim) { - /* - * 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; - } - - rv = (serrno > 0) ? serrno : -serrno; - IDN_KSTAT_INC(sip, si_notbufs); - IDN_KSTAT_INC(sip, si_noxmtbuf); /* MIB II */ - switch (rv) { - case ENOMEM: - case EBUSY: - case ENOLCK: - case ETIMEDOUT: - case EDQUOT: - /* - * These are all transient conditions - * which should be recoverable over - * time. - */ - rv = IDNXMIT_REQUEUE; - break; - - default: - rv = IDNXMIT_DROP; - break; - } - goto nocando; - } - - lock_clear(&dp->diowanted); - - hdrp = IDN_BUF2HDR(iobufp); - bufoffset = (smr_offset_t)IDN_ALIGNPTR(sizeof (smr_pkthdr_t), - data_rptr); - /* - * 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", - proc, dst_domid, sizeof (smr_pkthdr_t), - bufoffset, (void *)data_rptr); - - n_xfersize = MIN(xfersize, (IDN_SMR_BUFSIZE - bufoffset)); - if (xfersize != n_xfersize) { - PR_DATA("%s:%d: xfersize ADJUST (%d -> %d)\n", - proc, dst_domid, xfersize, n_xfersize); - cmn_err(CE_WARN, "%s: ERROR (xfersize = %d, > " - "bufsize(%d)-bufoffset(%d) = %d)", - proc, xfersize, IDN_SMR_BUFSIZE, - bufoffset, - IDN_SMR_BUFSIZE - bufoffset); - } -#endif /* DEBUG */ - xfersize = MIN(xfersize, (int)(IDN_SMR_BUFSIZE - bufoffset)); - - iodatap = IDN_BUF2DATA(iobufp, bufoffset); - mp = idn_fill_buffer(iodatap, xfersize, mp, &data_rptr); - - hdrp->b_netaddr = dst_netaddr.netaddr; - hdrp->b_netports = netports; - hdrp->b_offset = bufoffset; - hdrp->b_length = xfersize; - hdrp->b_next = IDN_NIL_SMROFFSET; - hdrp->b_rawio = 0; - hdrp->b_cksum = IDN_CKSUM_PKT(hdrp); - - xrv = idn_send_mboxdata(dst_domid, sip, channel, iobufp); - 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", - proc, dst_domid, channel, xrv); - (void) smr_buf_free(dst_domid, iobufp, xfersize); - - PR_DATA("%s:%d: (line %d) dec(dio) -> %d\n", - proc, dst_domid, __LINE__, dp->dio); - - rv = IDNXMIT_DROP; - IDN_KSTAT_INC(sip, si_macxmt_errors); - 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) - cmn_err(CE_WARN, - "%s: ERROR: sent multi-pkts (%d), len = %ld", - proc, pktcnt, orig_msglen); -#endif /* DEBUG */ - - PR_DATA("%s:%d: SENT %d packets (%d @ 0x%x)\n", - proc, dst_domid, pktcnt, dst_netaddr.net.chan, - dst_netaddr.net.netid); - - IDN_CHAN_LOCK_SEND(csp); - IDN_CHAN_SEND_DONE(csp); - IDN_CHAN_UNLOCK_SEND(csp); - - return (IDNXMIT_OKAY); - -nocando: - - if (csp) { - IDN_CHAN_LOCK_SEND(csp); - IDN_CHAN_SEND_DONE(csp); - IDN_CHAN_UNLOCK_SEND(csp); - } - - if (rv == IDNXMIT_REQUEUE) { - /* - * Better kick off monitor to check when - * it's ready to reenable the queues for - * this channel. - */ - idn_xmit_monitor_kickoff(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 -idn_send_data_loopback(idn_netaddr_t dst_netaddr, queue_t *wq, mblk_t *mp) -{ - register struct idnstr *stp; - struct idn *sip; - int rv = 0; - procname_t proc = "idn_send_data_loopback"; - - if (dst_netaddr.net.netid != idn_domain[idn.localid].dnetid) { - PR_DATA("%s: dst_netaddr.net.netid 0x%x != local 0x%x\n", - proc, dst_netaddr.net.netid, - idn_domain[idn.localid].dnetid); - rv = EADDRNOTAVAIL; - goto done; - } - stp = (struct idnstr *)wq->q_ptr; - if (!stp || !stp->ss_rq) { - rv = EDESTADDRREQ; - goto done; - } - sip = stp->ss_sip; - - idndl_read(sip, mp); - 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 * -idn_fill_buffer(caddr_t bufp, int size, mblk_t *mp, uchar_t **data_rptrp) -{ - int copysize; - - ASSERT(bufp && size); - - if (mp == NULL) - return (NULL); - - while ((size > 0) && mp) { - - copysize = MIN(mp->b_wptr - (*data_rptrp), size); - - if (copysize > 0) { - /* - * If there's data to copy, do it. - */ - bcopy((*data_rptrp), bufp, copysize); - (*data_rptrp) += copysize; - bufp += copysize; - size -= copysize; - } - if (mp->b_wptr <= (*data_rptrp)) { - /* - * If we emptied the mblk, then - * move on to the next one. - */ - for (mp = mp->b_cont; - mp && (mp->b_datap->db_type != M_DATA); - mp = mp->b_cont) - ; - if (mp) - *data_rptrp = mp->b_rptr; - } - } - 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 -idn_recv_proto(idn_protomsg_t *hp) -{ - int domid, cpuid; - int sync_lock = 0; - idn_domain_t *dp; - register uint_t mtype; - register uint_t msgtype, acktype; - idn_msgtype_t mt; - ushort_t dcookie, tcookie; - procname_t proc = "idn_recv_proto"; - - - if (idn.state == IDNGS_IGNORE) { - /* - * Fault injection to simulate non-responsive domain. - */ - return; - } - - domid = hp->m_domid; - cpuid = hp->m_cpuid; - msgtype = hp->m_msgtype; - acktype = hp->m_acktype; - dcookie = IDN_DCOOKIE(hp->m_cookie); - tcookie = IDN_TCOOKIE(hp->m_cookie); - /* - * 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 - * type of message that was ack/nack'd. - */ - if ((mtype = msgtype & IDNP_MSGTYPE_MASK) == 0) { - /* - * Received a pure ack/nack. - */ - mtype = acktype & IDNP_MSGTYPE_MASK; - } - - if (!VALID_MSGTYPE(mtype)) { - PR_PROTO("%s:%d: ERROR: invalid message type (0x%x)\n", - proc, domid, mtype); - return; - } - if (!VALID_CPUID(cpuid)) { - PR_PROTO("%s:%d: ERROR: invalid cpuid (%d)\n", - proc, domid, cpuid); - 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. - */ - ASSERT(msgtype != IDNP_DATA); - - /* - * We should never receive a request from ourself, - * except for commands in the case of broadcasts! - */ - if ((domid == idn.localid) && (mtype != IDNP_CMD)) { - char str[15]; - - inum2str(hp->m_msgtype, str); - - cmn_err(CE_WARN, - "IDN: 214: received message (%s[0x%x]) from self " - "(domid %d)", - str, hp->m_msgtype, domid); - return; - } - - IDN_SYNC_LOCK(); - /* - * 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; - } - - dp = &idn_domain[domid]; - IDN_DLOCK_EXCL(domid); - - /* - * 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. - * ack/fin - if received cookie is 0. - * nack/fin - if received cookie is 0. - */ - if (((msgtype & IDNP_MSGTYPE_MASK) != IDNP_NEGO) && - ((mtype != IDNP_FIN) || (dcookie && dp->dcookie_recv))) { - if (dp->dcookie_recv != dcookie) { - dp->dcookie_errcnt++; - if (dp->dcookie_err == 0) { - /* - * Set cookie error to prevent a - * possible flood of bogus cookies - * and thus error messages. - */ - dp->dcookie_err = 1; - cmn_err(CE_WARN, - "IDN: 215: invalid cookie (0x%x) " - "for message (0x%x) from domain %d", - dcookie, hp->m_msgtype, domid); - - PR_PROTO("%s:%d: received cookie (0x%x), " - "expected (0x%x) [errcnt = %d]\n", - proc, domid, dcookie, - dp->dcookie_recv, dp->dcookie_errcnt); - } - IDN_DUNLOCK(domid); - IDN_SYNC_UNLOCK(); - return; - } - } - dp->dcookie_err = 0; - IDN_GLOCK_EXCL(); - - idn_clear_awol(domid); - - IDN_GUNLOCK(); - if (!sync_lock) /* really don't need SYNC-LOCK past here */ - IDN_SYNC_UNLOCK(); - - /* - * Stop any timers that may have been outstanding for - * this domain, for this particular message type. - * Note that CFG timers are directly managed by - * config recv/send code. - */ - if ((mtype != IDNP_CFG) && (msgtype & IDNP_ACKNACK_MASK) && tcookie) { - IDN_MSGTIMER_STOP(domid, mtype, tcookie); - } - - /* - * 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. - */ - dp->dcpu_last = cpuid; - - mt.mt_mtype = (ushort_t)msgtype; - mt.mt_atype = (ushort_t)acktype; - mt.mt_cookie = tcookie; - - switch (mtype) { - case IDNP_NEGO: - (void) idn_recv_nego(domid, &mt, hp->m_xargs, dcookie); - break; - - case IDNP_CFG: - idn_recv_config(domid, &mt, hp->m_xargs); - break; - - case IDNP_CON: - (void) idn_recv_con(domid, &mt, hp->m_xargs); - break; - - case IDNP_FIN: - (void) idn_recv_fin(domid, &mt, hp->m_xargs); - break; - - case IDNP_CMD: - idn_recv_cmd(domid, &mt, hp->m_xargs); - break; - - case IDNP_DATA: - ASSERT(msgtype & IDNP_ACKNACK_MASK); - /* - * 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. - */ - (void) idn_recv_data(domid, &mt, hp->m_xargs); - break; - - default: - /* - * Should be receiving 0 inum and 0 acknack. - */ -#ifdef DEBUG - cmn_err(CE_PANIC, -#else /* DEBUG */ - cmn_err(CE_WARN, -#endif /* DEBUG */ - /* CSTYLED */ - "IDN: 216: (0x%x)msgtype/(0x%x)acktype rcvd from " - /* CSTYLED */ - "domain %d", msgtype, acktype, domid); - break; - } - - IDN_DUNLOCK(domid); - /* - * All receiving routines are responsible for dropping drwlock. - */ - - if (sync_lock) - IDN_SYNC_UNLOCK(); -} - -/* - * 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 -idn_send_config(int domid, int phase) -{ - idn_domain_t *dp; - int rv; - clock_t cfg_waittime = idn_msg_waittime[IDNP_CFG]; - procname_t proc = "idn_send_config"; - - ASSERT(IDN_DLOCK_IS_EXCL(domid)); - - dp = &idn_domain[domid]; - - ASSERT(dp->dstate == IDNDS_CONFIG); - - if (phase == 1) { - /* - * Reset stuff in dtmp to 0: - * dcfgphase - * dcksum - * dncfgitems - * dmaxnets - * dmboxpernet - */ - dp->dtmp = 0; - } - - if (dp->dcfgsnddone) { - if (!dp->dcfgrcvdone) { - IDN_MSGTIMER_START(domid, IDNP_CFG, 0, - cfg_waittime, NULL); - } - return; - } - - IDN_DLOCK_SHARED(idn.localid); - - PR_PROTO("%s:%d: sending %s config (phase %d)\n", - proc, domid, - idn_domain[idn.localid].dvote.v.master ? "MASTER" : "SLAVE", - phase); - - if (idn_domain[idn.localid].dvote.v.master) - rv = idn_send_master_config(domid, phase); - else - rv = idn_send_slave_config(domid, phase); - - IDN_DUNLOCK(idn.localid); - - if (rv >= 0) { - - if (rv == 1) { - dp->dcfgsnddone = 1; - PR_PROTO("%s:%d: SEND config DONE\n", proc, domid); - if (!dp->dcfgrcvdone) { - IDN_MSGTIMER_START(domid, IDNP_CFG, 0, - cfg_waittime, NULL); - } - } else { - IDN_MSGTIMER_START(domid, IDNP_CFG, 0, - cfg_waittime, NULL); - } - } -} - -/* - * Clear out the mailbox table. - * NOTE: This routine touches the SMR. - */ -static void -idn_reset_mboxtbl(idn_mboxtbl_t *mtp) -{ - int qi; - idn_mboxmsg_t *mp = &mtp->mt_queue[0]; - - qi = 0; - do { - mp[qi].ms_bframe = 0; - mp[qi].ms_owner = 0; - mp[qi].ms_flag = 0; - IDN_MMBOXINDEX_INC(qi); - } while (qi); -} - -static int -idn_get_mbox_config(int domid, int *mindex, smr_offset_t *mtable, - smr_offset_t *mdomain) -{ - idn_domain_t *dp, *ldp; - - dp = &idn_domain[domid]; - ldp = &idn_domain[idn.localid]; - - ASSERT(IDN_DLOCK_IS_EXCL(domid)); - ASSERT(IDN_DLOCK_IS_SHARED(idn.localid)); - ASSERT(IDN_GET_MASTERID() != IDN_NIL_DOMID); - - /* - * 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. - */ - if (ldp->dmbox.m_tbl == NULL) { - /* - * Local domain has not yet been assigned a - * (recv) mailbox table. This must be the - * initial connection of this domain. - */ - ASSERT(dp->dvote.v.master && !ldp->dvote.v.master); - ASSERT(mindex); - *mindex = domid; - } else { - idn_mboxtbl_t *mtp; - - mtp = IDN_MBOXTBL_PTR(ldp->dmbox.m_tbl, domid); - - ASSERT(mdomain); - *mdomain = IDN_ADDR2OFFSET(mtp); - - if (ldp->dvote.v.master) { - /* - * 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. - */ - mtp = IDN_MBOXAREA_BASE(idn.mboxarea, domid); - ASSERT(mtable); - *mtable = IDN_ADDR2OFFSET(mtp); - - dp->dmbox.m_tbl = mtp; - } - } - - return (0); -} - -/* - * RETURNS: - * 1 Unexpected/unnecessary phase. - * 0 Successfully handled, timer needed. - */ -static int -idn_send_master_config(int domid, int phase) -{ - idn_cfgsubtype_t cfg_subtype; - int rv = 0; - idn_domain_t *dp, *ldp; - idn_msgtype_t mt; - int nmcadr; - uint_t barpfn, larpfn; - uint_t cpus_u32, cpus_l32; - uint_t mcadr[3]; - smr_offset_t mbox_table, mbox_domain; - register int b, p, m; - procname_t proc = "idn_send_master_config"; - - ASSERT(IDN_DLOCK_IS_EXCL(domid)); - ASSERT(IDN_DLOCK_IS_SHARED(idn.localid)); - - dp = &idn_domain[domid]; - ldp = &idn_domain[idn.localid]; - - ASSERT(dp->dstate == IDNDS_CONFIG); - ASSERT(dp->dvote.v.master == 0); - ASSERT(ldp->dvote.v.master == 1); - - mt.mt_mtype = IDNP_CFG; - mt.mt_atype = 0; - mt.mt_cookie = 0; - m = 0; - mcadr[0] = mcadr[1] = mcadr[2] = 0; - cfg_subtype.val = 0; - - switch (phase) { - - case 1: - mbox_table = mbox_domain = IDN_NIL_SMROFFSET; - (void) idn_get_mbox_config(domid, NULL, &mbox_table, - &mbox_domain); - /* - * ---------------------------------------------------- - * Send: SLABSIZE, DATAMBOX.DOMAIN, DATAMBOX.TABLE - * ---------------------------------------------------- - */ - cfg_subtype.param.p[0] = IDN_CFGPARAM(IDNCFG_SIZE, - IDNCFGARG_SIZE_SLAB); - cfg_subtype.param.p[1] = IDN_CFGPARAM(IDNCFG_DATAMBOX, - IDNCFGARG_DATAMBOX_DOMAIN); - cfg_subtype.param.p[2] = IDN_CFGPARAM(IDNCFG_DATAMBOX, - IDNCFGARG_DATAMBOX_TABLE); - cfg_subtype.info.num = 3; - cfg_subtype.info.phase = phase; - dp->dcfgphase = phase; - - ASSERT(mbox_domain != IDN_NIL_SMROFFSET); - ASSERT(mbox_table != IDN_NIL_SMROFFSET); - - PR_PROTO("%s:%d:%d: sending SLABSIZE (%d), " - "DATAMBOX.DOMAIN (0x%x), DATAMBOX.TABLE (0x%x)\n", - proc, domid, phase, IDN_SLAB_BUFCOUNT, mbox_domain, - mbox_table); - - IDNXDC(domid, &mt, cfg_subtype.val, IDN_SLAB_BUFCOUNT, - mbox_domain, mbox_table); - break; - - case 2: - barpfn = idn.smr.locpfn; - larpfn = barpfn + (uint_t)btop(MB2B(IDN_SMR_SIZE)); - /* - * ---------------------------------------------------- - * Send: NETID, BARLAR - * ---------------------------------------------------- - */ - cfg_subtype.param.p[0] = IDN_CFGPARAM(IDNCFG_NETID, 0); - cfg_subtype.param.p[1] = IDN_CFGPARAM(IDNCFG_BARLAR, - IDNCFGARG_BARLAR_BAR); - cfg_subtype.param.p[2] = IDN_CFGPARAM(IDNCFG_BARLAR, - IDNCFGARG_BARLAR_LAR); - cfg_subtype.info.num = 3; - cfg_subtype.info.phase = phase; - dp->dcfgphase = phase; - - PR_PROTO("%s:%d:%d: sending NETID (%d), " - "BARPFN/LARPFN (0x%x/0x%x)\n", - proc, domid, phase, ldp->dnetid, barpfn, larpfn); - - IDNXDC(domid, &mt, cfg_subtype.val, - (uint_t)ldp->dnetid, barpfn, larpfn); - break; - - case 3: - nmcadr = ldp->dhw.dh_nmcadr; - cpus_u32 = UPPER32_CPUMASK(ldp->dcpuset); - cpus_l32 = LOWER32_CPUMASK(ldp->dcpuset); - /* - * ---------------------------------------------------- - * Send: CPUSET, NMCADR - * ---------------------------------------------------- - */ - cfg_subtype.param.p[0] = IDN_CFGPARAM(IDNCFG_CPUSET, - IDNCFGARG_CPUSET_UPPER); - cfg_subtype.param.p[1] = IDN_CFGPARAM(IDNCFG_CPUSET, - IDNCFGARG_CPUSET_LOWER); - cfg_subtype.param.p[2] = IDN_CFGPARAM(IDNCFG_NMCADR, 0); - cfg_subtype.info.num = 3; - cfg_subtype.info.phase = phase; - dp->dcfgphase = phase; - - PR_PROTO("%s:%d:%d: sending CPUSET (0x%x.%x), NMCADR (%d)\n", - proc, domid, phase, cpus_u32, cpus_l32, nmcadr); - - IDNXDC(domid, &mt, cfg_subtype.val, - cpus_u32, cpus_l32, nmcadr); - break; - - case 4: - /* - * ---------------------------------------------------- - * Send: BOARDSET, MTU, BUFSIZE - * ---------------------------------------------------- - */ - cfg_subtype.param.p[0] = IDN_CFGPARAM(IDNCFG_BOARDSET, 0); - cfg_subtype.param.p[1] = IDN_CFGPARAM(IDNCFG_SIZE, - IDNCFGARG_SIZE_MTU); - cfg_subtype.param.p[2] = IDN_CFGPARAM(IDNCFG_SIZE, - IDNCFGARG_SIZE_BUF); - cfg_subtype.info.num = 3; - cfg_subtype.info.phase = phase; - dp->dcfgphase = phase; - - PR_PROTO("%s:%d:%d: sending BOARDSET (0x%x), MTU (0x%lx), " - "BUFSIZE (0x%x)\n", proc, domid, phase, - ldp->dhw.dh_boardset, IDN_MTU, IDN_SMR_BUFSIZE); - - IDNXDC(domid, &mt, cfg_subtype.val, - ldp->dhw.dh_boardset, IDN_MTU, IDN_SMR_BUFSIZE); - break; - - case 5: - /* - * ---------------------------------------------------- - * Send: MAXNETS, MBOXPERNET, CKSUM - * ---------------------------------------------------- - */ - cfg_subtype.param.p[0] = IDN_CFGPARAM(IDNCFG_DATASVR, - IDNCFGARG_DATASVR_MAXNETS); - cfg_subtype.param.p[1] = IDN_CFGPARAM(IDNCFG_DATASVR, - IDNCFGARG_DATASVR_MBXPERNET); - cfg_subtype.param.p[2] = IDN_CFGPARAM(IDNCFG_OPTIONS, - IDNCFGARG_CHECKSUM); - cfg_subtype.info.num = 3; - cfg_subtype.info.phase = phase; - dp->dcfgphase = phase; - - PR_PROTO("%s:%d:%d: sending MAXNETS (%d), " - "MBOXPERNET (%d), CKSUM (%d)\n", - proc, domid, phase, - IDN_MAX_NETS, IDN_MBOX_PER_NET, - IDN_CHECKSUM); - - IDNXDC(domid, &mt, cfg_subtype.val, - IDN_MAX_NETS, IDN_MBOX_PER_NET, IDN_CHECKSUM); - break; - - case 6: - /* - * ---------------------------------------------------- - * Send: NWRSIZE (piggyback on MCADRs) - * ---------------------------------------------------- - */ - cfg_subtype.param.p[0] = IDN_CFGPARAM(IDNCFG_SIZE, - IDNCFGARG_SIZE_NWR); - 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) { - p = ((phase - 7) * 3) + 2; - for (b = 0; (b < MAX_BOARDS) && (p > 0); b++) - if (ldp->dhw.dh_mcadr[b]) - p--; - } else { - b = 0; - } - - for (; (b < MAX_BOARDS) && (m < 3); b++) { - if (ldp->dhw.dh_mcadr[b] == 0) - continue; - mcadr[m] = ldp->dhw.dh_mcadr[b]; - cfg_subtype.param.p[m] = IDN_CFGPARAM(IDNCFG_MCADR, b); - m++; - } - if (m > 0) { - if (phase == 6) { - PR_PROTO("%s:%d:%d: sending NWRSIZE (%d), " - "MCADRs (0x%x, 0x%x)\n", - proc, domid, phase, - mcadr[0], mcadr[1], mcadr[2]); - } else { - PR_PROTO("%s:%d:%d: sending MCADRs " - "(0x%x, 0x%x, 0x%x)\n", - proc, domid, phase, - mcadr[0], mcadr[1], mcadr[2]); - } - cfg_subtype.info.num = m; - cfg_subtype.info.phase = phase; - dp->dcfgphase = phase; - - IDNXDC(domid, &mt, cfg_subtype.val, - mcadr[0], mcadr[1], mcadr[2]); - } else { - rv = 1; - } - break; - } - - return (rv); -} - -/* - * RETURNS: - * 1 Unexpected/unnecessary phase. - * 0 Successfully handled. - */ -static int -idn_send_slave_config(int domid, int phase) -{ - idn_cfgsubtype_t cfg_subtype; - int rv = 0; - idn_domain_t *dp, *ldp; - smr_offset_t mbox_domain; - idn_msgtype_t mt; - int mbox_index; - uint_t cpus_u32, cpus_l32; - procname_t proc = "idn_send_slave_config"; - - ASSERT(IDN_DLOCK_IS_EXCL(domid)); - ASSERT(IDN_DLOCK_IS_SHARED(idn.localid)); - - mt.mt_mtype = IDNP_CFG; - mt.mt_atype = 0; - dp = &idn_domain[domid]; - ldp = &idn_domain[idn.localid]; - - ASSERT(dp->dstate == IDNDS_CONFIG); - ASSERT(ldp->dvote.v.master == 0); - - switch (phase) { - - case 1: - mbox_index = IDN_NIL_DOMID; - mbox_domain = IDN_NIL_SMROFFSET; - (void) idn_get_mbox_config(domid, &mbox_index, NULL, - &mbox_domain); - /* - * ---------------------------------------------------- - * Send: DATAMBOX.DOMAIN or DATAMBOX.INDEX, - * DATASVR.MAXNETS, DATASVR.MBXPERNET - * ---------------------------------------------------- - */ - cfg_subtype.val = 0; - if (mbox_index == IDN_NIL_DOMID) { - ASSERT(mbox_domain != IDN_NIL_SMROFFSET); - cfg_subtype.param.p[0] = IDN_CFGPARAM(IDNCFG_DATAMBOX, - IDNCFGARG_DATAMBOX_DOMAIN); - } else { - /* - * Should only be sending Index to - * the master and not another slave. - */ - ASSERT(dp->dvote.v.master); - ASSERT(mbox_domain == IDN_NIL_SMROFFSET); - cfg_subtype.param.p[0] = IDN_CFGPARAM(IDNCFG_DATAMBOX, - IDNCFGARG_DATAMBOX_INDEX); - } - cfg_subtype.param.p[1] = IDN_CFGPARAM(IDNCFG_DATASVR, - IDNCFGARG_DATASVR_MAXNETS); - cfg_subtype.param.p[2] = IDN_CFGPARAM(IDNCFG_DATASVR, - IDNCFGARG_DATASVR_MBXPERNET); - cfg_subtype.info.num = 3; - cfg_subtype.info.phase = phase; - dp->dcfgphase = phase; - - PR_PROTO("%s:%d:%d: sending DATAMBOX.%s (0x%x), " - "MAXNETS (%d), MBXPERNET (%d)\n", - proc, domid, phase, - (IDN_CFGPARAM_ARG(cfg_subtype.param.p[0]) - == IDNCFGARG_DATAMBOX_INDEX) ? "INDEX" : "DOMAIN", - (mbox_index == IDN_NIL_DOMID) ? mbox_domain : mbox_index, - IDN_MAX_NETS, IDN_MBOX_PER_NET); - - IDNXDC(domid, &mt, cfg_subtype.val, - ((mbox_index == IDN_NIL_DOMID) ? mbox_domain : mbox_index), - IDN_MAX_NETS, IDN_MBOX_PER_NET); - break; - - case 2: - cpus_u32 = UPPER32_CPUMASK(ldp->dcpuset); - cpus_l32 = LOWER32_CPUMASK(ldp->dcpuset); - /* - * ---------------------------------------------------- - * Send: NETID, CPUSET - * ---------------------------------------------------- - */ - cfg_subtype.val = 0; - cfg_subtype.param.p[0] = IDN_CFGPARAM(IDNCFG_NETID, 0); - cfg_subtype.param.p[1] = IDN_CFGPARAM(IDNCFG_CPUSET, - IDNCFGARG_CPUSET_UPPER); - cfg_subtype.param.p[2] = IDN_CFGPARAM(IDNCFG_CPUSET, - IDNCFGARG_CPUSET_LOWER); - cfg_subtype.info.num = 3; - cfg_subtype.info.phase = phase; - dp->dcfgphase = phase; - - PR_PROTO("%s:%d:%d: sending NETID (%d), " - "CPUSET (0x%x.%x)\n", proc, domid, phase, - ldp->dnetid, cpus_u32, cpus_l32); - - IDNXDC(domid, &mt, cfg_subtype.val, - (uint_t)ldp->dnetid, cpus_u32, cpus_l32); - break; - - case 3: - /* - * ---------------------------------------------------- - * Send: BOARDSET, MTU, BUFSIZE - * ---------------------------------------------------- - */ - cfg_subtype.val = 0; - cfg_subtype.param.p[0] = IDN_CFGPARAM(IDNCFG_BOARDSET, 0); - cfg_subtype.param.p[1] = IDN_CFGPARAM(IDNCFG_SIZE, - IDNCFGARG_SIZE_MTU); - cfg_subtype.param.p[2] = IDN_CFGPARAM(IDNCFG_SIZE, - IDNCFGARG_SIZE_BUF); - cfg_subtype.info.num = 3; - cfg_subtype.info.phase = phase; - dp->dcfgphase = phase; - - PR_PROTO("%s:%d:%d: sending BOARDSET (0x%x), MTU (0x%lx), " - "BUFSIZE (0x%x)\n", - proc, domid, phase, ldp->dhw.dh_boardset, IDN_MTU, - IDN_SMR_BUFSIZE); - - IDNXDC(domid, &mt, cfg_subtype.val, - ldp->dhw.dh_boardset, IDN_MTU, IDN_SMR_BUFSIZE); - break; - - case 4: - /* - * ---------------------------------------------------- - * Send: SLABSIZE, OPTIONS.CHECKSUM, NWR_SIZE - * ---------------------------------------------------- - */ - cfg_subtype.val = 0; - cfg_subtype.param.p[0] = IDN_CFGPARAM(IDNCFG_SIZE, - IDNCFGARG_SIZE_SLAB); - cfg_subtype.param.p[1] = IDN_CFGPARAM(IDNCFG_OPTIONS, - IDNCFGARG_CHECKSUM); - cfg_subtype.param.p[2] = IDN_CFGPARAM(IDNCFG_SIZE, - IDNCFGARG_SIZE_NWR); - cfg_subtype.info.num = 3; - cfg_subtype.info.phase = phase; - dp->dcfgphase = phase; - - PR_PROTO("%s:%d:%d: sending SLABSIZE (%d), CKSUM (%d), " - "NWRSIZE (%d)\n", - proc, domid, phase, IDN_SLAB_BUFCOUNT, - IDN_CHECKSUM, IDN_NWR_SIZE); - - IDNXDC(domid, &mt, cfg_subtype.val, - IDN_SLAB_BUFCOUNT, IDN_CHECKSUM, IDN_NWR_SIZE); - break; - - default: - rv = 1; - break; - } - - return (rv); -} - -#define CFG_FATAL ((uint_t)-1) /* reset link */ -#define CFG_CONTINUE 0x0000 /* looking for more */ -#define CFG_DONE 0x0001 /* got everything expected */ -#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) \ - (((ce) & CFG_ERR_MTU) ? IDNKERR_CONFIG_MTU : \ - ((ce) & CFG_ERR_BUF) ? IDNKERR_CONFIG_BUF : \ - ((ce) & CFG_ERR_SLAB) ? IDNKERR_CONFIG_SLAB : \ - ((ce) & CFG_ERR_NWR) ? IDNKERR_CONFIG_NWR : \ - ((ce) & CFG_ERR_NETS) ? IDNKERR_CONFIG_NETS : \ - ((ce) & CFG_ERR_MBOX) ? IDNKERR_CONFIG_MBOX : \ - ((ce) & CFG_ERR_NMCADR) ? IDNKERR_CONFIG_NMCADR : \ - ((ce) & CFG_ERR_MCADR) ? IDNKERR_CONFIG_MCADR : \ - ((ce) & CFG_ERR_CKSUM) ? IDNKERR_CONFIG_CKSUM : \ - ((ce) & CFG_ERR_SMR) ? IDNKERR_CONFIG_SMR : 0) - -#define CFGERR2FINARG(ce) \ - (((ce) & CFG_ERR_MTU) ? IDNFIN_ARG_CFGERR_MTU : \ - ((ce) & CFG_ERR_BUF) ? IDNFIN_ARG_CFGERR_BUF : \ - ((ce) & CFG_ERR_SLAB) ? IDNFIN_ARG_CFGERR_SLAB : \ - ((ce) & CFG_ERR_NWR) ? IDNFIN_ARG_CFGERR_NWR : \ - ((ce) & CFG_ERR_NETS) ? IDNFIN_ARG_CFGERR_NETS : \ - ((ce) & CFG_ERR_MBOX) ? IDNFIN_ARG_CFGERR_MBOX : \ - ((ce) & CFG_ERR_NMCADR) ? IDNFIN_ARG_CFGERR_NMCADR : \ - ((ce) & CFG_ERR_MCADR) ? IDNFIN_ARG_CFGERR_MCADR : \ - ((ce) & CFG_ERR_CKSUM) ? IDNFIN_ARG_CFGERR_CKSUM : \ - ((ce) & CFG_ERR_SMR) ? IDNFIN_ARG_CFGERR_SMR : IDNFIN_ARG_NONE) - -/* - * 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 -idn_recv_config(int domid, idn_msgtype_t *mtp, idn_xdcargs_t xargs) -{ - uint_t msg = mtp->mt_mtype; - uint_t rv, rv_expected, rv_actual; - int pnum; - int phase; - register int p; - register int c; - idn_mainmbox_t *mmp; - register uint_t subtype, subtype_arg; - idn_domain_t *dp; - int index; - idn_domain_t *ldp = &idn_domain[idn.localid]; - idn_mboxtbl_t *mbtp; - idn_cfgsubtype_t cfg_subtype; - idn_xdcargs_t cfg_arg; - idn_msgtype_t mt; - idnsb_error_t idnerr; - procname_t proc = "idn_recv_config"; - - ASSERT(domid != idn.localid); - - GET_XARGS(xargs, &cfg_subtype.val, &cfg_arg[0], &cfg_arg[1], - &cfg_arg[2]); - cfg_arg[3] = 0; - - dp = &idn_domain[domid]; - - ASSERT(IDN_DLOCK_IS_EXCL(domid)); - - if (dp->dstate != IDNDS_CONFIG) { - /* - * 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", - proc, domid, idnds_str[dp->dstate]); - return; - } - - if ((msg & IDNP_ACKNACK_MASK) || dp->dcfgsnddone) { - IDN_MSGTIMER_STOP(domid, IDNP_CFG, 0); - } - - if (msg & IDNP_ACKNACK_MASK) { - /* - * ack/cfg - */ - phase = GET_XARGS_CFG_PHASE(xargs); - - PR_PROTO("%s:%d: received ACK for CFG phase %d\n", - proc, domid, phase); - if (phase != (int)dp->dcfgphase) { - /* - * 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. - */ - IDN_MSGTIMER_START(domid, IDNP_CFG, dp->dcfgphase, - idn_msg_waittime[IDNP_CFG], NULL); - } else { - idn_send_config(domid, phase + 1); - - if (dp->dcfgsnddone && dp->dcfgrcvdone) { - IDN_DUNLOCK(domid); - IDN_SYNC_LOCK(); - IDN_DLOCK_EXCL(domid); - if (dp->dstate == IDNDS_CONFIG) { - dp->dxp = &xphase_con; - IDN_XSTATE_TRANSITION(dp, IDNXS_PEND); - bzero(xargs, sizeof (xargs)); - - (void) idn_xphase_transition(domid, - NULL, xargs); - } - IDN_SYNC_UNLOCK(); - } - } - return; - } - - pnum = (int)cfg_subtype.info.num; - phase = (int)cfg_subtype.info.phase; - - for (p = 0; p < pnum; p++) { - int board; -#ifdef DEBUG - uint_t val; - char *str; - - val = 0; - str = NULL; -#define RCVCFG(s, v) { str = (s); val = (v); } -#else -#define RCVCFG(s, v) {} -#endif /* DEBUG */ - - subtype = IDN_CFGPARAM_TYPE(cfg_subtype.param.p[p]); - subtype_arg = IDN_CFGPARAM_ARG(cfg_subtype.param.p[p]); - - switch (subtype) { - - case IDNCFG_BARLAR: - IDN_GLOCK_EXCL(); - switch (subtype_arg) { - - case IDNCFGARG_BARLAR_BAR: - if (idn.smr.rempfn == PFN_INVALID) { - idn.smr.rempfn = (pfn_t)cfg_arg[p]; - dp->dncfgitems++; - RCVCFG("BARLAR_BAR", cfg_arg[p]); - } - break; - - case IDNCFGARG_BARLAR_LAR: - if (idn.smr.rempfnlim == PFN_INVALID) { - idn.smr.rempfnlim = (pfn_t)cfg_arg[p]; - dp->dncfgitems++; - RCVCFG("BARLAR_LAR", cfg_arg[p]); - } - break; - - default: - cmn_err(CE_WARN, - "IDN 217: unknown CFGARG type (%d) " - "from domain %d", - subtype_arg, domid); - break; - } - IDN_GUNLOCK(); - break; - - case IDNCFG_MCADR: - board = subtype_arg; - if ((board >= 0) && (board < MAX_BOARDS) && - (dp->dhw.dh_mcadr[board] == 0)) { - dp->dhw.dh_mcadr[board] = cfg_arg[p]; - dp->dncfgitems++; - RCVCFG("MCADR", cfg_arg[p]); - } - break; - - case IDNCFG_NMCADR: - if (dp->dhw.dh_nmcadr == 0) { - dp->dhw.dh_nmcadr = cfg_arg[p]; - dp->dncfgitems++; - RCVCFG("NMCADR", cfg_arg[p]); - } - break; - - case IDNCFG_CPUSET: - switch (subtype_arg) { - - case IDNCFGARG_CPUSET_UPPER: - { - cpuset_t tmpset; - - MAKE64_CPUMASK(tmpset, cfg_arg[p], 0); - CPUSET_OR(dp->dcpuset, tmpset); - dp->dncfgitems++; - RCVCFG("CPUSET_UPPER", cfg_arg[p]); - break; - } - case IDNCFGARG_CPUSET_LOWER: - { - cpuset_t tmpset; - - MAKE64_CPUMASK(tmpset, 0, cfg_arg[p]); - CPUSET_OR(dp->dcpuset, tmpset); - dp->dncfgitems++; - RCVCFG("CPUSET_LOWER", cfg_arg[p]); - break; - } - default: - ASSERT(0); - break; - } - break; - - case IDNCFG_NETID: - if (dp->dnetid == (ushort_t)-1) { - dp->dnetid = (ushort_t)cfg_arg[p]; - dp->dncfgitems++; - RCVCFG("NETID", cfg_arg[p]); - } - break; - - case IDNCFG_BOARDSET: - if ((dp->dhw.dh_boardset & cfg_arg[p]) - == dp->dhw.dh_boardset) { - /* - * Boardset better include what we - * already know about. - */ - dp->dhw.dh_boardset = cfg_arg[p]; - dp->dncfgitems++; - RCVCFG("BOARDSET", cfg_arg[p]); - } - break; - - case IDNCFG_SIZE: - switch (subtype_arg) { - - case IDNCFGARG_SIZE_MTU: - if (dp->dmtu == 0) { - dp->dmtu = cfg_arg[p]; - dp->dncfgitems++; - RCVCFG("MTU", cfg_arg[p]); - } - break; - - case IDNCFGARG_SIZE_BUF: - if (dp->dbufsize == 0) { - dp->dbufsize = cfg_arg[p]; - dp->dncfgitems++; - RCVCFG("BUFSIZE", cfg_arg[p]); - } - break; - - case IDNCFGARG_SIZE_SLAB: - if (dp->dslabsize == 0) { - dp->dslabsize = (short)cfg_arg[p]; - dp->dncfgitems++; - RCVCFG("SLABSIZE", cfg_arg[p]); - } - break; - - case IDNCFGARG_SIZE_NWR: - if (dp->dnwrsize == 0) { - dp->dnwrsize = (short)cfg_arg[p]; - dp->dncfgitems++; - RCVCFG("NWRSIZE", cfg_arg[p]); - } - break; - - default: - ASSERT(0); - break; - } - break; - - case IDNCFG_DATAMBOX: - switch (subtype_arg) { - - case IDNCFGARG_DATAMBOX_TABLE: - if (ldp->dmbox.m_tbl || - !dp->dvote.v.master || - !VALID_NWROFFSET(cfg_arg[p], 4)) { - /* - * Only a master should be - * sending us a datambox table. - */ - break; - } - IDN_DLOCK_EXCL(idn.localid); - ldp->dmbox.m_tbl = (idn_mboxtbl_t *) - IDN_OFFSET2ADDR(cfg_arg[p]); - IDN_DUNLOCK(idn.localid); - dp->dncfgitems++; - RCVCFG("DATAMBOX.TABLE", cfg_arg[p]); - break; - - case IDNCFGARG_DATAMBOX_DOMAIN: - if (dp->dmbox.m_send->mm_smr_mboxp || - !VALID_NWROFFSET(cfg_arg[p], 4)) - break; - mbtp = (idn_mboxtbl_t *) - IDN_OFFSET2ADDR(cfg_arg[p]); - mmp = dp->dmbox.m_send; - for (c = 0; c < IDN_MAX_NETS; c++) { - - mutex_enter(&mmp[c].mm_mutex); - mmp[c].mm_smr_mboxp = mbtp; - mutex_exit(&mmp[c].mm_mutex); - - IDN_MBOXTBL_PTR_INC(mbtp); - } - if (c <= 0) - break; - dp->dncfgitems++; - RCVCFG("DATAMBOX.DOMAIN", cfg_arg[p]); - break; - - case IDNCFGARG_DATAMBOX_INDEX: - if (!ldp->dvote.v.master || - dp->dmbox.m_send->mm_smr_mboxp) { - /* - * 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; - } - ASSERT(dp->dmbox.m_tbl); - index = (int)cfg_arg[p]; - /* - * 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. - */ - mbtp = IDN_MBOXTBL_PTR(dp->dmbox.m_tbl, index); - mmp = dp->dmbox.m_send; - for (c = 0; c < IDN_MAX_NETS; c++) { - - mutex_enter(&mmp[c].mm_mutex); - mmp[c].mm_smr_mboxp = mbtp; - mutex_exit(&mmp[c].mm_mutex); - - IDN_MBOXTBL_PTR_INC(mbtp); - } - if (c <= 0) - break; - dp->dncfgitems++; - RCVCFG("DATAMBOX.INDEX", cfg_arg[p]); - break; - - default: - ASSERT(0); - break; - } - break; - - case IDNCFG_DATASVR: - switch (subtype_arg) { - - case IDNCFGARG_DATASVR_MAXNETS: - if (dp->dmaxnets) - break; - dp->dmaxnets = (uint_t)(cfg_arg[p] & 0x3f); - dp->dncfgitems++; - RCVCFG("DATASVR.MAXNETS", cfg_arg[p]); - break; - - case IDNCFGARG_DATASVR_MBXPERNET: - if (dp->dmboxpernet) - break; - dp->dmboxpernet = (uint_t)(cfg_arg[p] & 0x1ff); - dp->dncfgitems++; - RCVCFG("DATASVR.MBXPERNET", cfg_arg[p]); - break; - - default: - ASSERT(0); - break; - } - break; - - case IDNCFG_OPTIONS: - switch (subtype_arg) { - - case IDNCFGARG_CHECKSUM: - if (dp->dcksum) - break; - if ((cfg_arg[p] & 0xff) == 0) - dp->dcksum = 1; /* off */ - else - dp->dcksum = 2; /* on */ - dp->dncfgitems++; - RCVCFG("OPTIONS.CHECKSUM", cfg_arg[p]); - break; - - default: - ASSERT(0); - break; - } - - default: - break; - } -#ifdef DEBUG - PR_PROTO("%s:%d: received %s (0x%x)\n", - proc, domid, str ? str : "<empty>", val); -#endif /* DEBUG */ - } - - mt.mt_mtype = IDNP_ACK; - mt.mt_atype = IDNP_CFG; - mt.mt_cookie = mtp->mt_cookie; - CLR_XARGS(cfg_arg); - SET_XARGS_CFG_PHASE(cfg_arg, phase); - idn_send_acknack(domid, &mt, cfg_arg); - - rv_expected = rv_actual = 0; - - if (dp->dvote.v.master == 0) { - /* - * Remote domain is a slave, check if we've received - * all that we were expecting, and if so transition to - * the next state. - */ - rv = idn_check_slave_config(domid, &rv_expected, &rv_actual); - } 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. - */ - rv = idn_check_master_config(domid, &rv_expected, &rv_actual); - } - - switch (rv) { - case CFG_DONE: - /* - * All config info received that was expected, wrap up. - */ - if (!idn_recv_config_done(domid) && dp->dvote.v.master) { - IDN_DLOCK_EXCL(idn.localid); - ldp->dvote.v.connected = 1; - IDN_DUNLOCK(idn.localid); - } - 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.. - */ - IDN_MSGTIMER_START(domid, IDNP_CFG, 0, - idn_msg_waittime[IDNP_CFG], NULL); - } - 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. - */ - IDN_DUNLOCK(domid); - IDN_SYNC_LOCK(); - IDN_DLOCK_EXCL(domid); - /* - * If the state has changed from CONFIG - * then somebody else has taken over - * control of this domain so we can just - * bail out. - */ - if (dp->dstate == IDNDS_CONFIG) { - INIT_IDNKERR(&idnerr); - SET_IDNKERR_ERRNO(&idnerr, EPROTO); - SET_IDNKERR_IDNERR(&idnerr, IDNKERR_CONFIG_FATAL); - SET_IDNKERR_PARAM0(&idnerr, domid); - idn_update_op(IDNOP_ERROR, DOMAINSET(domid), &idnerr); - /* - * Keep this guy around so we can try again. - */ - DOMAINSET_ADD(idn.domset.ds_relink, domid); - IDN_HISTORY_LOG(IDNH_RELINK, domid, dp->dstate, - idn.domset.ds_relink); - (void) idn_disconnect(domid, IDNFIN_NORMAL, - IDNFIN_ARG_CFGERR_FATAL, - IDNFIN_SYNC_NO); - } - IDN_SYNC_UNLOCK(); - break; - - default: /* parameter conflict */ - IDN_DUNLOCK(domid); - IDN_SYNC_LOCK(); - IDN_DLOCK_EXCL(domid); - if (dp->dstate != IDNDS_CONFIG) { - /* - * Hmmm...changed in the short period - * we had dropped the lock, oh well. - */ - IDN_SYNC_UNLOCK(); - break; - } - c = 0; - for (p = 0; p < CFG_MAX_ERRORS; p++) - if (rv & (1 << p)) - c++; - INIT_IDNKERR(&idnerr); - SET_IDNKERR_ERRNO(&idnerr, EINVAL); - SET_IDNKERR_PARAM0(&idnerr, domid); - if (c > 1) { - SET_IDNKERR_IDNERR(&idnerr, IDNKERR_CONFIG_MULTIPLE); - SET_IDNKERR_PARAM1(&idnerr, c); - } else { - SET_IDNKERR_IDNERR(&idnerr, CFGERR2IDNKERR(rv)); - SET_IDNKERR_PARAM1(&idnerr, rv_expected); - SET_IDNKERR_PARAM2(&idnerr, rv_actual); - } - /* - * Any parameter conflicts are grounds for dismissal. - */ - if (idn.domset.ds_connected == 0) { - domainset_t domset; - /* - * We have no other connections yet. - * We must blow out of here completely - * unless we have relinkers left from - * a RECONFIG. - */ - IDN_GLOCK_EXCL(); - domset = ~idn.domset.ds_relink; - if (idn.domset.ds_relink == 0) { - IDN_GSTATE_TRANSITION(IDNGS_DISCONNECT); - } - domset &= ~idn.domset.ds_hitlist; - IDN_SET_NEW_MASTERID(IDN_NIL_DOMID); - IDN_GUNLOCK(); - IDN_DUNLOCK(domid); - - DOMAINSET_DEL(domset, idn.localid); - - idn_update_op(IDNOP_ERROR, DOMAINSET_ALL, &idnerr); - - PR_HITLIST("%s:%d: unlink_domainset(%x) due to " - "CFG error (relink=%x, hitlist=%x)\n", - proc, domid, domset, idn.domset.ds_relink, - idn.domset.ds_hitlist); - - idn_unlink_domainset(domset, IDNFIN_NORMAL, - CFGERR2FINARG(rv), - IDNFIN_OPT_UNLINK, - BOARDSET_ALL); - IDN_SYNC_UNLOCK(); - IDN_DLOCK_EXCL(domid); - } else { - PR_HITLIST("%s:%d: idn_disconnect(%d) due to CFG " - "error (conn=%x, relink=%x, hitlist=%x)\n", - proc, domid, domid, idn.domset.ds_connected, - idn.domset.ds_relink, idn.domset.ds_hitlist); - /* - * If we have other connections then - * we're only going to blow away this - * single connection. - */ - idn_update_op(IDNOP_ERROR, DOMAINSET(domid), &idnerr); - - DOMAINSET_DEL(idn.domset.ds_relink, domid); - (void) idn_disconnect(domid, IDNFIN_NORMAL, - CFGERR2FINARG(rv), IDNFIN_SYNC_NO); - IDN_SYNC_UNLOCK(); - } - 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 -idn_check_slave_config(int domid, uint_t *exp, uint_t *act) -{ - uint_t rv = 0; - idn_domain_t *ldp, *dp; - procname_t proc = "idn_check_slave_config"; - - dp = &idn_domain[domid]; - ldp = &idn_domain[idn.localid]; - - ASSERT(domid != idn.localid); - ASSERT(IDN_DLOCK_IS_EXCL(domid)); - ASSERT(dp->dstate == IDNDS_CONFIG); - - PR_PROTO("%s:%d: number received %d, number expected %d\n", - proc, domid, (int)dp->dncfgitems, IDN_SLAVE_NCFGITEMS); - - if ((int)dp->dncfgitems < IDN_SLAVE_NCFGITEMS) - return (CFG_CONTINUE); - - if ((dp->dnetid == (ushort_t)-1) || - CPUSET_ISNULL(dp->dcpuset) || - (dp->dhw.dh_boardset == 0) || - (dp->dmbox.m_send->mm_smr_mboxp == NULL) || - (dp->dmaxnets == 0) || - (dp->dmboxpernet == 0) || - (dp->dcksum == 0) || - (dp->dmtu == 0) || - (dp->dbufsize == 0) || - (dp->dslabsize == 0) || - (dp->dnwrsize == 0)) { - /* - * We received our IDN_SLAVE_NCFGITEMS config items, - * but not all what we were expecting! Gotta nack and - * close connection. - */ - cmn_err(CE_WARN, - "IDN: 218: missing some required config items from " - "domain %d", domid); - - rv = CFG_FATAL; - goto done; - } - - if (!valid_mtu(dp->dmtu)) { - cmn_err(CE_WARN, - "IDN: 219: remote domain %d MTU (%d) invalid " - "(local.mtu = %d)", dp->domid, dp->dmtu, ldp->dmtu); - - *exp = (uint_t)ldp->dmtu; - *act = (uint_t)dp->dmtu; - rv |= CFG_ERR_MTU; - } - if (!valid_bufsize(dp->dbufsize)) { - cmn_err(CE_WARN, - "IDN: 220: remote domain %d BUFSIZE (%d) invalid " - "(local.bufsize = %d)", dp->domid, dp->dbufsize, - ldp->dbufsize); - - *exp = (uint_t)ldp->dbufsize; - *act = (uint_t)dp->dbufsize; - rv |= CFG_ERR_BUF; - } - if (!valid_slabsize((int)dp->dslabsize)) { - cmn_err(CE_WARN, - "IDN: 221: remote domain %d SLABSIZE (%d) invalid " - "(local.slabsize = %d)", - dp->domid, dp->dslabsize, ldp->dslabsize); - - *exp = (uint_t)ldp->dslabsize; - *act = (uint_t)dp->dslabsize; - rv |= CFG_ERR_SLAB; - } - if (!valid_nwrsize((int)dp->dnwrsize)) { - cmn_err(CE_WARN, - "IDN: 223: remote domain %d NWRSIZE (%d) invalid " - "(local.nwrsize = %d)", - dp->domid, dp->dnwrsize, ldp->dnwrsize); - - *exp = (uint_t)ldp->dnwrsize; - *act = (uint_t)dp->dnwrsize; - rv |= CFG_ERR_NWR; - } - if ((int)dp->dmaxnets != IDN_MAX_NETS) { - cmn_err(CE_WARN, - "IDN: 224: remote domain %d MAX_NETS (%d) invalid " - "(local.maxnets = %d)", - dp->domid, (int)dp->dmaxnets, IDN_MAX_NETS); - - *exp = (uint_t)IDN_MAX_NETS; - *act = (uint_t)dp->dmaxnets; - rv |= CFG_ERR_NETS; - } - if ((int)dp->dmboxpernet != IDN_MBOX_PER_NET) { - cmn_err(CE_WARN, - "IDN: 225: remote domain %d MBOX_PER_NET (%d) " - "invalid (local.mboxpernet = %d)", - dp->domid, (int)dp->dmboxpernet, IDN_MBOX_PER_NET); - - *exp = (uint_t)IDN_MBOX_PER_NET; - *act = (uint_t)dp->dmboxpernet; - rv |= CFG_ERR_MBOX; - } - if ((dp->dcksum - 1) != (uchar_t)IDN_CHECKSUM) { - cmn_err(CE_WARN, - "IDN: 226: remote domain %d CHECKSUM flag (%d) " - "mismatches local domain's (%d)", - dp->domid, (int)dp->dcksum - 1, IDN_CHECKSUM); - - *exp = (uint_t)IDN_CHECKSUM; - *act = (uint_t)(dp->dcksum - 1); - rv |= CFG_ERR_CKSUM; - } - -done: - - return (rv ? rv : CFG_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 -idn_check_master_config(int domid, uint_t *exp, uint_t *act) -{ - uint_t rv = 0; - int nmcadr; - int total_expitems; - int p, m, err; - idn_domain_t *dp; - idn_domain_t *ldp = &idn_domain[idn.localid]; - procname_t proc = "idn_check_master_config"; - - dp = &idn_domain[domid]; - - ASSERT(IDN_GET_MASTERID() != idn.localid); - ASSERT(domid != idn.localid); - ASSERT(IDN_DLOCK_IS_EXCL(domid)); - ASSERT(dp->dstate == IDNDS_CONFIG); - - PR_PROTO("%s:%d: number received %d, minimum number expected %d\n", - proc, domid, (int)dp->dncfgitems, IDN_MASTER_NCFGITEMS); - - if ((int)dp->dncfgitems < IDN_MASTER_NCFGITEMS) - 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. - */ - total_expitems = IDN_MASTER_NCFGITEMS + dp->dhw.dh_nmcadr - 1; - if ((dp->dhw.dh_nmcadr == 0) || - ((int)dp->dncfgitems < total_expitems)) { - /* - * We have not yet received all the MCADRs - * we're expecting. - */ - PR_PROTO("%s:%d: haven't received all MCADRs yet.\n", - proc, domid); - return (CFG_CONTINUE); - } - - nmcadr = 0; - for (p = 0; p < MAX_BOARDS; p++) - if (dp->dhw.dh_mcadr[p] != 0) - nmcadr++; - - IDN_GLOCK_SHARED(); - if ((idn.smr.rempfn == PFN_INVALID) || - (idn.smr.rempfnlim == PFN_INVALID) || - (dp->dnetid == (ushort_t)-1) || - CPUSET_ISNULL(dp->dcpuset) || - (dp->dhw.dh_boardset == 0) || - (nmcadr != dp->dhw.dh_nmcadr) || - (dp->dmbox.m_send->mm_smr_mboxp == NULL) || - (ldp->dmbox.m_tbl == NULL) || - (dp->dmaxnets == 0) || - (dp->dmboxpernet == 0) || - (dp->dcksum == 0) || - (dp->dmtu == 0) || - (dp->dbufsize == 0) || - (dp->dnwrsize == 0)) { - - IDN_GUNLOCK(); - /* - * We received all of our config items, but not - * all what we were expecting! Gotta reset and - * close connection. - */ - cmn_err(CE_WARN, - "IDN: 227: missing some required config items from " - "domain %d", domid); - - rv = CFG_FATAL; - goto done; - } - if ((idn.smr.rempfnlim - idn.smr.rempfn) > btop(MB2B(IDN_SMR_SIZE))) { - /* - * 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. - */ - cmn_err(CE_WARN, - "IDN: 228: master's SMR (%ld) larger than " - "local's SMR (%ld)", - idn.smr.rempfnlim - idn.smr.rempfn, - btop(MB2B(IDN_SMR_SIZE))); - - *exp = (uint_t)IDN_SMR_SIZE; - *act = (uint_t)B2MB(ptob(idn.smr.rempfnlim - idn.smr.rempfn)); - rv |= CFG_ERR_SMR; - } - IDN_GUNLOCK(); - - if (!valid_mtu(dp->dmtu)) { - cmn_err(CE_WARN, - "IDN: 219: remote domain %d MTU (%d) invalid " - "(local.mtu = %d)", dp->domid, dp->dmtu, ldp->dmtu); - - *exp = (uint_t)ldp->dmtu; - *act = (uint_t)dp->dmtu; - rv |= CFG_ERR_MTU; - } - if (!valid_bufsize(dp->dbufsize)) { - cmn_err(CE_WARN, - "IDN: 220: remote domain %d BUFSIZE (%d) invalid " - "(local.bufsize = %d)", dp->domid, dp->dbufsize, - ldp->dbufsize); - - *exp = (uint_t)ldp->dbufsize; - *act = (uint_t)dp->dbufsize; - rv |= CFG_ERR_BUF; - } - if (!valid_nwrsize((int)dp->dnwrsize)) { - cmn_err(CE_WARN, - "IDN: 223: remote domain %d NWRSIZE (%d) invalid " - "(local.nwrsize = %d)", - dp->domid, dp->dnwrsize, ldp->dnwrsize); - - *exp = (uint_t)ldp->dnwrsize; - *act = (uint_t)dp->dnwrsize; - rv |= CFG_ERR_NWR; - } - if ((int)dp->dmaxnets != IDN_MAX_NETS) { - cmn_err(CE_WARN, - "IDN: 224: remote domain %d MAX_NETS (%d) invalid " - "(local.maxnets = %d)", - dp->domid, (int)dp->dmaxnets, IDN_MAX_NETS); - - *exp = (uint_t)IDN_MAX_NETS; - *act = (uint_t)dp->dmaxnets; - rv |= CFG_ERR_NETS; - } - if ((int)dp->dmboxpernet != IDN_MBOX_PER_NET) { - cmn_err(CE_WARN, - "IDN: 225: remote domain %d MBOX_PER_NET (%d) " - "invalid (local.mboxpernet = %d)", - dp->domid, (int)dp->dmboxpernet, IDN_MBOX_PER_NET); - - *exp = (uint_t)IDN_MBOX_PER_NET; - *act = (uint_t)dp->dmboxpernet; - rv |= CFG_ERR_MBOX; - } - if ((dp->dcksum - 1) != (uchar_t)IDN_CHECKSUM) { - cmn_err(CE_WARN, - "IDN: 226: remote domain %d CHECKSUM flag (%d) " - "mismatches local domain's (%d)", - dp->domid, (int)dp->dcksum - 1, IDN_CHECKSUM); - - *exp = (uint_t)IDN_CHECKSUM; - *act = (uint_t)(dp->dcksum - 1); - rv |= CFG_ERR_CKSUM; - } - nmcadr = 0; - err = 0; - for (m = 0; m < MAX_BOARDS; m++) { - if (!BOARD_IN_SET(dp->dhw.dh_boardset, m) && - dp->dhw.dh_mcadr[m]) { - cmn_err(CE_WARN, - "IDN: 229: remote domain %d boardset (0x%x) " - "conflicts with MCADR(board %d) [0x%x]", - dp->domid, (uint_t)dp->dhw.dh_boardset, m, - dp->dhw.dh_mcadr[m]); - err++; - } - if (dp->dhw.dh_mcadr[m]) - nmcadr++; - } - if (err) { - *exp = 0; - *act = err; - rv |= CFG_ERR_MCADR; - } else if (nmcadr != dp->dhw.dh_nmcadr) { - cmn_err(CE_WARN, - "IDN: 230: remote domain %d reported number of " - "MCADRs (%d) mismatches received (%d)", - dp->domid, dp->dhw.dh_nmcadr, nmcadr); - *exp = (uint_t)dp->dhw.dh_nmcadr; - *act = (uint_t)nmcadr; - rv |= CFG_ERR_NMCADR; - } - -done: - - return (rv ? rv : CFG_DONE); -} - -static int -idn_recv_config_done(int domid) -{ - boardset_t b_conflicts; - cpuset_t p_conflicts; - register int p, i; - register idn_domain_t *dp; - idnsb_error_t idnerr; - procname_t proc = "idn_recv_config_done"; - - ASSERT(domid != IDN_NIL_DOMID); - dp = &idn_domain[domid]; - ASSERT(IDN_DLOCK_IS_EXCL(domid)); - - /* - * Well, we received all that we were expecting - * so stop any CFG timers we had going. - */ - IDN_MSGTIMER_STOP(domid, IDNP_CFG, 0); - - dp->dncpus = 0; - for (p = 0; p < NCPU; p++) - if (CPU_IN_SET(dp->dcpuset, p)) - dp->dncpus++; - dp->dhw.dh_nboards = 0; - for (p = 0; p < MAX_BOARDS; p++) - if (BOARD_IN_SET(dp->dhw.dh_boardset, p)) - dp->dhw.dh_nboards++; - - IDN_GLOCK_EXCL(); - /* - * Verify dcpuset and dhw.dh_boardset don't - * conflict with any existing DC member. - */ - b_conflicts = idn.dc_boardset & dp->dhw.dh_boardset; - CPUSET_ZERO(p_conflicts); - CPUSET_OR(p_conflicts, idn.dc_cpuset); - CPUSET_AND(p_conflicts, dp->dcpuset); - - if (b_conflicts || !CPUSET_ISNULL(p_conflicts)) { - if (b_conflicts) { - cmn_err(CE_WARN, - "IDN: 231: domain %d boardset " - "(0x%x) conflicts with existing " - "IDN boardset (0x%x)", - domid, dp->dhw.dh_boardset, - b_conflicts); - } - if (!CPUSET_ISNULL(p_conflicts)) { - cmn_err(CE_WARN, - "IDN: 232: domain %d cpuset " - "(0x%x.%0x) conflicts with existing " - "IDN cpuset (0x%x.%0x)", domid, - UPPER32_CPUMASK(dp->dcpuset), - LOWER32_CPUMASK(dp->dcpuset), - UPPER32_CPUMASK(p_conflicts), - LOWER32_CPUMASK(p_conflicts)); - } - IDN_GUNLOCK(); - /* - * Need to disconnect and not retry with this guy. - */ - IDN_DUNLOCK(domid); - IDN_SYNC_LOCK(); - DOMAINSET_DEL(idn.domset.ds_relink, domid); - IDN_DLOCK_EXCL(domid); - - INIT_IDNKERR(&idnerr); - SET_IDNKERR_ERRNO(&idnerr, EPROTO); - SET_IDNKERR_IDNERR(&idnerr, IDNKERR_CONFIG_FATAL); - SET_IDNKERR_PARAM0(&idnerr, domid); - idn_update_op(IDNOP_ERROR, DOMAINSET(domid), &idnerr); - - (void) idn_disconnect(domid, IDNFIN_FORCE_HARD, - IDNFIN_ARG_CFGERR_FATAL, IDNFIN_SYNC_NO); - IDN_SYNC_UNLOCK(); - - return (-1); - } - - idn_mainmbox_reset(domid, dp->dmbox.m_send); - idn_mainmbox_reset(domid, dp->dmbox.m_recv); - -#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. - */ - if (!idn_cpu_per_board((void *)NULL, dp->dcpuset, &dp->dhw)) { - cmn_err(CE_WARN, - "IDN: 233: domain %d missing CPU per " - "memory boardset (0x%x), CPU boardset (0x%x)", - domid, dp->dhw.dh_boardset, - cpuset2boardset(dp->dcpuset)); - - IDN_GUNLOCK(); - /* - * Need to disconnect and not retry with this guy. - */ - IDN_DUNLOCK(domid); - IDN_SYNC_LOCK(); - DOMAINSET_DEL(idn.domset.ds_relink, domid); - IDN_DLOCK_EXCL(domid); - - INIT_IDNKERR(&idnerr); - SET_IDNKERR_ERRNO(&idnerr, EINVAL); - SET_IDNKERR_IDNERR(&idnerr, IDNKERR_CPU_CONFIG); - SET_IDNKERR_PARAM0(&idnerr, domid); - idn_update_op(IDNOP_ERROR, DOMAINSET(domid), &idnerr); - - (void) idn_disconnect(domid, IDNFIN_FORCE_HARD, - IDNFIN_ARG_CPUCFG, IDNFIN_SYNC_NO); - IDN_SYNC_UNLOCK(); - - return (-1); - } -#endif /* IDNBUG_CPUPERBOARD */ - - CPUSET_OR(idn.dc_cpuset, dp->dcpuset); - idn.dc_boardset |= dp->dhw.dh_boardset; - - IDN_GUNLOCK(); - - /* - * Set up the portmap for this domain. - */ - i = -1; - for (p = 0; p < NCPU; p++) { - BUMP_INDEX(dp->dcpuset, i); - dp->dcpumap[p] = (uchar_t)i; - } - - /* - * Got everything we need from the remote - * domain, now we can program hardware as needed. - */ - if (idn_program_hardware(domid) != 0) { - domainset_t domset; - /* - * Yikes! Failed to program hardware. - * Gotta bail. - */ - cmn_err(CE_WARN, - "IDN: 234: failed to program hardware for domain %d " - "(boardset = 0x%x)", - domid, dp->dhw.dh_boardset); - - IDN_DUNLOCK(domid); - /* - * If we're having problems programming our - * hardware we better unlink completely from - * the IDN before things get really bad. - */ - IDN_SYNC_LOCK(); - IDN_GLOCK_EXCL(); - IDN_GSTATE_TRANSITION(IDNGS_DISCONNECT); - domset = DOMAINSET_ALL; - DOMAINSET_DEL(domset, idn.localid); - IDN_SET_NEW_MASTERID(IDN_NIL_DOMID); - IDN_GUNLOCK(); - - INIT_IDNKERR(&idnerr); - SET_IDNKERR_ERRNO(&idnerr, EINVAL); - SET_IDNKERR_IDNERR(&idnerr, IDNKERR_HW_ERROR); - SET_IDNKERR_PARAM0(&idnerr, domid); - idn_update_op(IDNOP_ERROR, DOMAINSET_ALL, &idnerr); - - idn_unlink_domainset(domset, IDNFIN_NORMAL, IDNFIN_ARG_HWERR, - IDNFIN_OPT_UNLINK, BOARDSET_ALL); - - IDN_SYNC_UNLOCK(); - IDN_DLOCK_EXCL(domid); - - return (-1); - } - - /* - * Now that hardware has been programmed we can - * remap the SMR into our local space, if necessary. - */ - IDN_GLOCK_EXCL(); - 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. - */ - smr_remap(&kas, idn.smr.vaddr, idn.smr.rempfn, IDN_SMR_SIZE); - } - 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. - */ - - dp->dcfgrcvdone = 1; - PR_PROTO("%s:%d: RECV config DONE\n", proc, domid); - - if (dp->dcfgsnddone) { - idn_xdcargs_t xargs; - /* - * 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. - */ - IDN_DUNLOCK(domid); - IDN_SYNC_LOCK(); - IDN_DLOCK_EXCL(domid); - /* - * If the state has changed from CONFIG - * then somebody else has taken over - * control of this domain so we can just - * bail out. - */ - if (dp->dstate == IDNDS_CONFIG) { - dp->dxp = &xphase_con; - IDN_XSTATE_TRANSITION(dp, IDNXS_PEND); - bzero(xargs, sizeof (xargs)); - - (void) idn_xphase_transition(domid, NULL, xargs); - } - IDN_SYNC_UNLOCK(); - } - - return (0); -} - -static int -idn_verify_config_mbox(int domid) -{ - idn_domain_t *ldp, *dp; - idn_mainmbox_t *mmp; - idn_mboxtbl_t *mtp; - int c, rv = 0; - uint_t activeptr, readyptr; - ushort_t mbox_csum; - - ASSERT(IDN_DLOCK_IS_EXCL(domid)); - - dp = &idn_domain[domid]; - ldp = &idn_domain[idn.localid]; - - /* - * 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. - */ - IDN_DLOCK_SHARED(idn.localid); - /* - * 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. - */ - mmp = dp->dmbox.m_recv; - mtp = IDN_MBOXTBL_PTR(ldp->dmbox.m_tbl, domid); - for (c = 0; c < IDN_MAX_NETS; c++) { - mutex_enter(&mmp[c].mm_mutex); - ASSERT(!mmp[c].mm_smr_mboxp); - - mmp[c].mm_smr_mboxp = mtp; - mbox_csum = IDN_CKSUM_MBOX(&mtp->mt_header); - if (!VALID_MBOXHDR(&mtp->mt_header, c, mbox_csum)) { - cmn_err(CE_WARN, - "IDN: 235: [recv] mailbox (domain %d, " - "channel %d) SMR CORRUPTED - RELINK", - domid, c); - cmn_err(CE_CONT, - "IDN: 235: [recv] expected (cookie 0x%x, " - "cksum 0x%x) actual (cookie 0x%x, " - "cksum 0x%x)\n", - IDN_GET_MBOXHDR_COOKIE(&mtp->mt_header), - (int)mtp->mt_header.mh_cksum, - IDN_MAKE_MBOXHDR_COOKIE(0, 0, c), - (int)mbox_csum); - mutex_exit(&mmp[c].mm_mutex); - rv = -1; - break; - } - activeptr = mtp->mt_header.mh_svr_active_ptr; - readyptr = mtp->mt_header.mh_svr_ready_ptr; - /* - * Verify pointers are valid. - */ - if (!activeptr || !VALID_NWROFFSET(activeptr, 2) || - !readyptr || !VALID_NWROFFSET(readyptr, 2)) { - cmn_err(CE_WARN, - "IDN: 235: [recv] mailbox (domain %d, " - "channel %d) SMR CORRUPTED - RELINK", - domid, c); - cmn_err(CE_CONT, - "IDN: 235: [recv] activeptr (0x%x), " - "readyptr (0x%x)\n", - activeptr, readyptr); - mutex_exit(&mmp[c].mm_mutex); - rv = -1; - break; - } - mmp[c].mm_smr_activep = (ushort_t *)IDN_OFFSET2ADDR(activeptr); - mmp[c].mm_smr_readyp = (ushort_t *)IDN_OFFSET2ADDR(readyptr); - mutex_exit(&mmp[c].mm_mutex); - IDN_MBOXTBL_PTR_INC(mtp); - } - - IDN_DUNLOCK(idn.localid); - - if (rv) - return (rv); - - /* - * Now we need to translate SMR offsets for send mailboxes - * to actual virtual addresses. - */ - mmp = dp->dmbox.m_send; - for (c = 0; c < IDN_MAX_NETS; mmp++, c++) { - mutex_enter(&mmp->mm_mutex); - if ((mtp = mmp->mm_smr_mboxp) == NULL) { - mutex_exit(&mmp->mm_mutex); - rv = -1; - break; - } - - mbox_csum = IDN_CKSUM_MBOX(&mtp->mt_header); - - if (!VALID_MBOXHDR(&mtp->mt_header, c, mbox_csum)) { - cmn_err(CE_WARN, - "IDN: 235: [send] mailbox (domain %d, " - "channel %d) SMR CORRUPTED - RELINK", - domid, c); - cmn_err(CE_CONT, - "IDN: 235: [send] expected (cookie 0x%x, " - "cksum 0x%x) actual (cookie 0x%x, " - "cksum 0x%x)\n", - IDN_GET_MBOXHDR_COOKIE(&mtp->mt_header), - (int)mtp->mt_header.mh_cksum, - IDN_MAKE_MBOXHDR_COOKIE(0, 0, c), - (int)mbox_csum); - mutex_exit(&mmp->mm_mutex); - rv = -1; - break; - } - activeptr = mtp->mt_header.mh_svr_active_ptr; - readyptr = mtp->mt_header.mh_svr_ready_ptr; - /* - * Paranoid check. - */ - if (!activeptr || !VALID_NWROFFSET(activeptr, 2) || - !readyptr || !VALID_NWROFFSET(readyptr, 2)) { - cmn_err(CE_WARN, - "IDN: 235: [send] mailbox (domain %d, " - "channel %d) SMR CORRUPTED - RELINK", - domid, c); - cmn_err(CE_CONT, - "IDN: 235: [send] activeptr (0x%x), " - "readyptr (0x%x)\n", - activeptr, readyptr); - mutex_exit(&mmp->mm_mutex); - rv = -1; - break; - } - mmp->mm_smr_activep = (ushort_t *)IDN_OFFSET2ADDR(activeptr); - mmp->mm_smr_readyp = (ushort_t *)IDN_OFFSET2ADDR(readyptr); - idn_reset_mboxtbl(mtp); - mutex_exit(&mmp->mm_mutex); - IDN_MBOXTBL_PTR_INC(mtp); - } - - 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 -valid_mtu(uint_t mtu) -{ - return ((mtu == idn_domain[idn.localid].dmtu) && mtu); -} - -static int -valid_bufsize(uint_t bufsize) -{ - return ((bufsize == idn_domain[idn.localid].dbufsize) && bufsize); -} - -static int -valid_slabsize(int slabsize) -{ - return ((slabsize == idn_domain[idn.localid].dslabsize) && slabsize); -} - -static int -valid_nwrsize(int nwrsize) -{ - return ((nwrsize == idn_domain[idn.localid].dnwrsize) && nwrsize); -} - -static int -idn_program_hardware(int domid) -{ - int rv, is_master; - idn_domain_t *dp; - uint_t *mcadrp; - pfn_t rem_pfn, rem_pfnlimit; - procname_t proc = "idn_program_hardware"; - - PR_PROTO("%s:%d: program hw in domain %d w.r.t remote domain %d\n", - proc, domid, idn.localid, domid); - - dp = &idn_domain[domid]; - - ASSERT(domid != idn.localid); - ASSERT(IDN_DLOCK_IS_EXCL(domid)); - ASSERT(dp->dstate == IDNDS_CONFIG); - - IDN_GLOCK_EXCL(); - - if (DOMAIN_IN_SET(idn.domset.ds_hwlinked, domid)) { - IDN_GUNLOCK(); - return (0); - } - - DOMAINSET_ADD(idn.domset.ds_flush, domid); - CHECKPOINT_OPENED(IDNSB_CHKPT_CACHE, dp->dhw.dh_boardset, 1); - - 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; - if ((idn.localid == IDN_GET_MASTERID()) && - lock_try(&idn.first_hwlink)) { - /* - * This is our first HW link and I'm the - * master, which means we need to program - * our local bar/lar. - */ - ASSERT(idn.first_hwmasterid == (short)IDN_NIL_DOMID); - idn.first_hwmasterid = (short)idn.localid; - rem_pfn = idn.smr.locpfn; - rem_pfnlimit = idn.smr.locpfn + - btop(MB2B(IDN_SMR_SIZE)); - } else { - /* - * Otherwise, just a slave linking to - * another slave. No bar/lar updating - * necessary. - */ - rem_pfn = rem_pfnlimit = PFN_INVALID; - } - mcadrp = NULL; - } else { - /* - * If the remote domain is a master, then - * we need to program the CIC sm_mask/sm_bar/sm_lar, - * and PC's. - */ - is_master = 1; - rem_pfn = idn.smr.rempfn; - rem_pfnlimit = idn.smr.rempfnlim; - mcadrp = dp->dhw.dh_mcadr; - ASSERT(idn.first_hwmasterid == (short)IDN_NIL_DOMID); - idn.first_hwmasterid = (short)domid; - } - - PR_PROTO("%s:%d: ADD bset (0x%x)\n", proc, domid, dp->dhw.dh_boardset); - - rv = idnxf_shmem_add(is_master, dp->dhw.dh_boardset, - rem_pfn, rem_pfnlimit, mcadrp); - - if (rv == 0) { - DOMAINSET_ADD(idn.domset.ds_hwlinked, domid); - } else { - if (rem_pfn == idn.smr.locpfn) - lock_clear(&idn.first_hwlink); - - if (idn.first_hwmasterid == (short)domid) - idn.first_hwmasterid = (short)IDN_NIL_DOMID; - - (void) idnxf_shmem_sub(is_master, dp->dhw.dh_boardset); - } - - IDN_GUNLOCK(); - - return (rv); -} - -static int -idn_deprogram_hardware(int domid) -{ - int rv, is_master; - idn_domain_t *dp; - procname_t proc = "idn_deprogram_hardware"; - - - dp = &idn_domain[domid]; - - ASSERT(domid != idn.localid); - ASSERT(IDN_DLOCK_IS_EXCL(domid)); - - /* - * 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_GLOCK_EXCL(); - - if (!DOMAIN_IN_SET(idn.domset.ds_hwlinked, domid)) { - IDN_GUNLOCK(); - return (0); - } - - PR_PROTO("%s:%d: DEprogram hw in domain %d w.r.t remote domain %d\n", - proc, domid, idn.localid, domid); - - /* - * 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. - * This can occur if we lose a domain during the config/syn - * 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", proc, domid, dp->dhw.dh_boardset); - - if (idn.first_hwmasterid == (short)domid) { - is_master = 1; - idn.first_hwmasterid = (short)IDN_NIL_DOMID; - } else { - is_master = 0; - } - rv = idnxf_shmem_sub(is_master, dp->dhw.dh_boardset); - - if (rv == 0) - DOMAINSET_DEL(idn.domset.ds_hwlinked, domid); - - 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) -{ - idn_domain_t *dp, *ldp; - smr_slab_t *sp; - int c, masterid; - procname_t proc = "idn_deconfig"; - - ASSERT(IDN_SYNC_IS_LOCKED()); - ASSERT(IDN_DLOCK_IS_EXCL(domid)); - ASSERT(domid != idn.localid); - - ldp = &idn_domain[idn.localid]; - dp = &idn_domain[domid]; - - ASSERT(dp->dstate == IDNDS_DMAP); - - PR_PROTO("%s:%d: (dio=%d, dioerr=%d, dnslabs=%d)\n", - proc, domid, dp->dio, dp->dioerr, dp->dnslabs); - - IDN_GLOCK_EXCL(); - masterid = IDN_GET_MASTERID(); - - idn.dc_boardset &= ~dp->dhw.dh_boardset; - for (c = 0; c < NCPU; c++) { - if (CPU_IN_SET(dp->dcpuset, c)) { - CPUSET_DEL(idn.dc_cpuset, c); - } - } - - IDN_GUNLOCK(); - - (void) smr_buf_free_all(domid); - - if (idn.localid == masterid) { - /* - * Since I'm the master there may - * have been slabs in this domain's - * idn_domain[] entry. - */ - DSLAB_LOCK_EXCL(domid); - if ((sp = dp->dslab) != NULL) { - PR_PROTO("%s:%d: freeing up %d dead slabs\n", - proc, domid, dp->dnslabs); - smr_slab_free(domid, sp); - dp->dslab = NULL; - dp->dnslabs = 0; - dp->dslab_state = DSLAB_STATE_UNKNOWN; - } - DSLAB_UNLOCK(domid); - } else if (domid == masterid) { - /* - * 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. - */ - DSLAB_LOCK_EXCL(idn.localid); - ASSERT(dp->dslab == NULL); -#ifdef DEBUG - { - int nbusy = 0; - uint_t dommask = 0; - for (sp = ldp->dslab; sp; sp = sp->sl_next) { - smr_slabbuf_t *bp; - - if (!smr_slab_busy(sp)) - continue; - nbusy++; - for (bp = sp->sl_inuse; bp; bp = bp->sb_next) - if (bp->sb_domid != IDN_NIL_DOMID) - DOMAINSET_ADD(dommask, - bp->sb_domid); - } - if (nbusy) - PR_PROTO("%s:%d: found %d busy slabs " - "(dommask = 0x%x)\n", - proc, domid, nbusy, dommask); - } -#endif /* DEBUG */ - if ((sp = ldp->dslab) != NULL) { - PR_PROTO("%s:%d: freeing up %d local slab " - "structs\n", proc, domid, ldp->dnslabs); - smr_slab_garbage_collection(sp); - ldp->dslab = NULL; - ldp->dnslabs = 0; - ldp->dslab_state = DSLAB_STATE_UNKNOWN; - } - DSLAB_UNLOCK(idn.localid); - } - if (dp->dio) { - PR_PROTO("%s:%d: reset dio (%d) to 0\n", proc, domid, dp->dio); - dp->dio = 0; - } - dp->dioerr = 0; - - PR_PROTO("%s:%d: reset diocheck (%x) to 0\n", - proc, domid, dp->diocheck); - lock_clear(&dp->diocheck); - - CHECKPOINT_CLOSED(IDNSB_CHKPT_LINK, dp->dhw.dh_boardset, 2); - - /* - * 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 - * out caches now could result in a arbstop/hang - * if we have data that needs to go back to one - * of the remote domains that has already reprogrammed - * its hardware. - */ - ASSERT(!DOMAIN_IN_SET(idn.domset.ds_flush, domid)); - - (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? - */ - - IDN_DSTATE_TRANSITION(dp, IDNDS_CLOSED); - - idn_close_domain(domid); -} - -/* - * 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 -idn_shutdown_datapath(domainset_t domset, int force) -{ - int do_allchan; - idn_domain_t *dp; - register int d; - procname_t proc = "idn_shutdown_datapath"; - - - PR_CHAN("%s: domset = 0x%x\n", proc, (uint_t)domset); - - do_allchan = (domset == DOMAINSET_ALL) ? 1 : 0; - - DOMAINSET_DEL(domset, idn.localid); - - if (do_allchan) { - /* - * Need to stop all outgoing and - * incoming SMR references. - */ - idn_deactivate_channel(CHANSET_ALL, IDNCHAN_OFFLINE); - } - - /* - * 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) - idn_mainmbox_deactivate(domset); - - /* - * Flush out mailboxes (clear smr reference). - */ - for (d = 0; d < MAX_DOMAINS; d++) { - if (!DOMAIN_IN_SET(domset, d)) - continue; - - dp = &idn_domain[d]; - if ((dp->dmbox.m_send == NULL) && (dp->dmbox.m_recv == NULL)) - continue; - - IDN_MBOX_LOCK(d); - if (dp->dmbox.m_send) - (void) idn_mainmbox_flush(d, dp->dmbox.m_send); - if (dp->dmbox.m_recv) - (void) idn_mainmbox_flush(d, dp->dmbox.m_recv); - IDN_MBOX_UNLOCK(d); - } - /* - * Deactivate all domain references also. - * Only necessary if it wasn't already done above. - */ - if (!force) - idn_mainmbox_deactivate(domset); -} - -void -idn_send_cmd(int domid, idn_cmd_t cmdtype, uint_t arg1, uint_t arg2, uint_t - arg3) -{ - idn_msgtype_t mt; - procname_t proc = "idn_send_cmd"; - - mt.mt_mtype = IDNP_CMD; - mt.mt_atype = 0; - mt.mt_cookie = 0; - - ASSERT(IDN_DLOCK_IS_HELD(domid)); - - PR_PROTO("%s:%d: sending command %s\n", proc, domid, - VALID_IDNCMD(cmdtype) ? idncmd_str[cmdtype] : "unknown"); - - IDN_MSGTIMER_START(domid, IDNP_CMD, (ushort_t)cmdtype, - idn_msg_waittime[IDNP_CMD], &mt.mt_cookie); - - IDNXDC(domid, &mt, (uint_t)cmdtype, arg1, arg2, arg3); -} - -void -idn_send_cmdresp(int domid, idn_msgtype_t *mtp, idn_cmd_t cmdtype, uint_t arg1, - uint_t arg2, uint_t cerrno) -{ - idn_msgtype_t mt; - - ASSERT(IDN_DLOCK_IS_HELD(domid)); - - if (domid == idn.localid) { - /* - * It's possible local domain received a command - * from itself. However, we cannot send a normal - * "ack" response (XDC) to ourself. - */ - return; - } - - mt.mt_mtype = IDNP_CMD | IDNP_ACK; - mt.mt_atype = 0; - mt.mt_cookie = mtp->mt_cookie; - - IDNXDC(domid, &mt, (uint_t)cmdtype, arg1, arg2, cerrno); -} - -static void -idn_send_cmd_nackresp(int domid, idn_msgtype_t *mtp, idn_cmd_t cmdtype, - idn_nack_t nacktype) -{ - idn_msgtype_t mt; - - if (domid == idn.localid) - return; - - mt.mt_mtype = IDNP_CMD | IDNP_NACK; - mt.mt_atype = 0; - mt.mt_cookie = mtp->mt_cookie; - - (void) IDNXDC(domid, &mt, (uint_t)cmdtype, (uint_t)nacktype, 0, 0); -} - -void -idn_broadcast_cmd(idn_cmd_t cmdtype, uint_t arg1, uint_t arg2, uint_t arg3) -{ - idn_msgtype_t mt; - domainset_t domset; - procname_t proc = "idn_broadcast_cmd"; - - IDN_GLOCK_SHARED(); - - domset = idn.domset.ds_connected; - DOMAINSET_DEL(domset, idn.localid); - - PR_PROTO("%s: broadcasting command (%s) to domainset 0x%x\n", - proc, VALID_IDNCMD(cmdtype) ? idncmd_str[cmdtype] : "unknown", - domset); - - mt.mt_mtype = IDNP_CMD; - mt.mt_atype = 0; - mt.mt_cookie = 0; - - IDNXDC_BROADCAST(domset, &mt, (uint_t)cmdtype, arg1, arg2, arg3); - - 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. - */ - idn_local_cmd(cmdtype, arg1, arg2, arg3); -} - -/* - * Since xargs[0] contains the cmdtype, only xargs[1], xargs[2], xargs[3] - * are valid possible response arguments. - */ -static void -idn_recv_cmd(int domid, idn_msgtype_t *mtp, idn_xdcargs_t xargs) -{ - uint_t msg = mtp->mt_mtype; - register idn_domain_t *dp; - idn_cmd_t cmdtype; - uint_t acknack; - uint_t cmdarg1, cmdarg2, cmdarg3; - int islocal; - int unsup_cmd_sent, unsup_cmd_recvd; - procname_t proc = "idn_recv_cmd"; - - acknack = msg & IDNP_ACKNACK_MASK; - GET_XARGS(xargs, &cmdtype, &cmdarg1, &cmdarg2, &cmdarg3); - - dp = &idn_domain[domid]; - ASSERT(IDN_DLOCK_IS_EXCL(domid)); - - IDN_GLOCK_SHARED(); - - islocal = (domid == idn.localid); - - ASSERT(!acknack || (acknack & IDNP_ACKNACK_MASK)); - - PR_PROTO("%s:%d: (local=%d) acknack=0x%x, cmdtype=%s(%d), " - "a1=0x%x, a2=0x%x, a3=0x%x\n", - proc, domid, islocal, acknack, - VALID_IDNCMD(cmdtype) ? idncmd_str[cmdtype] : "unknown", - cmdtype, cmdarg1, cmdarg2, cmdarg3); - - unsup_cmd_sent = unsup_cmd_recvd = 0; - - if ((IDN_GET_MASTERID() == IDN_NIL_DOMID) || - (dp->dstate != IDNDS_CONNECTED)) { - /* - * 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", - proc, domid, IDN_GET_MASTERID(), - idnds_str[dp->dstate]); - - if (!islocal && !(acknack & IDNP_ACKNACK_MASK)) - idn_send_cmd_nackresp(domid, mtp, cmdtype, - IDNNACK_NOCONN); - IDN_GUNLOCK(); - return; - } - IDN_GUNLOCK(); - - if (acknack & IDNP_ACKNACK_MASK) { - idn_nack_t nack; - /* - * 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). - */ - nack = (idn_nack_t)cmdarg1; - if ((acknack & IDNP_NACK) && (nack == IDNNACK_BADCMD)) - unsup_cmd_sent++; - - if (islocal) { - /* - * Shouldn't be receiving local commands w/acks. - */ - cmdtype = (idn_cmd_t)0; - } - - switch (cmdtype) { - case IDNCMD_SLABALLOC: - idn_recv_slaballoc_resp(domid, cmdarg1, cmdarg2, - cmdarg3); - break; - - case IDNCMD_SLABFREE: - idn_recv_slabfree_resp(domid, cmdarg1, cmdarg2, - cmdarg3); - break; - - case IDNCMD_SLABREAP: - /* - * We only care if successful. - */ - if (acknack & IDNP_ACK) - idn_recv_slabreap_resp(domid, cmdarg1, cmdarg3); - break; - - case IDNCMD_NODENAME: - if ((acknack & IDNP_NACK) == 0) { - idn_recv_nodename_resp(domid, cmdarg1, 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", - proc, domid, - idncmd_str[IDNCMD_NODENAME], - idnds_str[dp->dstate]); - - if (dp->dstate == IDNDS_CONNECTED) - (void) timeout(idn_retry_nodename_req, - (void *)(uintptr_t)domid, hz); - default: - break; - } - break; - - default: - /* - * Unsupported command. - */ - unsup_cmd_recvd++; - break; - } - if (unsup_cmd_sent) { - PR_PROTO("%s:%d: unsupported command " - "requested (0x%x)\n", - proc, domid, cmdtype); - } - if (unsup_cmd_recvd) { - PR_PROTO("%s:%d: unsupported command " - "response (0x%x)\n", - proc, domid, cmdtype); - } - } else { - /* - * Receiving a regular cmd from a remote domain. - */ - switch (cmdtype) { - case IDNCMD_SLABALLOC: - idn_recv_slaballoc_req(domid, mtp, cmdarg1); - break; - - case IDNCMD_SLABFREE: - idn_recv_slabfree_req(domid, mtp, cmdarg1, cmdarg2); - break; - - case IDNCMD_SLABREAP: - idn_recv_slabreap_req(domid, mtp, cmdarg1); - break; - - case IDNCMD_NODENAME: - idn_recv_nodename_req(domid, mtp, cmdarg1); - break; - - default: - /* - * Unsupported command. - */ - unsup_cmd_recvd++; - break; - } - if (!islocal && unsup_cmd_recvd) { - /* - * Received an unsupported IDN command. - */ - idn_send_cmd_nackresp(domid, mtp, cmdtype, - IDNNACK_BADCMD); - } - } -} - -/* - * 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 -idn_local_cmd(idn_cmd_t cmdtype, uint_t arg1, uint_t arg2, uint_t arg3) -{ - idn_protojob_t *jp; - idn_domain_t *ldp = &idn_domain[idn.localid]; - procname_t proc = "idn_local_cmd"; - - PR_PROTO("%s: submitting local command %s on domain %d\n", - proc, VALID_IDNCMD(cmdtype) ? idncmd_str[cmdtype] : "unknown", - idn.localid); - - - jp = idn_protojob_alloc(KM_SLEEP); - - jp->j_msg.m_domid = ldp->domid; - jp->j_msg.m_msgtype = IDNP_CMD; - jp->j_msg.m_cookie = ldp->dcookie_recv; - SET_XARGS(jp->j_msg.m_xargs, cmdtype, arg1, arg2, arg3); - - idn_protojob_submit(ldp->domid, jp); -} - -/* - * 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 -idn_terminate_cmd(int domid, int serrno) -{ - idn_domain_t *dp; - idn_timer_t *tplist = NULL, *tp; - procname_t proc = "idn_terminate_cmd"; - - dp = &idn_domain[domid]; - - ASSERT(IDN_DLOCK_IS_EXCL(domid)); - - IDN_MSGTIMER_GET(dp, IDNP_CMD, tplist, 0); - /* - * At this point the timers are effectively terminated - * since when they're t_onq indication is set false. - */ - if (tplist == NULL) { - PR_PROTO("%s:%d: no outstanding cmds found\n", - proc, domid); - /* - * 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. - */ - } - ASSERT(tplist ? (tplist->t_back->t_forw == NULL) : 1); - - for (tp = tplist; tp; tp = tp->t_forw) { - ASSERT(tp->t_type == IDNP_CMD); - - PR_PROTO("%s:%d: found outstanding cmd: %s\n", - proc, domid, idncmd_str[tp->t_subtype]); - - switch (tp->t_subtype) { - 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_GLOCK_SHARED(); - ASSERT(domid == IDN_GET_MASTERID()); - ASSERT(idn.localid != IDN_GET_MASTERID()); - IDN_GUNLOCK(); -#endif /* DEBUG */ - (void) smr_slabwaiter_abort(idn.localid, serrno); - 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) { - IDN_TIMER_STOPALL(tplist); - } - - if (idn_domain[idn.localid].dvote.v.master) { - /* - * 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 slaballoc waiters\n", proc, domid); - (void) smr_slabwaiter_abort(domid, serrno); - - } else if (dp->dvote.v.master) { - PR_PROTO("%s:%d: abort (local domain) slaballoc waiters\n", - proc, domid); - (void) smr_slabwaiter_abort(idn.localid, serrno); - } -} - -static void -idn_send_acknack(int domid, idn_msgtype_t *mtp, idn_xdcargs_t xargs) -{ - idn_domain_t *dp = &idn_domain[domid]; - procname_t proc = "idn_send_acknack"; - - ASSERT(mtp ? (mtp->mt_mtype & IDNP_ACKNACK_MASK) : 1); - ASSERT(domid != IDN_NIL_DOMID); - -#ifdef DEBUG - { - STRING(mstr); - STRING(astr); - - INUM2STR(mtp->mt_mtype, mstr); - INUM2STR(mtp->mt_atype, astr); - - if (mtp->mt_mtype & IDNP_ACK) { - PR_PROTO("%s:%d: dstate=%s, msg=(%s/%s), " - "a1=0x%x, a2=0x%x, a3=0x%x, a4 = 0x%x\n", - proc, domid, idnds_str[dp->dstate], - astr, mstr, xargs[0], xargs[1], - xargs[2], xargs[3]); - } else { - idn_nack_t nack; - - nack = GET_XARGS_NACK_TYPE(xargs); - PR_PROTO("%s:%d: dstate=%s, msg=(%s/%s), " - "nack=%s(0x%x)\n", - proc, domid, idnds_str[dp->dstate], - astr, mstr, idnnack_str[nack], - (uint_t)nack); - } - } -#endif /* DEBUG */ - - (void) IDNXDC(domid, mtp, xargs[0], xargs[1], xargs[2], xargs[3]); -} - -/*ARGSUSED0*/ -static void -idn_prealloc_slab(int nslabs) -{ - register int s, serrno; - smr_slab_t *sp; - idn_domain_t *ldp = &idn_domain[idn.localid]; - procname_t proc = "idn_prealloc_slab"; - - IDN_GLOCK_SHARED(); - DSLAB_LOCK_SHARED(idn.localid); - if ((idn.state != IDNGS_ONLINE) || (ldp->dnslabs > 0)) { - /* - * Not in the proper state or slab already allocated. - */ - DSLAB_UNLOCK(idn.localid); - IDN_GUNLOCK(); - return; - } - IDN_GUNLOCK(); - ASSERT(!ldp->dslab); - - serrno = 0; - for (s = 0; (s < nslabs) && ((int)ldp->dnslabs < nslabs); s++) { - /* - * Returns with ldp->drwlock dropped. - */ - serrno = smr_slab_alloc(idn.localid, &sp); - if (serrno != 0) { - PR_PROTO("%s: FAILED to pre-alloc'd " - "slab (serrno = %d)\n", proc, serrno); - break; - } - /* - * State may have changed since smr_slab_alloc - * temporarily drops drwlock. Make sure we're - * still connected. - */ - PR_PROTO("%s: SUCCESSFULLY pre-alloc'd slab\n", proc); - - if (idn.state != IDNGS_ONLINE) { - PR_PROTO("%s: Lost connection..leaving\n", proc); - break; - } - } - - DSLAB_UNLOCK(idn.localid); -} - -/* - * 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 -idn_recv_slaballoc_req(int domid, idn_msgtype_t *mtp, uint_t slab_size) -{ - register idn_domain_t *dp; - procname_t proc = "idn_recv_slaballoc_req"; - - PR_PROTO("%s: slaballoc req from domain %d (size=0x%x)\n", - proc, domid, slab_size); - - dp = &idn_domain[domid]; - - ASSERT(IDN_DLOCK_IS_EXCL(domid)); - - IDN_GLOCK_SHARED(); - - if (idn.localid != IDN_GET_MASTERID()) { - IDN_GUNLOCK(); - /* - * It's a fatal error if the remote domain thinks - * we're the master. - */ - idn_send_slaballoc_resp(domid, mtp, 0, 0, EACCES); - - } else if (dp->dstate != IDNDS_CONNECTED) { - - IDN_GUNLOCK(); - /* - * It's a fatal error if we don't yet have a - * connection established with the requestor. - */ - idn_send_slaballoc_resp(domid, mtp, 0, 0, ENOLINK); - } else { - int serrno; - smr_slab_t *sp; - smr_offset_t slab_offset; - - IDN_GUNLOCK(); - DSLAB_LOCK_SHARED(domid); - IDN_DUNLOCK(domid); - /* - * We're connected and we're the master. - * smr_slab_alloc() returns with dp->drwlock dropped. - */ - if ((serrno = smr_slab_alloc(domid, &sp)) == 0) { - /* - * Successfully allocated slab for remote slave. - */ - slab_offset = IDN_ADDR2OFFSET(sp->sl_start); - slab_size = sp->sl_end - sp->sl_start; - ASSERT((slab_offset != 0) && (slab_size != 0)); - } else { - slab_offset = slab_size = 0; - } - DSLAB_UNLOCK(domid); - /* - * The drwlock is dropped during smr_slab_alloc. - * During that time our connection with the given - * domain may have changed. Better check again. - */ - IDN_DLOCK_SHARED(domid); - if ((dp->dstate != IDNDS_CONNECTED) && !serrno) { - /* - * Connection broke. Keep the slab here. - */ - DSLAB_LOCK_EXCL(domid); - IDN_DUNLOCK(domid); - smr_slab_free(domid, sp); - DSLAB_UNLOCK(domid); - slab_offset = slab_size = 0; - serrno = ECANCELED; - IDN_DLOCK_SHARED(domid); - } - /* - * Send response. - * Note that smr_slab_alloc automatically installs - * slab into domains respective idn_domain entry - * to be associated with that domain. - */ - idn_send_slaballoc_resp(domid, mtp, slab_offset, slab_size, - serrno); - } -} - -static void -idn_send_slaballoc_resp(int domid, idn_msgtype_t *mtp, smr_offset_t slab_offset, - uint_t slab_size, int serrno) -{ - procname_t proc = "idn_send_slaballoc_resp"; - - PR_PROTO("%s: slaballoc resp to domain %d (off=0x%x, size=0x%x) " - "[serrno = %d]\n", - proc, domid, slab_offset, slab_size, serrno); - - idn_send_cmdresp(domid, mtp, IDNCMD_SLABALLOC, slab_offset, slab_size, - serrno); -} - -/* - * 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 -idn_recv_slaballoc_resp(int domid, smr_offset_t slab_offset, uint_t slab_size, - int serrno) -{ - smr_slab_t *sp = NULL; - int rv; - procname_t proc = "idn_recv_slaballoc_resp"; - - - ASSERT(IDN_DLOCK_IS_EXCL(domid)); - - PR_PROTO("%s: slaballoc resp from domain %d (off=0x%x, size=0x%x) " - "[serrno = %d]\n", - proc, domid, slab_offset, slab_size, serrno); - - if (!serrno) { - IDN_GLOCK_SHARED(); - 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", - proc, domid, IDN_GET_MASTERID()); - serrno = EPROTO; - } - IDN_GUNLOCK(); - - if (!serrno && - !VALID_NWROFFSET(slab_offset, IDN_SMR_BUFSIZE)) { - PR_PROTO("%s: slab offset (0x%x) out of range " - "(0-0x%lx)\n", - proc, slab_offset, MB2B(IDN_NWR_SIZE)); - serrno = EPROTO; - } else if (!serrno) { - sp = GETSTRUCT(smr_slab_t, 1); - sp->sl_start = IDN_OFFSET2ADDR(slab_offset); - sp->sl_end = sp->sl_start + slab_size; - smr_alloc_buflist(sp); - } - } - - /* - * 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) { - DSLAB_LOCK_EXCL(idn.localid); - } - rv = smr_slaballoc_put(idn.localid, sp, 1, serrno); - if (!serrno) { - DSLAB_UNLOCK(idn.localid); - } - - 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", - proc, domid, IDN_GET_MASTERID()); - idn_send_cmd(domid, IDNCMD_SLABFREE, slab_offset, - slab_size, 0); - } - if (sp) { - smr_free_buflist(sp); - FREESTRUCT(sp, smr_slab_t, 1); - } - } -} - -/* - * Note that slab reaping is effectively performed asynchronously - * since the request will be received a protocol server. - */ -static void -idn_recv_slabreap_req(int domid, idn_msgtype_t *mtp, int nslabs) -{ - procname_t proc = "idn_recv_slabreap_req"; - - PR_PROTO("%s: slab reap request (nslabs = %d)\n", proc, nslabs); - - ASSERT(IDN_DLOCK_IS_EXCL(domid)); - - IDN_GLOCK_SHARED(); - if (domid != IDN_GET_MASTERID()) { - /* - * Only the master can request that slabs be reaped. - */ - IDN_GUNLOCK(); - PR_PROTO("%s: only master can request slab reaping\n", proc); - - idn_send_cmdresp(domid, mtp, IDNCMD_SLABREAP, 0, 0, EACCES); - - return; - } - IDN_GUNLOCK(); - - if (nslabs != 0) { - IDN_DUNLOCK(domid); - smr_slab_reap(idn.localid, &nslabs); - IDN_DLOCK_SHARED(domid); - } - - PR_PROTO("%s: slab reap result (nslabs = %d)\n", proc, nslabs); - - /* - * Go ahead and send the reap response back before we start - * free'ing off the individual slabs. - */ - idn_send_slabreap_resp(domid, mtp, nslabs, 0); -} - -static void -idn_recv_slabreap_resp(int domid, int nslabs, int serrno) -{ - procname_t proc = "idn_recv_slabreap_resp"; - - ASSERT(IDN_DLOCK_IS_EXCL(domid)); - - if ((idn.localid != IDN_GET_MASTERID()) || (idn.localid == domid)) { - PR_PROTO("%s: unexpected slabreap resp received " - "(domid = %d)\n", proc, domid); - ASSERT(0); - return; - } - PR_PROTO("%s: recvd reap response from domain %d for %d slabs " - "[serrno = %d]\n", proc, domid, nslabs, serrno); -} - -/* - * Not really necessary to send slabreap response. - * XXX - perhaps useful to master for accounting or - * throttling of further reaping? - */ -static void -idn_send_slabreap_resp(int domid, idn_msgtype_t *mtp, int nslabs, int serrno) -{ - idn_send_cmdresp(domid, mtp, IDNCMD_SLABREAP, nslabs, 0, serrno); -} - -/* - * Slave -> Master ONLY - * Master never sends slabfree request to itself. - */ -static void -idn_recv_slabfree_req(int domid, idn_msgtype_t *mtp, smr_offset_t slab_offset, - uint_t slab_size) -{ - smr_slab_t *sp; - int serrno; - caddr_t s_start, s_end; - procname_t proc = "idn_recv_slabfree_req"; - - ASSERT(IDN_DLOCK_IS_EXCL(domid)); - - if (domid == IDN_GET_MASTERID()) { - PR_PROTO("%s: unexpected slabfree req received (domid = %d)\n", - proc, domid); - idn_send_slabfree_resp(domid, mtp, slab_offset, slab_size, - EACCES); - return; - } - if (slab_size > IDN_SLAB_SIZE) { - PR_PROTO("%s: unexpected slab size. exp %d, recvd %d\n", - proc, IDN_SLAB_SIZE, slab_size); - idn_send_slabfree_resp(domid, mtp, slab_offset, slab_size, - EINVAL); - return; - } - s_start = IDN_OFFSET2ADDR(slab_offset); - s_end = s_start + slab_size; - /* - * 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. - */ - DSLAB_LOCK_EXCL(domid); - if ((sp = smr_slaballoc_get(domid, s_start, s_end)) != NULL) { - smr_slab_free(domid, sp); - serrno = 0; - } else { - serrno = EINVAL; - } - DSLAB_UNLOCK(domid); - - idn_send_slabfree_resp(domid, mtp, slab_offset, slab_size, serrno); -} - -/* - * Master -> Slave ONLY - */ -static void -idn_recv_slabfree_resp(int domid, uint_t slab_offset, uint_t slab_size, int - serrno) -{ - procname_t proc = "idn_recv_slabfree_resp"; - - ASSERT(IDN_DLOCK_IS_EXCL(domid)); - - if (domid != IDN_GET_MASTERID()) { - PR_PROTO("%s: unexpected slabfree resp received (domid = %d)\n", - proc, domid); - ASSERT(0); - return; - } - if (slab_size > IDN_SLAB_SIZE) { - PR_PROTO("%s: unexpected slab size. exp %d, recvd %d\n", - proc, IDN_SLAB_SIZE, slab_size); - ASSERT(0); - return; - } - PR_PROTO("%s: recvd free resp from dom %d " - "- slab (off/size) 0x%x/0x%x [serrno = %d]\n", - proc, domid, slab_offset, slab_size, serrno); -} - -static void -idn_send_slabfree_resp(int domid, idn_msgtype_t *mtp, uint_t slab_offset, - uint_t slab_size, int serrno) -{ - idn_send_cmdresp(domid, mtp, IDNCMD_SLABFREE, slab_offset, slab_size, - serrno); -} - -static void -idn_retry_nodename_req(void *arg) -{ - int domid = (int)(uintptr_t)arg; - - idn_send_nodename_req(domid); -} - -static void -idn_send_nodename_req(int domid) -{ - caddr_t b_bufp; - smr_offset_t bufoffset; - int serrno; - idn_domain_t *dp = &idn_domain[domid]; - procname_t proc = "idn_send_nodename_req"; - - /* - * Need to drop domain lock across - * SMR allocation. - */ - serrno = smr_buf_alloc(domid, MAXDNAME+1, &b_bufp); - - IDN_DLOCK_SHARED(domid); - if (dp->dstate != IDNDS_CONNECTED) { - /* - * Lost connection. - */ - PR_PROTO("%s:%d: connection lost [dstate = %s]\n", - proc, domid, idnds_str[dp->dstate]); - IDN_DUNLOCK(domid); - if (!serrno) - (void) smr_buf_free(domid, b_bufp, MAXDNAME+1); - 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", - proc, domid, idnds_str[dp->dstate]); - (void) timeout(idn_retry_nodename_req, (void *)(uintptr_t)domid, - hz); - IDN_DUNLOCK(domid); - return; - } - - *b_bufp = (char)MAXDNAME; - bufoffset = IDN_ADDR2OFFSET(b_bufp); - - idn_send_cmd(domid, IDNCMD_NODENAME, bufoffset, 0, 0); - IDN_DUNLOCK(domid); -} - -static void -idn_send_nodename_resp(int domid, idn_msgtype_t *mtp, smr_offset_t bufoffset, - int serrno) -{ - idn_send_cmdresp(domid, mtp, IDNCMD_NODENAME, (uint_t)bufoffset, 0, - serrno); -} - -static void -idn_recv_nodename_req(int domid, idn_msgtype_t *mtp, smr_offset_t bufoffset) -{ - caddr_t b_bufp; - int length; - idn_domain_t *ldp = &idn_domain[idn.localid]; - procname_t proc = "idn_recv_nodename_req"; - - IDN_DLOCK_EXCL(idn.localid); - if (!strlen(ldp->dname)) { - if (!strlen(utsname.nodename)) { - /* - * Local domain's nodename hasn't been - * set yet. - */ - IDN_DUNLOCK(idn.localid); - idn_send_cmd_nackresp(domid, mtp, IDNCMD_NODENAME, - IDNNACK_RETRY); - return; - } - (void) strncpy(ldp->dname, utsname.nodename, MAXDNAME - 1); - } - IDN_DLOCK_DOWNGRADE(idn.localid); - - if (!VALID_NWROFFSET(bufoffset, IDN_SMR_BUFSIZE)) { - PR_PROTO("%s:%d: invalid SMR offset received (0x%x)\n", - proc, domid, bufoffset); - IDN_DUNLOCK(idn.localid); - idn_send_nodename_resp(domid, mtp, bufoffset, EINVAL); - return; - } - - b_bufp = IDN_OFFSET2ADDR(bufoffset); - length = (int)(*b_bufp++ & 0xff); - - if (length < strlen(ldp->dname)) { - PR_PROTO("%s:%d: buffer not big enough (req %lu, got %d)\n", - proc, domid, strlen(ldp->dname), length); - IDN_DUNLOCK(idn.localid); - idn_send_nodename_resp(domid, mtp, bufoffset, EINVAL); - return; - } - - (void) strncpy(b_bufp, ldp->dname, MAXDNAME); - b_bufp[MAXDNAME-1] = 0; - IDN_DUNLOCK(idn.localid); - - idn_send_nodename_resp(domid, mtp, bufoffset, 0); -} - -static void -idn_recv_nodename_resp(int domid, smr_offset_t bufoffset, int serrno) -{ - caddr_t b_bufp; - idn_domain_t *dp = &idn_domain[domid]; - procname_t proc = "idn_recv_nodename_resp"; - - ASSERT(IDN_DLOCK_IS_EXCL(domid)); - - if (!VALID_NWROFFSET(bufoffset, IDN_SMR_BUFSIZE)) { - PR_PROTO("%s:%d: invalid SMR offset received (0x%x)\n", - proc, domid, bufoffset); - return; - } - - if (serrno == 0) { - b_bufp = IDN_OFFSET2ADDR(bufoffset) + 1; - b_bufp[MAXDNAME-1] = 0; - - if (strlen(b_bufp) > 0) { - (void) strncpy(dp->dname, b_bufp, MAXDNAME); - PR_PROTO("%s:%d: received nodename(%s)\n", - proc, domid, dp->dname); - } - } - - (void) smr_buf_free(domid, b_bufp - 1, MAXDNAME + 1); -} - -/* - * The master allocations the SMR management structures. - */ -static int -idn_master_init() -{ - idn_domain_t *ldp = &idn_domain[idn.localid]; - size_t reserved_size = 0; - caddr_t reserved_area = NULL; - procname_t proc = "idn_master_init"; - - ASSERT(IDN_GLOCK_IS_EXCL()); - ASSERT(IDN_DLOCK_IS_EXCL(idn.localid)); - - if (idn.mboxarea != NULL) { - PR_PROTO("%s: master data already initialized\n", proc); - return (0); - } - - PR_PROTO("%s: initializing master data (domid = %d)\n", - proc, idn.localid); - - /* - * 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. - */ - reserved_size = IDNROUNDUP(IDN_MBOXAREA_SIZE, IDN_SMR_BUFSIZE); - - PR_PROTO("%s: reserving %lu bytes for mailbox area\n", - proc, reserved_size); - -#ifdef DEBUG - if (reserved_size > (size_t)IDN_SLAB_SIZE) { - PR_PROTO("%s: WARNING mbox area (%ld) > slab size (%d)\n", - proc, reserved_size, IDN_SLAB_SIZE); - } -#endif /* DEBUG */ - /* - * Initialize the pool of slabs and SMR I/O buffers. - */ - if (smr_slabpool_init(reserved_size, &reserved_area) != 0) { - idn_master_deinit(); - return (-1); - } - - ASSERT(idn.mboxarea == NULL); - ASSERT(reserved_area); - - bzero(reserved_area, reserved_size); - - idn.mboxarea = (idn_mboxtbl_t *)reserved_area; - ldp->dmbox.m_tbl = IDN_MBOXAREA_BASE(idn.mboxarea, idn.localid); - /* - * Initialize the SMR pointers in the entire - * mailbox table. - */ - idn_mboxarea_init(idn.mboxarea, IDN_MBOXAREA_SIZE / IDN_MBOXTBL_SIZE); - - return (0); -} - -static void -idn_master_deinit() -{ - idn_domain_t *ldp; - smr_slab_t *sp; - procname_t proc = "idn_master_deinit"; - - ASSERT(IDN_GLOCK_IS_EXCL()); - ASSERT(IDN_DLOCK_IS_EXCL(idn.localid)); - - if (idn.mboxarea == NULL) { - PR_PROTO("%s: master data already deinitialized\n", proc); - return; - } - - ldp = &idn_domain[idn.localid]; - - PR_PROTO("%s: deinitializing master data (domid = %d)\n", - proc, idn.localid); - - ldp->dmbox.m_tbl = NULL; - idn.mboxarea = NULL; - /* - * Master may still be holding onto slabs of his own. - */ - DSLAB_LOCK_EXCL(idn.localid); - sp = ldp->dslab; - ldp->dslab = NULL; - ldp->dnslabs = 0; - if (sp) - smr_slab_free(idn.localid, sp); - ldp->dslab_state = DSLAB_STATE_UNKNOWN; - DSLAB_UNLOCK(idn.localid); - - smr_slabpool_deinit(); -} - -static int -idn_mark_awol(int domid, clock_t *atime) -{ - clock_t awol; - idn_domain_t *dp = &idn_domain[domid]; - - ASSERT(IDN_SYNC_IS_LOCKED()); - ASSERT(IDN_GLOCK_IS_EXCL()); - - if (!DOMAIN_IN_SET(idn.domset.ds_awol, domid)) { - DOMAINSET_ADD(idn.domset.ds_awol, domid); - idn.nawols++; - } - awol = ddi_get_lbolt(); - if (dp->dawol.a_count++ == 0) - dp->dawol.a_time = awol; - dp->dawol.a_last = awol; - if ((awol - dp->dawol.a_msg) >= (clock_t)(idn_awolmsg_interval * hz)) - dp->dawol.a_msg = awol; - else - awol = 0; - - *atime = awol; - - idn_awol_event_set(dp->dhw.dh_boardset); - - return (dp->dawol.a_count); -} - -void -idn_clear_awol(int domid) -{ - idn_domain_t *dp = &idn_domain[domid]; - - ASSERT(IDN_SYNC_IS_LOCKED()); - ASSERT(IDN_GLOCK_IS_EXCL()); - if (DOMAIN_IN_SET(idn.domset.ds_awol, domid)) { - DOMAINSET_DEL(idn.domset.ds_awol, domid); - idn.nawols--; - } - if (dp->dawol.a_count > 0) { - dp->dawol.a_count = 0; - dp->dawol.a_last = dp->dawol.a_time; - dp->dawol.a_time = 0; - dp->dawol.a_msg = 0; - - idn_awol_event_clear(dp->dhw.dh_boardset); - } -} - -/* - * A timer expired. - */ -void -idn_timer_expired(void *arg) -{ - idn_domain_t *dp; - char *op = "UNKNOWN"; - clock_t awol = 0; - int awolcount, dcpu, domid; - idn_timer_t *tp = (idn_timer_t *)arg; - idn_timerq_t *tq = NULL; - uint_t token; - char dname[MAXDNAME]; - procname_t proc = "idn_timer_expired"; - STRING(str); - - tq = tp->t_q; - - ASSERT(tp->t_domid != IDN_NIL_DOMID); - - IDN_TIMERQ_LOCK(tq); - - INUM2STR(tp->t_type, str); - - if (tp->t_onq == 0) { - PR_TIMER("%s: timer CAUGHT TERMINATION (type = %s)\n", - proc, str); - /* - * Timer was dequeued. Somebody is trying - * to shut it down. - */ - IDN_TIMERQ_UNLOCK(tq); - return; - } - - IDN_TIMER_DEQUEUE(tq, tp); - - IDN_TIMERQ_UNLOCK(tq); - - IDN_SYNC_LOCK(); - IDN_DLOCK_EXCL(tp->t_domid); - - domid = tp->t_domid; - - dp = &idn_domain[domid]; - (void) strcpy(dname, dp->dname); - dcpu = dp->dcpu; - - IDN_TIMER_EXEC(tp); - -#ifdef DEBUG - PR_TIMER("%s:%d: [%s] timer EXPIRED (C=0x%x, P=0x%llx, X=0x%llx)\n", - proc, tp->t_domid, str, tp->t_cookie, - tp->t_posttime, tp->t_exectime); -#endif /* DEBUG */ - - /* - * IMPORTANT: - * Each case is responsible for dropping SYNC_LOCK & DLOCK. - */ - switch (tp->t_type) { - case IDNP_DATA: - IDN_SYNC_UNLOCK(); - /* - * 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. - */ - IDN_DLOCK_DOWNGRADE(domid); - if (dp->diocheck && dp->dmbox.m_send) { - (void) idn_reclaim_mboxdata(domid, 0, -1); - if (dp->dio >= IDN_WINDOW_EMAX) { - idn_msgtype_t mt; - /* - * Restart timer for another - * go around. - */ - IDN_MSGTIMER_START(domid, IDNP_DATA, 0, - idn_msg_waittime[IDNP_DATA], - &mt.mt_cookie); - } else { - lock_clear(&dp->diocheck); - } - } - IDN_DUNLOCK(domid); - break; - - case IDNP_NEGO: - /* - * If we're not in a NEGO transition, then - * just ignore this timeout. - */ - if (dp->dxp == &xphase_nego) { - uint_t token; - - IDN_GLOCK_EXCL(); - op = "CONNECT"; - awolcount = idn_mark_awol(domid, &awol); - IDN_GUNLOCK(); - - idn_nego_cleanup_check(domid, IDN_NIL_DOMID, - IDN_NIL_DCPU); - - IDN_XSTATE_TRANSITION(dp, IDNXS_PEND); - token = IDN_RETRY_TOKEN(domid, IDNRETRY_NEGO); - idn_retry_submit(idn_retry_nego, NULL, token, - idn_msg_retrytime[(int)IDNRETRY_NEGO]); - } - IDN_DUNLOCK(domid); - IDN_SYNC_UNLOCK(); - 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. - */ - if (tp->t_subtype == (ushort_t)IDNCMD_NODENAME) { - PR_PROTO("%s:%d: timedout waiting for nodename\n", - proc, domid); - IDN_DUNLOCK(domid); - IDN_SYNC_UNLOCK(); - break; - } - - IDN_GLOCK_EXCL(); - if (idn.state == IDNGS_ONLINE) { - domainset_t domset; - int masterid = IDN_GET_MASTERID(); - - IDN_GKSTAT_GLOBAL_EVENT(gk_reconfigs, - gk_reconfig_last); - - PR_PROTO("%s:%d: RECONFIG trying old masterid = %d\n", - proc, domid, masterid); - - IDN_GSTATE_TRANSITION(IDNGS_RECONFIG); - IDN_SET_NEW_MASTERID(masterid); - IDN_GUNLOCK(); - IDN_DUNLOCK(domid); - - domset = idn.domset.ds_trans_on | - idn.domset.ds_connected; - - idn_unlink_domainset(domset, IDNFIN_NORMAL, - IDNFIN_ARG_NONE, IDNFIN_OPT_RELINK, BOARDSET_ALL); - } else { - IDN_GUNLOCK(); - IDN_DUNLOCK(domid); - } - IDN_SYNC_UNLOCK(); - break; - - case IDNP_CON: - if (tp->t_subtype == (ushort_t)IDNCON_QUERY) { - /* - * Timed out sending a CON-query. This is - * non-fatal. We simply need to retry. - */ - IDN_GLOCK_EXCL(); - op = "CONNECT"; - awolcount = idn_mark_awol(domid, &awol); - IDN_GUNLOCK(); - token = IDN_RETRY_TOKEN(domid, IDNRETRY_CONQ); - idn_retry_submit(idn_retry_query, NULL, token, - idn_msg_retrytime[(int)IDNRETRY_CONQ]); - IDN_DUNLOCK(domid); - IDN_SYNC_UNLOCK(); - 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. - */ - IDN_GLOCK_EXCL(); - op = "CONNECT"; - awolcount = idn_mark_awol(domid, &awol); - IDN_GUNLOCK(); - DOMAINSET_ADD(idn.domset.ds_relink, domid); - IDN_HISTORY_LOG(IDNH_RELINK, domid, dp->dstate, - idn.domset.ds_relink); - (void) idn_disconnect(domid, IDNFIN_FORCE_SOFT, - IDNFIN_ARG_NONE, IDNFIN_SYNC_NO); - IDN_DUNLOCK(domid); - IDN_SYNC_UNLOCK(); - break; - - case IDNP_FIN: - /* - * Timeouts here simply try to retry. - */ - IDN_GLOCK_EXCL(); - op = "DISCONNECT"; - awolcount = idn_mark_awol(domid, &awol); - IDN_GUNLOCK(); - if (tp->t_subtype == (ushort_t)IDNFIN_QUERY) { - int d; - domainset_t rdyset; - /* - * 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++) { - if (FIN_IS_FORCE(idn_domain[d].dfin)) { - DOMAINSET_ADD(rdyset, d); - } - } - if (rdyset) - (void) idn_sync_register(domid, - IDNSYNC_DISCONNECT, - rdyset, IDNSYNC_REG_REG); - - token = IDN_RETRY_TOKEN(domid, IDNRETRY_FINQ); - idn_retry_submit(idn_retry_query, NULL, token, - idn_msg_retrytime[(int)IDNRETRY_FINQ]); - IDN_DUNLOCK(domid); - IDN_SYNC_UNLOCK(); - break; - } - - if (dp->dfin == IDNFIN_FORCE_SOFT) { - IDN_FSTATE_TRANSITION(dp, IDNFIN_FORCE_HARD); - } - /* - * 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_sync_register_awol(domid); - - dp->dxp = &xphase_fin; - IDN_XSTATE_TRANSITION(dp, IDNXS_PEND); - token = IDN_RETRY_TOKEN(domid, IDNRETRY_FIN); - idn_retry_submit(idn_retry_fin, NULL, token, - idn_msg_retrytime[(int)IDNRETRY_FIN]); - IDN_DUNLOCK(domid); - IDN_SYNC_UNLOCK(); - break; - - default: - - ASSERT(0); - IDN_DUNLOCK(domid); - IDN_SYNC_UNLOCK(); - break; - } - - IDN_TIMER_FREE(tp); - - if (awol) { - if (strlen(dname) > 0) { - cmn_err(CE_WARN, - "IDN: 236: domain (%s) [ID %d] not " - "responding to %s [#%d]", - dname, domid, op, awolcount); - } else { - cmn_err(CE_WARN, - "IDN: 236: domain [ID %d, CPU %d] not " - "responding to %s [#%d]", - domid, dcpu, op, awolcount); - } - } -} - -#if 0 -static int -idn_retry_check(uint_t token) -{ - int i, count = 0; - int domid = IDN_RETRY_TOKEN2DOMID(token); - int key = IDN_RETRY_TOKEN2TYPE(token); - idn_retry_job_t *rp; - idn_retry_queue_t *qp; - - qp = &idn.retryqueue; - - mutex_enter(&qp->rq_mutex); - - for (i = 0, rp = qp->rq_jobs; i < qp->rq_count; i++, rp = rp->rj_next) - if ((domid == IDN_RETRY_TOKEN2DOMID(rp->rj_token)) && - ((key == IDN_RETRY_TYPEALL) || (rp->rj_token == token))) - count++; - - mutex_exit(&qp->rq_mutex); - - return (count); -} -#endif /* 0 */ - -static void -idn_retry_execute(void *arg) -{ - idn_retry_job_t *rp = (idn_retry_job_t *)arg; - idn_retry_queue_t *qp; - - qp = &idn.retryqueue; - - mutex_enter(&qp->rq_mutex); - if (rp->rj_onq == 0) { - /* - * Job has already been claimed by - * retry termination routine. - * Bail out. - */ - mutex_exit(&qp->rq_mutex); - return; - } - rp->rj_next->rj_prev = rp->rj_prev; - rp->rj_prev->rj_next = rp->rj_next; - if (--(qp->rq_count) == 0) - qp->rq_jobs = NULL; - else if (qp->rq_jobs == rp) - qp->rq_jobs = rp->rj_next; - mutex_exit(&qp->rq_mutex); - - (*rp->rj_func)(rp->rj_token, rp->rj_arg); - - IDNRETRY_FREEJOB(rp); -} - -/* - * - */ -static void -idn_retry_submit(void (*func)(uint_t token, void *arg), void *arg, uint_t token, - clock_t ticks) -{ - idn_retry_job_t *rp, *cp; - idn_retry_queue_t *qp; - int c; - procname_t proc = "idn_retry_submit"; - - if (ticks < 0) { - PR_PROTO("%s: (token = 0x%x) WARNING ticks = %ld\n", - proc, token, ticks); - return; - } - if (ticks == 0) /* At least one tick to get into background */ - ticks++; - - PR_PROTO("%s: token = 0x%x\n", proc, token); - - qp = &idn.retryqueue; - - mutex_enter(&qp->rq_mutex); - for (c = 0, cp = qp->rq_jobs; c < qp->rq_count; cp = cp->rj_next, c++) { - if (cp->rj_token == token) { - PR_PROTO("%s: token = (%d,0x%x) already present\n", - proc, IDN_RETRY_TOKEN2DOMID(token), - IDN_RETRY_TOKEN2TYPE(token)); - break; - } - } - - if (c < qp->rq_count) { - mutex_exit(&qp->rq_mutex); - return; - } - - rp = IDNRETRY_ALLOCJOB(); - rp->rj_func = func; - rp->rj_arg = arg; - rp->rj_token = token; - rp->rj_prev = rp->rj_next = rp; - - if (qp->rq_jobs == NULL) { - qp->rq_jobs = rp; - } else { - rp->rj_next = qp->rq_jobs; - rp->rj_prev = qp->rq_jobs->rj_prev; - rp->rj_next->rj_prev = rp; - rp->rj_prev->rj_next = rp; - } - rp->rj_onq = 1; - qp->rq_count++; - rp->rj_id = timeout(idn_retry_execute, (caddr_t)rp, ticks); - mutex_exit(&qp->rq_mutex); -} - -int -idn_retry_terminate(uint_t token) -{ - int i, domid; - uint_t key, count; - idn_retry_job_t *rp, *nrp, *fp; - idn_retry_queue_t *qp; - procname_t proc = "idn_retry_terminate"; - - key = IDN_RETRY_TOKEN2TYPE(token); - domid = IDN_RETRY_TOKEN2DOMID(token); - fp = NULL; - qp = &idn.retryqueue; - - mutex_enter(&qp->rq_mutex); - for (i = count = 0, rp = qp->rq_jobs; i < qp->rq_count; i++) { - nrp = rp->rj_next; - if ((domid == IDN_RETRY_TOKEN2DOMID(rp->rj_token)) && - ((key == IDN_RETRY_TYPEALL) || - (rp->rj_token == token))) { - /* - * 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. - */ - rp->rj_onq = 0; - rp->rj_next->rj_prev = rp->rj_prev; - rp->rj_prev->rj_next = rp->rj_next; - if (qp->rq_jobs == rp) - qp->rq_jobs = rp->rj_next; - rp->rj_next = fp; - fp = rp; - count++; - } - rp = nrp; - } - - if ((qp->rq_count -= count) == 0) - qp->rq_jobs = NULL; - - mutex_exit(&qp->rq_mutex); - - PR_PROTO("%s: token = (%d,0x%x), dequeued = %d\n", - proc, domid, key, count); - - for (; fp; fp = nrp) { - (void) untimeout(fp->rj_id); - - nrp = fp->rj_next; - IDNRETRY_FREEJOB(fp); - } - - 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 -idn_protocol_init(int nservers) -{ - int i; - idn_protojob_t *jp; - register idn_protoqueue_t *protoq; - - if (nservers <= 0) { - cmn_err(CE_WARN, - "IDN: 237: invalid number (%d) of protocol servers", - nservers); - return (-1); - } - - idn.protocol.p_jobpool = kmem_cache_create("idn_protocol_jobcache", - sizeof (idn_protojob_t), 0, NULL, NULL, NULL, NULL, NULL, 0); - if (idn.protocol.p_jobpool == NULL) { - cmn_err(CE_WARN, - "IDN: 238: kmem_cache_create(jobcache) failed"); - return (-1); - } - - /* - * Initialize static cache for protojob. - */ - mutex_init(&idn_protojob_cache_lock, NULL, MUTEX_DRIVER, NULL); - jp = &idn_protojob_cache[0]; - for (i = 1; i < IDN_DMV_PENDING_MAX; jp = jp->j_next, i++) { - jp->j_cache = 1; - jp->j_next = &idn_protojob_cache[i]; - } - jp->j_cache = 1; - jp->j_next = NULL; - idn_protojob_cache_list = &idn_protojob_cache[0]; - - /* - * Init morgue semaphore. - */ - sema_init(&idn.protocol.p_morgue, 0, NULL, SEMA_DEFAULT, NULL); - /* - * Alloc server queues. - */ - idn.protocol.p_serverq = GETSTRUCT(idn_protoqueue_t, nservers); - - /* - * Init server queues. - */ - protoq = idn.protocol.p_serverq; - for (i = 0; i < nservers; protoq++, i++) { - mutex_init(&protoq->q_mutex, NULL, MUTEX_DRIVER, NULL); - cv_init(&protoq->q_cv, NULL, CV_DEFAULT, NULL); - protoq->q_id = i; - protoq->q_joblist = NULL; - protoq->q_joblist_tail = NULL; - protoq->q_die = 0; - protoq->q_morgue = &idn.protocol.p_morgue; - /* - * Create protocol server thread. - */ - protoq->q_threadp = thread_create(NULL, 0, - idn_protocol_server, (caddr_t)&i, sizeof (i), &p0, - TS_RUN, maxclsyspri); - } - /* - * The servers are kept in the p_server[] array, however - * we'll build a linked list of them to facilitate debugging. - */ - protoq = idn.protocol.p_serverq; - for (i = 0; i < (nservers - 1); protoq++, i++) - protoq->q_next = (protoq + 1); - protoq->q_next = NULL; - - idn.nservers = nservers; - - return (idn.nservers); -} - -void -idn_protocol_deinit() -{ - register int i; - int nservers; - register idn_protoqueue_t *protoq; - - nservers = idn.nservers; - - if (nservers <= 0) - return; - - /* - * Make sure the servers are dead. - */ - idn_protocol_server_killall(); - ASSERT(idn.nservers == 0); - /* - * Destroy the mutexes. - */ - protoq = idn.protocol.p_serverq; - for (i = 0; i < nservers; protoq++, i++) { - mutex_destroy(&protoq->q_mutex); - cv_destroy(&protoq->q_cv); - } - /* - * Free up the protoqueue memory. - */ - FREESTRUCT(idn.protocol.p_serverq, idn_protoqueue_t, nservers); - idn.protocol.p_serverq = NULL; - /* - * Destroy the morgue semaphore. - */ - sema_destroy(&idn.protocol.p_morgue); - - if (idn.protocol.p_jobpool) { - kmem_cache_destroy(idn.protocol.p_jobpool); - idn.protocol.p_jobpool = NULL; - } -} - -static void -idn_protocol_server(int *id) -{ - idn_protoqueue_t *pq; - idn_protojob_t *jl; - register idn_protojob_t *jp; - procname_t proc = "idn_protocol_server"; - - if (id == NULL) { - PR_PROTO("%s: id == NULL, thread exiting\n", proc); - return; - } - ASSERT((*id >= 0) && (*id < idn_protocol_nservers)); - - pq = &idn.protocol.p_serverq[*id]; - - ASSERT(pq->q_id == *id); - - PR_PROTO("%s: id %d starting up (pq = 0x%p)\n", - proc, pq->q_id, (void *)pq); - - /*CONSTCOND*/ - while (1) { - mutex_enter(&pq->q_mutex); - - while (((jl = pq->q_joblist) == NULL) && !pq->q_die) - cv_wait(&pq->q_cv, &pq->q_mutex); - - pq->q_joblist = pq->q_joblist_tail = NULL; - - if (pq->q_die) { - /* - * We've been killed. Need to check-in - * at the morgue. - */ - pq->q_threadp = NULL; - mutex_exit(&pq->q_mutex); - PR_PROTO("%s: thread (%d) killed...bye bye\n", - proc, pq->q_id); - for (jp = jl; jp; jp = jl) { - jl = jp->j_next; - idn_protojob_free(jp); - } - sema_v(pq->q_morgue); - thread_exit(); - /*NOTREACHED*/ - } - mutex_exit(&pq->q_mutex); - - /* - * We can process the jobs asynchronously while more are - * put on. - */ - for (jp = jl; jp; jp = jl) { - jl = jp->j_next; - idn_recv_proto(&(jp->j_msg)); - idn_protojob_free(jp); - } - } -} - -/* - * Kill off all the protocol servers. - */ -static void -idn_protocol_server_killall() -{ - register idn_protoqueue_t *pq; - int i; - procname_t proc = "idn_protocol_server_killall"; - - PR_PROTO("%s: killing off %d protocol servers\n", - proc, idn.nservers); - - pq = idn.protocol.p_serverq; - for (i = 0; i < idn.nservers; pq++, i++) { - mutex_enter(&pq->q_mutex); - pq->q_die = 1; - cv_signal(&pq->q_cv); - mutex_exit(&pq->q_mutex); - } - - while (idn.nservers > 0) { - sema_p(&idn.protocol.p_morgue); - idn.nservers--; - } -} - -idn_protojob_t * -idn_protojob_alloc(int kmflag) -{ - idn_protojob_t *jp; - - jp = kmem_cache_alloc(idn.protocol.p_jobpool, kmflag); - if (jp == NULL) { - mutex_enter(&idn_protojob_cache_lock); - if ((jp = idn_protojob_cache_list) != NULL) - idn_protojob_cache_list = jp->j_next; - mutex_exit(&idn_protojob_cache_lock); - } else { - jp->j_cache = 0; - } - - return (jp); -} - -static void -idn_protojob_free(idn_protojob_t *jp) -{ - ASSERT(jp); - - if (jp->j_cache) { - mutex_enter(&idn_protojob_cache_lock); - jp->j_next = idn_protojob_cache_list; - idn_protojob_cache_list = jp; - mutex_exit(&idn_protojob_cache_lock); - } else { - kmem_cache_free(idn.protocol.p_jobpool, (void *)jp); - } -} - -void -idn_protojob_submit(int cookie, idn_protojob_t *jp) -{ - idn_protoqueue_t *pq; - int serverid; - procname_t proc = "idn_protojob_submit"; - STRING(str); - - if (jp == NULL) - return; - - serverid = IDN_PROTOCOL_SERVER_HASH(cookie); - - pq = &idn.protocol.p_serverq[serverid]; - - INUM2STR(jp->j_msg.m_msgtype, str); - PR_PROTO("%s: job (d=%d, m=0x%x, %s) submitted to " - "protocol server %d\n", proc, jp->j_msg.m_domid, - jp->j_msg.m_msgtype, str, serverid); - - mutex_enter(&pq->q_mutex); - /* - * Can't submit jobs to dying servers. - */ - if (!pq->q_die) { - if (pq->q_joblist_tail) { - pq->q_joblist_tail->j_next = jp; - pq->q_joblist_tail = jp; - } else { - pq->q_joblist = pq->q_joblist_tail = jp; - } - jp->j_next = NULL; - cv_signal(&pq->q_cv); - } else { - PR_PROTO("%s: protocol server dead. freeing protojob\n", - proc); - idn_protojob_free(jp); - } - mutex_exit(&pq->q_mutex); -} - -static void -idn_mboxarea_init(idn_mboxtbl_t *mtp, register int ntbls) -{ - register int d; - caddr_t state_ptr = NULL, mtbasep = (caddr_t)mtp; - idn_mboxtbl_t *amtp; - procname_t proc = "idn_mboxarea_init"; - - ASSERT(mtp && (ntbls > 0)); - - PR_PROTO("%s: init mboxtbl (0x%p) ntbls = %d\n", - proc, (void *)mtp, ntbls); - - for (d = 0; d < ntbls; d++) { - register int pd, sd; - register int ch; - - mtp->mt_header.mh_svr_active = 0; - mtp->mt_header.mh_svr_ready = 0; - /* - * 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. - */ - pd = (d / MAX_DOMAINS) / IDN_MAX_NETS; - sd = (d / IDN_MAX_NETS) % MAX_DOMAINS; - 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. - */ - amtp = IDN_MBOXTBL_ABS_PTR(mtbasep, pd, 0, ch); - - state_ptr = (caddr_t)&amtp->mt_header.mh_svr_active; - mtp->mt_header.mh_svr_active_ptr = IDN_ADDR2OFFSET(state_ptr); - - state_ptr = (caddr_t)&amtp->mt_header.mh_svr_ready; - mtp->mt_header.mh_svr_ready_ptr = IDN_ADDR2OFFSET(state_ptr); - - mtp->mt_header.mh_cookie = IDN_MAKE_MBOXHDR_COOKIE(pd, sd, ch); - - mtp->mt_header.mh_cksum = IDN_CKSUM_MBOX(&mtp->mt_header); - - IDN_MBOXTBL_PTR_INC(mtp); - } - /* - * 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. - */ - PR_PROTO("%s: flushing ecache's of local (master) domain\n", proc); - - idnxf_flushall_ecache(); -} - -idn_mainmbox_t * -idn_mainmbox_init(int domid, int mbx) -{ - idn_mainmbox_t *mmp; - int c; - idn_mainmbox_t *cmp; - procname_t proc = "idn_mainmbox_init"; - - ASSERT(idn_domain[domid].dcpu != IDN_NIL_DCPU); - ASSERT(IDN_DLOCK_IS_HELD(domid)); - - PR_PROTO("%s: initializing main %s mailbox for domain %d\n", - proc, IDNMBOX_IS_RECV(mbx) ? "RECV" : "SEND", domid); - - cmp = GETSTRUCT(idn_mainmbox_t, IDN_MAX_NETS); - for (c = 0; c < IDN_MAX_NETS; c++) { - mmp = &cmp[c]; - mmp->mm_channel = (short)c; - mutex_init(&mmp->mm_mutex, NULL, MUTEX_DRIVER, NULL); - mmp->mm_domid = (short)domid; - mmp->mm_type = mbx; - } - mmp = cmp; - /* - * The actual SMR mailbox (mmp->mm_smr_mboxp) gets setup - * when the SMR is setup. - */ - - return (mmp); -} - -static void -idn_mainmbox_reset(int domid, idn_mainmbox_t *cmp) -{ - idn_mainmbox_t *mmp; - int c; - procname_t proc = "idn_mainmbox_reset"; - - ASSERT(IDN_DLOCK_IS_EXCL(domid)); - - PR_PROTO("%s: reseting main %s mailbox for domain %d\n", - proc, IDNMBOX_IS_RECV(cmp->mm_type) ? "RECV" : "SEND", domid); - - for (c = 0; c < IDN_MAX_NETS; c++) { - mmp = &cmp[c]; - - mmp->mm_channel = (short)c; - mmp->mm_domid = (short)domid; - mmp->mm_count = 0; - mmp->mm_flags = 0; - mmp->mm_qiget = mmp->mm_qiput = 0; - mmp->mm_csp = NULL; - ASSERT(mmp->mm_type == cmp->mm_type); - } -} - -void -idn_mainmbox_deinit(int domid, idn_mainmbox_t *mmp) -{ - procname_t proc = "idn_mainmbox_deinit"; - - ASSERT(IDN_DLOCK_IS_HELD(domid)); - - PR_PROTO("%s: deinitializing main %s mailbox for domain %d\n", - proc, IDNMBOX_IS_RECV(mmp->mm_type) ? "RECV" : "SEND", domid); - - ASSERT(idn_domain_is_registered(domid, -1, NULL) == 0); - - FREESTRUCT(mmp, idn_mainmbox_t, IDN_MAX_NETS); -} - -static void -idn_mainmbox_activate(int domid) -{ - register int c; - idn_domain_t *dp = &idn_domain[domid]; - procname_t proc = "idn_mainmbox_activate"; - - ASSERT(IDN_DLOCK_IS_HELD(domid)); - - PR_PROTO("%s:%d: activating main mailbox\n", proc, domid); - - for (c = 0; c < IDN_MAX_NETS; c++) - idn_mainmbox_chan_register(domid, &dp->dmbox.m_send[c], - &dp->dmbox.m_recv[c], 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 -idn_mainmbox_deactivate(ushort_t domset) -{ - int svr_count; - procname_t proc = "idn_mainmbox_deactivate"; - - - if (domset == 0) - return; - - PR_PROTO("%s: %s deactivating main mailboxes for domset 0x%x\n", - proc, (domset == (ushort_t)-1) ? "STOP-ALL" : "NORMAL", domset); - - svr_count = idn_mainmbox_chan_unregister(domset, -1); - - PR_PROTO("%s: deactivated %d chansvrs (domset 0x%x)\n", - proc, svr_count, domset); -} - -static void -idn_mainmbox_chan_register(int domid, idn_mainmbox_t *send_mmp, - idn_mainmbox_t *recv_mmp, int channel) -{ - ASSERT(IDN_DLOCK_IS_HELD(domid)); - - /* - * Obtain receive mailbox lock first. - */ - mutex_enter(&recv_mmp->mm_mutex); - mutex_enter(&send_mmp->mm_mutex); - - ASSERT(recv_mmp->mm_channel == (short)channel); - ASSERT(send_mmp->mm_channel == (short)channel); - - recv_mmp->mm_csp = &idn.chan_servers[channel]; - recv_mmp->mm_count = 0; - recv_mmp->mm_dropped = 0; - recv_mmp->mm_flags = 0; - - send_mmp->mm_csp = &idn.chan_servers[channel]; - send_mmp->mm_count = 0; - send_mmp->mm_dropped = 0; - send_mmp->mm_flags = 0; - - mutex_exit(&send_mmp->mm_mutex); - mutex_exit(&recv_mmp->mm_mutex); - - /* - * 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. - */ - ASSERT(idn.chan_servers); - /* - * Have to get the channel server under - * control so we can add ourselves. - * Returns w/c_mutex. - */ - IDN_CHAN_LOCK_GLOBAL(&idn.chan_servers[channel]); - /* - * Add the following domain (mailbox) for monitoring - * by the respective channel server. - */ - idn_chan_addmbox(channel, DOMAINSET(domid)); - - IDN_CHAN_UNLOCK_GLOBAL(&idn.chan_servers[channel]); -} - -/* - * Unregister the given domain from the specified channel(s) for monitoring. - */ -static int -idn_mainmbox_chan_unregister(ushort_t domset, int channel) -{ - int c, dd_count; - int min_chan, max_chan; - procname_t proc = "idn_mainmbox_chan_unregister"; - - PR_CHAN("%s: deactivating main mailboxes (channel %d) " - "for domset 0x%x\n", proc, channel, domset); - - if (channel == -1) { - min_chan = 0; - max_chan = IDN_MAX_NETS - 1; - } else { - min_chan = max_chan = channel; - } - /* - * Point all the data dispatchers to the same morgue - * so we can kill them all at once. - */ - dd_count = 0; - for (c = min_chan; c <= max_chan; c++) { - - /* - * Have to get the channel server under - * control so we can remove ourselves. - * Returns w/c_mutex held. - */ - IDN_CHAN_LOCK_GLOBAL(&idn.chan_servers[c]); - /* - * Delete the following domain (mailbox) from - * monitoring by the respective channel server. - */ - idn_chan_delmbox(c, (ushort_t)domset); - - IDN_CHAN_UNLOCK_GLOBAL(&idn.chan_servers[c]); - dd_count++; - } - PR_CHAN("%s: deactivated %d channel mboxes for domset 0x%x, chan %d\n", - proc, dd_count, domset, channel); - return (dd_count); -} - -/* - * Check if the given domain is registered with the given channel(s). - */ -int -idn_domain_is_registered(int domid, int channel, idn_chanset_t *chansetp) -{ - int regcount; - int c, min_chan, max_chan; - idn_chanset_t chanset; - procname_t proc = "idn_domain_is_registered"; - - CHANSET_ZERO(chanset); - - if (idn.chan_servers == NULL) { - PR_CHAN("%s: idn.chan_servers == NULL!!\n", proc); - return (0); - } - - if (channel == -1) { - min_chan = 0; - max_chan = IDN_MAX_NETS - 1; - } else { - min_chan = max_chan = channel; - } - - regcount = 0; - - for (c = min_chan; c <= max_chan; c++) { - idn_chansvr_t *csp; - - csp = &idn.chan_servers[c]; - IDN_CHAN_LOCK_SEND(csp); - /* - * 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. - */ - if (IDN_CHAN_DOMAIN_IS_REGISTERED(csp, domid)) { - regcount++; - CHANSET_ADD(chanset, c); - } - - IDN_CHAN_UNLOCK_SEND(csp); - } - - PR_CHAN("%s: domid %d mbox reg'd with %d channels [0x%x] (req=%d)\n", - proc, domid, regcount, chanset, channel); - - if (chansetp) - *chansetp = chanset; - - return (regcount); -} - -static int -idn_mainmbox_flush(int domid, idn_mainmbox_t *mmp) -{ - 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; - idn_chanset_t chanset; - procname_t proc = "idn_mainmbox_flush"; - - - if (mmp == NULL) - return (0); - - CHANSET_ZERO(chanset); - - mbox_type = mmp->mm_type; - ASSERT((mbox_type == IDNMMBOX_TYPE_SEND) || - (mbox_type == IDNMMBOX_TYPE_RECV)); - - mbox_str = (mbox_type == IDNMMBOX_TYPE_SEND) ? "SEND" : "RECV"; - - /* - * Determine which channels this domain is registered - * with. If he's not registered with any, then we - * can't touch the SMR. - */ - (void) idn_domain_is_registered(domid, -1, &chanset); - - for (c = 0; c < IDN_MAX_NETS; c++) { - ushort_t mbox_csum; - - if (mmp[c].mm_smr_mboxp == NULL) - continue; - mutex_enter(&mmp[c].mm_mutex); - ASSERT(mmp[c].mm_type == mbox_type); - 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 " - "w/chan %d - DUMPING SMR reference\n", - proc, domid, mbox_str, c); - lost_io = IDN_MMBOXINDEX_DIFF(mmp[c].mm_qiput, - mmp[c].mm_qiget); -#ifdef DEBUG - if (mbox_type == IDNMMBOX_TYPE_RECV) { - PR_CHAN("%s:%d:%s: blowing away %d " - "incoming pkts\n", - proc, domid, mbox_str, lost_io); - } else { - PR_CHAN("%s:%d:%s: blowing away %d/%d " - "outstanding pkts\n", - proc, domid, mbox_str, lost_io, - idn_domain[domid].dio); - } -#endif /* DEBUG */ - } - mmp[c].mm_qiput = mmp[c].mm_qiget = 0; - mmp[c].mm_smr_mboxp = NULL; - total_lost_io += lost_io; - } - if (mmp[c].mm_smr_mboxp) { - mbox_csum = - IDN_CKSUM_MBOX(&mmp[c].mm_smr_mboxp->mt_header); - if (!VALID_NWRADDR(mmp[c].mm_smr_mboxp, 4) || - !VALID_MBOXHDR(&mmp[c].mm_smr_mboxp->mt_header, - c, mbox_csum)) { - lost_io = IDN_MMBOXINDEX_DIFF(mmp[c].mm_qiput, - mmp[c].mm_qiget); -#ifdef DEBUG - if (mbox_type == IDNMMBOX_TYPE_RECV) { - PR_CHAN("%s:%d:%s: bad mbox. blowing " - "away %d incoming pkts\n", - proc, domid, mbox_str, lost_io); - } else { - PR_CHAN("%s:%d:%s: bad mbox. blowing " - "away %d/%d outstanding pkts\n", - proc, domid, mbox_str, lost_io, - idn_domain[domid].dio); - } -#endif /* DEBUG */ - mmp[c].mm_smr_mboxp = NULL; - mmp[c].mm_qiput = mmp[c].mm_qiget = 0; - total_lost_io += lost_io; - } - } - if (mmp[c].mm_smr_mboxp == NULL) { - mutex_exit(&mmp[c].mm_mutex); - continue; - } - mqp = &mmp[c].mm_smr_mboxp->mt_queue[0]; - 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 { - if (mqp[qi].ms_owner) - count++; - mqp[qi].ms_owner = 0; - IDN_MMBOXINDEX_INC(qi); - } while (qi); - - lost_io = IDN_MMBOXINDEX_DIFF(mmp[c].mm_qiput, mmp[c].mm_qiget); - total_lost_io += lost_io; - - mmp[c].mm_qiput = mmp[c].mm_qiget = 0; - mmp[c].mm_smr_mboxp = NULL; - mutex_exit(&mmp[c].mm_mutex); - - total_count += count; - - PR_CHAN("%s:%d:%s: flushed out %d mbox entries for chan %d\n", - proc, domid, mbox_str, count, c); - } - - if (total_lost_io && (mbox_type == IDNMMBOX_TYPE_SEND)) { - 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. - */ - lost_bufs = smr_buf_free_all(domid); - - PR_CHAN("%s:%d:%s: flushed %d/%d buffers from slabs\n", - proc, domid, mbox_str, lost_bufs, total_lost_io); - } - - PR_CHAN("%s:%d:%s: flushed total of %d mailbox entries (lost %d)\n", - proc, domid, mbox_str, total_count, total_lost_io); - - return (total_count); -} - -void -idn_chanserver_bind(int net, int cpuid) -{ - int ocpuid; - cpu_t *cp; - idn_chansvr_t *csp; - kthread_id_t tp; - procname_t proc = "idn_chanserver_bind"; - - csp = &idn.chan_servers[net]; - IDN_CHAN_LOCK_GLOBAL(csp); - - mutex_enter(&cpu_lock); /* protect checking cpu_ready_set */ - ocpuid = csp->ch_bound_cpuid; - cp = cpu_get(cpuid); - if ((cpuid != -1) && ((cp == NULL) || !cpu_is_online(cp))) { - mutex_exit(&cpu_lock); - cmn_err(CE_WARN, - "IDN: 239: invalid CPU ID (%d) specified for " - "IDN net %d", - cpuid, net); - IDN_CHAN_UNLOCK_GLOBAL(csp); - return; - } - if ((tp = csp->ch_recv_threadp) == NULL) { - /* - * Thread is not yet active. Set ch_bound_cpuid - * so when thread activates it will automatically - * bind itself. - */ - csp->ch_bound_cpuid = -1; - csp->ch_bound_cpuid_pending = cpuid; - } else { - if (ocpuid != -1) { - thread_affinity_clear(tp); - csp->ch_bound_cpuid = -1; - } - if (cpuid >= 0) { - thread_affinity_set(tp, cpuid); - csp->ch_bound_cpuid = cpuid; - } - csp->ch_bound_cpuid_pending = -1; - } - mutex_exit(&cpu_lock); - - PR_CHAN("%s: bound net/channel (%d) from cpuid %d to%scpuid %d\n", - proc, net, ocpuid, tp ? " " : " (pending) ", cpuid); - - IDN_CHAN_UNLOCK_GLOBAL(csp); -} - -#ifdef DEBUG -static idn_mboxhdr_t *prev_mhp[IDN_MAXMAX_NETS]; -#endif /* DEBUG */ -/* - * Get access to the respective channel server's synchronization - * header which resides in SMR space. - */ -static idn_mboxhdr_t * -idn_chan_server_syncheader(int channel) -{ - idn_domain_t *ldp = &idn_domain[idn.localid]; - idn_mboxtbl_t *mtp; - idn_mboxhdr_t *mhp; - ushort_t mbox_csum; - procname_t proc = "idn_chan_server_syncheader"; - - ASSERT(IDN_CHAN_RECV_IS_LOCKED(&idn.chan_servers[channel])); - - IDN_DLOCK_SHARED(idn.localid); - - if (ldp->dmbox.m_tbl == NULL) { - PR_CHAN("%s: local dmbox.m_tbl == NULL\n", proc); - IDN_DUNLOCK(idn.localid); - return (NULL); - } - - mtp = IDN_MBOXTBL_PTR_CHAN(ldp->dmbox.m_tbl, channel); - mhp = &mtp->mt_header; - mbox_csum = IDN_CKSUM_MBOX(&mtp->mt_header); - -#ifdef DEBUG - if (mhp != prev_mhp[channel]) { - prev_mhp[channel] = mhp; - PR_CHAN("%s: chan_server (%d) cookie = 0x%x (exp 0x%x)\n", - proc, channel, IDN_GET_MBOXHDR_COOKIE(mhp), - IDN_MAKE_MBOXHDR_COOKIE(0, 0, channel)); - PR_CHAN("%s: chan_server (%d) actv_ptr = 0x%x (exp 0x%x)\n", - proc, channel, mhp->mh_svr_active_ptr, - IDN_ADDR2OFFSET(&mhp->mh_svr_active)); - PR_CHAN("%s: chan_server (%d) ready_ptr = 0x%x (exp 0x%x)\n", - proc, channel, mhp->mh_svr_ready_ptr, - IDN_ADDR2OFFSET(&mhp->mh_svr_ready)); - PR_CHAN("%s: chan_server (%d) mbox_cksum = 0x%x (exp 0x%x)\n", - proc, channel, (int)mhp->mh_cksum, (int)mbox_csum); - } -#endif /* DEBUG */ - - if ((IDN_ADDR2OFFSET(&mhp->mh_svr_active) != - mhp->mh_svr_active_ptr) || - (IDN_ADDR2OFFSET(&mhp->mh_svr_ready) != mhp->mh_svr_ready_ptr) || - !VALID_MBOXHDR(mhp, channel, mbox_csum)) { - idn_chansvr_t *csp; - - csp = &idn.chan_servers[channel]; - if (IDN_CHANNEL_IS_RECV_CORRUPTED(csp) == 0) { - IDN_CHANSVC_MARK_RECV_CORRUPTED(csp); - - cmn_err(CE_WARN, - "IDN: 240: (channel %d) SMR CORRUPTED " - "- RELINK", channel); - cmn_err(CE_CONT, - "IDN: 240: (channel %d) cookie " - "(expected 0x%x, actual 0x%x)\n", - channel, - IDN_MAKE_MBOXHDR_COOKIE(0, 0, channel), - mhp->mh_cookie); - cmn_err(CE_CONT, - "IDN: 240: (channel %d) actv_flg " - "(expected 0x%x, actual 0x%x)\n", - channel, mhp->mh_svr_active_ptr, - IDN_ADDR2OFFSET(&mhp->mh_svr_active)); - cmn_err(CE_CONT, - "IDN: 240: (channel %d) ready_flg " - "(expected 0x%x, actual 0x%x)\n", - channel, mhp->mh_svr_ready_ptr, - IDN_ADDR2OFFSET(&mhp->mh_svr_ready)); - } - - mhp = NULL; - } - IDN_DUNLOCK(idn.localid); - - PR_CHAN("%s: channel(%d) mainhp = 0x%p\n", proc, channel, (void *)mhp); - - return (mhp); -} - -#define CHANSVR_SYNC_CACHE(csp, mmp, chan) \ -{ \ - ASSERT(IDN_CHAN_RECV_IS_LOCKED(csp)); \ - if ((csp)->ch_recv_changed) { \ - register int _d; \ - (csp)->ch_recv_scanset = (csp)->ch_recv_scanset_pending; \ - (csp)->ch_recv_domset = (csp)->ch_recv_domset_pending; \ - for (_d = 0; _d < MAX_DOMAINS; _d++) { \ - if (DOMAIN_IN_SET((csp)->ch_recv_domset, _d)) { \ - (mmp)[_d] = \ - &idn_domain[_d].dmbox.m_recv[chan]; \ - } else { \ - (mmp)[_d] = NULL; \ - } \ - } \ - (csp)->ch_recv_changed = 0; \ - } \ -} -#define CHANSVR_NEXT_DOMID(csp, i, d) \ -{ \ - (i) = ((i) + 1) & (MAX_DOMAINS - 1); \ - (d) = (int)(((csp)->ch_recv_scanset >> ((i) << 2)) & 0xf); \ -} -#define CHANSVR_RESET_INDEX(i) ((i) = -1) - -#ifdef DEBUG -static idn_mainmbox_t *Mmp[IDN_MAXMAX_NETS][MAX_DOMAINS]; -#endif /* DEBUG */ - -static void -idn_chan_server(idn_chansvr_t **cspp) -{ - idn_mboxhdr_t *mainhp; - register idn_chansvr_t *csp; - register idn_mboxmsg_t *mqp; -#ifdef DEBUG - idn_mainmbox_t **mmp; -#else - idn_mainmbox_t *mmp[MAX_DOMAINS]; -#endif /* DEBUG */ - register int qi; - struct idn *sip; - int channel; - int cpuid; - int empty; - int tot_pktcount, tot_dropcount; - register int index; - register int domid; - register int idleloops; - procname_t proc = "idn_chan_server"; - - -#ifdef DEBUG - mmp = &Mmp[(*cspp)->ch_id][0]; - bzero(mmp, MAX_DOMAINS * sizeof (idn_mainmbox_t *)); -#else /* DEBUG */ - bzero(mmp, sizeof (mmp)); -#endif /* DEBUG */ - - tot_pktcount = tot_dropcount = 0; - - ASSERT(cspp && *cspp); - - csp = *cspp; - channel = csp->ch_id; - sip = IDN_INST2SIP(channel); - ASSERT(sip); - - PR_CHAN("%s: CHANNEL SERVER (channel %d) GOING ACTIVE...\n", - proc, channel); - - IDN_CHAN_LOCK_RECV(csp); - IDN_CHAN_RECV_INPROGRESS(csp); - ASSERT(csp->ch_recv_threadp == curthread); - mutex_enter(&cpu_lock); - if ((cpuid = csp->ch_bound_cpuid_pending) != -1) { - cpu_t *cp = cpu_get(cpuid); - /* - * We've been requested to bind to - * a particular cpu. - */ - if ((cp == NULL) || !cpu_is_online(cp)) { - /* - * Cpu seems to have gone away or gone offline - * since originally requested. - */ - mutex_exit(&cpu_lock); - cmn_err(CE_WARN, - "IDN: 239: invalid CPU ID (%d) specified for " - "IDN net %d", - cpuid, channel); - } else { - csp->ch_bound_cpuid = cpuid; - affinity_set(csp->ch_bound_cpuid); - mutex_exit(&cpu_lock); - } - csp->ch_bound_cpuid_pending = -1; - } else { - mutex_exit(&cpu_lock); - } - if (csp->ch_bound_cpuid != -1) { - PR_CHAN("%s: thread bound to cpuid %d\n", - proc, csp->ch_bound_cpuid); - } - /* - * 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. - */ - CHANSVR_SYNC_CACHE(csp, mmp, channel); - - mainhp = ((csp->ch_recv_domcount > 0) && - IDN_CHANNEL_IS_RECV_ACTIVE(csp)) - ? idn_chan_server_syncheader(channel) : NULL; - - if (mainhp && IDN_CHANNEL_IS_RECV_ACTIVE(csp)) - mainhp->mh_svr_active = 1; - - ASSERT(csp->ch_recv_domcount ? - (csp->ch_recv_scanset && csp->ch_recv_domset) : 1); - - IDN_CHAN_UNLOCK_RECV(csp); - - empty = 0; - idleloops = 0; - CHANSVR_RESET_INDEX(index); - - /* - * --------------------------------------------- - */ - /*CONSTCOND*/ - while (1) { - register int pktcount; - register int dropcount; - ushort_t mbox_csum; - idn_mboxtbl_t *smr_mboxp; /* points to SMR space */ - register smr_offset_t bufoffset; -#ifdef DEBUG - register smr_pkthdr_t *hdrp; - idn_netaddr_t netaddr; -#endif /* DEBUG */ - - /* - * Speed through and find the next available domid. - */ - CHANSVR_NEXT_DOMID(csp, index, domid); - - if (!index) { - /* - * We only check state changes when - * we wrap around. Done for performance. - */ - if (!IDN_CHANNEL_IS_RECV_ACTIVE(csp) || - csp->ch_recv.c_checkin || - (idn.state != IDNGS_ONLINE)) { - - PR_DATA("%s: (channel %d) %s\n", - proc, channel, - IDN_CHANNEL_IS_DETACHED(csp) - ? "DEAD" : - IDN_CHANNEL_IS_PENDING(csp) - ? "IDLED" : - IDN_CHANNEL_IS_ACTIVE(csp) - ? "ACTIVE" : "DISABLED"); - goto cc_sleep; - } - } - if (csp->ch_recv.c_checkin) - goto cc_sleep; - - if (empty == csp->ch_recv_domcount) { - empty = 0; - goto cc_slowdown; - } - - ASSERT(mmp[domid] != NULL); - - mutex_enter(&mmp[domid]->mm_mutex); - if ((smr_mboxp = mmp[domid]->mm_smr_mboxp) == NULL) { - /* - * Somebody is trying to shut things down. - */ - empty++; - mutex_exit(&mmp[domid]->mm_mutex); - continue; - } - ASSERT(mmp[domid]->mm_channel == (short)channel); - /* - * 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. - */ - qi = mmp[domid]->mm_qiget; - - /* - * Check the mailbox header if checksum is turned on. - */ - mbox_csum = IDN_CKSUM_MBOX(&smr_mboxp->mt_header); - if (!VALID_MBOXHDR(&smr_mboxp->mt_header, channel, mbox_csum)) { - IDN_KSTAT_INC(sip, si_mboxcrc); - IDN_KSTAT_INC(sip, si_ierrors); - if (!(mmp[domid]->mm_flags & IDNMMBOX_FLAG_CORRUPTED)) { - cmn_err(CE_WARN, - "IDN: 241: [recv] (domain %d, " - "channel %d) SMR CORRUPTED - RELINK", - domid, channel); - mmp[domid]->mm_flags |= IDNMMBOX_FLAG_CORRUPTED; - } - empty = 0; - mutex_exit(&mmp[domid]->mm_mutex); - goto cc_sleep; - } - mutex_exit(&mmp[domid]->mm_mutex); - mqp = &smr_mboxp->mt_queue[0]; - - pktcount = dropcount = 0; - - if (mqp[qi].ms_owner == 0) - goto cc_next; - - bufoffset = IDN_BFRAME2OFFSET(mqp[qi].ms_bframe); - - if (!VALID_NWROFFSET(bufoffset, IDN_SMR_BUFSIZE)) { - /* ASSERT(0); */ - mqp[qi].ms_flag |= IDN_MBOXMSG_FLAG_ERR_BADOFFSET; - mqp[qi].ms_owner = 0; - IDN_MMBOXINDEX_INC(qi); - dropcount++; - - IDN_KSTAT_INC(sip, si_smraddr); - IDN_KSTAT_INC(sip, si_ierrors); - - } else { - PR_DATA("%s: (channel %d) pkt (off 0x%x, " - "qiget %d) from domain %d\n", - proc, channel, bufoffset, qi, domid); -#ifdef DEBUG - - hdrp = IDN_BUF2HDR(IDN_OFFSET2ADDR(bufoffset)); - netaddr.netaddr = hdrp->b_netaddr; - ASSERT(netaddr.net.chan == (ushort_t)channel); -#endif /* DEBUG */ - - if (idn_recv_mboxdata(channel, - IDN_OFFSET2ADDR(bufoffset)) < 0) { - mutex_enter(&mmp[domid]->mm_mutex); - if (!(mmp[domid]->mm_flags & - IDNMMBOX_FLAG_CORRUPTED)) { - cmn_err(CE_WARN, - "IDN: 241: [recv] (domain " - "%d, channel %d) SMR " - "CORRUPTED - RELINK", - domid, channel); - mmp[domid]->mm_flags |= - IDNMMBOX_FLAG_CORRUPTED; - } - mutex_exit(&mmp[domid]->mm_mutex); - } - - mqp[qi].ms_owner = 0; - IDN_MMBOXINDEX_INC(qi); - pktcount++; - } - -cc_next: - - mutex_enter(&mmp[domid]->mm_mutex); - if (mmp[domid]->mm_smr_mboxp) { - if (dropcount) - mmp[domid]->mm_dropped += dropcount; - mmp[domid]->mm_qiget = qi; - mmp[domid]->mm_count += pktcount; - } - mutex_exit(&mmp[domid]->mm_mutex); - - if (pktcount == 0) { - empty++; - } else { - csp->ch_recv_waittime = IDN_NETSVR_WAIT_MIN; - empty = 0; - idleloops = 0; - - PR_DATA("%s: (channel %d) dom=%d, pktcnt=%d\n", - proc, channel, domid, pktcount); - } - - continue; - -cc_slowdown: - -#ifdef DEBUG - if (idleloops == 0) { - PR_DATA("%s: (channel %d) going SOFT IDLE...\n", - proc, channel); - } -#endif /* DEBUG */ - if (idleloops++ < IDN_NETSVR_SPIN_COUNT) { - /* - * At this level we only busy-wait. - * Get back into action. - */ - continue; - } - idleloops = 0; - -cc_sleep: - - if (mainhp) - mainhp->mh_svr_active = 0; - - IDN_CHAN_LOCK_RECV(csp); - -cc_die: - - ASSERT(IDN_CHAN_RECV_IS_LOCKED(csp)); - - if (!IDN_CHANNEL_IS_RECV_ACTIVE(csp) && - IDN_CHANNEL_IS_DETACHED(csp)) { - /* - * Time to die... - */ - PR_CHAN("%s: (channel %d) serviced %d " - "packets, drop = %d\n", proc, channel, - tot_pktcount, tot_dropcount); - PR_CHAN("%s: (channel %d) TERMINATING\n", - proc, channel); - PR_CHAN("%s: (channel %d) ch_morguep = %p\n", - proc, channel, (void *)csp->ch_recv_morguep); - - csp->ch_recv_threadp = NULL; -#ifdef DEBUG - for (index = 0; index < csp->ch_recv_domcount; - index++) { - if ((int)((csp->ch_recv_scanset >> - (index*4)) & 0xf) == domid) { - PR_DATA("%s: WARNING (channel %d) " - "DROPPING domid %d...\n", - proc, channel, domid); - } - } -#endif /* DEBUG */ - IDN_CHAN_RECV_DONE(csp); - - sema_v(csp->ch_recv_morguep); - - IDN_CHAN_UNLOCK_RECV(csp); - - thread_exit(); - /* not reached */ - } - - do { - if (IDN_CHANNEL_IS_DETACHED(csp)) { - PR_CHAN("%s: (channel %d) going to DIE...\n", - proc, channel); - goto cc_die; - } -#ifdef DEBUG - if (IDN_CHANNEL_IS_RECV_ACTIVE(csp) && - (csp->ch_recv_waittime <= IDN_NETSVR_WAIT_MAX)) { - PR_CHAN("%s: (channel %d) going SOFT IDLE " - "(waittime = %d ticks)...\n", - proc, channel, - csp->ch_recv_waittime); - } else { - PR_CHAN("%s: (channel %d) going " - "HARD IDLE...\n", proc, channel); - } -#endif /* DEBUG */ - IDN_CHAN_RECV_DONE(csp); - - /* - * 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. - */ - while (csp->ch_recv.c_checkin) - cv_wait(&csp->ch_recv_cv, - &csp->ch_recv.c_mutex); - - if (csp->ch_recv_waittime > IDN_NETSVR_WAIT_MAX) - cv_wait(&csp->ch_recv_cv, - &csp->ch_recv.c_mutex); - else - (void) cv_reltimedwait(&csp->ch_recv_cv, - &csp->ch_recv.c_mutex, - csp->ch_recv_waittime, TR_CLOCK_TICK); - - IDN_CHAN_RECV_INPROGRESS(csp); - - IDN_KSTAT_INC(sip, si_sigsvr); - - if (csp->ch_recv_waittime <= IDN_NETSVR_WAIT_MAX) - csp->ch_recv_waittime <<= - IDN_NETSVR_WAIT_SHIFT; - - } while (!IDN_CHANNEL_IS_RECV_ACTIVE(csp)); - - /* - * Before we see the world (and touch SMR space), - * see if we've been told to die. - */ - mainhp = NULL; - /* - * 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). - */ - CHANSVR_SYNC_CACHE(csp, mmp, channel); - if (csp->ch_recv_domcount <= 0) { - /* - * Everybody disappeared on us. - * Go back to sleep. - */ - goto cc_die; - } - ASSERT(csp->ch_recv_scanset && csp->ch_recv_domset); - - mainhp = idn_chan_server_syncheader(channel); - if (mainhp == NULL) { - /* - * Bummer...we're idling... - */ - goto cc_die; - } - - mainhp->mh_svr_active = 1; - - IDN_CHAN_UNLOCK_RECV(csp); - /* - * Reset the domid index after sleeping. - */ - CHANSVR_RESET_INDEX(index); - - 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 -idn_chan_flush(idn_chansvr_t *csp) -{ - queue_t *rq; - struct idn *sip; - int flush_type = 0; - idn_chaninfo_t *csend, *crecv; - procname_t proc = "idn_chan_flush"; - - csend = &csp->ch_send; - crecv = &csp->ch_recv; - - mutex_enter(&crecv->c_mutex); - mutex_enter(&csend->c_mutex); - - if (crecv->c_state & IDN_CHANSVC_STATE_FLUSH) - flush_type |= FLUSHR; - - if (csend->c_state & IDN_CHANSVC_STATE_FLUSH) - flush_type |= FLUSHW; - - if (flush_type) { - rq = NULL; - rw_enter(&idn.struprwlock, RW_READER); - if ((sip = IDN_INST2SIP(csp->ch_id)) != NULL) - rq = sip->si_ipq; - rw_exit(&idn.struprwlock); - 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", - proc, flush_type, csp->ch_id); - - (void) putnextctl1(rq, M_FLUSH, flush_type); - } - crecv->c_state &= ~IDN_CHANSVC_STATE_FLUSH; - csend->c_state &= ~IDN_CHANSVC_STATE_FLUSH; - - if (crecv->c_waiters) - cv_broadcast(&crecv->c_cv); - } - - mutex_exit(&csend->c_mutex); - mutex_exit(&crecv->c_mutex); -} -#endif /* 0 */ - -/* - * Locks are with respect to SEND/RECV locks (c_mutex). - * - * STOP/SUSPEND/DETACH - * - Entered with locks dropped, leave with locks held. - * DETACH - lock dropped manually. - * RESTART/RESUME - * - Entered with locks held, leave with locks dropped. - * ATTACH - * - both enter and leave with locks dropped. - */ -static void -idn_chan_action(int channel, idn_chanaction_t chanaction, int wait) -{ - uchar_t clr_state, set_state; - uint_t is_running; - domainset_t closed_slabwaiters = 0; - struct idn *sip; - idn_chansvr_t *csp; - idn_chaninfo_t *csend, *crecv; - procname_t proc = "idn_chan_action"; - - ASSERT((channel >= 0) && (channel < IDN_MAX_NETS)); - ASSERT(idn.chan_servers); - - csp = &idn.chan_servers[channel]; - - PR_CHAN("%s: requesting %s for channel %d\n", - proc, chanaction_str[(int)chanaction], channel); - - csend = &csp->ch_send; - crecv = &csp->ch_recv; - - ASSERT(IDN_CHAN_GLOBAL_IS_LOCKED(csp)); - - clr_state = set_state = 0; - - switch (chanaction) { - case IDNCHAN_ACTION_DETACH: - clr_state = IDN_CHANSVC_STATE_MASK; - /*FALLTHROUGH*/ - - case IDNCHAN_ACTION_STOP: - clr_state |= IDN_CHANSVC_STATE_ENABLED; - /*FALLTHROUGH*/ - - case IDNCHAN_ACTION_SUSPEND: - clr_state |= IDN_CHANSVC_STATE_ACTIVE; - - /* - * Must maintain this locking order. - * Set asynchronous check-in flags. - */ - crecv->c_checkin = 1; - csend->c_checkin = 1; - - is_running = 0; - if ((csend->c_inprogress || crecv->c_inprogress) && - wait && (csp->ch_recv_threadp != curthread)) { - - rw_enter(&idn.struprwlock, RW_READER); - if ((sip = IDN_INST2SIP(channel)) != NULL) { - /* - * Temporarily turn off the STREAM - * to give a chance to breath. - */ - is_running = sip->si_flags & IDNRUNNING; - if (is_running) - sip->si_flags &= ~IDNRUNNING; - } - rw_exit(&idn.struprwlock); - } - - mutex_enter(&crecv->c_mutex); - crecv->c_state &= ~clr_state; - - mutex_enter(&csend->c_mutex); - csend->c_state &= ~clr_state; - - /* - * 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 - * suspend/stop. - */ - if (wait && (csp->ch_recv_threadp != curthread)) { - int do_flush = 0; - - if (csend->c_inprogress || crecv->c_inprogress) - do_flush++; - - if (do_flush) { - rw_enter(&idn.struprwlock, RW_READER); - if ((sip = IDN_INST2SIP(channel)) != NULL) { - /* - * Temporarily turn off the STREAM - * to give a chance to breath. - */ - if (sip->si_flags & IDNRUNNING) { - is_running = 1; - sip->si_flags &= ~IDNRUNNING; - } - } - rw_exit(&idn.struprwlock); - } - - /* - * 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. - */ - closed_slabwaiters = csp->ch_reg_domset; - DOMAINSET_ADD(closed_slabwaiters, idn.localid); - if (closed_slabwaiters) - smr_slabwaiter_close(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) { - mutex_exit(&crecv->c_mutex); - while (csend->c_inprogress) { - csend->c_waiters++; - cv_wait(&csend->c_cv, - &csend->c_mutex); - csend->c_waiters--; - } - /* - * Maintain lock ordering. - * Eventually we will catch - * him due to the flag settings. - */ - mutex_exit(&csend->c_mutex); - mutex_enter(&crecv->c_mutex); - mutex_enter(&csend->c_mutex); - } - if (crecv->c_inprogress) { - mutex_exit(&csend->c_mutex); - while (crecv->c_inprogress) { - crecv->c_waiters++; - cv_wait(&crecv->c_cv, - &crecv->c_mutex); - crecv->c_waiters--; - } - mutex_enter(&csend->c_mutex); - } - } while (csend->c_inprogress); - } - - if (is_running) { - /* - * Restore the IDNRUNNING bit in - * the flags to let them know the - * channel is still alive. - */ - rw_enter(&idn.struprwlock, RW_READER); - if ((sip = IDN_INST2SIP(channel)) != NULL) - sip->si_flags |= IDNRUNNING; - rw_exit(&idn.struprwlock); - } - - if (closed_slabwaiters) { - /* - * We can reopen now since at this point no new - * slabwaiters will attempt to come in and wait. - */ - smr_slabwaiter_open(csp->ch_reg_domset); - } - - crecv->c_checkin = 0; - csend->c_checkin = 0; - - /* - * ALL leave with locks held. - */ - PR_CHAN("%s: action (%s) for channel %d - COMPLETED\n", - proc, chanaction_str[(int)chanaction], channel); - break; - - case IDNCHAN_ACTION_ATTACH: - mutex_enter(&crecv->c_mutex); - mutex_enter(&csend->c_mutex); - set_state |= csp->ch_state & IDN_CHANSVC_STATE_ATTACHED; - /*FALLTHROUGH*/ - - case IDNCHAN_ACTION_RESTART: - set_state |= csp->ch_state & IDN_CHANSVC_STATE_ENABLED; - /*FALLTHROUGH*/ - - case IDNCHAN_ACTION_RESUME: - ASSERT(IDN_CHAN_LOCAL_IS_LOCKED(csp)); - set_state |= csp->ch_state & IDN_CHANSVC_STATE_ACTIVE; - - crecv->c_state |= set_state; - csend->c_state |= set_state; - - /* - * The channel server itself could come through this - * flow, so obviously no point in attempting to wake - * ourself up!. - */ - if (csp->ch_recv_threadp && (csp->ch_recv_threadp != curthread)) - cv_signal(&csp->ch_recv_cv); - - PR_CHAN("%s: action (%s) for channel %d - COMPLETED\n", - proc, chanaction_str[(int)chanaction], channel); - - /* - * Leaves with lock released. - */ - mutex_exit(&csend->c_mutex); - mutex_exit(&crecv->c_mutex); - break; - - default: - ASSERT(0); - break; - } -} - -static void -idn_chan_addmbox(int channel, ushort_t domset) -{ - idn_chansvr_t *csp; - register int d; - procname_t proc = "idn_chan_addmbox"; - - PR_CHAN("%s: adding domset 0x%x main mailboxes to channel %d\n", - proc, domset, channel); - - ASSERT(idn.chan_servers); - - csp = &idn.chan_servers[channel]; - - /* - * Adding domains to a channel can be - * asynchonous, so we don't bother waiting. - */ - IDN_CHANNEL_SUSPEND(channel, 0); - - /* - * 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; - } - IDN_CHANSVR_SCANSET_ADD_PENDING(csp, d); - DOMAINSET_ADD(csp->ch_recv_domset_pending, d); - IDN_CHAN_DOMAIN_REGISTER(csp, d); - - PR_CHAN("%s: domain %d (channel %d) RECV (pending) " - "scanset = 0x%lx\n", proc, d, channel, - csp->ch_recv_scanset_pending); - PR_CHAN("%s: domain %d (channel %d) domset = 0x%x\n", - proc, d, channel, (uint_t)csp->ch_reg_domset); - - CHECKPOINT_OPENED(IDNSB_CHKPT_CHAN, - idn_domain[d].dhw.dh_boardset, 1); - } - if (domset) - csp->ch_recv_changed = 1; - - IDN_CHANNEL_RESUME(channel); -} - -static void -idn_chan_delmbox(int channel, ushort_t domset) -{ - idn_chansvr_t *csp; - register int d; - procname_t proc = "idn_chan_delmbox"; - - PR_CHAN("%s: deleting domset 0x%x main mailboxes from channel %d\n", - proc, domset, channel); - - ASSERT(idn.chan_servers); - - csp = &idn.chan_servers[channel]; - - /* - * 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. - */ - IDN_CHANNEL_SUSPEND(channel, 1); - - /* - * 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. - */ - ASSERT(csp->ch_recv_domcount > 0); - IDN_CHANSVR_SCANSET_DEL_PENDING(csp, d); - DOMAINSET_DEL(csp->ch_recv_domset_pending, d); - IDN_CHAN_DOMAIN_UNREGISTER(csp, d); - - PR_CHAN("%s: domain %d (channel %d) RECV (pending) " - "scanset = 0x%lx\n", proc, d, channel, - csp->ch_recv_scanset_pending); - PR_CHAN("%s: domain %d (channel %d) domset = 0x%x\n", - proc, d, channel, (uint_t)csp->ch_reg_domset); - - CHECKPOINT_CLOSED(IDNSB_CHKPT_CHAN, - idn_domain[d].dhw.dh_boardset, 2); - - } - if (domset) - csp->ch_recv_changed = 1; - - IDN_CHANNEL_RESUME(channel); -} - -static int -idn_valid_etherheader(struct ether_header *ehp) -{ - uchar_t *eap; - - eap = &ehp->ether_dhost.ether_addr_octet[0]; - - if ((eap[IDNETHER_ZERO] != 0) && (eap[IDNETHER_ZERO] != 0xff)) - return (0); - - if ((eap[IDNETHER_COOKIE1] != IDNETHER_COOKIE1_VAL) && - (eap[IDNETHER_COOKIE1] != 0xff)) - return (0); - - if ((eap[IDNETHER_COOKIE2] != IDNETHER_COOKIE2_VAL) && - (eap[IDNETHER_COOKIE2] != 0xff)) - return (0); - - if ((eap[IDNETHER_RESERVED] != IDNETHER_RESERVED_VAL) && - (eap[IDNETHER_RESERVED] != 0xff)) - return (0); - - if (!VALID_UCHANNEL(eap[IDNETHER_CHANNEL]) && - (eap[IDNETHER_CHANNEL] != 0xff)) - return (0); - - if (!VALID_UDOMAINID(IDN_NETID2DOMID(eap[IDNETHER_NETID])) && - (eap[IDNETHER_NETID] != 0xff)) - return (0); - - return (1); -} - -/* - * Packet header has already been filled in. - * RETURNS: 0 - * ENOLINK - * EPROTO - * ENOSPC - */ -/*ARGSUSED*/ -static int -idn_send_mboxdata(int domid, struct idn *sip, int channel, caddr_t bufp) -{ - idn_mainmbox_t *mmp; - idn_mboxmsg_t *mqp; - smr_pkthdr_t *hdrp; - smr_offset_t bufoffset; - idn_netaddr_t dst; - ushort_t mbox_csum; - int rv = 0; - int pktlen, qi; - procname_t proc = "idn_send_mboxdata"; - - mmp = idn_domain[domid].dmbox.m_send; - if (mmp == NULL) { - PR_DATA("%s: dmbox.m_send == NULL\n", proc); - IDN_KSTAT_INC(sip, si_linkdown); - return (ENOLINK); - } - - mmp += channel; - mutex_enter(&mmp->mm_mutex); - - if (mmp->mm_smr_mboxp == NULL) { - PR_DATA("%s: (d %d, chn %d) mm_smr_mboxp == NULL\n", - proc, domid, channel); - IDN_KSTAT_INC(sip, si_linkdown); - rv = ENOLINK; - goto send_err; - } - mbox_csum = IDN_CKSUM_MBOX(&mmp->mm_smr_mboxp->mt_header); - if (mbox_csum != mmp->mm_smr_mboxp->mt_header.mh_cksum) { - PR_DATA("%s: (d %d, chn %d) mbox hdr cksum (%d) " - "!= actual (%d)\n", - proc, domid, channel, mbox_csum, - mmp->mm_smr_mboxp->mt_header.mh_cksum); - if ((mmp->mm_flags & IDNMMBOX_FLAG_CORRUPTED) == 0) { - cmn_err(CE_WARN, - "IDN: 241: [send] (domain %d, " - "channel %d) SMR CORRUPTED - RELINK", - domid, channel); - mmp->mm_flags |= IDNMMBOX_FLAG_CORRUPTED; - } - IDN_KSTAT_INC(sip, si_mboxcrc); - IDN_KSTAT_INC(sip, si_oerrors); - rv = EPROTO; - goto send_err; - } - - bufoffset = IDN_ADDR2OFFSET(bufp); - hdrp = IDN_BUF2HDR(bufp); - pktlen = hdrp->b_length; - dst.netaddr = hdrp->b_netaddr; - ASSERT(dst.net.chan == (ushort_t)channel); - - mqp = &mmp->mm_smr_mboxp->mt_queue[0]; - qi = mmp->mm_qiput; - - if (mqp[qi].ms_owner) { - PR_DATA("%s: mailbox FULL (qiput=%d, qiget=%d)\n", - proc, mmp->mm_qiput, mmp->mm_qiget); - IDN_KSTAT_INC(sip, si_txfull); - rv = ENOSPC; - goto send_err; - } - if (mqp[qi].ms_flag & IDN_MBOXMSG_FLAG_RECLAIM) { - smr_offset_t recl_bufoffset; - /* - * 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. - */ - recl_bufoffset = IDN_BFRAME2OFFSET(mqp[qi].ms_bframe); - - PR_DATA("%s: attempting reclaim (domain %d) " - "(qiput=%d, b_off=0x%x)\n", - proc, domid, qi, recl_bufoffset); - - if (VALID_NWROFFSET(recl_bufoffset, IDN_SMR_BUFSIZE)) { - int recl; - caddr_t b_bufp; - smr_pkthdr_t *b_hdrp; - - b_bufp = IDN_OFFSET2ADDR(recl_bufoffset); - b_hdrp = IDN_BUF2HDR(b_bufp); - - if (IDN_CKSUM_PKT(b_hdrp) != b_hdrp->b_cksum) { - IDN_KSTAT_INC(sip, si_crc); - IDN_KSTAT_INC(sip, si_fcs_errors); - IDN_KSTAT_INC(sip, si_reclaim); - IDN_KSTAT_INC(sip, si_oerrors); - } - - recl = smr_buf_free(domid, b_bufp, b_hdrp->b_length); -#ifdef DEBUG - if (recl == 0) { - PR_DATA("%s: SUCCESSFULLY reclaimed buf " - "(domain %d)\n", proc, domid); - } else { - PR_DATA("%s: WARNING: reclaim failed (FREE) " - "(domain %d)\n", proc, domid); - } -#endif /* DEBUG */ - } else { - IDN_KSTAT_INC(sip, si_smraddr); - IDN_KSTAT_INC(sip, si_reclaim); - PR_DATA("%s: WARNING: reclaim failed (BAD OFFSET) " - "(domain %d)\n", proc, domid); - } - } - - if (*mmp->mm_smr_readyp == 0) { - mmp->mm_qiput = qi; - IDN_KSTAT_INC(sip, si_linkdown); - rv = ENOLINK; - goto send_err; - } - - mqp[qi].ms_flag = IDN_MBOXMSG_FLAG_RECLAIM; - mqp[qi].ms_bframe = IDN_OFFSET2BFRAME(bufoffset); - /* membar_stst(); */ - mqp[qi].ms_owner = 1; - - IDN_MMBOXINDEX_INC(qi); - - mmp->mm_qiput = qi; - - mmp->mm_count++; - - if ((*mmp->mm_smr_readyp) && !(*mmp->mm_smr_activep)) { - idn_msgtype_t mt; - - mt.mt_mtype = IDNP_DATA; - mt.mt_atype = 0; - IDN_KSTAT_INC(sip, si_xdcall); - (void) IDNXDC(domid, &mt, (uint_t)dst.net.chan, 0, 0, 0); - } - mutex_exit(&mmp->mm_mutex); - IDN_KSTAT_INC(sip, si_opackets); - IDN_KSTAT_INC(sip, si_opackets64); - IDN_KSTAT_ADD(sip, si_xmtbytes, pktlen); - IDN_KSTAT_ADD(sip, si_obytes64, (uint64_t)pktlen); - - return (0); - -send_err: - mmp->mm_dropped++; - - mutex_exit(&mmp->mm_mutex); - - return (rv); -} - -static int -idn_recv_mboxdata(int channel, caddr_t bufp) -{ - smr_pkthdr_t *hdrp; - struct idn *sip; - mblk_t *mp = nilp(mblk_t); - int pktlen; - int apktlen; - int rv = 0; - smr_offset_t bufoffset; - ushort_t csum; - idn_netaddr_t dst, daddr; - procname_t proc = "idn_recv_mboxdata"; - - hdrp = IDN_BUF2HDR(bufp); - - csum = IDN_CKSUM_PKT(hdrp); - - sip = IDN_INST2SIP(channel); - if (sip == NULL) { - /*LINTED*/ - sip = IDN_INST2SIP(0); - } - ASSERT(sip); - - if (csum != hdrp->b_cksum) { - PR_DATA("%s: bad checksum(%x) != expected(%x)\n", - proc, (uint_t)csum, (uint_t)hdrp->b_cksum); - IDN_KSTAT_INC(sip, si_crc); - IDN_KSTAT_INC(sip, si_fcs_errors); - rv = -1; - goto recv_err; - } - - daddr.net.chan = (ushort_t)channel; - daddr.net.netid = (ushort_t)idn.localid; - - dst.netaddr = hdrp->b_netaddr; - bufoffset = hdrp->b_offset; - - if (dst.netaddr != daddr.netaddr) { - PR_DATA("%s: wrong dest netaddr (0x%x), expected (0x%x)\n", - proc, dst.netaddr, daddr.netaddr); - IDN_KSTAT_INC(sip, si_nolink); - IDN_KSTAT_INC(sip, si_macrcv_errors); - goto recv_err; - } - pktlen = hdrp->b_length; - apktlen = pktlen; - - if ((pktlen <= 0) || (pktlen > IDN_DATA_SIZE)) { - PR_DATA("%s: invalid packet length (%d) <= 0 || > %lu\n", - proc, pktlen, IDN_DATA_SIZE); - IDN_KSTAT_INC(sip, si_buff); - IDN_KSTAT_INC(sip, si_toolong_errors); - goto recv_err; - } - - mp = allocb(apktlen + IDN_ALIGNSIZE, BPRI_LO); - if (mp == nilp(mblk_t)) { - PR_DATA("%s: allocb(pkt) failed\n", proc); - IDN_KSTAT_INC(sip, si_allocbfail); - IDN_KSTAT_INC(sip, si_norcvbuf); /* MIB II */ - goto recv_err; - } - ASSERT(DB_TYPE(mp) == M_DATA); - /* - * Copy data packet into its streams buffer. - * Align pointers for maximum bcopy performance. - */ - mp->b_rptr = (uchar_t *)IDN_ALIGNPTR(mp->b_rptr, bufoffset); - bcopy(IDN_BUF2DATA(bufp, bufoffset), mp->b_rptr, apktlen); - mp->b_wptr = mp->b_rptr + pktlen; - - if (IDN_CHECKSUM && - !idn_valid_etherheader((struct ether_header *)mp->b_rptr)) { - freeb(mp); - mp = nilp(mblk_t); - PR_DATA("%s: etherheader CORRUPTED\n", proc); - IDN_KSTAT_INC(sip, si_crc); - IDN_KSTAT_INC(sip, si_fcs_errors); - rv = -1; - goto recv_err; - } - - idndl_read(NULL, mp); - -recv_err: - - if (mp == nilp(mblk_t)) { - IDN_KSTAT_INC(sip, si_ierrors); - } - - 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 -idn_reclaim_mboxdata(int domid, int channel, int nbufs) -{ - idn_mainmbox_t *mmp; - idn_mboxmsg_t *mqp; - smr_pkthdr_t *hdrp; - idn_domain_t *dp; - int qi; - int mi; - int reclaim_cnt = 0; - int free_cnt; - ushort_t csum; - struct idn *sip; - smr_offset_t reclaim_list, curr, prev; - procname_t proc = "idn_reclaim_mboxdata"; - - - sip = IDN_INST2SIP(channel); - if (sip == NULL) { - /*LINTED*/ - sip = IDN_INST2SIP(0); - } - ASSERT(sip); - - dp = &idn_domain[domid]; - - PR_DATA("%s: requested %d buffers from domain %d\n", - proc, nbufs, domid); - - if (lock_try(&dp->dreclaim_inprogress) == 0) { - /* - * Reclaim is already in progress, don't - * bother. - */ - PR_DATA("%s: reclaim already in progress\n", proc); - return (0); - } - - if (dp->dmbox.m_send == NULL) - return (0); - - reclaim_list = curr = prev = IDN_NIL_SMROFFSET; - - mi = (int)dp->dreclaim_index; - do { - ushort_t mbox_csum; - - mmp = &dp->dmbox.m_send[mi]; - /* do-while continues down */ - ASSERT(mmp); - if (mutex_tryenter(&mmp->mm_mutex) == 0) { - /* - * This channel is busy, move on. - */ - IDN_MBOXCHAN_INC(mi); - continue; - } - - if (mmp->mm_smr_mboxp == NULL) { - PR_DATA("%s: no smr pointer for domid %d, chan %d\n", - proc, domid, (int)mmp->mm_channel); - ASSERT(mmp->mm_qiget == mmp->mm_qiput); - mutex_exit(&mmp->mm_mutex); - IDN_MBOXCHAN_INC(mi); - continue; - } - mbox_csum = IDN_CKSUM_MBOX(&mmp->mm_smr_mboxp->mt_header); - if (mbox_csum != mmp->mm_smr_mboxp->mt_header.mh_cksum) { - PR_DATA("%s: (d %d, chn %d) mbox hdr " - "cksum (%d) != actual (%d)\n", - proc, domid, (int)mmp->mm_channel, mbox_csum, - mmp->mm_smr_mboxp->mt_header.mh_cksum); - IDN_KSTAT_INC(sip, si_mboxcrc); - IDN_KSTAT_INC(sip, si_oerrors); - mutex_exit(&mmp->mm_mutex); - IDN_MBOXCHAN_INC(mi); - continue; - } - mqp = &mmp->mm_smr_mboxp->mt_queue[0]; - qi = mmp->mm_qiget; - - while (!mqp[qi].ms_owner && - (mqp[qi].ms_flag & IDN_MBOXMSG_FLAG_RECLAIM) && - nbufs) { - idn_mboxmsg_t *msp; - int badbuf; - - badbuf = 0; - msp = &mqp[qi]; - - if (msp->ms_flag & IDN_MBOXMSG_FLAG_ERRMASK) { - PR_DATA("%s: msg.flag ERROR(0x%x) (off=0x%x, " - "domid=%d, qiget=%d)\n", proc, - (uint_t)(msp->ms_flag & - IDN_MBOXMSG_FLAG_ERRMASK), - IDN_BFRAME2OFFSET(msp->ms_bframe), - domid, qi); - } - prev = curr; - curr = IDN_BFRAME2OFFSET(mqp[qi].ms_bframe); - - if (!VALID_NWROFFSET(curr, IDN_SMR_BUFSIZE)) { - badbuf = 1; - IDN_KSTAT_INC(sip, si_reclaim); - } 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. - */ - hdrp = IDN_BUF2HDR(IDN_OFFSET2ADDR(curr)); - csum = IDN_CKSUM_PKT(hdrp); - - if (csum != hdrp->b_cksum) { - badbuf = 1; - IDN_KSTAT_INC(sip, si_crc); - IDN_KSTAT_INC(sip, si_fcs_errors); - IDN_KSTAT_INC(sip, si_reclaim); - if (!(mmp->mm_flags & - IDNMMBOX_FLAG_CORRUPTED)) { - cmn_err(CE_WARN, - "IDN: 241: [send] " - "(domain %d, channel " - "%d) SMR CORRUPTED - " - "RELINK", - domid, channel); - mmp->mm_flags |= - IDNMMBOX_FLAG_CORRUPTED; - } - - } else if (reclaim_list == IDN_NIL_SMROFFSET) { - reclaim_list = curr; - } else { - caddr_t bufp; - - bufp = IDN_OFFSET2ADDR(prev); - hdrp = IDN_BUF2HDR(bufp); - hdrp->b_next = curr; - } - } - - mqp[qi].ms_flag = 0; - - IDN_MMBOXINDEX_INC(qi); - - if (!badbuf) { - nbufs--; - reclaim_cnt++; - } - - if (qi == mmp->mm_qiget) - break; - } - mmp->mm_qiget = qi; - - mutex_exit(&mmp->mm_mutex); - - IDN_MBOXCHAN_INC(mi); - - } while ((mi != (int)dp->dreclaim_index) && nbufs); - - dp->dreclaim_index = (uchar_t)mi; - - if (reclaim_list != IDN_NIL_SMROFFSET) { - hdrp = IDN_BUF2HDR(IDN_OFFSET2ADDR(curr)); - hdrp->b_next = IDN_NIL_SMROFFSET; - } - - PR_DATA("%s: reclaimed %d buffers from domain %d\n", - proc, reclaim_cnt, domid); - - if (reclaim_cnt == 0) { - lock_clear(&dp->dreclaim_inprogress); - return (0); - } - - /* - * Now actually go and reclaim (free) the buffers. - */ - free_cnt = 0; - - for (curr = reclaim_list; curr != IDN_NIL_SMROFFSET; ) { - caddr_t bufp; - - bufp = IDN_OFFSET2ADDR(curr); - hdrp = IDN_BUF2HDR(bufp); - csum = IDN_CKSUM_PKT(hdrp); - if (csum != hdrp->b_cksum) { - /* - * Once corruption is detected we - * can't trust our list any further. - * These buffers are effectively lost. - */ - cmn_err(CE_WARN, - "IDN: 241: [send] (domain %d, channel %d) SMR " - "CORRUPTED - RELINK", domid, channel); - break; - } - - curr = hdrp->b_next; - - if (!smr_buf_free(domid, bufp, hdrp->b_length)) - free_cnt++; - } - - if ((dp->dio < IDN_WINDOW_EMAX) && dp->diocheck) { - lock_clear(&dp->diocheck); - IDN_MSGTIMER_STOP(domid, IDNP_DATA, 0); - } - -#ifdef DEBUG - if (free_cnt != reclaim_cnt) { - PR_DATA("%s: *** WARNING *** freecnt(%d) != reclaim_cnt (%d)\n", - proc, free_cnt, reclaim_cnt); - } -#endif /* DEBUG */ - - lock_clear(&dp->dreclaim_inprogress); - - return (reclaim_cnt); -} - -void -idn_signal_data_server(int domid, ushort_t channel) -{ - idn_nack_t nacktype = 0; - idn_domain_t *dp; - idn_chansvr_t *csp; - int c, min_chan, max_chan; - idn_mainmbox_t *mmp; - procname_t proc = "idn_signal_data_server"; - - - if (domid == IDN_NIL_DOMID) - return; - - dp = &idn_domain[domid]; - - if (dp->dawol.a_count > 0) { - /* - * Domain was previously AWOL, but no longer. - */ - IDN_SYNC_LOCK(); - IDN_GLOCK_EXCL(); - idn_clear_awol(domid); - IDN_GUNLOCK(); - IDN_SYNC_UNLOCK(); - } - /* - * Do a precheck before wasting time trying to acquire the lock. - */ - if ((dp->dstate != IDNDS_CONNECTED) || !IDN_DLOCK_TRY_SHARED(domid)) { - /* - * 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 (dp->dstate != IDNDS_CONNECTED) { - /* - * If we reach here, then no connection. - * Send no response if this is the case. - */ - nacktype = IDNNACK_NOCONN; - 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. - */ - if ((mmp = dp->dmbox.m_recv) == NULL) { - /* - * No local mailbox. - */ - nacktype = IDNNACK_BADCFG; - goto send_dresp; - } - if ((channel != IDN_BROADCAST_ALLCHAN) && (channel >= IDN_MAX_NETS)) { - nacktype = IDNNACK_BADCHAN; - goto send_dresp; - } - if (channel == IDN_BROADCAST_ALLCHAN) { - PR_DATA("%s: requested signal to ALL channels on domain %d\n", - proc, domid); - min_chan = 0; - max_chan = IDN_MAX_NETS - 1; - } else { - PR_DATA("%s: requested signal to channel %d on domain %d\n", - proc, channel, domid); - min_chan = max_chan = (int)channel; - } - mmp += min_chan; - for (c = min_chan; c <= max_chan; mmp++, c++) { - - /* - * 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. - */ - csp = &idn.chan_servers[c]; - - if (csp->ch_recv.c_checkin) { - PR_DATA("%s: chansvr (%d) for domid %d CHECK-IN\n", - proc, c, domid); - 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", - proc, c, domid); - continue; - } - - if (IDN_CHANNEL_IS_PENDING(csp)) { - /* - * Lock is pending. Submit asynchronous - * job to activate and move-on. - */ - IDN_CHAN_UNLOCK_RECV(csp); - idn_submit_chanactivate_job(c); - continue; - } - - /* - * If he ain't active, we ain't talkin'. - */ - if (IDN_CHANNEL_IS_RECV_ACTIVE(csp) == 0) { - IDN_CHAN_UNLOCK_RECV(csp); - PR_DATA("%s: chansvr (%d) for domid %d inactive\n", - proc, c, domid); - continue; - } - - if (mutex_tryenter(&mmp->mm_mutex) == 0) { - IDN_CHAN_UNLOCK_RECV(csp); - continue; - } - - if (mmp->mm_csp != csp) { - /* - * Not registered. - */ - mutex_exit(&mmp->mm_mutex); - IDN_CHAN_UNLOCK_RECV(csp); - continue; - - } - if (mmp->mm_smr_mboxp == NULL) { - /* - * No SMR mailbox. - */ - mutex_exit(&mmp->mm_mutex); - IDN_CHAN_UNLOCK_RECV(csp); - continue; - } - mutex_exit(&mmp->mm_mutex); - - if (csp->ch_recv.c_inprogress) { - /* - * Data server is already active. - */ - IDN_CHAN_UNLOCK_RECV(csp); - PR_DATA("%s: chansvr (%d) for domid %d already actv\n", - proc, c, domid); - continue; - } - ASSERT(csp == &idn.chan_servers[c]); - - - PR_DATA("%s: signaling data dispatcher for chan %d dom %d\n", - proc, c, domid); - ASSERT(csp); - cv_signal(&csp->ch_recv_cv); - IDN_CHAN_UNLOCK_RECV(csp); - } - - if (!nacktype || (channel == IDN_BROADCAST_ALLCHAN)) { - /* - * If there were no real errors or we were - * handling multiple channels, then just - * return. - */ - IDN_DUNLOCK(domid); - return; - } - -send_dresp: - - PR_DATA("%s: sending NACK (%s) back to domain %d (cpu %d)\n", - proc, idnnack_str[nacktype], domid, idn_domain[domid].dcpu); - - idn_send_dataresp(domid, nacktype); - - IDN_DUNLOCK(domid); -} - -/*ARGSUSED*/ -static int -idn_recv_data(int domid, idn_msgtype_t *mtp, idn_xdcargs_t xargs) -{ -#ifdef DEBUG - uint_t msg = mtp ? mtp->mt_mtype : 0; - uint_t msgarg = mtp ? mtp->mt_atype : 0; - procname_t proc = "idn_recv_data"; - - PR_PROTO("%s:%d: DATA message received (msg = 0x%x, msgarg = 0x%x)\n", - proc, domid, msg, msgarg); - PR_PROTO("%s:%d: xargs = (0x%x, 0x%x, 0x%x, 0x%x)\n", - proc, domid, xargs[0], xargs[1], xargs[2], xargs[3]); -#endif /* DEBUG */ - - return (0); -} - -/* - * Only used when sending a negative response. - */ -static void -idn_send_dataresp(int domid, idn_nack_t nacktype) -{ - idn_msgtype_t mt; - - ASSERT(IDN_DLOCK_IS_HELD(domid)); - - if (idn_domain[domid].dcpu == IDN_NIL_DCPU) - return; - - mt.mt_mtype = IDNP_NACK; - mt.mt_atype = IDNP_DATA; - - (void) IDNXDC(domid, &mt, (uint_t)nacktype, 0, 0, 0); -} - -/* - * Checksum routine used in checksum smr_pkthdr_t and idn_mboxhdr_t. - */ -static ushort_t -idn_cksum(register ushort_t *hdrp, register int count) -{ - register int i; - register ushort_t sum = 0; - - for (i = 0; i < count; i++) - sum += hdrp[i]; - - sum = (sum >> 16) + (sum & 0xffff); - sum += (sum >> 16); - - return (~sum); -} - -/* - * ------------------------------------------------ - */ - -int -idn_open_channel(int channel) -{ - int masterid; - idn_chansvr_t *csp; - struct idn *sip; - procname_t proc = "idn_open_channel"; - - if (channel >= IDN_MAX_NETS) { - cmn_err(CE_WARN, - "IDN: 242: maximum channels (%d) already open", - IDN_MAX_NETS); - return (-1); - } - IDN_GLOCK_EXCL(); - - ASSERT(idn.chan_servers != NULL); - - csp = &idn.chan_servers[channel]; - - IDN_CHAN_LOCK_GLOBAL(csp); - - if (IDN_CHANNEL_IS_ATTACHED(csp)) { - PR_CHAN("%s: channel %d already open\n", proc, channel); - IDN_CHAN_UNLOCK_GLOBAL(csp); - IDN_GUNLOCK(); - return (0); - } - - /* - * Need to zero out the kstats now that we're activating - * this channel. - */ - for (sip = idn.sip; sip; sip = sip->si_nextp) { - if (sip->si_dip && (ddi_get_instance(sip->si_dip) == channel)) { - bzero(&sip->si_kstat, sizeof (sip->si_kstat)); - break; - } - } - - IDN_CHANSVC_MARK_ATTACHED(csp); - idn.nchannels++; - CHANSET_ADD(idn.chanset, channel); - IDN_CHANNEL_ATTACH(channel); - - IDN_CHAN_UNLOCK_GLOBAL(csp); - - /* - * We increase our window threshold each time a channel - * is opened. - */ - ASSERT(idn.nchannels > 0); - IDN_WINDOW_EMAX = IDN_WINDOW_MAX + - ((idn.nchannels - 1) * IDN_WINDOW_INCR); - - PR_CHAN("%s: channel %d is OPEN (nchannels = %d)\n", - proc, channel, idn.nchannels); - - 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) { - idn_domain_t *dp; - - dp = &idn_domain[masterid]; - IDN_DLOCK_SHARED(masterid); - if (dp->dvote.v.master && (dp->dstate == IDNDS_CONNECTED)) - (void) idn_activate_channel(CHANSET(channel), - IDNCHAN_ONLINE); - IDN_DUNLOCK(masterid); - } - - return (0); -} - -void -idn_close_channel(int channel, idn_chanop_t chanop) -{ - idn_chansvr_t *csp; - procname_t proc = "idn_close_channel"; - - - ASSERT(idn.chan_servers != NULL); - - csp = &idn.chan_servers[channel]; - - IDN_GLOCK_EXCL(); - - IDN_CHAN_LOCK_GLOBAL(csp); - if (IDN_CHANNEL_IS_DETACHED(csp)) { - PR_CHAN("%s: channel %d already closed\n", proc, channel); - IDN_CHAN_UNLOCK_GLOBAL(csp); - IDN_GUNLOCK(); - return; - } - IDN_CHAN_UNLOCK_GLOBAL(csp); - - idn_deactivate_channel(CHANSET(channel), chanop); - - IDN_CHAN_LOCK_GLOBAL(csp); - - if (chanop == IDNCHAN_HARD_CLOSE) { - idn.nchannels--; - CHANSET_DEL(idn.chanset, channel); - /* - * We increase our window threshold each time a channel - * is opened. - */ - if (idn.nchannels <= 0) - IDN_WINDOW_EMAX = 0; - else - IDN_WINDOW_EMAX = IDN_WINDOW_MAX + - ((idn.nchannels - 1) * IDN_WINDOW_INCR); - } - - PR_CHAN("%s: channel %d is (%s) CLOSED (nchannels = %d)\n", - proc, channel, - (chanop == IDNCHAN_SOFT_CLOSE) ? "SOFT" - : (chanop == IDNCHAN_HARD_CLOSE) ? "HARD" : "OFFLINE", - idn.nchannels); - - IDN_CHAN_UNLOCK_GLOBAL(csp); - IDN_GUNLOCK(); -} - -static int -idn_activate_channel(idn_chanset_t chanset, idn_chanop_t chanop) -{ - int c, rv = 0; - procname_t proc = "idn_activate_channel"; - - PR_CHAN("%s: chanset = 0x%x, chanop = %s\n", - proc, chanset, chanop_str[chanop]); - - if (idn.state != IDNGS_ONLINE) { - /* - * 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++) { - idn_chansvr_t *csp; - idn_mboxhdr_t *mainhp; - struct idn *sip; - - if (!CHAN_IN_SET(chanset, c)) - continue; - csp = &idn.chan_servers[c]; - - if (chanop == IDNCHAN_ONLINE) { - IDN_CHAN_LOCK_GLOBAL(csp); - } 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)) { - PR_CHAN("%s: channel %d NOT open\n", proc, c); - IDN_CHAN_UNLOCK_GLOBAL(csp); - continue; - - } - - if (IDN_CHANNEL_IS_ACTIVE(csp)) { - - PR_CHAN("%s: channel %d already active\n", proc, c); - rv++; - IDN_CHAN_UNLOCK_GLOBAL(csp); - continue; - - } - /* - * Channel activation can happen asynchronously. - */ - IDN_CHANNEL_SUSPEND(c, 0); - - if (IDN_CHANNEL_IS_PENDING(csp) && (chanop == IDNCHAN_OPEN)) { - - PR_CHAN("%s: ACTIVATING channel %d\n", proc, c); - - if (idn_activate_channel_services(c) >= 0) { - PR_CHAN("%s: Setting channel %d ACTIVE\n", - proc, c); - IDN_CHANSVC_MARK_ACTIVE(csp); - rv++; - } - } else if (!IDN_CHANNEL_IS_PENDING(csp) && - (chanop == IDNCHAN_ONLINE)) { - PR_CHAN("%s: Setting channel %d PENDING\n", proc, c); - - IDN_CHANSVC_MARK_PENDING(csp); - } - /* - * 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) && - ((mainhp = idn_chan_server_syncheader(c)) != NULL)) { - PR_CHAN("%s: marking chansvr (mhp=0x%p) %d READY\n", - proc, (void *)mainhp, c); - mainhp->mh_svr_ready = 1; - } - - IDN_CHANNEL_RESUME(c); - sip = IDN_INST2SIP(c); - ASSERT(sip); - if (sip->si_wantw) { - mutex_enter(&idn.sipwenlock); - idndl_wenable(sip); - mutex_exit(&idn.sipwenlock); - } - IDN_CHAN_UNLOCK_GLOBAL(csp); - - } - /* - * Returns "not active", i.e. value of 0 indicates - * no channels are activated. - */ - return (rv == 0); -} - -static void -idn_deactivate_channel(idn_chanset_t chanset, idn_chanop_t chanop) -{ - int c; - procname_t proc = "idn_deactivate_channel"; - - PR_CHAN("%s: chanset = 0x%x, chanop = %s\n", - proc, chanset, chanop_str[chanop]); - - for (c = 0; c < IDN_MAX_NETS; c++) { - idn_chansvr_t *csp; - idn_mboxhdr_t *mainhp; - - if (!CHAN_IN_SET(chanset, c)) - continue; - - csp = &idn.chan_servers[c]; - - IDN_CHAN_LOCK_GLOBAL(csp); - - if (((chanop == IDNCHAN_SOFT_CLOSE) && - !IDN_CHANNEL_IS_ACTIVE(csp)) || - ((chanop == IDNCHAN_HARD_CLOSE) && - IDN_CHANNEL_IS_DETACHED(csp)) || - ((chanop == IDNCHAN_OFFLINE) && - !IDN_CHANNEL_IS_ENABLED(csp))) { - - ASSERT(!IDN_CHANNEL_IS_RECV_ACTIVE(csp)); - ASSERT(!IDN_CHANNEL_IS_SEND_ACTIVE(csp)); - - PR_CHAN("%s: channel %d already deactivated\n", - proc, c); - IDN_CHAN_UNLOCK_GLOBAL(csp); - continue; - } - - switch (chanop) { - case IDNCHAN_OFFLINE: - IDN_CHANSVC_MARK_IDLE(csp); - IDN_CHANSVC_MARK_DISABLED(csp); - IDN_CHANNEL_STOP(c, 1); - mainhp = idn_chan_server_syncheader(c); - if (mainhp != NULL) - mainhp->mh_svr_ready = 0; - break; - - case IDNCHAN_HARD_CLOSE: - IDN_CHANSVC_MARK_DETACHED(csp); - IDN_CHANNEL_DETACH(c, 1); - mainhp = idn_chan_server_syncheader(c); - if (mainhp != NULL) - mainhp->mh_svr_ready = 0; - break; - - default: - IDN_CHANSVC_MARK_IDLE(csp); - IDN_CHANNEL_SUSPEND(c, 1); - ASSERT(IDN_CHANNEL_IS_ATTACHED(csp)); - break; - } - - lock_clear(&csp->ch_actvlck); - lock_clear(&csp->ch_initlck); - - PR_CHAN("%s: DEACTIVATING channel %d (%s)\n", proc, c, - chanop_str[chanop]); - PR_CHAN("%s: removing chanset 0x%x data svrs for " - "each domain link\n", proc, chanset); - - (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 pri_t idn_chansvr_pri = (7 * MAXCLSYSPRI) / 8; - -static int -idn_activate_channel_services(int channel) -{ - idn_chansvr_t *csp; - procname_t proc = "idn_activate_channel_services"; - - - ASSERT((channel >= 0) && (channel < IDN_MAX_NETS)); - - csp = &idn.chan_servers[channel]; - - ASSERT(IDN_CHAN_GLOBAL_IS_LOCKED(csp)); - ASSERT(IDN_CHAN_LOCAL_IS_LOCKED(csp)); - - if (csp->ch_recv_threadp) { - /* - * There's an existing dispatcher! - * Must have been idle'd during an earlier - * stint. - */ - ASSERT(csp->ch_id == (uchar_t)channel); - PR_CHAN("%s: existing chansvr FOUND for (c=%d)\n", - proc, channel); - - if (IDN_CHANNEL_IS_PENDING(csp) == 0) - return (-1); - - PR_CHAN("%s: chansvr (c=%d) Rstate = 0x%x, Sstate = 0x%x\n", - proc, channel, csp->ch_recv.c_state, - csp->ch_send.c_state); - - cv_signal(&csp->ch_recv_cv); - - return (0); - } - - if (IDN_CHANNEL_IS_PENDING(csp) == 0) - return (-1); - - csp->ch_id = (uchar_t)channel; - - PR_CHAN("%s: init channel %d server\n", proc, channel); - - csp->ch_recv_morguep = GETSTRUCT(ksema_t, 1); - sema_init(csp->ch_recv_morguep, 0, NULL, SEMA_DRIVER, NULL); - - csp->ch_recv.c_inprogress = 0; - csp->ch_recv.c_waiters = 0; - csp->ch_recv.c_checkin = 0; - csp->ch_recv_changed = 1; - - csp->ch_recv_domset = csp->ch_reg_domset; - - csp->ch_recv_waittime = IDN_NETSVR_WAIT_MIN; - - csp->ch_recv_threadp = thread_create(NULL, 0, - idn_chan_server, &csp, sizeof (csp), &p0, TS_RUN, idn_chansvr_pri); - - csp->ch_send.c_inprogress = 0; - csp->ch_send.c_waiters = 0; - csp->ch_send.c_checkin = 0; - - 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 -idn_deactivate_channel_services(int channel, idn_chanop_t chanop) -{ - idn_chansvr_t *csp; - int cs_count; - int c; - idn_chanset_t chanset; - ksema_t *central_morguep = NULL; - procname_t proc = "idn_deactivate_channel_services"; - - - ASSERT(idn.chan_servers); - - PR_CHAN("%s: deactivating channel %d services\n", proc, channel); - - /* - * XXX - * Old code allowed us to deactivate multiple channel - * servers at once. Keep for now just in case. - */ - chanset = CHANSET(channel); - - /* - * 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; - - csp = &idn.chan_servers[c]; - ASSERT(IDN_CHAN_GLOBAL_IS_LOCKED(csp)); - ASSERT(IDN_CHAN_LOCAL_IS_LOCKED(csp)); - - if (csp->ch_recv_threadp == NULL) { - /* - * 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); - IDN_CHAN_UNLOCK_LOCAL(csp); - IDN_CHAN_UNLOCK_GLOBAL(csp); - continue; - } - ASSERT(csp->ch_id == (uchar_t)c); - - /* - * 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. - */ - cv_signal(&csp->ch_recv_cv); - IDN_CHAN_UNLOCK_LOCAL(csp); - IDN_CHAN_UNLOCK_GLOBAL(csp); - cs_count++; - continue; - } - - PR_CHAN("%s: pointing chansvr %d to morgue (0x%p)\n", - proc, c, central_morguep ? (void *)central_morguep - : (void *)(csp->ch_recv_morguep)); - - if (central_morguep == NULL) { - central_morguep = csp->ch_recv_morguep; - } else { - sema_destroy(csp->ch_recv_morguep); - FREESTRUCT(csp->ch_recv_morguep, ksema_t, 1); - - csp->ch_recv_morguep = central_morguep; - } - cv_signal(&csp->ch_recv_cv); - if (csp->ch_recv.c_waiters > 0) - cv_broadcast(&csp->ch_recv.c_cv); - /* - * 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. - */ - csp->ch_bound_cpuid_pending = csp->ch_bound_cpuid; - csp->ch_bound_cpuid = -1; - IDN_CHAN_UNLOCK_LOCAL(csp); - IDN_CHAN_UNLOCK_GLOBAL(csp); - cs_count++; - } - PR_CHAN("%s: signaled %d chansvrs for chanset 0x%x\n", - proc, cs_count, chanset); - - if ((chanop == IDNCHAN_SOFT_CLOSE) || (chanop == IDNCHAN_OFFLINE)) - return (cs_count); - - PR_CHAN("%s: waiting for %d (chnset=0x%x) chan svrs to term\n", - proc, cs_count, chanset); - PR_CHAN("%s: morguep = 0x%p\n", proc, (void *)central_morguep); - - ASSERT((cs_count > 0) ? (central_morguep != NULL) : 1); - while (cs_count-- > 0) - sema_p(central_morguep); - - if (central_morguep) { - sema_destroy(central_morguep); - FREESTRUCT(central_morguep, ksema_t, 1); - } - - return (cs_count); -} - -int -idn_chanservers_init() -{ - int c; - idn_chansvr_t *csp; - - - if (idn.chan_servers) - return (0); - - idn.chan_servers = GETSTRUCT(idn_chansvr_t, IDN_MAXMAX_NETS); - - for (c = 0; c < IDN_MAXMAX_NETS; c++) { - csp = &idn.chan_servers[c]; - mutex_init(&csp->ch_send.c_mutex, NULL, MUTEX_DEFAULT, NULL); - mutex_init(&csp->ch_recv.c_mutex, NULL, MUTEX_DEFAULT, NULL); - cv_init(&csp->ch_send.c_cv, NULL, CV_DRIVER, NULL); - cv_init(&csp->ch_recv.c_cv, NULL, CV_DRIVER, NULL); - cv_init(&csp->ch_recv_cv, NULL, CV_DRIVER, NULL); - csp->ch_bound_cpuid = -1; - csp->ch_bound_cpuid_pending = -1; - } - - return (c); -} - -void -idn_chanservers_deinit() -{ - int c; - idn_chansvr_t *csp; - - - if (idn.chan_servers == NULL) - return; - - for (c = 0; c < IDN_MAXMAX_NETS; c++) { - csp = &idn.chan_servers[c]; - - mutex_destroy(&csp->ch_send.c_mutex); - mutex_destroy(&csp->ch_recv.c_mutex); - cv_destroy(&csp->ch_send.c_cv); - cv_destroy(&csp->ch_recv.c_cv); - cv_destroy(&csp->ch_recv_cv); - } - - FREESTRUCT(idn.chan_servers, idn_chansvr_t, IDN_MAXMAX_NETS); - idn.chan_servers = NULL; -} - -static void -idn_exec_chanactivate(void *chn) -{ - int not_active, channel; - idn_chansvr_t *csp; - - channel = (int)(uintptr_t)chn; - - IDN_GLOCK_SHARED(); - if (idn.chan_servers == NULL) { - IDN_GUNLOCK(); - return; - } - csp = &idn.chan_servers[channel]; - - 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 (IDN_CHANNEL_IS_PENDING(csp) && lock_try(&csp->ch_actvlck)) { - IDN_CHAN_UNLOCK_GLOBAL(csp); - not_active = idn_activate_channel(CHANSET(channel), - IDNCHAN_OPEN); - if (not_active) - lock_clear(&csp->ch_actvlck); - } else { - IDN_CHAN_UNLOCK_GLOBAL(csp); - } -} - -/* - * 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 -idn_submit_chanactivate_job(int channel) -{ - idn_chansvr_t *csp; - - if (idn.chan_servers == NULL) - return; - csp = &idn.chan_servers[channel]; - - if (lock_try(&csp->ch_initlck) == 0) - return; - - (void) timeout(idn_exec_chanactivate, (caddr_t)(uintptr_t)channel, 1); -} - -/*ARGSUSED0*/ -static void -idn_xmit_monitor(void *unused) -{ - int c, d; - idn_chansvr_t *csp; - idn_chanset_t wake_set; - domainset_t conset; - smr_slab_t *sp; - procname_t proc = "idn_xmit_monitor"; - - CHANSET_ZERO(wake_set); - - mutex_enter(&idn.xmit_lock); - if ((idn.xmit_tid == NULL) || !idn.xmit_chanset_wanted) { - idn.xmit_tid = NULL; - mutex_exit(&idn.xmit_lock); - PR_XMON("%s: bailing out\n", proc); - return; - } - - /* - * No point in transmitting unless state - * is ONLINE. - */ - if (idn.state != IDNGS_ONLINE) - goto retry; - - conset = idn.domset.ds_connected; - - /* - * 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; - - if (idn_domain[d].dcpu != IDN_NIL_DCPU) - (void) idn_reclaim_mboxdata(d, 0, -1); - - IDN_DUNLOCK(d); - } - - /* - * Now check if we were successful in getting - * any buffers. - */ - DSLAB_LOCK_SHARED(idn.localid); - sp = idn_domain[idn.localid].dslab; - for (; sp; sp = sp->sl_next) - if (sp->sl_free) - break; - DSLAB_UNLOCK(idn.localid); - - /* - * If there are no buffers available, - * no point in reenabling the queues. - */ - if (sp == NULL) - goto retry; - - CHANSET_ZERO(wake_set); - for (c = 0; c < IDN_MAX_NETS; c++) { - int pending_bits; - struct idn *sip; - - if (!CHAN_IN_SET(idn.xmit_chanset_wanted, c)) - continue; - - csp = &idn.chan_servers[c]; - if (!IDN_CHAN_TRYLOCK_GLOBAL(csp)) - continue; - - pending_bits = csp->ch_state & IDN_CHANSVC_PENDING_BITS; - - sip = IDN_INST2SIP(c); - - if (!csp->ch_send.c_checkin && - (pending_bits == IDN_CHANSVC_PENDING_BITS) && - sip && (sip->si_flags & IDNRUNNING)) { - - IDN_CHAN_UNLOCK_GLOBAL(csp); - CHANSET_ADD(wake_set, c); - - PR_XMON("%s: QENABLE for channel %d\n", proc, c); - - rw_enter(&idn.struprwlock, RW_READER); - mutex_enter(&idn.sipwenlock); - idndl_wenable(sip); - mutex_exit(&idn.sipwenlock); - rw_exit(&idn.struprwlock); - } else { - IDN_CHAN_UNLOCK_GLOBAL(csp); - } - } - - /* - * Clear the channels we enabled. - */ - idn.xmit_chanset_wanted &= ~wake_set; - -retry: - - if (idn.xmit_chanset_wanted == 0) - idn.xmit_tid = NULL; - else - idn.xmit_tid = timeout(idn_xmit_monitor, NULL, - idn_xmit_monitor_freq); - - mutex_exit(&idn.xmit_lock); -} - -void -idn_xmit_monitor_kickoff(int chan_wanted) -{ - procname_t proc = "idn_xmit_monitor_kickoff"; - - mutex_enter(&idn.xmit_lock); - - if (chan_wanted < 0) { - /* - * Wants all channels. - */ - idn.xmit_chanset_wanted = CHANSET_ALL; - } else { - CHANSET_ADD(idn.xmit_chanset_wanted, chan_wanted); - } - - if (idn.xmit_tid != (timeout_id_t)NULL) { - /* - * A monitor is already running, so - * he will catch the new "wants" when - * he comes around. - */ - mutex_exit(&idn.xmit_lock); - return; - } - - PR_XMON("%s: xmit_mon kicked OFF (chanset = 0x%x)\n", - proc, idn.xmit_chanset_wanted); - - idn.xmit_tid = timeout(idn_xmit_monitor, NULL, idn_xmit_monitor_freq); - - mutex_exit(&idn.xmit_lock); -} diff --git a/usr/src/uts/sun4u/starfire/io/idn_smr.c b/usr/src/uts/sun4u/starfire/io/idn_smr.c deleted file mode 100644 index be520d731c..0000000000 --- a/usr/src/uts/sun4u/starfire/io/idn_smr.c +++ /dev/null @@ -1,2178 +0,0 @@ -/* - * 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 - * or http://www.opensolaris.org/os/licensing. - * 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. - * Copyright (c) 2016 by Delphix. All rights reserved. - * - * Inter-Domain Network - * - * Shared Memory Region (SMR) supporting code. - */ - -#include <sys/types.h> -#include <sys/param.h> -#include <sys/machparam.h> -#include <sys/debug.h> -#include <sys/cpuvar.h> -#include <sys/kmem.h> -#include <sys/mutex.h> -#include <sys/rwlock.h> -#include <sys/systm.h> -#include <sys/machlock.h> -#include <sys/membar.h> -#include <sys/mman.h> -#include <vm/hat.h> -#include <vm/as.h> -#include <vm/hat_sfmmu.h> -#include <sys/vm_machparam.h> -#include <sys/x_call.h> - -#include <sys/idn.h> - -#ifdef DEBUG -#define DIOCHECK(domid) \ -{ \ - int _dio; \ - if ((_dio = idn_domain[domid].dio) < 0) { \ - cmn_err(CE_WARN, \ - ">>>>> file %s, line %d: domain %d, dio = %d", \ - __FILE__, __LINE__, (domid), _dio); \ - } \ -} -#else -#define DIOCHECK(domid) -#endif /* DEBUG */ - -static int smr_slab_alloc_local(int domid, smr_slab_t **spp); -static int smr_slab_alloc_remote(int domid, smr_slab_t **spp); -static void smr_slab_free_local(int domid, smr_slab_t *sp); -static void smr_slab_free_remote(int domid, smr_slab_t *sp); -static int smr_slabwaiter_register(int domid); -static int smr_slabwaiter_unregister(int domid, smr_slab_t **spp); -static int smr_slaballoc_wait(int domid, smr_slab_t **spp); -static smr_slab_t *smr_slab_reserve(int domid); -static void smr_slab_unreserve(int domid, smr_slab_t *sp); -static void smr_slab_reap_global(); - -/* - * Can only be called by the master. Allocate a slab from the - * local pool representing the SMR, on behalf of the given - * domain. Slab is either being requested for use by the - * local domain (i.e. domid == idn.localid), or it's being - * allocated to give to a remote domain which requested one. - * In the base of allocating on behalf of a remote domain, - * smr_slab_t structure is used simply to manage ownership. - * - * Returns: smr_slaballoc_wait - * (EINVAL, ETIMEDOUT) - * smr_slabwatier_unregister - * (0, EINVAL, EBUSY, ENOMEM) - * ENOLCK - */ -static int -smr_slab_alloc_local(int domid, smr_slab_t **spp) -{ - int serrno = 0; - int nwait; - smr_slab_t *sp; - idn_domain_t *dp; - - - /* - * Only the master can make local allocations. - */ - ASSERT(IDN_GET_MASTERID() != IDN_NIL_DOMID); - ASSERT(idn.localid == IDN_GET_MASTERID()); - - *spp = NULL; - - dp = &idn_domain[domid]; - ASSERT(DSLAB_READ_HELD(domid)); - ASSERT(dp->dslab_state == DSLAB_STATE_LOCAL); - - /* - * Register myself with the waiting list. - */ - nwait = smr_slabwaiter_register(domid); - - if (nwait > 1) { - /* - * XXX - old comment? - * Need to drop the read lock _after_ registering - * ourselves with the potential wait list for this allocation. - * Although this allocation is not a remote one, we could - * still have multiple threads on the master trying to - * satisfy (allocate) request on behalf of a remote domain. - */ - /* - * Somebody is already in the process of satisfying - * the allocation request for this respective - * domain. All we need to do is wait and let - * it happen. - */ - serrno = smr_slaballoc_wait(domid, spp); - return (serrno); - } - /* - * I'm the original slab requester for this domain. It's local - * so go ahead and do the job. - */ - - if ((sp = smr_slab_reserve(domid)) == NULL) - serrno = ENOMEM; - - /* - * Allocation may have failed. In either case we've - * got to do the put to at least wake potential waiters up. - */ - if (!serrno) { - if (DSLAB_LOCK_TRYUPGRADE(domid) == 0) { - DSLAB_UNLOCK(domid); - DSLAB_LOCK_EXCL(domid); - } - } - - (void) smr_slaballoc_put(domid, sp, 0, serrno); - - /* - * If serrno is ENOLCK here, then we must have failed - * on the upgrade above, so lock already dropped. - */ - if (serrno != ENOLCK) { - /* - * Need to drop since reaping may be recursive? - */ - DSLAB_UNLOCK(domid); - } - - /* - * Since we were the original requester but never went - * to sleep, we need to directly unregister ourselves - * from the waiting list. - */ - serrno = smr_slabwaiter_unregister(domid, spp); - - /* - * Now that we've satisfied the request, let's check if any - * reaping is necessary. Only the master does this and only - * when allocating slabs, an infrequent event :-o - */ - smr_slab_reap_global(); - - ASSERT((serrno == 0) ? (*spp != NULL) : (*spp == NULL)); - - DSLAB_LOCK_SHARED(domid); - - return (serrno); -} - -/* - * Can only be called by a slave on behalf of himself. Need to - * make a request to the master to allocate a slab of SMR buffers - * for the local domain. - * - * Returns: smr_slaballoc_wait - * (0, EINVAL, EBUSY, ENOMEM) - * ENOLCK - * ECANCELED - */ -static int -smr_slab_alloc_remote(int domid, smr_slab_t **spp) -{ - int nwait; - int serrno = 0; - int bailout = 0; - int masterid; - idn_domain_t *dp, *mdp = NULL; - procname_t proc = "smr_slab_alloc_remote"; - - /* - * Only slaves make remote allocations. - */ - ASSERT(idn.localid != IDN_GET_MASTERID()); - ASSERT(domid == idn.localid); - ASSERT(IDN_GET_MASTERID() != IDN_NIL_DOMID); - - *spp = NULL; - - dp = &idn_domain[domid]; - ASSERT(DSLAB_READ_HELD(domid)); - ASSERT(dp->dslab_state == DSLAB_STATE_REMOTE); - - /* - * Register myself with the slaballoc waiting list. - * Note that only allow one outstanding allocation - * request for the given domain. Other callers which - * detect a slab is needed simply get stuck on the - * waiting list waiting for the original caller to - * get the job done. - * The waiter_register routine will allocate the necessary - * slab structure which will ultimately be inserted in - * the domain's slab list via smr_slaballoc_put(). - */ - nwait = smr_slabwaiter_register(domid); - - /* - * Make sure we have a connection with the master - * before we wait around for nothing and send a - * command off to nowhere. - * First do a quick (no lock) check for global okayness. - */ - if ((idn.state != IDNGS_ONLINE) || - ((masterid = IDN_GET_MASTERID()) == IDN_NIL_DOMID)) { - bailout = 1; - serrno = ECANCELED; - } - /* - * We need to drop our read lock _before_ acquiring the - * slaballoc waiter lock. This is necessary because the - * thread that receives the slab alloc response and fills - * in the slab structure will need to grab the domain write - * lock while holding onto the slaballoc waiter lock. - * Potentially could deadlock if we didn't drop our domain - * lock before. Plus, we've registered. - * - * 4093209 - Note also that we do this _after_ the check for - * idn.masterid where we grab the READER global - * lock. This is to prevent somebody from - * changing our state after we drop the drwlock. - * A deadlock can occur when shutting down a - * domain we're holding the - */ - - if (!bailout) { - mdp = &idn_domain[masterid]; - /* - * Global state is okay. Let's double check the - * state of our actual target domain. - */ - if (mdp->dstate != IDNDS_CONNECTED) { - bailout = 1; - serrno = ECANCELED; - } else if (IDN_DLOCK_TRY_SHARED(masterid)) { - if (mdp->dstate != IDNDS_CONNECTED) { - bailout = 1; - serrno = ECANCELED; - IDN_DUNLOCK(masterid); - } else if (nwait != 1) { - IDN_DUNLOCK(masterid); - } - /* - * Note that keep the drwlock(read) for - * the target (master) domain if it appears - * we're the lucky one to send the command. - * We hold onto the lock until we've actually - * sent the command out. - * We don't reach this place unless it - * appears everything is kosher with - * the target (master) domain. - */ - } else { - bailout = 1; - serrno = ENOLCK; - } - } - - if (bailout) { - ASSERT(serrno); - /* - * Gotta bail. Abort operation. Error result - * will be picked up when we attempt to wait. - */ - PR_SMR("%s: BAILING OUT on behalf domain %d " - "(err=%d, gs=%s, ms=%s)\n", - proc, domid, serrno, idngs_str[idn.state], - (masterid == IDN_NIL_DOMID) - ? "unknown" : idnds_str[idn_domain[masterid].dstate]); - (void) smr_slabwaiter_abort(domid, serrno); - - } else if (nwait == 1) { - /* - * We are the original requester. Initiate the - * actual request to the master. - */ - idn_send_cmd(masterid, IDNCMD_SLABALLOC, IDN_SLAB_SIZE, 0, 0); - ASSERT(mdp); - IDN_DUNLOCK(masterid); - } - - /* - * Wait here for response. Once awakened func returns - * with slab structure possibly filled with gifts! - */ - serrno = smr_slaballoc_wait(domid, spp); - - return (serrno); -} - -/* - * Allocate a slab from the Master on behalf - * of the given domain. Note that master uses - * this function to allocate slabs on behalf of - * remote domains also. - * Entered with drwlock held. - * Leaves with drwlock dropped. - * Returns: EDQUOT - * EINVAL - * ENOLCK - * smr_slab_alloc_local - * smr_slab_alloc_remote - * (0, EINVAL, EBUSY, ENOMEM) - */ -int -smr_slab_alloc(int domid, smr_slab_t **spp) -{ - int serrno = 0; - idn_domain_t *dp; - procname_t proc = "smr_slab_alloc"; - - - dp = &idn_domain[domid]; - - ASSERT(DSLAB_READ_HELD(domid)); - ASSERT(dp->dslab_state != DSLAB_STATE_UNKNOWN); - - *spp = NULL; - - switch (dp->dslab_state) { - case DSLAB_STATE_UNKNOWN: - cmn_err(CE_WARN, - "IDN: 300: no slab allocations without a master"); - serrno = EINVAL; - break; - - case DSLAB_STATE_LOCAL: - /* - * If I'm the master, then get a slab - * from the local SMR pool, but only - * if the number of allocated slabs has - * not been exceeded. - */ - if (((int)dp->dnslabs < IDN_SLAB_MAXPERDOMAIN) || - !IDN_SLAB_MAXPERDOMAIN) - serrno = smr_slab_alloc_local(domid, spp); - else - serrno = EDQUOT; - break; - - case DSLAB_STATE_REMOTE: - /* - * Have to make a remote request. - * In order to prevent overwhelming the master - * with a bunch of requests that it won't be able - * to handle we do a check to see if we're still - * under quota. Note that the limit is known - * apriori based on the SMR/NWR size and - * IDN_SLAB_MINTOTAL. Domains must have the same - * size SMR/NWR, however they can have different - * IDN_SLAB_MINTOTAL. Thus a domain could throttle - * itself however it wishes. - */ - if (((int)dp->dnslabs < IDN_SLAB_MAXPERDOMAIN) || - !IDN_SLAB_MAXPERDOMAIN) - serrno = smr_slab_alloc_remote(domid, spp); - else - serrno = EDQUOT; - break; - - default: - cmn_err(CE_WARN, - "IDN: 301: (ALLOC) unknown slab state (%d) " - "for domain %d", dp->dslab_state, domid); - serrno = EINVAL; - break; - } - - if (*spp == NULL) { - PR_SMR("%s: failed to allocate %s slab [serrno = %d]\n", - proc, (idn.localid == IDN_GET_MASTERID()) ? - "local" : "remote", serrno); - } - - if (serrno) { - IDN_GKSTAT_GLOBAL_EVENT(gk_slabfail, gk_slabfail_last); - } - - return (serrno); -} - -static void -smr_slab_free_local(int domid, smr_slab_t *sp) -{ - int rv; - - /* - * Do a slaballoc_put just in case there may have - * been waiters for slabs for this respective domain - * before we unreserve this slab. - */ - rv = smr_slaballoc_put(domid, sp, 0, 0); - - if (rv == -1) { - /* - * Put failed. Must not have been any waiters. - * Go ahead and unreserve the space. - */ - smr_slab_unreserve(domid, sp); - } -} - -static void -smr_slab_free_remote(int domid, smr_slab_t *sp) -{ - smr_offset_t slab_offset; - int slab_size; - int rv; - int masterid; - - ASSERT(domid == idn.localid); - ASSERT(idn.localid != IDN_GET_MASTERID()); - ASSERT(DSLAB_WRITE_HELD(domid)); - ASSERT(idn_domain[domid].dslab_state == DSLAB_STATE_REMOTE); - - masterid = IDN_GET_MASTERID(); - - ASSERT(masterid != IDN_NIL_DOMID); - - slab_offset = IDN_ADDR2OFFSET(sp->sl_start); - slab_size = (int)(sp->sl_end - sp->sl_start); - - /* - * Do a slaballoc_put just in case there may have - * been waiters for slabs for this domain before - * returning back to the master. - */ - rv = smr_slaballoc_put(domid, sp, 0, 0); - - if ((rv == -1) && (masterid != IDN_NIL_DOMID)) { - /* - * Put failed. No waiters so free the local data - * structure ship the SMR range off to the master. - */ - smr_free_buflist(sp); - FREESTRUCT(sp, smr_slab_t, 1); - - IDN_DLOCK_SHARED(masterid); - idn_send_cmd(masterid, IDNCMD_SLABFREE, slab_offset, slab_size, - 0); - IDN_DUNLOCK(masterid); - } -} - -/* - * Free up the list of slabs passed - */ -void -smr_slab_free(int domid, smr_slab_t *sp) -{ - smr_slab_t *nsp = NULL; - - ASSERT(DSLAB_WRITE_HELD(domid)); - - if (sp == NULL) - return; - - ASSERT(IDN_GET_MASTERID() != IDN_NIL_DOMID); - - switch (idn_domain[domid].dslab_state) { - case DSLAB_STATE_UNKNOWN: - cmn_err(CE_WARN, "IDN: 302: no slab free without a master"); - break; - - case DSLAB_STATE_LOCAL: - /* - * If I'm the master then put the slabs - * back to the local SMR pool. - */ - for (; sp; sp = nsp) { - nsp = sp->sl_next; - smr_slab_free_local(domid, sp); - } - break; - - case DSLAB_STATE_REMOTE: - /* - * If the domid is my own then I'm freeing - * a slab back to the Master. - */ - for (; sp; sp = nsp) { - nsp = sp->sl_next; - smr_slab_free_remote(domid, sp); - } - break; - - default: - cmn_err(CE_WARN, - "IDN: 301: (FREE) unknown slab state (%d) for domain %d", - idn_domain[domid].dslab_state, domid); - break; - } -} - -/* - * Free up the list of slab data structures ONLY. - * This is called during a fatal shutdown of the master - * where we need to garbage collect the locally allocated - * data structures used to manage slabs allocated to the - * local domain. Should never be called by a master since - * the master can do a regular smr_slab_free. - */ -void -smr_slab_garbage_collection(smr_slab_t *sp) -{ - smr_slab_t *nsp; - - ASSERT(idn_domain[idn.localid].dvote.v.master == 0); - - if (sp == NULL) - return; - /* - * Since this is only ever called by a slave, - * the slab structure size always contains a buflist. - */ - for (; sp; sp = nsp) { - nsp = sp->sl_next; - smr_free_buflist(sp); - FREESTRUCT(sp, smr_slab_t, 1); - } -} - -/* - * Allocate a SMR buffer on behalf of the local domain - * which is ultimately targeted for the given domain. - * - * IMPORTANT: This routine is going to drop the domain rwlock (drwlock) - * for the domain on whose behalf the request is being - * made. This routine canNOT block on trying to - * reacquire the drwlock. If it does block then somebody - * must have the write lock on the domain which most likely - * means the domain is going south anyway, so just bail on - * this buffer. Higher levels will retry if needed. - * - * XXX - Support larger than IDN_SMR_BUFSIZE allocations? - * - * Returns: A negative return value indicates lock lost on domid. - * EINVAL, ENOLINK, ENOLCK(internal) - * smr_slaballoc_wait - * (EINVAL, ETIMEDOUT) - * smr_slabwatier_unregister - * (0, EINVAL, EBUSY, ENOMEM) - */ -int -smr_buf_alloc(int domid, uint_t len, caddr_t *bufpp) -{ - register idn_domain_t *dp, *ldp; - smr_slab_t *sp; - caddr_t bufp = NULL; - int serrno; - procname_t proc = "smr_buf_alloc"; - - dp = &idn_domain[domid]; - /* - * Local domain can only allocate on behalf of - * itself if this is a priviledged call and the - * caller is the master. - */ - ASSERT((domid != idn.localid) && (domid != IDN_NIL_DOMID)); - - *bufpp = NULL; - - if (len > IDN_DATA_SIZE) { - cmn_err(CE_WARN, - "IDN: 303: buffer len %d > IDN_DATA_SIZE (%lu)", - len, IDN_DATA_SIZE); - IDN_GKSTAT_GLOBAL_EVENT(gk_buffail, gk_buffail_last); - return (EINVAL); - } - - /* - * Need to go to my local slab list to find - * a buffer. - */ - ldp = &idn_domain[idn.localid]; - /* - * Now we loop trying to locate a buffer out of our - * slabs. We continue this until either we find a - * buffer or we're unable to allocate a slab. Note - * that new slabs are allocated to the front. - */ - DSLAB_LOCK_SHARED(idn.localid); - sp = ldp->dslab; - do { - int spl, all_empty; - - if (sp == NULL) { - if ((serrno = smr_slab_alloc(idn.localid, &sp)) != 0) { - PR_SMR("%s:%d: failed to allocate " - "slab [serrno = %d]", - proc, domid, serrno); - DSLAB_UNLOCK(idn.localid); - IDN_GKSTAT_GLOBAL_EVENT(gk_buffail, - gk_buffail_last); - return (serrno); - } - /* - * Of course, the world may have changed while - * we dropped the lock. Better make sure we're - * still established. - */ - if (dp->dstate != IDNDS_CONNECTED) { - PR_SMR("%s:%d: state changed during slab " - "alloc (dstate = %s)\n", - proc, domid, idnds_str[dp->dstate]); - DSLAB_UNLOCK(idn.localid); - IDN_GKSTAT_GLOBAL_EVENT(gk_buffail, - gk_buffail_last); - return (ENOLINK); - } - /* - * We were able to allocate a slab. Should - * be at the front of the list, spin again. - */ - sp = ldp->dslab; - } - /* - * If we have reached here then we have a slab! - * Hopefully there are free bufs there :-o - */ - spl = splhi(); - all_empty = 1; - for (; sp && !bufp; sp = sp->sl_next) { - smr_slabbuf_t *bp; - - if (sp->sl_free == NULL) - continue; - - if (!lock_try(&sp->sl_lock)) { - all_empty = 0; - continue; - } - - if ((bp = sp->sl_free) == NULL) { - lock_clear(&sp->sl_lock); - continue; - } - - sp->sl_free = bp->sb_next; - bp->sb_next = sp->sl_inuse; - sp->sl_inuse = bp; - /* - * Found a free buffer. - */ - bp->sb_domid = domid; - bufp = bp->sb_bufp; - lock_clear(&sp->sl_lock); - } - splx(spl); - - if (!all_empty && !bufp) { - /* - * If we still haven't found a buffer, but - * there's still possibly a buffer available, - * then try again. Only if we're absolutely - * sure all slabs are empty do we attempt - * to allocate a new one. - */ - sp = ldp->dslab; - } - } while (bufp == NULL); - - *bufpp = bufp; - - ATOMIC_INC(dp->dio); - - DSLAB_UNLOCK(idn.localid); - - return (0); -} - -/* - * Free a buffer allocated to the local domain back to - * its respective slab. Slabs are freed via the slab-reap command. - * XXX - Support larger than IDN_SMR_BUFSIZE allocations? - */ -int -smr_buf_free(int domid, caddr_t bufp, uint_t len) -{ - register smr_slab_t *sp; - smr_slabbuf_t *bp, **bpp; - idn_domain_t *ldp; - int buffreed; - int lockheld = (len == (uint_t)-1); - - /* - * We should never be free'ing a buffer on - * behalf of ourselves as we are never the - * target for allocated SMR buffers. - */ - ASSERT(domid != idn.localid); - - sp = NULL; - buffreed = 0; - ldp = &idn_domain[idn.localid]; - - DSLAB_LOCK_SHARED(idn.localid); - - if (((uintptr_t)bufp & (IDN_SMR_BUFSIZE-1)) && - (IDN_ADDR2OFFSET(bufp) % IDN_SMR_BUFSIZE)) { - cmn_err(CE_WARN, - "IDN: 304: buffer (0x%p) from domain %d not on a " - "%d boundary", (void *)bufp, domid, IDN_SMR_BUFSIZE); - goto bfdone; - } - if (!lockheld && (len > IDN_DATA_SIZE)) { - cmn_err(CE_WARN, - "IDN: 305: buffer length (%d) from domain %d greater " - "than IDN_DATA_SIZE (%lu)", - len, domid, IDN_DATA_SIZE); - goto bfdone; - } - - for (sp = ldp->dslab; sp; sp = sp->sl_next) - if ((bufp >= sp->sl_start) && (bufp < sp->sl_end)) - break; - - if (sp) { - int spl; - - spl = splhi(); - while (!lock_try(&sp->sl_lock)) - ; - bpp = &sp->sl_inuse; - for (bp = *bpp; bp; bp = *bpp) { - if (bp->sb_bufp == bufp) - break; - bpp = &bp->sb_next; - } - if (bp) { - ASSERT(bp->sb_domid == domid); - buffreed++; - bp->sb_domid = IDN_NIL_DOMID; - *bpp = bp->sb_next; - bp->sb_next = sp->sl_free; - sp->sl_free = bp; - } - lock_clear(&sp->sl_lock); - splx(spl); - } -bfdone: - if (buffreed) { - ATOMIC_DEC(idn_domain[domid].dio); - DIOCHECK(domid); - } else { - cmn_err(CE_WARN, - "IDN: 306: unknown buffer (0x%p) from domain %d", - (void *)bufp, domid); - ATOMIC_INC(idn_domain[domid].dioerr); - } - - DSLAB_UNLOCK(idn.localid); - - return (sp ? 0 : -1); -} - -/* - * Alternative interface to smr_buf_free, but with local drwlock - * held. - */ -/* ARGSUSED2 */ -int -smr_buf_free_locked(int domid, caddr_t bufp, uint_t len) -{ - return (smr_buf_free(domid, bufp, (uint_t)-1)); -} - -/* - * Free any and all buffers associated with the given domain. - * Assumption is that domain is dead and buffers are not in use. - * Returns: Number of buffers freed. - * -1 if error. - */ -int -smr_buf_free_all(int domid) -{ - register smr_slab_t *sp; - register smr_slabbuf_t *bp, **bpp; - idn_domain_t *ldp; - int nbufsfreed = 0; - procname_t proc = "smr_buf_free_all"; - - /* - * We should never be free'ing buffers on - * behalf of ourself - */ - ASSERT(domid != idn.localid); - - if (!VALID_DOMAINID(domid)) { - cmn_err(CE_WARN, "IDN: 307: domain ID (%d) invalid", domid); - return (-1); - } - - ldp = &idn_domain[idn.localid]; - - /* - * We grab the writer lock so that we don't have any - * competition during a "free-all" call. - * No need to grab individual slab locks when holding - * dslab(writer). - */ - DSLAB_LOCK_EXCL(idn.localid); - - for (sp = ldp->dslab; sp; sp = sp->sl_next) { - bpp = &sp->sl_inuse; - for (bp = *bpp; bp; bp = *bpp) { - if (bp->sb_domid == domid) { - bp->sb_domid = IDN_NIL_DOMID; - *bpp = bp->sb_next; - bp->sb_next = sp->sl_free; - sp->sl_free = bp; - nbufsfreed++; - } else { - bpp = &bp->sb_next; - } - } - } - - if (nbufsfreed > 0) { - ATOMIC_SUB(idn_domain[domid].dio, nbufsfreed); - idn_domain[domid].dioerr = 0; - DIOCHECK(domid); - } - - DSLAB_UNLOCK(idn.localid); - - PR_SMR("%s: freed %d buffers for domain %d\n", proc, nbufsfreed, domid); - - return (nbufsfreed); -} - -int -smr_buf_reclaim(int domid, int nbufs) -{ - int num_reclaimed = 0; - idn_domain_t *ldp, *dp; - procname_t proc = "smr_buf_reclaim"; - - ldp = &idn_domain[idn.localid]; - dp = &idn_domain[domid]; - - ASSERT(domid != idn.localid); - - if (ATOMIC_CAS(&dp->dreclaim_inprogress, 0, 1)) { - /* - * Reclaim is already in progress, don't - * bother. - */ - PR_DATA("%s: reclaim already in progress\n", proc); - return (0); - } - - PR_SMR("%s: requested %d buffers from domain %d\n", proc, nbufs, domid); - - if (dp->dio && nbufs) { - register smr_slab_t *sp; - int spl; - - DSLAB_LOCK_SHARED(idn.localid); - spl = splhi(); - for (sp = ldp->dslab; sp && nbufs; sp = sp->sl_next) { - register smr_slabbuf_t *bp, **bpp; - - if (sp->sl_inuse == NULL) - continue; - - if (!lock_try(&sp->sl_lock)) - continue; - - if (sp->sl_inuse == NULL) { - lock_clear(&sp->sl_lock); - continue; - } - - bpp = &sp->sl_inuse; - for (bp = *bpp; bp && nbufs; bp = *bpp) { - if (bp->sb_domid == domid) { - /* - * Buffer no longer in use, - * reclaim it. - */ - bp->sb_domid = IDN_NIL_DOMID; - *bpp = bp->sb_next; - bp->sb_next = sp->sl_free; - sp->sl_free = bp; - num_reclaimed++; - nbufs--; - } else { - bpp = &bp->sb_next; - } - } - lock_clear(&sp->sl_lock); - } - splx(spl); - - if (num_reclaimed > 0) { - ATOMIC_SUB(dp->dio, num_reclaimed); - DIOCHECK(domid); - } - DSLAB_UNLOCK(idn.localid); - } - - PR_SMR("%s: reclaimed %d buffers from domain %d\n", - proc, num_reclaimed, domid); - - return (num_reclaimed); -} - -/* - * Returns 1 If any buffers are locked for the given slab. - * 0 If all buffers are free for the given slab. - * - * The caller is assumed to have the slab protected so that no - * new allocations are attempted from it. Also, this is only - * valid to be called with respect to slabs that were allocated - * on behalf of the local domain, i.e. the master is not expected - * to call this function with (slave) slab "representatives". - */ -int -smr_slab_busy(smr_slab_t *sp) -{ - return ((sp && sp->sl_inuse) ? 1 : 0); -} - -int -smr_slabwaiter_init() -{ - register int i; - struct slabwaiter *wp; - - if (idn.slabwaiter != NULL) - return (0); - - /* - * Initialize the slab waiting area for MAX_DOMAINS. - */ - idn.slabwaiter = GETSTRUCT(struct slabwaiter, MAX_DOMAINS); - wp = idn.slabwaiter; - for (i = 0; i < MAX_DOMAINS; wp++, i++) { - wp->w_closed = 0; - mutex_init(&wp->w_mutex, NULL, MUTEX_DEFAULT, NULL); - cv_init(&wp->w_cv, NULL, CV_DEFAULT, NULL); - } - - return (0); -} - -void -smr_slabwaiter_deinit() -{ - register int i; - struct slabwaiter *wp; - - if ((wp = idn.slabwaiter) == NULL) - return; - - for (i = 0; i < MAX_DOMAINS; wp++, i++) { - ASSERT(wp->w_nwaiters == 0); - ASSERT(wp->w_sp == NULL); - cv_destroy(&wp->w_cv); - mutex_destroy(&wp->w_mutex); - } - - FREESTRUCT(idn.slabwaiter, struct slabwaiter, MAX_DOMAINS); - idn.slabwaiter = NULL; -} - -void -smr_slabwaiter_open(domainset_t domset) -{ - int d; - struct slabwaiter *wp; - - if ((domset == 0) || !idn.slabwaiter) - return; - - wp = idn.slabwaiter; - - for (d = 0; d < MAX_DOMAINS; wp++, d++) { - if (!DOMAIN_IN_SET(domset, d)) - continue; - mutex_enter(&wp->w_mutex); - wp->w_closed = 0; - mutex_exit(&wp->w_mutex); - } -} - -void -smr_slabwaiter_close(domainset_t domset) -{ - int d; - struct slabwaiter *wp; - - if ((domset == 0) || !idn.slabwaiter) - return; - - wp = idn.slabwaiter; - - for (d = 0; d < MAX_DOMAINS; wp++, d++) { - if (!DOMAIN_IN_SET(domset, d)) - continue; - mutex_enter(&wp->w_mutex); - wp->w_closed = 1; - cv_broadcast(&wp->w_cv); - mutex_exit(&wp->w_mutex); - } -} - -/* - * Register the caller with the waiting list for the - * given domain. - * - * Protocol: - * 1st Local requester: register -> alloc -> - * put(wakeup|xdc) -> unregister - * Nth Local requester: register -> wait - * 1st Remote requester: register -> xdc -> wait - * Nth Remote requester: register -> wait - * - * Remote Responder: local alloc -> put(xdc) - * Local Handler: xdc -> put(wakeup) - * - * E.g. A standard slave allocation request: - * slave master - * ----- ------ - * idn_slab_alloc(remote) - * - register - * - xdc -> idn_handler - * - wait ... - * idn_slab_alloc(local) - * - register - * - alloc - * - put - * . wakeup [local] - * - unregister - * idn_handler <- - xdc - * - put DONE - * . wakeup [local] - * | - * V - * - wait - * . unregister - * DONE - */ -static int -smr_slabwaiter_register(int domid) -{ - struct slabwaiter *wp; - int nwait; - procname_t proc = "smr_slabwaiter_register"; - - - ASSERT(domid != IDN_NIL_DOMID); - - ASSERT(DSLAB_READ_HELD(domid)); - - wp = &idn.slabwaiter[domid]; - - ASSERT(MUTEX_NOT_HELD(&wp->w_mutex)); - - mutex_enter(&wp->w_mutex); - - nwait = ++(wp->w_nwaiters); - ASSERT(nwait > 0); - - PR_SMR("%s: domain = %d, (new)nwaiters = %d\n", proc, domid, nwait); - - if (nwait > 1) { - /* - * There are already waiters for slab allocations - * with respect to this domain. - */ - PR_SMR("%s: existing waiters for slabs for domain %d\n", - proc, domid); - mutex_exit(&wp->w_mutex); - - return (nwait); - } - PR_SMR("%s: initial waiter for slabs for domain %d\n", proc, domid); - /* - * We are the first requester of a slab allocation for this - * respective domain. Need to prep waiting area for - * subsequent arrival of a slab. - */ - wp->w_sp = NULL; - wp->w_done = 0; - wp->w_serrno = 0; - - mutex_exit(&wp->w_mutex); - - return (nwait); -} - -/* - * It is assumed that the caller had previously registered, - * but wakeup did not occur due to caller never waiting. - * Thus, slaballoc mutex is still held by caller. - * - * Returns: 0 - * EINVAL - * EBUSY - * w_serrno (smr_slaballoc_put) - * (0, ENOLCK, ENOMEM, EDQUOT, EBUSY, ECANCELED) - */ -static int -smr_slabwaiter_unregister(int domid, smr_slab_t **spp) -{ - struct slabwaiter *wp; - int serrno = 0; - procname_t proc = "smr_slabwaiter_unregister"; - - - ASSERT(domid != IDN_NIL_DOMID); - - wp = &idn.slabwaiter[domid]; - - mutex_enter(&wp->w_mutex); - - PR_SMR("%s: domain = %d, nwaiters = %d\n", proc, domid, wp->w_nwaiters); - - if (wp->w_nwaiters <= 0) { - /* - * Hmmm...nobody is registered! - */ - PR_SMR("%s: NO WAITERS (domid = %d)\n", proc, domid); - mutex_exit(&wp->w_mutex); - return (EINVAL); - } - (wp->w_nwaiters)--; - /* - * Is our present under the tree? - */ - if (!wp->w_done) { - /* - * Bummer...no presents. Let the caller know - * via a null slab pointer. - * Note that we don't clean up immediately since - * message might still come in for other waiters. - * Thus, late sleepers may still get a chance. - */ - PR_SMR("%s: bummer no slab allocated for domain %d\n", - proc, domid); - ASSERT(wp->w_sp == NULL); - (*spp) = NULL; - serrno = wp->w_closed ? ECANCELED : EBUSY; - - } else { - (*spp) = wp->w_sp; - serrno = wp->w_serrno; - -#ifdef DEBUG - if (serrno == 0) { - register smr_slab_t *sp; - - ASSERT(wp->w_sp); - PR_SMR("%s: allocation succeeded (domain %d)\n", - proc, domid); - - DSLAB_LOCK_SHARED(domid); - for (sp = idn_domain[domid].dslab; sp; sp = sp->sl_next) - if (sp == wp->w_sp) - break; - if (sp == NULL) - cmn_err(CE_WARN, - "%s:%d: slab ptr = NULL", - proc, domid); - DSLAB_UNLOCK(domid); - } else { - PR_SMR("%s: allocation failed (domain %d) " - "[serrno = %d]\n", proc, domid, serrno); - } -#endif /* DEBUG */ - } - if (wp->w_nwaiters == 0) { - /* - * Last one turns out the lights. - */ - PR_SMR("%s: domain %d last waiter, turning out lights\n", - proc, domid); - wp->w_sp = NULL; - wp->w_done = 0; - wp->w_serrno = 0; - } - mutex_exit(&wp->w_mutex); - - return (serrno); -} - -/* - * Called to abort any slaballoc requests on behalf of the - * given domain. - */ -int -smr_slabwaiter_abort(int domid, int serrno) -{ - ASSERT(serrno != 0); - - return (smr_slaballoc_put(domid, NULL, 0, serrno)); -} - -/* - * Put ourselves into a timedwait waiting for slab to be - * allocated. - * Returns with slaballoc mutex dropped. - * - * Returns: EINVAL - * ETIMEDOUT - * smr_slabwatier_unregister - * (0, EINVAL, EBUSY, ENOMEM) - */ -static int -smr_slaballoc_wait(int domid, smr_slab_t **spp) -{ - struct slabwaiter *wp; - int serrno = 0, serrno_unreg; - procname_t proc = "smr_slaballoc_wait"; - - - wp = &idn.slabwaiter[domid]; - - ASSERT(MUTEX_NOT_HELD(&wp->w_mutex)); - - mutex_enter(&wp->w_mutex); - - PR_SMR("%s: domain = %d, nwaiters = %d, wsp = 0x%p\n", - proc, domid, wp->w_nwaiters, (void *)wp->w_sp); - - if (wp->w_nwaiters <= 0) { - /* - * Hmmm...no waiters registered. - */ - PR_SMR("%s: domain %d, no waiters!\n", proc, domid); - mutex_exit(&wp->w_mutex); - return (EINVAL); - } - ASSERT(DSLAB_READ_HELD(domid)); - DSLAB_UNLOCK(domid); - - if (!wp->w_done && !wp->w_closed) { - int rv; - - /* - * Only wait if data hasn't arrived yet. - */ - PR_SMR("%s: domain %d, going to sleep...\n", proc, domid); - - rv = cv_reltimedwait_sig(&wp->w_cv, &wp->w_mutex, - IDN_SLABALLOC_WAITTIME, TR_CLOCK_TICK); - if (rv == -1) - serrno = ETIMEDOUT; - - PR_SMR("%s: domain %d, awakened (reason = %s)\n", - proc, domid, (rv == -1) ? "TIMEOUT" : "SIGNALED"); - } - /* - * We've awakened or request already filled! - * Unregister ourselves. - */ - mutex_exit(&wp->w_mutex); - - /* - * Any gifts will be entered into spp. - */ - serrno_unreg = smr_slabwaiter_unregister(domid, spp); - - /* - * Leave with reader lock on dslab_lock. - */ - DSLAB_LOCK_SHARED(domid); - - if ((serrno_unreg == EBUSY) && (serrno == ETIMEDOUT)) - return (serrno); - else - return (serrno_unreg); -} - -/* - * A SMR slab was allocated on behalf of the given domain. - * Wakeup anybody that may have been waiting for the allocation. - * Note that if the domain is a remote one, i.e. master is allocating - * on behalf of a slave, it's up to the caller to transmit the - * allocation response to that domain. - * The force flag indicates that we want to install the slab for - * the given user regardless of whether there are waiters or not. - * This is used primarily in situations where a slave may have timed - * out before the response actually arrived. In this situation we - * don't want to send slab back to the master after we went through - * the trouble of allocating one. Master is _not_ allowed to do this - * for remote domains. - * - * Returns: -1 Non-registered waiter or waiting area garbaged. - * 0 Successfully performed operation. - */ -int -smr_slaballoc_put(int domid, smr_slab_t *sp, int forceflag, int serrno) -{ - idn_domain_t *dp; - struct slabwaiter *wp; - procname_t proc = "smr_slaballoc_put"; - - - dp = &idn_domain[domid]; - - ASSERT(!serrno ? DSLAB_WRITE_HELD(domid) : 1); - - if (domid == IDN_NIL_DOMID) - return (-1); - - ASSERT(serrno ? (sp == NULL) : (sp != NULL)); - - wp = &idn.slabwaiter[domid]; - - mutex_enter(&wp->w_mutex); - - PR_SMR("%s: domain = %d, bufp = 0x%p, ebufp = 0x%p, " - "(f = %d, se = %d)\n", proc, domid, - (sp ? (void *)sp->sl_start : 0), - (sp ? (void *)sp->sl_end : 0), forceflag, serrno); - - if (wp->w_nwaiters <= 0) { - /* - * There are no waiters!! Must have timed out - * and left. Oh well... - */ - PR_SMR("%s: no slaballoc waiters found for domain %d\n", - proc, domid); - if (!forceflag || serrno || !sp) { - /* - * No waiters and caller doesn't want to force it. - */ - mutex_exit(&wp->w_mutex); - return (-1); - } - PR_SMR("%s: forcing slab onto domain %d\n", proc, domid); - ASSERT(domid == idn.localid); - ASSERT(wp->w_sp == NULL); - wp->w_done = 0; - /* - * Now we fall through and let it be added in the - * regular manor. - */ - } - if (wp->w_done) { - /* - * There's at least one waiter so there has - * to be a slab structure waiting for us. - * If everything is going smoothly, there should only - * be one guy coming through the path of inserting - * an error or good slab. However, if a disconnect was - * detected, you may get several guys coming through - * trying to let everybody know. - */ - ASSERT(wp->w_serrno ? - (wp->w_sp == NULL) : (wp->w_sp != NULL)); - - cv_broadcast(&wp->w_cv); - mutex_exit(&wp->w_mutex); - - return (-1); - } - if (serrno != 0) { - /* - * Bummer...allocation failed. This call is simply - * to wake up the sleepers and let them know. - */ - PR_SMR("%s: slaballoc failed for domain %d\n", proc, domid); - wp->w_serrno = serrno; - wp->w_done = 1; - cv_broadcast(&wp->w_cv); - mutex_exit(&wp->w_mutex); - - return (0); - } - PR_SMR("%s: putting slab into struct (domid=%d, localid=%d)\n", - proc, domid, idn.localid); - /* - * Prep the slab structure. - */ - - if (domid == idn.localid) { - /* - * Allocation was indeed for me. - * Slab may or may not be locked when - * we reach. Normally they will be locked - * if we're being called on behalf of a - * free, and not locked if on behalf of - * a new allocation request. - */ - lock_clear(&sp->sl_lock); - smr_alloc_buflist(sp); -#ifdef DEBUG - } else { - uint_t rv; - /* - * Slab was not allocated on my behalf. Must be - * a master request on behalf of some other domain. - * Prep appropriately. Slab should have been locked - * by smr_slab_reserve. - */ - rv = lock_try(&sp->sl_lock); - ASSERT(!rv); - ASSERT(sp->sl_domid == (short)domid); -#endif /* DEBUG */ - } - - /* - * Slab is ready to go. Insert it into the domain's - * slab list so once we wake everybody up they'll find it. - * You better have write lock if you're putting treasures - * there. - */ - ASSERT(DSLAB_WRITE_HELD(domid)); - - sp->sl_next = dp->dslab; - dp->dslab = sp; - dp->dnslabs++; - - /* - * It's possible to fall through here without waiters. - * This is a case where forceflag was set. - */ - if (wp->w_nwaiters > 0) { - wp->w_sp = sp; - wp->w_serrno = serrno; - wp->w_done = 1; - cv_broadcast(&wp->w_cv); - } else { - ASSERT(forceflag); - wp->w_sp = NULL; - wp->w_serrno = 0; - wp->w_done = 0; - } - mutex_exit(&wp->w_mutex); - - return (0); -} - -/* - * Get the slab representing [bufp,ebufp] from the respective - * domain's pool if all the buffers are free. Remove them from - * the domain's list and return it. - * If bufp == NULL, then return however many free ones you - * can find. - * List of slabs are returned locked (sl_lock). - * XXX - Need minimum limit to make sure we don't free up _all_ - * of our slabs! However, during a shutdown we will need - * method to free them all up regardless of locking. - */ -smr_slab_t * -smr_slaballoc_get(int domid, caddr_t bufp, caddr_t ebufp) -{ - idn_domain_t *dp; - smr_slab_t *retsp, *sp, **psp; - int foundit, islocal = 0; - int nslabs; - procname_t proc = "smr_slaballoc_get"; - - PR_SMR("%s: getting slab for domain %d [bufp=0x%p, ebufp=0x%p]\n", - proc, domid, (void *)bufp, (void *)ebufp); - - dp = &idn_domain[domid]; - - ASSERT(DSLAB_WRITE_HELD(domid)); - - if ((sp = dp->dslab) == NULL) { - PR_SMR("%s: oops, no slabs for domain %d\n", proc, domid); - return (NULL); - } - /* - * If domid is myself then I'm trying to get a slab out - * of my local pool. Otherwise, I'm the master and - * I'm trying to get the slab representative from the - * global pool. - */ - if (domid == idn.localid) - islocal = 1; - - if (bufp != NULL) { - nslabs = -1; - } else { - nslabs = *(int *)ebufp; - if (nslabs == 0) { - PR_SMR("%s: requested nslabs (%d) <= 0\n", - proc, nslabs); - return (NULL); - } else if (nslabs < 0) { - /* - * Caller wants them all! - */ - nslabs = (int)dp->dnslabs; - } - } - - retsp = NULL; - foundit = 0; - for (psp = &dp->dslab; sp; sp = *psp) { - int isbusy; - - if (bufp && (sp->sl_start != bufp)) { - psp = &sp->sl_next; - continue; - } - - if (bufp && (ebufp > sp->sl_end)) { - PR_SMR("%s: bufp/ebufp (0x%p/0x%p) " - "expected (0x%p/0x%p)\n", proc, (void *)bufp, - (void *)ebufp, (void *)sp->sl_start, - (void *)sp->sl_end); - ASSERT(0); - } - /* - * We found the desired slab. Make sure - * it's free. - */ - foundit++; - isbusy = 0; - if (islocal) { - int spl; - - /* - * Some of the buffers in the slab - * are still in use. Unlock the - * buffers we locked and bail out. - */ - spl = splhi(); - if (!lock_try(&sp->sl_lock)) { - isbusy = 1; - foundit--; - } else if (sp->sl_inuse) { - lock_clear(&sp->sl_lock); - isbusy = 1; - foundit--; - } - splx(spl); - } else { - /* - * If not local, then I'm the master getting - * a slab from one of the slaves. In this case, - * their slab structs will always be locked. - */ - ASSERT(!lock_try(&sp->sl_lock)); - } - if (!isbusy) { - /* - * Delete the entry from the list and slap - * it onto our return list. - */ - *psp = sp->sl_next; - sp->sl_next = retsp; - retsp = sp; - } else { - psp = &sp->sl_next; - } - /* - * If bufp == NULL (alternate interface) and we haven't - * found the desired number of slabs yet, keep looking. - */ - if (bufp || (foundit == nslabs)) - break; - } - dp->dnslabs -= (short)foundit; - - if (foundit) { - PR_SMR("%s: found %d free slabs (domid = %d)\n", proc, foundit, - domid); - } else { - PR_SMR("%s: no free slabs found (domid = %d)\n", proc, domid); - } - - /* - * If this is the alternate interface, need to return - * the number of slabs found in the ebufp parameter. - */ - if (bufp == NULL) - *(int *)ebufp = foundit; - - return (retsp); -} - -/* - * Wrapper to hide alternate interface to smr_slaballoc_get() - */ -smr_slab_t * -smr_slaballoc_get_n(int domid, int *nslabs) -{ - smr_slab_t *sp; - - ASSERT(DSLAB_WRITE_HELD(domid)); - - sp = smr_slaballoc_get(domid, NULL, (caddr_t)nslabs); - - return (sp); -} - -/* - * Only called by master. Initialize slab pool based on local SMR. - * Returns number of slabs initialized. - * reserved_size = Length of area at the front of the NWR portion - * of the SMR to reserve and not make available for - * slab allocations. Must be a IDN_SMR_BUFSIZE multiple. - * reserved_area = Pointer to reserved area, if any. - */ -int -smr_slabpool_init(size_t reserved_size, caddr_t *reserved_area) -{ - size_t nwr_available; - int minperpool, ntotslabs, nxslabs, nslabs; - register int p, pp; - register caddr_t bufp; - register smr_slab_t *sp; - - ASSERT(IDN_GLOCK_IS_EXCL()); - ASSERT(IDN_GET_MASTERID() != IDN_NIL_DOMID); - - *reserved_area = NULL; - - nwr_available = MB2B(IDN_NWR_SIZE) - reserved_size; - - if ((idn.localid != IDN_GET_MASTERID()) || - (nwr_available < IDN_SLAB_SIZE) || - (idn.slabpool != NULL) || - ((reserved_size != 0) && (reserved_size & (IDN_SMR_BUFSIZE-1)))) { - return (-1); - } - - idn.slabpool = GETSTRUCT(struct slabpool, 1); - idn.slabpool->ntotslabs = ntotslabs = nwr_available / IDN_SLAB_SIZE; - ASSERT(ntotslabs > 0); - minperpool = (ntotslabs < IDN_SLAB_MINPERPOOL) ? - 1 : IDN_SLAB_MINPERPOOL; - idn.slabpool->npools = (ntotslabs + (minperpool - 1)) / minperpool; - - if ((idn.slabpool->npools & 1) == 0) { - /* - * npools needs to be odd for hashing algorithm. - */ - idn.slabpool->npools++; - } - ASSERT(idn.slabpool->npools > 0); - minperpool = (ntotslabs < idn.slabpool->npools) ? - 1 : (ntotslabs / idn.slabpool->npools); - - /* - * Calculate the number of extra slabs that will need to - * be alloted to the pools. This number will be less than - * npools. Only one extra slab is allocated to each pool - * until we have assigned all the extra slabs. - */ - if (ntotslabs > (idn.slabpool->npools * minperpool)) - nxslabs = ntotslabs - (idn.slabpool->npools * minperpool); - else - nxslabs = 0; - ASSERT((nxslabs >= 0) && (nxslabs < idn.slabpool->npools)); - - idn.slabpool->pool = GETSTRUCT(struct smr_slabtbl, - idn.slabpool->npools); - sp = GETSTRUCT(smr_slab_t, idn.slabpool->ntotslabs); - - idn.slabpool->savep = sp; - bufp = idn.smr.vaddr + reserved_size; - - for (p = nslabs = 0; - (p < idn.slabpool->npools) && (ntotslabs > 0); - p++, ntotslabs -= nslabs) { - - nslabs = (ntotslabs < minperpool) ? ntotslabs : minperpool; - if (nxslabs > 0) { - nslabs++; - nxslabs--; - } - idn.slabpool->pool[p].sarray = sp; - for (pp = 0; pp < nslabs; pp++) { - - sp->sl_next = NULL; - sp->sl_start = bufp; - sp->sl_end = bufp = sp->sl_start + IDN_SLAB_SIZE; - sp->sl_lock = 0; - sp->sl_domid = (short)IDN_NIL_DOMID; - - sp++; - } - idn.slabpool->pool[p].nfree = nslabs; - idn.slabpool->pool[p].nslabs = nslabs; - } - ASSERT((ntotslabs == 0) && (nxslabs == 0)); - /* - * We should be at the end of the SMR at this point. - */ - ASSERT(bufp == (idn.smr.vaddr + reserved_size - + (idn.slabpool->ntotslabs * IDN_SLAB_SIZE))); - - if (reserved_size != 0) - *reserved_area = idn.smr.vaddr; - - return (0); -} - -void -smr_slabpool_deinit() -{ - if (idn.slabpool == NULL) - return; - - FREESTRUCT(idn.slabpool->savep, smr_slab_t, idn.slabpool->ntotslabs); - FREESTRUCT(idn.slabpool->pool, struct smr_slabtbl, - idn.slabpool->npools); - FREESTRUCT(idn.slabpool, struct slabpool, 1); - - idn.slabpool = NULL; -} - -void -smr_alloc_buflist(smr_slab_t *sp) -{ - int n, nbufs; - caddr_t sbufp; - smr_slabbuf_t *hp, *bp; - - if (sp->sl_head) - return; - - nbufs = (sp->sl_end - sp->sl_start) / IDN_SMR_BUFSIZE; - ASSERT(nbufs > 0); - if (nbufs <= 0) { - sp->sl_head = sp->sl_free = sp->sl_inuse = NULL; - return; - } - - hp = GETSTRUCT(smr_slabbuf_t, nbufs); - - sbufp = sp->sl_start; - for (n = 0, bp = hp; n < nbufs; bp++, n++) { - bp->sb_bufp = sbufp; - bp->sb_domid = IDN_NIL_DOMID; - bp->sb_next = bp + 1; - sbufp += IDN_SMR_BUFSIZE; - } - (--bp)->sb_next = NULL; - - sp->sl_head = sp->sl_free = hp; - sp->sl_inuse = NULL; -} - -void -smr_free_buflist(smr_slab_t *sp) -{ - int nbufs; - - if (sp->sl_head == NULL) - return; - - nbufs = (sp->sl_end - sp->sl_start) / IDN_SMR_BUFSIZE; - - FREESTRUCT(sp->sl_head, smr_slabbuf_t, nbufs); - - sp->sl_head = sp->sl_free = sp->sl_inuse = NULL; -} - -/* - * Returns: 0 Successfully located a slab. - * -1 Failure. - */ -static smr_slab_t * -smr_slab_reserve(int domid) -{ - register int p, nextp, s, nexts; - register smr_slab_t *spa; - int startp, starts; - int foundone = 0; - int spl; - procname_t proc = "smr_slab_reserve"; - - p = startp = SMR_SLABPOOL_HASH(domid); - nextp = -1; - - spl = splhi(); - while ((nextp != startp) && !foundone) { - - s = starts = SMR_SLAB_HASH(p, domid); - nexts = -1; - spa = &(idn.slabpool->pool[p].sarray[0]); - - while ((nexts != starts) && !foundone) { - if (lock_try(&spa[s].sl_lock)) { - foundone = 1; - break; - } - nexts = SMR_SLAB_HASHSTEP(p, s); - s = nexts; - } - if (foundone) - break; - nextp = SMR_SLABPOOL_HASHSTEP(p); - p = nextp; - } - splx(spl); - - if (foundone) { - ASSERT((&spa[s] >= idn.slabpool->savep) && - (&spa[s] < (idn.slabpool->savep + - idn.slabpool->ntotslabs))); - - spa[s].sl_domid = (short)domid; - - ATOMIC_DEC(idn.slabpool->pool[p].nfree); - - if (domid == idn.localid) { - smr_slab_t *nsp; - /* - * Caller is actually reserving a slab for - * themself which means they'll need the full - * slab structure to represent all of the I/O - * buffers. The "spa" is just a representative - * and doesn't contain the space to manage the - * individual buffers. Need to alloc a full-size - * struct. - * Note that this results in the returning - * smr_slab_t structure being unlocked. - */ - ASSERT(idn.localid == IDN_GET_MASTERID()); - nsp = GETSTRUCT(smr_slab_t, 1); - nsp->sl_start = spa[s].sl_start; - nsp->sl_end = spa[s].sl_end; - smr_alloc_buflist(nsp); - spa = nsp; - PR_SMR("%s: allocated full slab struct for domain %d\n", - proc, domid); - } else { - /* - * Slab structure gets returned locked. - */ - spa += s; - } - - PR_SMR("%s: allocated slab 0x%p (start=0x%p, size=%lu) for " - "domain %d\n", proc, (void *)spa, (void *)spa->sl_start, - spa->sl_end - spa->sl_start, domid); - } else { - PR_SMR("%s: FAILED to allocate for domain %d\n", - proc, domid); - spa = NULL; - } - - return (spa); -} - -static void -smr_slab_unreserve(int domid, smr_slab_t *sp) -{ - register int p, nextp, s, nexts; - register smr_slab_t *spa; - int foundit = 0; - int startp, starts; - caddr_t bufp; - procname_t proc = "smr_slab_unreserve"; - - bufp = sp->sl_start; - p = startp = SMR_SLABPOOL_HASH(domid); - nextp = -1; - - while ((nextp != startp) && !foundit) { - - s = starts = SMR_SLAB_HASH(p, domid); - nexts = -1; - spa = &(idn.slabpool->pool[p].sarray[0]); - - while ((nexts != starts) && !foundit) { - if (spa[s].sl_start == bufp) { - foundit = 1; - break; - } - nexts = SMR_SLAB_HASHSTEP(p, s); - s = nexts; - } - if (foundit) - break; - nextp = SMR_SLABPOOL_HASHSTEP(p); - p = nextp; - } - if (foundit) { - ASSERT((&spa[s] >= idn.slabpool->savep) && - (&spa[s] < (idn.slabpool->savep + - idn.slabpool->ntotslabs))); - ASSERT(!lock_try(&spa[s].sl_lock)); - ASSERT(spa[s].sl_domid == (short)domid); - - spa[s].sl_next = NULL; - spa[s].sl_domid = (short)IDN_NIL_DOMID; - lock_clear(&spa[s].sl_lock); - - ATOMIC_INC(idn.slabpool->pool[p].nfree); - - PR_SMR("%s: freed (bufp=0x%p) for domain %d\n", - proc, (void *)bufp, domid); - - if (domid == idn.localid) { - /* - * Caller is actually unreserving a slab of their - * own. Note that only the master calls this - * routine. Since the master's local slab - * structures do not get entered into the global - * "representative" pool, we need to free up the - * data structure that was passed in. - */ - ASSERT(idn.localid == IDN_GET_MASTERID()); - ASSERT(sp != &spa[s]); - - smr_free_buflist(sp); - FREESTRUCT(sp, smr_slab_t, 1); - } else { - ASSERT(sp == &spa[s]); - } - } else { - /* - * Couldn't find slab entry for given buf! - */ - PR_SMR("%s: FAILED to free (bufp=0x%p) for domain %d\n", - proc, (void *)bufp, domid); - } -} - -/* - * The Reap Protocol: - * master slave - * ------ ----- - * smr_slab_reap_global - * - idn_broadcast_cmd(SLABREAP) -> idn_recv_cmd(SLABREAP) - * . idn_local_cmd(SLABREAP) - idn_recv_slabreap_req - * - smr_slab_reap . smr_slab_reap - * . smr_slaballoc_get_n - smr_slaballoc_get_n - * . smr_slab_free - smr_slab_free - * - smr_slab_free_local . smr_slab_free_remote - * . smr_slab_unreserve - * <- - idn_send_cmd(SLABFREE) - * idn_recv_cmd(SLABFREE) - * - idn_recv_slabfree_req - * . smr_slaballoc_get - * . smr_slab_free - * - smr_slab_free_local - * . smr_slab_unreserve - * . idn_send_slabfree_resp -> idn_recv_cmd(SLABFREE | ack) - * - idn_recv_slabfree_resp - * - * idn_recv_cmd(SLABREAP | ack) <- . idn_send_slabreap_resp - * - idn_recv_slabreap_resp DONE - * DONE - * - * Check available slabs and if we're below the threshold, kick - * off reaping to all remote domains. There is no guarantee remote - * domains will be able to free up any. - */ -static void -smr_slab_reap_global() -{ - register int p, npools; - register int total_free = 0; - register struct smr_slabtbl *tblp; - static clock_t reap_last = 0; - procname_t proc = "smr_slab_reap_global"; - clock_t now; - - ASSERT(IDN_GET_MASTERID() != IDN_NIL_DOMID); - - DSLAB_LOCK_SHARED(idn.localid); - if (idn_domain[idn.localid].dslab_state != DSLAB_STATE_LOCAL) { - PR_SMR("%s: only allowed by master (%d)\n", - proc, IDN_GET_MASTERID()); - DSLAB_UNLOCK(idn.localid); - return; - } - DSLAB_UNLOCK(idn.localid); - - now = ddi_get_lbolt(); - if ((now > 0) && (now > reap_last) && - ((now - reap_last) < IDN_REAP_INTERVAL)) - return; - - reap_last = now; - - ASSERT(idn.slabpool); - - npools = idn.slabpool->npools; - tblp = idn.slabpool->pool; - - for (p = 0; p < npools; tblp++, p++) - total_free += tblp->nfree; - - if (total_free <= IDN_SLAB_THRESHOLD) { - int diff, reap_per_domain; - - PR_SMR("%s: kicking off reaping " - "(total_free = %d, min = %d)\n", - proc, total_free, IDN_SLAB_THRESHOLD); - - diff = IDN_SLAB_THRESHOLD - total_free; - reap_per_domain = (diff < idn.ndomains) ? - 1 : (diff / idn.ndomains); - - idn_broadcast_cmd(IDNCMD_SLABREAP, reap_per_domain, 0, 0); - } -} - -void -smr_slab_reap(int domid, int *nslabs) -{ - register int d; - int nreclaimed; - smr_slab_t *sp; - domainset_t reapset; - procname_t proc = "smr_slab_reap"; - - /* - * Should only be called on behalf of local - * domain. - */ - if (domid != idn.localid) { - PR_SMR("%s: called by domain %d, should only be local (%d)\n", - proc, domid, idn.localid); - ASSERT(0); - return; - } - /* - * Try and reclaim some buffers so we can possibly - * free up some slabs. - */ - reapset = idn.domset.ds_connected; - - IDN_GKSTAT_GLOBAL_EVENT(gk_reaps, gk_reap_last); - - nreclaimed = 0; - for (d = 0; d < MAX_DOMAINS; d++) { - int nr; - idn_domain_t *dp; - - if (!DOMAIN_IN_SET(reapset, d)) - continue; - - IDN_DLOCK_SHARED(d); - - dp = &idn_domain[d]; - if ((d == idn.localid) || (dp->dcpu < 0)) { - IDN_DUNLOCK(d); - continue; - } - /* - * Clean up any dead I/O errors if possible. - */ - if (dp->dioerr > 0) { - idn_domain_t *ldp; - register int cnt; - register smr_slabbuf_t *bp; - /* - * We need to grab the writer lock to prevent - * anybody from allocating buffers while we - * traverse the slabs outstanding. - */ - cnt = 0; - ldp = &idn_domain[idn.localid]; - IDN_DLOCK_EXCL(idn.localid); - DSLAB_LOCK_EXCL(idn.localid); - for (sp = ldp->dslab; sp; sp = sp->sl_next) - for (bp = sp->sl_inuse; bp; bp = bp->sb_next) - if (bp->sb_domid == d) - cnt++; - DSLAB_UNLOCK(idn.localid); - ASSERT((dp->dio + dp->dioerr) >= cnt); - dp->dio = cnt; - dp->dioerr = 0; - IDN_DUNLOCK(idn.localid); - } - if ((dp->dstate == IDNDS_CONNECTED) && - ((nr = idn_reclaim_mboxdata(d, 0, -1)) > 0)) - nreclaimed += nr; - - IDN_DUNLOCK(d); - } - - DSLAB_LOCK_EXCL(domid); - sp = smr_slaballoc_get_n(domid, nslabs); - if (sp) { - IDN_GKSTAT_ADD(gk_reap_count, (ulong_t)(*nslabs)); - smr_slab_free(domid, sp); - } - DSLAB_UNLOCK(domid); -} - -/* - * --------------------------------------------------------------------- - * Remap the (IDN) shared memory region to a new physical address. - * Caller is expected to have performed a ecache flush if needed. - * --------------------------------------------------------------------- - */ -void -smr_remap(struct as *as, register caddr_t vaddr, - register pfn_t new_pfn, uint_t mblen) -{ - tte_t tte; - size_t blen; - pgcnt_t p, npgs; - procname_t proc = "smr_remap"; - - if (va_to_pfn(vaddr) == new_pfn) { - PR_REMAP("%s: vaddr (0x%p) already mapped to pfn (0x%lx)\n", - proc, (void *)vaddr, new_pfn); - return; - } - - blen = MB2B(mblen); - npgs = btopr(blen); - ASSERT(npgs != 0); - - PR_REMAP("%s: va = 0x%p, pfn = 0x%lx, npgs = %ld, mb = %d MB (%ld)\n", - proc, (void *)vaddr, new_pfn, npgs, mblen, blen); - - /* - * Unmap the SMR virtual address from it's current - * mapping. - */ - hat_unload(as->a_hat, vaddr, blen, HAT_UNLOAD_UNLOCK); - - if (new_pfn == PFN_INVALID) - return; - - /* - * Map the SMR to the new physical address space, - * presumably a remote pfn. Cannot use hat_devload - * because it will think pfn represents non-memory, - * since it may extend beyond its physmax. - */ - for (p = 0; p < npgs; p++) { - sfmmu_memtte(&tte, new_pfn, PROT_READ | PROT_WRITE | HAT_NOSYNC, - TTE8K); - sfmmu_tteload(as->a_hat, &tte, vaddr, NULL, HAT_LOAD_LOCK); - - vaddr += MMU_PAGESIZE; - new_pfn++; - } - - PR_REMAP("%s: remapped %ld pages (expected %ld)\n", - proc, npgs, btopr(MB2B(mblen))); -} diff --git a/usr/src/uts/sun4u/starfire/io/idn_xf.c b/usr/src/uts/sun4u/starfire/io/idn_xf.c deleted file mode 100644 index 797f2479a8..0000000000 --- a/usr/src/uts/sun4u/starfire/io/idn_xf.c +++ /dev/null @@ -1,1694 +0,0 @@ -/* - * 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 - * or http://www.opensolaris.org/os/licensing. - * 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. - * Copyright (c) 2016 by Delphix. All rights reserved. - */ - -#include <sys/types.h> -#include <sys/sysmacros.h> -#include <sys/open.h> -#include <sys/param.h> -#include <sys/vm_machparam.h> -#include <sys/machparam.h> -#include <sys/systm.h> -#include <sys/signal.h> -#include <sys/cred.h> -#include <sys/user.h> -#include <sys/proc.h> -#include <sys/vnode.h> -#include <sys/uio.h> -#include <sys/buf.h> -#include <sys/file.h> -#include <sys/kmem.h> -#include <sys/stat.h> -#include <sys/stream.h> -#include <sys/stropts.h> -#include <sys/strsubr.h> -#include <sys/poll.h> -#include <sys/debug.h> -#include <sys/conf.h> -#include <sys/ddi.h> -#include <sys/sunddi.h> -#include <sys/errno.h> -#include <sys/modctl.h> -#include <sys/x_call.h> -#include <sys/cpuvar.h> -#include <sys/machcpuvar.h> -#include <sys/machsystm.h> - -#include <sys/pda.h> -#include <sys/starfire.h> -#include <sys/idn.h> -#include <sys/idn_xf.h> - -kmutex_t idn_xf_mutex; /* to serialize hardware access */ -/* - * This data structure is referenced during the cross-call - * update of the CICs. The semaphore is used for synchronization - * when waiting for completion of the respective operation. - * We want IDNCIC_TIMEOUT ticks for all the cpus to check-in - * before we bail out and fail the operation. - */ -#define IDNCIC_TIMEOUT (30*hz) -#define IDNCIC_TIMECHK (hz/3) -#define IDNCIC_UNKNOWN 0 -#define IDNCIC_OK 1 /* values for xf_errcic */ -#define IDNCIC_ERR 2 -#define IDNCIC_BUSY 3 - -#ifdef DEBUG -#define NCICREGS 3 /* smmask, smbar, smlar */ -#define CICREG_SMMASK 0 -#define CICREG_SMBAR 1 -#define CICREG_SMLAR 2 - -#define RESET_CIC_HISTORY() \ - (xf_cicboards = xf_cicbuses = 0, \ - bzero(xf_cicregs, sizeof (xf_cicregs))) - -#define UPDATE_CIC_HISTORY(reg, brd, bus, val) \ - (BOARDSET_ADD(xf_cicboards, (brd)), \ - BOARDSET_ADD(xf_cicbuses, (bus)), \ - xf_cicregs[brd][bus][reg] = (val)) - -#define DUMP_CIC_HISTORY() \ -{ \ - if (idn_debug & IDNDBG_XF) { \ - int _bd, _bs; \ - procname_t _proc = "dump_cic_history"; \ - for (_bd = 0; _bd < MAX_BOARDS; _bd++) { \ - if (!BOARD_IN_SET(xf_cicboards, _bd)) \ - continue; \ - for (_bs = 0; _bs < MAX_ABUSES; _bs++) { \ - if (!BOARD_IN_SET(xf_cicbuses, _bs)) \ - continue; \ - printf("%s: (bd.bs = %d.%d) m/b/l = " \ - "%x/%x/%x\n", _proc, _bd, _bs, \ - xf_cicregs[_bd][_bs][CICREG_SMMASK], \ - xf_cicregs[_bd][_bs][CICREG_SMBAR], \ - xf_cicregs[_bd][_bs][CICREG_SMLAR]); \ - } \ - } \ - DEBUG_DELAY(); \ - } \ -} - -/* - * Globally updated during CIC reg updates. Everybody has - * a unique location, so no concern about updates stepping - * on each other. - */ -static ushort_t xf_cicboards, xf_cicbuses; -static uint_t xf_cicregs[MAX_BOARDS][MAX_ABUSES][NCICREGS]; -#else /* DEBUG */ -#define RESET_CIC_HISTORY() -#define UPDATE_CIC_HISTORY(reg, brd, bus, val) -#define DUMP_CIC_HISTORY() -#endif /* DEBUG */ - -struct idnxf_cic_info { /* protected by idn_xf_mutex */ -/* 0 */ short xf_abus_mask; -/* 2 */ boardset_t xf_boardset; -/* 4 */ uint_t xf_smbase; -/* 8 */ uint_t xf_smlimit; -/* c */ int xf_doadd; - -/* 10 */ int xf_count; /* atomically updated */ -/* 14 */ time_t xf_start_time; -/* 18 */ kcondvar_t xf_cv; -/* 1a */ short xf_errtimer; -/* 1c */ int xf_errcnt; /* atomically updated */ - -/* 20 */ uchar_t xf_errcic[MAX_BOARDS][MAX_ABUSES]; - -/* 60 */ kmutex_t xf_mutex; -}; /* sizeof = 0x68 = 104 (26X) */ - -static struct idnxf_cic_info idnxf_cic_info; -#ifdef DEBUG -static uint_t o_idn_debug; -#endif /* DEBUG */ - -int idn_check_cpu_per_board = 1; - -static int pc_prep_cic_buffer(int cpuid, uint_t cicdata); -static int cic_write_sm_mask(int board, int bus, boardset_t sm_mask); -static int cic_write_sm_bar(int board, int bus, uint_t sm_bar); -static int cic_write_sm_lar(int board, int bus, uint_t sm_lar); -static int cic_get_smmask_bit(void); -static int pc_write_madr(pda_handle_t ph, - int lboard, int rboard, uint_t madr); -static boardset_t get_boardset(pda_handle_t ph, int *nboards); -static int verify_smregs(int brd, int bus, boardset_t smmask, - uint_t smbase, uint_t smlimit); -static void idnxf_shmem_wakeup(void *arg); -static void idnxf_shmem_update_one(uint64_t arg1, uint64_t arg2); -static int idnxf_shmem_update_all(pda_handle_t ph, - boardset_t boardset, uint_t smbase, - uint_t smlimit, int doadd); - -#define PHYSIO_ST(paddr, val) (stphysio((paddr), (val))) -#define PHYSIO_LD(paddr) (ldphysio(paddr)) -#define PHYSIO_STH(paddr, val) (sthphysio((paddr), (val))) -#define PHYSIO_LDH(paddr) (ldhphysio(paddr)) - -#ifdef DEBUG -#define DEBUG_DELAY() (drv_usecwait(5000)) /* 5 ms */ -#else /* DEBUG */ -#define DEBUG_DELAY() -#endif /* DEBUG */ - - -/* - * --------------------------------------------------------------------- - */ -boardset_t -cic_read_domain_mask(int board, int bus) -{ - u_longlong_t csr_addr; - boardset_t domain_mask; - procname_t proc = "cic_read_domain_mask"; - - ASSERT(CPUID_TO_BOARDID(CPU->cpu_id) == board); - - csr_addr = MAKE_CIC_CSR_PA(board, CSR_TYPE_CIC, CIC_DOMAIN_MASK_ADDR, - bus); - PR_XF("%s: (bd=%d, bs=%d) csr_addr = 0x%llx\n", - proc, board, bus, csr_addr); - - domain_mask = (boardset_t)PHYSIO_LDH(csr_addr); - - return (domain_mask); -} - -boardset_t -cic_read_sm_mask(int board, int bus) -{ - u_longlong_t csr_addr; - boardset_t sm_mask; - procname_t proc = "cic_read_sm_mask"; - - ASSERT(CPUID_TO_BOARDID(CPU->cpu_id) == board); - - csr_addr = MAKE_CIC_CSR_PA(board, CSR_TYPE_CIC, CIC_SM_MASK_ADDR, - bus); - PR_XF("%s: (bd=%d, bs=%d) csr_addr = 0x%llx\n", - proc, board, bus, csr_addr); - - sm_mask = (boardset_t)PHYSIO_LDH(csr_addr); - - return (sm_mask); -} - -static int -cic_write_sm_mask(int board, int bus, boardset_t sm_mask) -{ - u_longlong_t csr_addr; - int cnt; - procname_t proc = "cic_write_sm_mask"; - - ASSERT(CPUID_TO_BOARDID(CPU->cpu_id) == board); - - sm_mask &= 0xffff; - /* - * Before we can write to the CIC, we need to set - * up the CIC write data buffer in the PC. - */ - if (pc_prep_cic_buffer(CPU->cpu_id, (uint_t)sm_mask) < 0) - return (-1); - - /* - * Now we can write to the CIC. - */ - csr_addr = MAKE_CIC_CSR_PA(board, CSR_TYPE_CIC, CIC_SM_MASK_ADDR, - bus); - PR_XF("%s: (bd=%d, bs=%d) csr_addr = 0x%llx\n", - proc, board, bus, csr_addr); - PR_XF("%s: writing sm_mask = 0x%x\n", - proc, (ushort_t)sm_mask); - - UPDATE_CIC_HISTORY(CICREG_SMMASK, board, bus, sm_mask); - - PHYSIO_STH(csr_addr, (ushort_t)sm_mask); - /* - * Read back for verification. - */ - for (cnt = 0; (PHYSIO_LDH(csr_addr) != sm_mask) && (cnt < 10); cnt++) - ; - - return ((cnt == 10) ? -1 : 0); -} - -uint_t -cic_read_sm_bar(int board, int bus) -{ - u_longlong_t csr_addr; - uint_t sm_bar; - procname_t proc = "cic_read_sm_bar"; - - ASSERT(CPUID_TO_BOARDID(CPU->cpu_id) == board); - - csr_addr = MAKE_CIC_CSR_PA(board, CSR_TYPE_CIC, CIC_SM_BAR_MSB_ADDR, - bus); - PR_XF("%s:MSB: (bd=%d, bs=%d) csr_addr = 0x%llx\n", - proc, board, bus, csr_addr); - - sm_bar = (uint_t)PHYSIO_LDH(csr_addr); - sm_bar <<= 16; - - csr_addr = MAKE_CIC_CSR_PA(board, CSR_TYPE_CIC, CIC_SM_BAR_LSB_ADDR, - bus); - PR_XF("%s:LSB: (bd=%d, bs=%d) csr_addr = 0x%llx\n", - proc, board, bus, csr_addr); - - sm_bar |= (uint_t)PHYSIO_LDH(csr_addr); - - return (sm_bar); -} - -static int -cic_write_sm_bar(int board, int bus, uint_t sm_bar) -{ - int cnt; - u_longlong_t csr_addr; - uint_t sm_bar_lsb, sm_bar_msb; - procname_t proc = "cic_write_sm_bar"; - - ASSERT(CPUID_TO_BOARDID(CPU->cpu_id) == board); - - sm_bar_lsb = sm_bar & 0xffff; - sm_bar_msb = (sm_bar >> 16) & 0xffff; - - /* - * Before we can write to the CIC, we need to set - * up the CIC write data buffer in the PC. - */ - if (pc_prep_cic_buffer(CPU->cpu_id, sm_bar_msb) < 0) - return (-1); - - csr_addr = MAKE_CIC_CSR_PA(board, CSR_TYPE_CIC, CIC_SM_BAR_MSB_ADDR, - bus); - PR_XF("%s:MSB: (bd=%d, bs=%d) csr_addr = 0x%llx\n", - proc, board, bus, csr_addr); - PR_XF("%s:MSB: sm_bar[31:16] = 0x%x\n", - proc, (ushort_t)sm_bar_msb); - - UPDATE_CIC_HISTORY(CICREG_SMBAR, board, bus, sm_bar); - - PHYSIO_STH(csr_addr, (ushort_t)sm_bar_msb); - for (cnt = 0; - ((uint_t)PHYSIO_LDH(csr_addr) != sm_bar_msb) && (cnt < 10); - cnt++) - ; - if (cnt == 10) { - cmn_err(CE_WARN, - "IDN: 500: failed to write sm_bar (msb) (0x%x)", - (uint_t)sm_bar_msb); - return (-1); - } - - /* - * Now to LSB portion. - */ - if (pc_prep_cic_buffer(CPU->cpu_id, sm_bar_lsb) < 0) - return (-1); - - csr_addr = MAKE_CIC_CSR_PA(board, CSR_TYPE_CIC, CIC_SM_BAR_LSB_ADDR, - bus); - PR_XF("%s:LSB: (bd=%d, bs=%d) csr_addr = 0x%llx\n", - proc, board, bus, csr_addr); - PR_XF("%s:LSB: sm_bar[15:0] = 0x%x\n", - proc, (ushort_t)sm_bar_lsb); - - PHYSIO_STH(csr_addr, (ushort_t)sm_bar_lsb); - for (cnt = 0; - ((uint_t)PHYSIO_LDH(csr_addr) != sm_bar_lsb) && (cnt < 10); - cnt++) - ; - if (cnt == 10) { - cmn_err(CE_WARN, - "IDN: 500: failed to write sm_bar (lsb) (0x%x)", - (uint_t)sm_bar_lsb); - return (-1); - } - - return (0); -} - -uint_t -cic_read_sm_lar(int board, int bus) -{ - u_longlong_t csr_addr; - uint_t sm_lar; - procname_t proc = "cic_read_sm_lar"; - - ASSERT(CPUID_TO_BOARDID(CPU->cpu_id) == board); - - csr_addr = MAKE_CIC_CSR_PA(board, CSR_TYPE_CIC, CIC_SM_LAR_MSB_ADDR, - bus); - PR_XF("%s:MSB: (bd=%d, bs=%d) csr_addr = 0x%llx\n", - proc, board, bus, csr_addr); - - sm_lar = (uint_t)PHYSIO_LDH(csr_addr); - sm_lar <<= 16; - - csr_addr = MAKE_CIC_CSR_PA(board, CSR_TYPE_CIC, CIC_SM_LAR_LSB_ADDR, - bus); - PR_XF("%s:LSB: (bd=%d, bs=%d) csr_addr = 0x%llx\n", - proc, board, bus, csr_addr); - - sm_lar |= (uint_t)PHYSIO_LDH(csr_addr); - - return (sm_lar); -} - -static int -cic_write_sm_lar(int board, int bus, uint_t sm_lar) -{ - int cnt; - u_longlong_t csr_addr; - uint_t sm_lar_lsb, sm_lar_msb; - procname_t proc = "cic_write_sm_lar"; - - ASSERT(CPUID_TO_BOARDID(CPU->cpu_id) == board); - - sm_lar_lsb = sm_lar & 0xffff; - sm_lar_msb = (sm_lar >> 16) & 0xffff; - - /* - * Before we can write to the CIC, we need to set - * up the CIC write data buffer in the PC. - */ - if (pc_prep_cic_buffer(CPU->cpu_id, sm_lar_msb) < 0) - return (-1); - - csr_addr = MAKE_CIC_CSR_PA(board, CSR_TYPE_CIC, CIC_SM_LAR_MSB_ADDR, - bus); - PR_XF("%s:MSB: (bd=%d, bs=%d) csr_addr = 0x%llx\n", - proc, board, bus, csr_addr); - PR_XF("%s:MSB: sm_lar[31:16] = 0x%x\n", - proc, (ushort_t)sm_lar_msb); - - UPDATE_CIC_HISTORY(CICREG_SMLAR, board, bus, sm_lar); - - PHYSIO_STH(csr_addr, (ushort_t)sm_lar_msb); - for (cnt = 0; - ((uint_t)PHYSIO_LDH(csr_addr) != sm_lar_msb) && (cnt < 10); - cnt++) - ; - if (cnt == 10) { - cmn_err(CE_WARN, - "IDN: 501: failed to write sm_lar (msb) (0x%x)", - (uint_t)sm_lar_msb); - return (-1); - } - - /* - * Now to LSB portion. - */ - if (pc_prep_cic_buffer(CPU->cpu_id, sm_lar_lsb) < 0) - return (-1); - - csr_addr = MAKE_CIC_CSR_PA(board, CSR_TYPE_CIC, CIC_SM_LAR_LSB_ADDR, - bus); - PR_XF("%s:LSB: (bd=%d, bs=%d) csr_addr = 0x%llx\n", - proc, board, bus, csr_addr); - PR_XF("%s:LSB: sm_lar[15:0] = 0x%x\n", - proc, (ushort_t)sm_lar_lsb); - - PHYSIO_STH(csr_addr, (ushort_t)sm_lar_lsb); - for (cnt = 0; - ((uint_t)PHYSIO_LDH(csr_addr) != sm_lar_lsb) && (cnt < 10); - cnt++) - ; - if (cnt == 10) { - cmn_err(CE_WARN, - "IDN: 501: failed to write sm_lar (lsb) (0x%x)", - (uint_t)sm_lar_lsb); - return (-1); - } - - return (0); -} - -static int -cic_get_smmask_bit(void) -{ - u_longlong_t csr_addr; - int board; - uint_t config1; - procname_t proc = "cic_get_smmask_bit"; - - affinity_set(CPU_CURRENT); - - board = CPUID_TO_BOARDID(CPU->cpu_id); - /* - * Now that I'm stuck on this cpu I can go look at this - * board's CIC registers. - */ - csr_addr = MAKE_CIC_CSR_PA(board, CSR_TYPE_CIC, CIC_CONFIG1_ADDR, 0); - PR_XF("%s: (bd=%d) csr_addr = 0x%llx (via cpu %d)\n", - proc, board, csr_addr, (int)CPU->cpu_id); - - config1 = (uint_t)PHYSIO_LDH(csr_addr); - - config1 = CIC_CONFIG1_SMMASK_BIT(config1); - - affinity_clear(); - - return (config1); -} - -static int -pc_prep_cic_buffer(int cpuid, uint_t cicdata) -{ - int rv; - int brd, port; - u_longlong_t csr_addr; - register int cnt; - procname_t proc = "pc_prep_cic_buffer"; - - - ASSERT(CPU->cpu_id == cpuid); - - port = cpuid % plat_max_cpu_units_per_board(); - brd = CPUID_TO_BOARDID(cpuid); - - csr_addr = STARFIRE_PC_CICBUF_ADDR(brd, port); - - /* - * csr_addr now points to CIC write buffer which resides - * in PC register space. - */ - PR_XF("%s: (cpu=%d) csr_addr = 0x%llx\n", proc, cpuid, csr_addr); - - PHYSIO_ST(csr_addr, cicdata); - - /* - * Now we need to read back the data to guarantee - * it got there. Part of the PC protocol. - */ - for (cnt = 0; (PHYSIO_LD(csr_addr) != cicdata) && (cnt < 10); - cnt++) - ; - - rv = 0; - if (cnt == 10) { - cmn_err(CE_WARN, - "IDN: 502: unable to store data (0x%x) to " - "CIC buffer (0x%llx)", - cicdata, csr_addr); - rv = -1; - } else if (cnt >= 1) { - PR_XF("%s: MULTIPLE READS (cpu=%d) cnt = %d\n", - proc, cpuid, cnt); - } - - return (rv); -} - -/* - * -------------------------------------------------- - * Write the given MC address decoding register contents (madr) of - * the respective remote board (rboard) into all the PCs located on - * the local board (lboard). - * -------------------------------------------------- - */ -static int -pc_write_madr(pda_handle_t ph, int lboard, int rboard, uint_t madr) -{ - u_longlong_t pc_madr_addr; - register int p, ioc; - register ushort_t procset, iocset; - int rv = 0; - uint_t rd_madr; - board_desc_t *lbp; - procname_t proc = "pc_write_madr"; - - lbp = pda_get_board_info(ph, lboard); - - ASSERT(lbp); - ASSERT((lbp->bda_board & BDAN_MASK) == BDAN_GOOD); - - procset = lbp->bda_proc; - iocset = lbp->bda_ioc; - - /* - * Update the PCs for the cpus. - */ - for (p = 0; p < MAX_PROCMODS; procset >>= 4, p++) { - int i; - - if (!((procset & BDAN_MASK) == BDAN_GOOD)) - continue; - - pc_madr_addr = (u_longlong_t)STARFIRE_PC_MADR_ADDR(lboard, - rboard, p); - - /* - * On this first iteration of updating the PC - * we need to turn off the MADR VALID bit so that - * there's no accidental usage of the entry before - * all four bytes have been updated in the PC. - */ - if (madr != 0) { - /* - * Need to clear valid bit on first - * go around. - */ - madr &= ~STARFIRE_PC_MADR_VALIDBIT; - } - PR_XF("%s: write madr(0x%x) to pc_addr(0x%llx) " - "[lb=%d, rb=%d, cpu=%d]\n", - proc, madr, pc_madr_addr, lboard, rboard, p); - DEBUG_DELAY(); - - for (i = 0; i < 20; i++) { - PHYSIO_ST(pc_madr_addr, madr); - /* - * Read back for sanity check. - */ - rd_madr = PHYSIO_LD(pc_madr_addr); - if (madr == rd_madr) - break; - } - if (i > 0) { - PR_XF("%s: WARNING: (1) lb=%d, rb=%d, " - "madr=0x%x (i=%d)\n", - proc, lboard, rboard, madr, i); - } - if (rd_madr != madr) { - cmn_err(CE_WARN, - "IDN: 503: (invalidate) failed to update " - "PC madr (expected 0x%x, actual 0x%x)", - madr, rd_madr); - rv++; - continue; - } - if (madr == 0) { - continue; - } else { - /* - * Turn the valid bit back on. - */ - madr |= STARFIRE_PC_MADR_VALIDBIT; - } - PR_XF("%s: write madr(0x%x) to pc_addr(0x%llx) " - "[lb=%d, rb=%d, cpu=%d]\n", - proc, madr, pc_madr_addr, lboard, rboard, p); - DEBUG_DELAY(); - - for (i = 0; i < 20; i++) { - PHYSIO_ST(pc_madr_addr, madr); - /* - * Read back for sanity check. - */ - rd_madr = PHYSIO_LD(pc_madr_addr); - if (madr == rd_madr) - break; - } - if (i > 0) { - PR_XF("%s: WARNING: (2) lb=%d, rb=%d, " - "madr=0x%x (i=%d)\n", - proc, lboard, rboard, madr, i); - } - if (rd_madr != madr) { - cmn_err(CE_WARN, - "IDN: 503: (validate) failed to update " - "PC madr (expected 0x%x, actual 0x%x)", - madr, rd_madr); - rv++; - } - } - /* - * Update the PCs for the iocs. - */ - for (ioc = 0; ioc < MAX_IOCS; iocset >>= 4, ioc++) { - int i; - - if (!((iocset & BDAN_MASK) == BDAN_GOOD)) - continue; - - pc_madr_addr = (u_longlong_t)STARFIRE_PC_MADR_ADDR(lboard, - rboard, ioc + 4); - - if (madr != 0) { - /* - * Need to clear valid bit on first - * go around. - */ - madr &= ~STARFIRE_PC_MADR_VALIDBIT; - } - PR_XF("%s: write madr(0x%x) to iopc_madr_addr(0x%llx) " - "[lb=%d, rb=%d, ioc=%d]\n", - proc, madr, pc_madr_addr, lboard, rboard, ioc); - DEBUG_DELAY(); - - for (i = 0; i < 20; i++) { - PHYSIO_ST(pc_madr_addr, madr); - /* - * Read back for sanity check. - */ - rd_madr = PHYSIO_LD(pc_madr_addr); - if (madr == rd_madr) - break; - } - if (i > 0) { - PR_XF("%s: WARNING: (3) lb=%d, rb=%d, " - "madr=0x%x (i=%d)\n", - proc, lboard, rboard, madr, i); - } - if (rd_madr != madr) { - cmn_err(CE_WARN, - "IDN: 504: (invalidate) failed to update " - "IOPC madr (expected 0x%x, actual 0x%x)", - madr, rd_madr); - rv++; - continue; - } - - if (madr == 0) { - continue; - } else { - /* - * Turn the valid bit back on. - */ - madr |= STARFIRE_PC_MADR_VALIDBIT; - } - - PR_XF("%s: write madr(0x%x) to iopc_madr_addr(0x%llx) " - "[lb=%d, rb=%d, ioc=%d]\n", - proc, madr, pc_madr_addr, lboard, rboard, ioc); - DEBUG_DELAY(); - - for (i = 0; i < 20; i++) { - PHYSIO_ST(pc_madr_addr, madr); - /* - * Read back for sanity check. - */ - rd_madr = PHYSIO_LD(pc_madr_addr); - if (madr == rd_madr) - break; - } - if (i > 0) { - PR_XF("%s: WARNING: (4) lb=%d, rb=%d, " - "madr=0x%x (i=%d)\n", - proc, lboard, rboard, madr, i); - } - if (rd_madr != madr) { - cmn_err(CE_WARN, - "IDN: 504: (validate) failed to update " - "IOPC madr (expected 0x%x, actual 0x%x)", - madr, rd_madr); - rv++; - } - } - - return (rv ? -1 : 0); -} - -/* - * -------------------------------------------------- - * Read the array of MC address decoding registers from one of the - * PCs on the local board (lboard) into the given in array (mc_adr). - * -------------------------------------------------- - */ -void -pc_read_madr(pda_handle_t ph, int lboard, uint_t mc_adr[], int local_only) -{ - u_longlong_t pc_madr_addr; - register int p, ioc; - register ushort_t procset, iocset; - int brd; - board_desc_t *lbp; - - lbp = pda_get_board_info(ph, lboard); - - ASSERT(lbp); - ASSERT((lbp->bda_board & BDAN_MASK) == BDAN_GOOD); - - procset = lbp->bda_proc; - iocset = lbp->bda_ioc; - - for (p = 0; p < MAX_PROCMODS; procset >>= 4, p++) - if ((procset & BDAN_MASK) == BDAN_GOOD) - break; - - if (p == MAX_PROCMODS) { - /* - * Couldn't find a PC off a cpu, let's check the - * IOCs. - */ - for (ioc = 0; ioc < MAX_IOCS; iocset >>= 4, ioc++) - if ((iocset & BDAN_MASK) == BDAN_GOOD) - break; - if (ioc == MAX_IOCS) { - cmn_err(CE_WARN, - "IDN: 505: board %d missing any valid PCs", - lboard); - return; - } - p = ioc + 4; - } - - pc_madr_addr = (u_longlong_t)STARFIRE_PC_MADR_ADDR(lboard, 0, p); - /* - * pc_madr_addr = Starts at entry for board 0. - */ - for (brd = 0; brd < MAX_BOARDS; brd++) { - /* - * It's possible our local PC may have old entries to - * AWOL domains. Only want to pay attention to PC - * entries corresponding to our boards. - */ - lbp = pda_get_board_info(ph, brd); - if (!local_only || ((lbp->bda_board & BDAN_MASK) == BDAN_GOOD)) - mc_adr[brd] = PHYSIO_LD(pc_madr_addr); - else - mc_adr[brd] = 0; - - pc_madr_addr += ((u_longlong_t)1 << - STARFIRE_PC_MADR_BOARD_SHIFT); - } -} - -/* - * -------------------------------------------------- - * Read the MC address decoding register contents for all - * possible boards and store the results in their respective - * slot in mc_adr. Keep a count of non-zero MC ADRs and - * return that. - * -------------------------------------------------- - */ -void -mc_get_adr_all(pda_handle_t ph, uint_t mc_adr[], int *nmcadr) -{ - int brd; - uint_t madr[MAX_BOARDS]; - - /* - * Note that each PC has a complete copy of all MC contents - * and so all we have to do is read one PC rather than - * each of the MCs in the system. - */ - brd = CPUID_TO_BOARDID(CPU->cpu_id); - pc_read_madr(ph, brd, madr, 1); - - *nmcadr = 0; - for (brd = 0; brd < MAX_BOARDS; brd++) - if ((mc_adr[brd] = madr[brd]) != 0) - (*nmcadr)++; -} - -static boardset_t -get_boardset(pda_handle_t ph, int *nboards) -{ - int brd; - int nbrds = 0; - boardset_t bmask; - - if (nboards != NULL) - *nboards = 0; - - bmask = 0; - for (brd = 0; brd < MAX_BOARDS; brd++) { - if (pda_board_present(ph, brd)) { - bmask |= 1 << brd; - nbrds++; - } - } - if (nboards != NULL) - *nboards = (short)nbrds; - - return (bmask); -} - -int -update_local_hw_config(idn_domain_t *ldp, struct hwconfig *loc_hw) -{ - procname_t proc = "update_local_hw_config"; - - ASSERT(IDN_DLOCK_IS_EXCL(ldp->domid)); - ASSERT(IDN_GLOCK_IS_EXCL()); - ASSERT(ldp == &idn_domain[idn.localid]); - - if (ldp->dhw.dh_boardset != loc_hw->dh_boardset) { - int c; - - PR_PROTO("%s: NEW HW CONFIG (old_bset = 0x%x, " - "new_bset = 0x%x)\n", - proc, ldp->dhw.dh_boardset, loc_hw->dh_boardset); - - PR_PROTO("%s: clearing boardset 0x%x\n", proc, - ldp->dhw.dh_boardset & ~loc_hw->dh_boardset); - PR_PROTO("%s: setting boardset 0x%x\n", proc, - loc_hw->dh_boardset & ~ldp->dhw.dh_boardset); - - idn.dc_boardset &= ~ldp->dhw.dh_boardset; - idn.dc_boardset |= loc_hw->dh_boardset; - for (c = 0; c < NCPU; c++) { - if (CPU_IN_SET(ldp->dcpuset, c)) { - CPUSET_DEL(idn.dc_cpuset, c); - } - } - CPUSET_OR(idn.dc_cpuset, cpu_ready_set); - - bcopy(loc_hw, &ldp->dhw, sizeof (ldp->dhw)); - ldp->dcpuset = cpu_ready_set; - ldp->dcpu = cpu0.cpu_id; - ldp->dncpus = (int)ncpus; - ldp->dvote.v.nmembrds = ldp->dhw.dh_nmcadr - 1; - ldp->dvote.v.ncpus = (int)ldp->dncpus - 1; - ldp->dvote.v.board = CPUID_TO_BOARDID(CPU->cpu_id); - - return (1); - } else { - PR_PROTO("%s: NO change detected\n", proc); - return (0); - } -} - -int -get_hw_config(struct hwconfig *loc_hw) -{ - pda_handle_t ph; - boardset_t domainset; - int bd; - int nmcadr; - int nboards; - procname_t proc = "get_hw_config"; - - ASSERT(loc_hw != NULL); - - bzero(loc_hw, sizeof (*loc_hw)); - /* - * See if sm_mask is writable. - * XXX - Should be the same for all CIC's. Do we - * we need to verify? - */ - if (cic_get_smmask_bit() == 0) { - /* - * If smmask is not writable, we can not allow - * IDN operations. - */ - cmn_err(CE_WARN, - "IDN: 506: cic sm_mask is not writeable"); - return (-1); - } - /* - * Map in the post2obp structure so we can find - * valid boards and hardware asics. - */ - ph = pda_open(); - if (ph == (pda_handle_t)NULL) { - cmn_err(CE_WARN, - "IDN: 507: failed to map-in post2obp structure"); - return (-1); - } else if (!pda_is_valid(ph)) { - cmn_err(CE_WARN, "IDN: 508: post2obp checksum invalid"); - pda_close(ph); - return (-1); - } - /* - * Need to read the MC address decoding registers - * so that they can be given to other domains. - */ - loc_hw->dh_boardset = get_boardset(ph, &nboards); - loc_hw->dh_nboards = (short)nboards; - ASSERT(loc_hw->dh_boardset & (1 << CPUID_TO_BOARDID(CPU->cpu_id))); - - mc_get_adr_all(ph, loc_hw->dh_mcadr, &nmcadr); - loc_hw->dh_nmcadr = (short)nmcadr; - - affinity_set(CPU_CURRENT); - /* - * There will always be a bus 0 (logical). - */ - bd = CPUID_TO_BOARDID(CPU->cpu_id); - domainset = (boardset_t)cic_read_domain_mask(bd, 0); - affinity_clear(); - - if (!idn_cpu_per_board(ph, cpu_ready_set, loc_hw)) { - pda_close(ph); - return (-1); - } - - pda_close(ph); - - -#ifdef DEBUG - { - int brd; - - for (brd = 0; brd < MAX_BOARDS; brd++) - if (loc_hw->dh_mcadr[brd] != 0) { - PR_XF("%s: brd %d, mc = 0x%x\n", - proc, brd, loc_hw->dh_mcadr[brd]); - } - } -#endif /* DEBUG */ - - if ((loc_hw->dh_boardset != domainset) || (loc_hw->dh_nmcadr < 1)) - return (-1); - else - return (0); -} - -/* - * Function called via timeout() to wakeup a possibly stuck - * idnxf_shmem_update_all() should not all cpus check-in after a - * x-call to update their respective CICs. - */ -/*ARGSUSED0*/ -static void -idnxf_shmem_wakeup(void *arg) -{ - struct idnxf_cic_info *idnxfp = (struct idnxf_cic_info *)arg; - int count; - int expired; - procname_t proc = "idnxf_shmem_wakeup"; - - expired = ((ddi_get_lbolt() - idnxfp->xf_start_time) >= - IDNCIC_TIMEOUT) ? 1 : 0; - - if ((count = idnxfp->xf_count) == 0) { - /* - * Everybody has finished. Wakeup the requester. - */ - mutex_enter(&idnxfp->xf_mutex); - cv_signal(&idnxfp->xf_cv); - mutex_exit(&idnxfp->xf_mutex); - - } else if ((count > 0) && expired) { - /* - * There are still active cic updaters and time - * has expired. Bail on them. - */ - idnxfp->xf_errtimer = 1; -#ifdef DEBUG - /* - * Special debug case since idn_debug - * may have been temporarily cleared - * during xc_some. - */ - if ((idn_debug | o_idn_debug) & IDNDBG_REGS) - printf("%s: TIMEOUT...bailing on %d lost CIC " - "updates...\n", proc, count); -#endif /* DEBUG */ - - ATOMIC_SUB(idnxfp->xf_count, count); - - mutex_enter(&idnxfp->xf_mutex); - cv_signal(&idnxfp->xf_cv); - mutex_exit(&idnxfp->xf_mutex); - - } else { - (void) timeout(idnxf_shmem_wakeup, (caddr_t)idnxfp, - (clock_t)IDNCIC_TIMECHK); - } -} - -/* - * Called indirectly from idnxf_shmem_update_all() via a xcall - * for the recepient cpu to update the CICs on its respective - * board. - * IMPORTANT: NO console output from this routine!! - */ -static void -idnxf_shmem_update_one(uint64_t arg1, uint64_t arg2) -{ - struct idnxf_cic_info *idnxfp = (struct idnxf_cic_info *)arg1; - time_t start_time = (time_t)arg2; - int rv, cpuid, brd, bus; - boardset_t smmask; - - - cpuid = CPU->cpu_id; - brd = CPUID_TO_BOARDID(cpuid); - - if (idnxfp->xf_start_time != start_time) { - /* - * Ooops! Not my place to intrude. - */ - idnxf_cic_info.xf_errcic[brd][0] = IDNCIC_BUSY; - ATOMIC_INC(idnxf_cic_info.xf_errcnt); - - goto done; - } - - /* - * We're executing out of the context of a cross-call - * so we're effectively bound! :) - */ - for (bus = 0; bus < MAX_ABUSES; bus++) { - /* - * XXX - need to worry about shuffle?? - */ - if (!(idnxfp->xf_abus_mask & (1 << bus))) - continue; - smmask = cic_read_sm_mask(brd, bus); - - if (idnxfp->xf_doadd) { - smmask |= idnxfp->xf_boardset; - (void) cic_write_sm_mask(brd, bus, smmask); - - if (idnxfp->xf_smbase != (uint_t)-1) { - (void) cic_write_sm_bar(brd, bus, - idnxfp->xf_smbase); - (void) cic_write_sm_lar(brd, bus, - idnxfp->xf_smlimit); - } - /* - * Verify data got there! - */ - rv = verify_smregs(brd, bus, smmask, idnxfp->xf_smbase, - idnxfp->xf_smlimit); - } else { - smmask &= ~idnxfp->xf_boardset; - (void) cic_write_sm_mask(brd, bus, smmask); - - if (!smmask) { - /* - * Update the LAR first so that we effectively - * disable the register without possibly - * opening the window to transaction we - * don't care about. Updating the LAR first - * will guarantee we effectively turn it - * off immediately. - */ - (void) cic_write_sm_lar(brd, bus, 0); - (void) cic_write_sm_bar(brd, bus, 1); - - rv = verify_smregs(brd, bus, smmask, 1, 0); - } else { - rv = verify_smregs(brd, bus, smmask, - (uint_t)-1, (uint_t)-1); - } - } - if (rv) { - idnxf_cic_info.xf_errcic[brd][bus] = IDNCIC_ERR; - ATOMIC_INC(idnxf_cic_info.xf_errcnt); - } else { - idnxf_cic_info.xf_errcic[brd][bus] = IDNCIC_OK; - } - } - -done: - ATOMIC_DEC(idnxf_cic_info.xf_count); -} - -static int -idnxf_shmem_update_all(pda_handle_t ph, boardset_t boardset, - uint_t smbase, uint_t smlimit, int doadd) -{ - cpuset_t target_cpuset; - int target_count; - int rv = 0; - int c, brd, bus; - short abus_mask; - time_t start_time; - procname_t proc = "idnxf_shmem_update_all"; - - - ASSERT(MUTEX_HELD(&idn_xf_mutex)); - - pda_get_busmask(ph, &abus_mask, NULL); - - CPUSET_ZERO(target_cpuset); - target_count = 0; - /* - * Build a cpuset of target cpus (one per board) to - * be used to send the CIC update xcall. - */ - for (brd = 0; brd < MAX_BOARDS; brd++) { - /* - * Need to target an available cpu on the target board - * so that we can look at the CICs on that board. - */ - c = board_to_ready_cpu(brd, cpu_ready_set); - - if (c == -1) { - /* - * If there's no cpu on this board, no - * need to update the CICs. - */ - continue; - } - CPUSET_ADD(target_cpuset, c); - target_count++; - } - - if (CPUSET_ISNULL(target_cpuset)) { - PR_REGS("%s: NO target cpus to update!!\n", proc); - return (0); - } - - RESET_CIC_HISTORY(); - - /* - * Broadcast out the CIC update request and then - * sit back and wait for dinner to arrive! - * Let's set up the global structure all the xcall - * recepients will read. - */ - start_time = ddi_get_lbolt(); - /* - * Set the start time. Make sure it's different - * then the previous run. - */ - if (start_time <= idnxf_cic_info.xf_start_time) - start_time++; - idnxf_cic_info.xf_start_time = start_time; - - idnxf_cic_info.xf_abus_mask = abus_mask; - idnxf_cic_info.xf_boardset = boardset; - idnxf_cic_info.xf_smbase = smbase; - idnxf_cic_info.xf_smlimit = smlimit; - idnxf_cic_info.xf_doadd = doadd; - idnxf_cic_info.xf_count = target_count; - idnxf_cic_info.xf_errcnt = 0; - idnxf_cic_info.xf_errtimer = 0; - bzero(&idnxf_cic_info.xf_errcic, sizeof (idnxf_cic_info.xf_errcic)); - - /* - * Broadcast out the xcall to do the task. - */ -#ifdef DEBUG - { - uint_t tu32, tl32; - - tu32 = UPPER32_CPUMASK(target_cpuset); - tl32 = LOWER32_CPUMASK(target_cpuset); - PR_REGS("%s: (start %ld) broadcasting CIC - " - "%s to cpus 0x%x.%0x\n", - proc, start_time, doadd ? "LINK" : "UNLINK", - tu32, tl32); - } - - /* - * Can't dump debug during cross-calls. - */ - o_idn_debug = idn_debug; - idn_debug = 0; -#endif /* DEBUG */ - - xc_attention(target_cpuset); - - xc_some(target_cpuset, idnxf_shmem_update_one, - (uint64_t)&idnxf_cic_info, (uint64_t)start_time); - - xc_dismissed(target_cpuset); - - ASSERT(idnxf_cic_info.xf_count == 0); - -#ifdef DEBUG - idn_debug = o_idn_debug; - o_idn_debug = 0; -#endif /* DEBUG */ - - PR_REGS("%s: waiting for completion of %d CIC - %s...\n", - proc, idnxf_cic_info.xf_count, doadd ? "LINKS" : "UNLINKS"); - PR_REGS("%s: CIC - %s have checked IN.\n", - proc, doadd ? "LINKS" : "UNLINKS"); - - /* - * Modifying xf_start_time effectively disables any - * possible outstanding xcall's since they don't touch - * idnxf_cic_info unless their given start_time matches - * that in the idnxf_cic_info structure. - */ - idnxf_cic_info.xf_start_time++; - - PR_REGS("%s: xf_errcnt = %d, xf_errtimer = %d\n", - proc, idnxf_cic_info.xf_errcnt, idnxf_cic_info.xf_errtimer); - DUMP_CIC_HISTORY(); - /* - * Should errors be fatal? (panic). - */ - rv = 0; - for (c = 0; c < NCPU; c++) { - if (!CPU_IN_SET(target_cpuset, c)) - continue; - brd = CPUID_TO_BOARDID(c); - - for (bus = 0; bus < MAX_ABUSES; bus++) { - - if (!(abus_mask & (1 << bus))) - continue; - - switch (idnxf_cic_info.xf_errcic[brd][bus]) { - case IDNCIC_UNKNOWN: - /* - * Unknown is only an error if the - * timer expired. - */ - if (!idnxf_cic_info.xf_errtimer) - break; - cmn_err(CE_WARN, - "IDN: 509: CPU %d never responded " - "to CIC update", c); - /*FALLTHROUGH*/ - - case IDNCIC_ERR: - cmn_err(CE_WARN, - "IDN: 510: failed write-smregs " - "(bd=%d, bs=%d, sm(bar=0x%x, " - "lar=0x%x))", - brd, bus, smbase, smlimit); - rv++; - break; - - case IDNCIC_BUSY: - cmn_err(CE_WARN, "IDN: 511: update-one " - "(cpu=%d, bd=%d) time conflict", - c, brd); - /* - * Should never occur. Not fatal, - * just continue. - */ - break; - - default: - PR_REGS("%s: board %d, bus %d " - "(bar=0x%x,lar=0x%x) - update OK\n", - proc, brd, bus, smbase, smlimit); - break; - } - } - } - - return (rv ? -1 : 0); -} - -/* - * Add the respective boardset/base/limit/mcadr's to the local - * domain's hardware configuration with respect to the SMR. - * - * is_master Indicates remote domain is a master. - */ -int -idnxf_shmem_add(int is_master, boardset_t boardset, pfn_t pfnbase, - pfn_t pfnlimit, uint_t *mcadr) -{ - int rv = 0; - register int brd, rbrd; - register boardset_t localboardset; - uint_t madr; - uint_t smbase, smlimit; - pda_handle_t ph; - procname_t proc = "idnxf_shmem_add"; - - - localboardset = idn_domain[idn.localid].dhw.dh_boardset; - - ASSERT(localboardset && boardset && ((localboardset & boardset) == 0)); - ASSERT(is_master ? (pfnbase && pfnlimit && mcadr) : 1); - - if (pfnbase != PFN_INVALID) { - smbase = (uint_t)PFN_TO_SMADDR(pfnbase); - smlimit = (uint_t)PFN_TO_SMADDR(pfnlimit); - } else { - smbase = smlimit = (uint_t)-1; - } - PR_REGS("%s: is_master=%d, boardset=0x%x, smbase=0x%x, smlimit=%x\n", - proc, is_master, boardset, smbase, smlimit); - - /* - * Need to serialize hardware access so we don't have multiple - * threads attempting to access hardware regs simulataneously. - * This should not be a significant performance penalty since - * the hardware is only touched when domains are linking or - * unlinking. - */ - mutex_enter(&idn_xf_mutex); - - /* - * Map in the post2obp structure so we can find - * bus config information. - */ - ph = pda_open(); - if (ph == (pda_handle_t)NULL) { - cmn_err(CE_WARN, - "IDN: 507: failed to map-in post2obp structure"); - rv = -1; - goto done; - - } else if (!pda_is_valid(ph)) { - cmn_err(CE_WARN, "IDN: 508: post2obp checksum invalid"); - rv = -1; - goto done; - } - /* - * Take a checkpoint in bbsram for diagnostic purposes. - */ - CHECKPOINT_OPENED(IDNSB_CHKPT_SMR, boardset, 1); - - rv = idnxf_shmem_update_all(ph, boardset, smbase, smlimit, 1); - - if (rv || (is_master == 0)) - goto done; - - /* - * If this is a slave (i.e. remote domain is_master), - * then we need to deprogram our PCs. - */ - PR_REGS("%s: updating PC regs (lboardset=0x%x, rboardset=0x%x)\n", - proc, localboardset, boardset); - - for (brd = 0; brd < MAX_BOARDS; brd++) { - - if (!BOARD_IN_SET(localboardset, brd)) - continue; - /* - * If this is a slave (i.e. remote domain is_master), - * then we need to program our PCs. - */ - for (rbrd = 0; rbrd < MAX_BOARDS; rbrd++) { - - if ((madr = mcadr[rbrd]) == 0) - continue; - - ASSERT(BOARD_IN_SET(boardset, rbrd)); - /* - * Write the MC adr for the respective - * remote board (rbrd) into the PCs of - * the given local board (brd). - */ - if (pc_write_madr(ph, brd, rbrd, madr) < 0) { - cmn_err(CE_WARN, - "IDN: 512: failed [add] write-madr " - "(bd=%d, rbd=%d, madr=0x%x)", - brd, rbrd, madr); - rv = -1; - goto done; - } - } - } - -done: - if (ph) - pda_close(ph); - - mutex_exit(&idn_xf_mutex); - /* - * XXX - * - * Failure here is fatal. Disable IDN? - * NOn-zero return value will at least prevent - * linkage with domain - probably sufficient. - */ - return (rv); -} - -/* - * Remove the respective boardset from the local domain's - * hardware configuration with respect to the SMR. - * - * is_master Indicates remote domain is a master. - */ -int -idnxf_shmem_sub(int is_master, boardset_t boardset) -{ - int rv = 0; - register int brd, rbrd; - register boardset_t localboardset; - pda_handle_t ph; - procname_t proc = "idnxf_shmem_sub"; - - localboardset = idn_domain[idn.localid].dhw.dh_boardset; - - ASSERT(localboardset && boardset && ((localboardset & boardset) == 0)); - - PR_REGS("%s: is_master=%d, boardset=0x%x\n", - proc, is_master, boardset); - - /* - * Need to serialize hardware access so we don't have multiple - * threads attempting to access hardware regs simulataneously. - * This should not be a significant performance penalty since - * the hardware is only touched when domains are linking or - * unlinking. - */ - mutex_enter(&idn_xf_mutex); - - /* - * Map in the post2obp structure so we can find - * bus config information. - */ - ph = pda_open(); - if (ph == (pda_handle_t)NULL) { - cmn_err(CE_WARN, - "IDN: 507: failed to map-in post2obp structure"); - rv = -1; - goto done; - - } else if (!pda_is_valid(ph)) { - cmn_err(CE_WARN, "IDN: 508: post2obp checksum invalid"); - rv = -1; - goto done; - } - /* - * Take a checkpoint in bbsram for diagnostic purposes. - */ - CHECKPOINT_CLOSED(IDNSB_CHKPT_SMR, boardset, 2); - - rv = idnxf_shmem_update_all(ph, boardset, (uint_t)-1, (uint_t)-1, 0); - - if (rv || (is_master == 0)) - goto done; - - /* - * If this is a slave (i.e. remote domain is_master), - * then we need to deprogram our PCs. - */ - PR_REGS("%s: reseting PC regs (lboardset=0x%x, rboardset=0x%x)\n", - proc, localboardset, boardset); - - for (brd = 0; brd < MAX_BOARDS; brd++) { - - if (!BOARD_IN_SET(localboardset, brd)) - continue; - - for (rbrd = 0; rbrd < MAX_BOARDS; rbrd++) { - - if (!BOARD_IN_SET(boardset, rbrd)) - continue; - /* - * Clear the MC adr for the respective - * remote board (rbrd) into the PCs of - * the given local board (brd). - */ - if (pc_write_madr(ph, brd, rbrd, 0) < 0) { - cmn_err(CE_WARN, - "IDN: 512: failed [del] write-madr " - "(bd=%d, rbd=%d, madr=0x%x)", - brd, rbrd, 0); - rv = -1; - goto done; - } - } - } - -done: - if (ph) - pda_close(ph); - mutex_exit(&idn_xf_mutex); - - return (rv); -} - -/* - * We cannot cross-trap cpu_flush_ecache since it references - * %g7 via CPU. It's possible that %g7 may not be set up - * when the trap comes in, and could thus cause a crash. - * Well...at least that's what has been happening when I - * tried x-calls within an xc_attention (KMISS) panic. - * Instead we use cross-calls. However, since we can't - * xc_attention around a cross-call, we have not guaranteed - * way of knowing the operation succeeded. To synchronize - * this flush operation across cpus, we use a semaphore - * which is V'd by the receiving cpus and P'd by the caller - * initiating the all-cpus flush. - */ -/*ARGSUSED0*/ -void -idn_flush_ecache(uint64_t arg1, uint64_t arg2) -{ - extern void cpu_flush_ecache(void); - - cpu_flush_ecache(); - /* - * Paranoia...Give things a chance to drain. - */ - drv_usecwait(500000); /* 500 msec */ -} -/* - * Flush the ecache's of all the cpus within this domain of - * any possible SMR references. - * This logic is borrowed from ecc.c:cpu_flush_ecache(). - */ -void -idnxf_flushall_ecache() -{ - cpuset_t local_cpuset; - procname_t proc = "idnxf_flushall_ecache"; - - - PR_XF("%s: flushing ecache (cpu_ready_set = 0x%x.%x)\n", proc, - UPPER32_CPUMASK(cpu_ready_set), LOWER32_CPUMASK(cpu_ready_set)); - - CHECKPOINT_CACHE_CLEAR_DEBUG(1); - CHECKPOINT_CACHE_STEP_DEBUG(0x1, 2); - - local_cpuset = cpu_ready_set; - - xc_attention(local_cpuset); - - /* - * We tell each cpu to do a flush and then we hit - * a semaphore to synchronize with all of them - * to guarantee they have completed the flush before - * we continue on. We have to do this type of - * sychronization since we can't xc_attention around - * a cross-call. - */ - CHECKPOINT_CACHE_STEP_DEBUG(0x2, 3); - - xc_all(idn_flush_ecache, 0, 0); - - CHECKPOINT_CACHE_STEP_DEBUG(0x4, 4); - - xc_dismissed(local_cpuset); - - CHECKPOINT_CACHE_STEP_DEBUG(0x8, 5); -} - -/* - * -------------------------------------------------- - */ -static int -verify_smregs(int brd, int bus, boardset_t smmask, uint_t smbase, uint_t - smlimit) -{ - int rv = 0; - uint_t smreg; - - if (smmask != (boardset_t)-1) { - smreg = (uint_t)cic_read_sm_mask(brd, bus); - if (smreg != (uint_t)smmask) { - cmn_err(CE_WARN, - "IDN: 513: sm-mask error " - "(expected = 0x%x, actual = 0x%x)", - (uint_t)smmask, smreg); - rv++; - } - } - - if (smbase != (uint_t)-1) { - smreg = cic_read_sm_bar(brd, bus); - if (smreg != smbase) { - cmn_err(CE_WARN, - "IDN: 514: sm-base error " - "(expected = 0x%x, actual = 0x%x)", - smbase, smreg); - rv++; - } - } - - if (smlimit != (uint_t)-1) { - smreg = cic_read_sm_lar(brd, bus); - if (smreg != smlimit) { - cmn_err(CE_WARN, - "IDN: 515: sm-limit error " - "(expected = 0x%x, actual = 0x%x)", - smlimit, smreg); - rv++; - } - } - - return (rv ? -1 : 0); -} - -/* - * ------------------------------------------------------------- - */ -int -idn_cpu_per_board(pda_handle_t ph, cpuset_t cset, struct hwconfig *hwp) -{ - int b, err = 0; - boardset_t bset, cpu_bset; - board_desc_t *lbp; - - if (!idn_check_cpu_per_board) - return (1); - - bset = hwp->dh_boardset; - CPUSET_TO_BOARDSET(cset, cpu_bset); - - /* - * Every board has at least one cpu, we're happy. - */ - if (cpu_bset == bset) - return (1); - - /* - * Well, not all boards had cpus. That's okay so - * long as they don't have memory also. - * Get rid of the boards that have a cpu. - */ - bset &= ~cpu_bset; - /* - * None of the remaining boards in the set shold have mem. - */ - err = 0; - - /* - * A NULL post2obp pointer indicates we're checking - * the config of a remote domain. Since we can't - * look at the post2obp of the remote domain, we'll - * have to trust what it passed us in its config. - */ - if (ph && !pda_is_valid(ph)) { - cmn_err(CE_WARN, "IDN: 508: post2obp checksum invalid"); - return (0); - } - - for (b = 0; b < MAX_BOARDS; b++) { - if (!BOARD_IN_SET(bset, b)) - continue; - - lbp = ph ? pda_get_board_info(ph, b) : NULL; - - if ((lbp && - (BDA_NBL(lbp->bda_board, BDA_MC_NBL) == BDAN_GOOD)) || - (!lbp && hwp->dh_mcadr[b])) { - err++; - cmn_err(CE_WARN, - "IDN: 516: (%s) board %d has memory, " - "but no CPUs - CPU per memory board REQUIRED", - ph ? "local" : "remote", b); - } - } - - return (err ? 0 : 1); -} diff --git a/usr/src/uts/sun4u/starfire/io/memctrl.c b/usr/src/uts/sun4u/starfire/io/memctrl.c deleted file mode 100644 index 953542f3cb..0000000000 --- a/usr/src/uts/sun4u/starfire/io/memctrl.c +++ /dev/null @@ -1,276 +0,0 @@ -/* - * 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 - * or http://www.opensolaris.org/os/licensing. - * 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" - -/* - * Starfire Memory Controller specific routines. - */ - -#include <sys/debug.h> -#include <sys/types.h> -#include <sys/errno.h> -#include <sys/dditypes.h> -#include <sys/conf.h> -#include <sys/ddi.h> -#include <sys/sunddi.h> -#include <sys/sunndi.h> -#include <sys/ddi_impldefs.h> -#include <sys/promif.h> -#include <sys/machsystm.h> - -#include <sys/starfire.h> - -struct mc_dimm_table { - int mc_type; - int mc_module_size; /* module size in MB */ -}; - -static struct mc_dimm_table dimmsize_table[] = { - { 4, 8 }, - { 6, 8 }, - { 11, 32 }, - { 15, 128 }, - { 0, 0 } -}; - -#define MC_MB(mb) ((mb) * 1048576ull) - -struct mc_seg_size { - uint_t seg_mask; - uint64_t seg_size; -}; - -struct mc_seg_size mc_seg_table[] = { - { 0x7f, MC_MB(64) }, - { 0x7e, MC_MB(128) }, - { 0x7c, MC_MB(256) }, - { 0x78, MC_MB(512) }, - { 0x70, MC_MB(1024) }, - { 0x60, MC_MB(2048) }, - { 0x40, MC_MB(4096) }, - { 0, 0 } -}; - -/* - * Alignment of memory between MC's. - */ -uint64_t -mc_get_mem_alignment() -{ - return (STARFIRE_MC_MEMBOARD_ALIGNMENT); -} - -uint64_t -mc_get_asr_addr(pnode_t nodeid) -{ - int rlen; - uint64_t psi_addr; - struct sf_memunit_regspec reg; - - rlen = prom_getproplen(nodeid, "reg"); - if (rlen != sizeof (struct sf_memunit_regspec)) - return ((uint64_t)-1); - - if (prom_getprop(nodeid, "reg", (caddr_t)®) < 0) - return ((uint64_t)-1); - - psi_addr = ((uint64_t)reg.regspec_addr_hi) << 32; - psi_addr |= (uint64_t)reg.regspec_addr_lo; - - return (STARFIRE_MC_ASR_ADDR(psi_addr)); -} - -uint64_t -mc_get_idle_addr(pnode_t nodeid) -{ - int rlen; - uint64_t psi_addr; - struct sf_memunit_regspec reg; - - rlen = prom_getproplen(nodeid, "reg"); - if (rlen != sizeof (struct sf_memunit_regspec)) - return ((uint64_t)-1); - - if (prom_getprop(nodeid, "reg", (caddr_t)®) < 0) - return ((uint64_t)-1); - - psi_addr = ((uint64_t)reg.regspec_addr_hi) << 32; - psi_addr |= (uint64_t)reg.regspec_addr_lo; - - return (STARFIRE_MC_IDLE_ADDR(psi_addr)); -} - -int -mc_get_dimm_size(pnode_t nodeid) -{ - uint64_t psi_addr; - uint_t dimmtype; - int i, rlen; - struct sf_memunit_regspec reg; - - rlen = prom_getproplen(nodeid, "reg"); - if (rlen != sizeof (struct sf_memunit_regspec)) - return (-1); - - if (prom_getprop(nodeid, "reg", (caddr_t)®) < 0) - return (-1); - - psi_addr = ((uint64_t)reg.regspec_addr_hi) << 32; - psi_addr |= (uint64_t)reg.regspec_addr_lo; - psi_addr = STARFIRE_MC_DIMMTYPE_ADDR(psi_addr); - - if (psi_addr == (uint64_t)-1) - return (-1); - - dimmtype = ldphysio(psi_addr); - dimmtype &= STARFIRE_MC_DIMMSIZE_MASK; - - for (i = 0; dimmsize_table[i].mc_type != 0; i++) - if (dimmsize_table[i].mc_type == dimmtype) - break; - - return (dimmsize_table[i].mc_module_size); -} - -uint64_t -mc_get_alignment_mask(pnode_t nodeid) -{ - uint64_t psi_addr, seg_sz; - uint_t mcreg, seg_sz_mask; - int i, rlen; - struct sf_memunit_regspec reg; - - rlen = prom_getproplen(nodeid, "reg"); - if (rlen != sizeof (struct sf_memunit_regspec)) - return (-1); - - if (prom_getprop(nodeid, "reg", (caddr_t)®) < 0) - return (-1); - - psi_addr = ((uint64_t)reg.regspec_addr_hi) << 32; - psi_addr |= (uint64_t)reg.regspec_addr_lo; - psi_addr = STARFIRE_MC_ASR_ADDR(psi_addr); - - if (psi_addr == (uint64_t)-1) - return (-1); - - mcreg = ldphysio(psi_addr); - seg_sz_mask = (mcreg & STARFIRE_MC_MASK_MASK) >> 8; - - for (i = 0; mc_seg_table[i].seg_size != 0; i++) - if (mc_seg_table[i].seg_mask == seg_sz_mask) - break; - - if (mc_seg_table[i].seg_size == 0) - seg_sz = mc_get_mem_alignment(); - else - seg_sz = mc_seg_table[i].seg_size; - -#ifdef DEBUG - printf("nodeid %x, mc asr addr %lx, val %x, seg_sz_mask %x, " - "seg_sz %lx\n", nodeid, psi_addr, mcreg, seg_sz_mask, seg_sz); -#endif /* DEBUG */ - - return (seg_sz - 1); -} - -int -mc_read_asr(pnode_t nodeid, uint_t *mcregp) -{ - uint64_t psi_addr; - - *mcregp = 0; - - psi_addr = mc_get_asr_addr(nodeid); - if (psi_addr == (uint64_t)-1) - return (-1); - - *mcregp = ldphysio(psi_addr); - - return (0); -} - -int -mc_write_asr(pnode_t nodeid, uint_t mcreg) -{ - uint_t mcreg_rd; - uint64_t psi_addr; - - psi_addr = mc_get_asr_addr(nodeid); - if (psi_addr == (uint64_t)-1) - return (-1); - - stphysio(psi_addr, mcreg); - - mcreg_rd = ldphysio(psi_addr); - ASSERT(mcreg_rd == mcreg); - - return ((mcreg_rd != mcreg) ? -1 : 0); -} - -uint64_t -mc_asr_to_pa(uint_t mcreg) -{ - uint64_t pa, masr, addrmask, lowbitmask; - - /* - * Remove memory present bit. - */ - masr = (uint64_t)(mcreg & ~STARFIRE_MC_MEM_PRESENT_MASK); - /* - * Get mask for bits 32-26. - */ - lowbitmask = masr & (uint64_t)STARFIRE_MC_MASK_MASK; - lowbitmask <<= STARFIRE_MC_MASK_SHIFT; - addrmask = STARFIRE_MC_ADDR_HIBITS | lowbitmask; - - pa = (masr << STARFIRE_MC_BASE_SHIFT) & addrmask; - - return (pa); -} - -uint_t -mc_pa_to_asr(uint_t masr, uint64_t pa) -{ - uint64_t addrmask, lowbitmask; - uint_t base; - - /* - * Get mask for bits 32-26. - */ - lowbitmask = masr & (uint64_t)STARFIRE_MC_MASK_MASK; - lowbitmask <<= STARFIRE_MC_MASK_SHIFT; - addrmask = STARFIRE_MC_ADDR_HIBITS | lowbitmask; - - base = (pa & addrmask) >> STARFIRE_MC_BASE_SHIFT; - masr &= ~ STARFIRE_MC_MEM_BASEADDR_MASK; - masr |= base & STARFIRE_MC_MEM_BASEADDR_MASK; - - ASSERT(mc_asr_to_pa(masr) == pa); - - return (masr); -} diff --git a/usr/src/uts/sun4u/starfire/io/ngdr.conf b/usr/src/uts/sun4u/starfire/io/ngdr.conf deleted file mode 100644 index 85b7a4e81f..0000000000 --- a/usr/src/uts/sun4u/starfire/io/ngdr.conf +++ /dev/null @@ -1,28 +0,0 @@ -# -# 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 -# or http://www.opensolaris.org/os/licensing. -# 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 (c) 2001 by Sun Microsystems, Inc. -# All rights reserved. -# -#ident "%Z%%M% %I% %E% SMI" - -name="ngdr" parent="pseudo" instance=0; diff --git a/usr/src/uts/sun4u/starfire/io/portctrl.c b/usr/src/uts/sun4u/starfire/io/portctrl.c deleted file mode 100644 index adfe173833..0000000000 --- a/usr/src/uts/sun4u/starfire/io/portctrl.c +++ /dev/null @@ -1,271 +0,0 @@ -/* - * 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 - * or http://www.opensolaris.org/os/licensing. - * 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 1990-2002 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -#pragma ident "%Z%%M% %I% %E% SMI" - -#include <sys/types.h> -#include <sys/cmn_err.h> -#include <sys/kmem.h> -#include <sys/debug.h> -#include <sys/machsystm.h> -#include <sys/starfire.h> - -/* - * Interrupt target translation data for - * Starfire's Port controller asics - */ -struct pc_ittrans_data { - kmutex_t ittrans_lock; /* lock for ITTR array */ - volatile uint64_t *ittrans_mondovec[32]; /* mondovecreg addr array */ - uint64_t ittransreg_physaddr[32]; /* ITTREG physaddr array */ -}; - -/* - * Setup and initialize the soft table that - * represent the Starfire interrupt target translation - * registers in the Port controller asics. There is one - * for each sysio/pci instance. - */ -void -pc_ittrans_init(int upa_id, caddr_t *ittptr_cookie) -{ - int i; - uint64_t physaddr; - struct pc_ittrans_data *tmpptr; - - ASSERT(ittptr_cookie != NULL); - - /* - * Allocate the data structure to support starfire's - * interrupt target translations - */ - tmpptr = (struct pc_ittrans_data *) - kmem_zalloc(sizeof (struct pc_ittrans_data), - KM_SLEEP); - - /* Initialize the ittrans lock */ - mutex_init(&tmpptr->ittrans_lock, NULL, MUTEX_DEFAULT, NULL); - - /* - * Construct the base physical address of the - * ITTR registers associated with this PC asics - */ - physaddr = STARFIRE_UPAID2UPS(upa_id); - physaddr |= (STARFIRE_PSI_BASE | STARFIRE_PSI_PCREG_OFF | - STARFIRE_PC_INT_MAP); - - /* - * Initialize the ITTR table - * This soft table is used to represent the interrupt - * target translation hardware registers in the Starfire's - * PC asics. There are 32 slots and each slot consists of - * a mondovec regaddr entry and the physical address of - * the that ITT register. A empty slot is one whose - * mondovec entry is null. To reserve/use a slot for a - * particular intr mapping reg, we simply find - * a empty slot and write in the mondovec mapping - * regaddr into the mondovec field. - */ - for (i = 0; i < 32; i++) { - tmpptr->ittrans_mondovec[i] = NULL; - tmpptr->ittransreg_physaddr[i] = physaddr + i*16; - } - - *ittptr_cookie = (caddr_t)tmpptr; -} - -void -pc_ittrans_uninit(caddr_t ittr_cookie) -{ - struct pc_ittrans_data *tmpptr; - - ASSERT(ittr_cookie != NULL); - - tmpptr = (struct pc_ittrans_data *)ittr_cookie; - - mutex_destroy(&tmpptr->ittrans_lock); - kmem_free((int *)ittr_cookie, sizeof (struct pc_ittrans_data)); -} - -/* - * This routine searches for a slot in the soft ITTR table - * that was reserved earlier by matching the mondovec - * mapping regaddr argument with the corresponding field in - * the table. Note that the soft ITTR table mirrors the - * corresponding hw table in the starfire port controller(PC) - * asics. A new slot will be obtained if the slot cannot - * be found. (not reserved previously). The routine then programs - * in the target cpu id into the PC ITTR hardware, updates the - * soft table and return the index to this slot as the target - * id cookie. - */ -int -pc_translate_tgtid(caddr_t ittr_cookie, int cpu_id, - volatile uint64_t *mondovec_addr) -{ - struct pc_ittrans_data *ittptr; - int i; - int foundslot = -1; - - ASSERT(ittr_cookie != NULL); - - ittptr = (struct pc_ittrans_data *)ittr_cookie; - - mutex_enter(&ittptr->ittrans_lock); - - /* - * Search the mondovec addrlist to see if we - * already reserved/used a slot for this particular - * mondovec mapping regaddr. - */ - for (i = 0; i < 32; i++) { - if (mondovec_addr == ittptr->ittrans_mondovec[i]) { - /* - * found the slot that matches the - * mondo vec in question - */ - foundslot = i; - break; - } - if (foundslot == -1 && ittptr->ittrans_mondovec[i] == NULL) - /* keep track of a empty slot */ - foundslot = i; - } - - if (foundslot != -1) { - /* We found a slot for this mondo vec, let's use it */ - stphysio(ittptr->ittransreg_physaddr[foundslot], - STARFIRE_UPAID2HWMID(cpu_id)); - ittptr->ittrans_mondovec[foundslot] = mondovec_addr; - } else { - cmn_err(CE_PANIC, "No more ITTR slots!!"); - } - - mutex_exit(&ittptr->ittrans_lock); - return (foundslot); -} - -/* - * This routine searches the interrupt target translation table - * (if exists) for a slot that was reserved/used earlier by - * matching the mondovec_addr input argument with the mondovec - * field in the table. The routine then free the found slot by - * resetting it to zero. - */ -void -pc_ittrans_cleanup(caddr_t ittr_cookie, - volatile uint64_t *mondovec_addr) -{ - - struct pc_ittrans_data *ittptr; - int i; - int foundslot = -1; - - ASSERT(ittr_cookie != NULL); - - ittptr = (struct pc_ittrans_data *)ittr_cookie; - - mutex_enter(&ittptr->ittrans_lock); - - /* - * Search the mondovec addrlist for the reserved/used - * slot associated with this particular mondo vector. - */ - for (i = 0; i < 32; i++) { - if (mondovec_addr == ittptr->ittrans_mondovec[i]) { - /* - * found the slot that matches the - * mondo vec in question - */ - foundslot = i; - break; - } - } - - if (foundslot != -1) { - /* We found a slot for this mondo vec, clear it */ - ittptr->ittrans_mondovec[foundslot] = 0; - } - - mutex_exit(&ittptr->ittrans_lock); -} - -int -pc_madr_add(int lboard, int rboard, int proc, uint_t madr) -{ - register int i; - uint_t madr_rd, madr_off; - uint64_t pc_madr_addr; - - pc_madr_addr = STARFIRE_PC_MADR_ADDR(lboard, rboard, proc); - - /* - * First write with Presence bit disabled - * and then with it enabled. - */ - madr_off = madr & ~STARFIRE_MC_MEM_PRESENT_MASK; - stphysio(pc_madr_addr, madr_off); - - for (i = 0; i < 20; i++) { - madr_rd = ldphysio(pc_madr_addr); - if (madr_off == madr_rd) - break; - } - if (madr_off != madr_rd) { - cmn_err(CE_WARN, - "pc_madr_add: (1) failed to update " - "PC MADR (%d, %d, %d, 0x%x)\n", - lboard, rboard, proc, madr); - return (-1); - } - if (madr == madr_off) { - /* - * Caller wanted to write value out there - * with presence bit turned off, which is - * what we just completed. So, we're finished. - */ - return (0); - } - /* - * Now write with Presence bit enabled. - */ - stphysio(pc_madr_addr, madr); - - for (i = 0; i < 20; i++) { - madr_rd = ldphysio(pc_madr_addr); - if (madr == madr_rd) - break; - } - if (madr != madr_rd) { - cmn_err(CE_WARN, - "pc_madr_add: (2) failed to update " - "PC MADR (%d, %d, %d, 0x%x)\n", - lboard, rboard, proc, madr); - return (-1); - } - - return (0); -} diff --git a/usr/src/uts/sun4u/starfire/ml/drmach.il.cpp b/usr/src/uts/sun4u/starfire/ml/drmach.il.cpp deleted file mode 100644 index f948876aa4..0000000000 --- a/usr/src/uts/sun4u/starfire/ml/drmach.il.cpp +++ /dev/null @@ -1,222 +0,0 @@ -/* - * 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 - * or http://www.opensolaris.org/os/licensing. - * 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 2001,2003 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -#pragma ident "%Z%%M% %I% %E% SMI" - -/* - * This file is through cpp before being used as - * an inline. It contains support routines used - * only by DR for the copy-rename sequence. - */ - -#if defined(lint) -#include <sys/types.h> -#endif /* lint */ - -#ifndef INLINE - -#include <sys/asm_linkage.h> - -#else /* INLINE */ - -#define ENTRY_NP(x) .inline x,0 -#define retl /* nop */ -#define SET_SIZE(x) .end - -#endif /* INLINE */ - -#include <sys/privregs.h> -#include <sys/sun4asi.h> -#include <sys/machparam.h> - -/* - * Bcopy routine used by DR to copy - * between physical addresses. - * Borrowed from Starfire DR 2.6. - */ -#if defined(lint) - -/*ARGSUSED*/ -void -bcopy32_il(uint64_t paddr1, uint64_t paddr2) -{} - -#else /* lint */ - - ENTRY_NP(bcopy32_il) - .register %g2, #scratch - .register %g3, #scratch - rdpr %pstate, %o4 - andn %o4, PSTATE_IE | PSTATE_AM, %g3 ! clear IE, AM bits - wrpr %g0, %g3, %pstate - - ldxa [%o0]ASI_MEM, %o2 - add %o0, 8, %o0 - ldxa [%o0]ASI_MEM, %o3 - add %o0, 8, %o0 - ldxa [%o0]ASI_MEM, %g1 - add %o0, 8, %o0 - ldxa [%o0]ASI_MEM, %g2 - - stxa %o2, [%o1]ASI_MEM - add %o1, 8, %o1 - stxa %o3, [%o1]ASI_MEM - add %o1, 8, %o1 - stxa %g1, [%o1]ASI_MEM - add %o1, 8, %o1 - stxa %g2, [%o1]ASI_MEM - - retl - wrpr %g0, %o4, %pstate ! restore earlier pstate register value - SET_SIZE(bcopy32_il) - -#endif /* lint */ - -#if defined(lint) - -/*ARGSUSED*/ -void -flush_ecache_il(uint64_t physaddr, uint_t size, uint_t linesize) -{} - -#else /* lint */ - - ENTRY_NP(flush_ecache_il) - srl %o1, 0, %o1 ! clear upper 32 bits - srl %o2, 0, %o2 ! clear upper 32 bits - rdpr %pstate, %o3 - andn %o3, PSTATE_IE | PSTATE_AM, %o4 - wrpr %g0, %o4, %pstate ! clear AM to access 64 bit physaddr - b 2f - nop -1: - ldxa [%o0 + %o1]ASI_MEM, %g0 ! start reading from physaddr + size -2: - subcc %o1, %o2, %o1 - bgeu,a 1b - nop - - ! retl - wrpr %g0, %o3, %pstate ! restore earlier pstate - SET_SIZE(flush_ecache_il) - -#endif /* lint */ - -#if defined(lint) - -/*ARGUSED*/ -void -stphysio_il(uint64_t physaddr, u_int value) -{} - -/*ARGSUSED*/ -u_int -ldphysio_il(uint64_t physaddr) -{ return(0); } - -#else /* lint */ - - ENTRY_NP(stphysio_il) - rdpr %pstate, %o2 /* read PSTATE reg */ - andn %o2, PSTATE_IE | PSTATE_AM, %o3 - wrpr %g0, %o3, %pstate - stwa %o1, [%o0]ASI_IO /* store value via bypass ASI */ - retl - wrpr %g0, %o2, %pstate /* restore the PSTATE */ - SET_SIZE(stphysio_il) - - ! - ! load value at physical address in I/O space - ! - ! u_int ldphysio_il(uint64_t physaddr) - ! - ENTRY_NP(ldphysio_il) - rdpr %pstate, %o2 /* read PSTATE reg */ - andn %o2, PSTATE_IE | PSTATE_AM, %o3 - wrpr %g0, %o3, %pstate - lduwa [%o0]ASI_IO, %o0 /* load value via bypass ASI */ - retl - wrpr %g0, %o2, %pstate /* restore pstate */ - SET_SIZE(ldphysio_il) - -#endif /* lint */ - -#if defined(lint) - -/* - * Argument to drmach_exec_script_il is a pointer to: - * - * typedef struct { - * uint64_t masr_addr; - * uint_t masr; - * uint_t _filler; - * } drmach_rename_script_t; - */ - -/*ARGUSED*/ -void -drmach_exec_script_il(void *sp) -{} - -#else /* lint */ - - ENTRY_NP(drmach_exec_script_il) - mov %o0, %o2 -0: /* cache script */ - ldx [%o2], %o1 - cmp %g0, %o1 - bnz,pt %xcc, 0b - add %o2, 16, %o2 - - rdpr %pstate, %o4 /* read PSTATE reg */ - andn %o4, PSTATE_IE | PSTATE_AM, %o1 - wrpr %g0, %o1, %pstate - - b 2f /* cache it */ - nop -1: - ldx [%o0], %o1 - cmp %g0, %o1 - bz,pn %xcc, 5f - ld [%o0 + 8], %o2 - b 3f - stwa %o2, [%o1]ASI_IO -2: - b 4f /* cache it */ - nop -3: - add %o0, 16, %o0 - b 1b - lduwa [%o1]ASI_IO, %g0 /* read back to insure written */ -4: - b 1b /* caching done */ - nop -5: - retl - wrpr %g0, %o4, %pstate /* restore the PSTATE */ - SET_SIZE(drmach_exec_script_il) - -#endif /* lint */ diff --git a/usr/src/uts/sun4u/starfire/ml/drmach_asm.s b/usr/src/uts/sun4u/starfire/ml/drmach_asm.s deleted file mode 100644 index 3c825df992..0000000000 --- a/usr/src/uts/sun4u/starfire/ml/drmach_asm.s +++ /dev/null @@ -1,361 +0,0 @@ -/* - * 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 - * or http://www.opensolaris.org/os/licensing. - * See the License for the specific language governing permissions - * and limitations under the License. - * - * When distributing Covered Code, include this CDDL HEADER in each - * file and include the License file at usr/src/OPENSOLARIS.LICENSE. - * If applicable, add the following below this CDDL HEADER, with the - * fields enclosed by brackets "[]" replaced with your own identifying - * information: Portions Copyright [yyyy] [name of copyright owner] - * - * CDDL HEADER END - */ -/* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -#pragma ident "%Z%%M% %I% %E% SMI" - -/* - * This file is through cpp before being used as - * an inline. It contains support routines used - * only by DR for the copy-rename sequence. - */ - -#if defined(lint) -#include <sys/types.h> -#else -#include "assym.h" -#endif /* lint */ - -#include <sys/asm_linkage.h> -#include <sys/param.h> -#include <sys/privregs.h> -#include <sys/machasi.h> -#include <sys/spitregs.h> -#include <sys/mmu.h> -#include <sys/machthread.h> -#include <sys/pte.h> -#include <sys/stack.h> -#include <sys/vis.h> - -#ifndef lint - -/* - * arg1 = icache_size - * arg2 = icache_linesize - */ -#define ICACHE_FLUSHALL(lbl, arg1, arg2, tmp1) \ - ldxa [%g0]ASI_LSU, tmp1 ;\ - btst LSU_IC, tmp1 ;\ - bz,pn %icc, lbl/**/1 ;\ - sub arg1, arg2, tmp1 ;\ -lbl/**/0: ;\ - stxa %g0, [tmp1]ASI_IC_TAG ;\ - membar #Sync ;\ - cmp %g0, tmp1 ;\ - bne,pt %icc, lbl/**/0 ;\ - sub tmp1, arg2, tmp1 ;\ -lbl/**/1: - -/* - * arg1 = dcache_size - * arg2 = dcache_linesize - */ -#define DCACHE_FLUSHALL(lbl, arg1, arg2, tmp1) \ - ldxa [%g0]ASI_LSU, tmp1 ;\ - btst LSU_DC, tmp1 ;\ - bz,pn %icc, lbl/**/1 ;\ - sub arg1, arg2, tmp1 ;\ -lbl/**/0: ;\ - stxa %g0, [tmp1]ASI_DC_TAG ;\ - membar #Sync ;\ - cmp %g0, tmp1 ;\ - bne,pt %icc, lbl/**/0 ;\ - sub tmp1, arg2, tmp1 ;\ -lbl/**/1: - -/* - * arg1 = ecache flush physaddr - * arg2 = size - * arg3 = ecache_linesize - */ -#define ECACHE_FLUSHALL(lbl, arg1, arg2, arg3, tmp1, tmp2) \ - rdpr %pstate, tmp1 ;\ - andn tmp1, PSTATE_IE | PSTATE_AM, tmp2 ;\ - wrpr %g0, tmp2, %pstate ;\ - b lbl/**/1 ;\ -lbl/**/0: ;\ - sub arg2, arg3, arg2 ;\ -lbl/**/1: ;\ - brgez,a arg2, lbl/**/0 ;\ - ldxa [arg1 + arg2]ASI_MEM, %g0 ;\ - wrpr %g0, tmp1, %pstate - -#ifdef SF_ERRATA_32 -#define SF_WORKAROUND(tmp1, tmp2) \ - sethi %hi(FLUSH_ADDR), tmp2 ;\ - set MMU_PCONTEXT, tmp1 ;\ - stxa %g0, [tmp1]ASI_DMMU ;\ - flush tmp2 ; -#else -#define SF_WORKAROUND(tmp1, tmp2) -#endif /* SF_ERRATA_32 */ - -/* - * arg1 = vaddr - * arg2 = ctxnum - * - disable interrupts and clear address mask - * to access 64 bit physaddr - * - Blow out the TLB. - * . If it's kernel context, then use primary context. - * . Otherwise, use secondary. - */ -#define VTAG_FLUSHPAGE(lbl, arg1, arg2, tmp1, tmp2, tmp3, tmp4) \ - rdpr %pstate, tmp1 ;\ - andn tmp1, PSTATE_IE | PSTATE_AM, tmp2 ;\ - wrpr tmp2, 0, %pstate ;\ - brnz,pt arg2, lbl/**/1 ;\ - sethi %hi(FLUSH_ADDR), tmp2 ;\ - stxa %g0, [arg1]ASI_DTLB_DEMAP ;\ - stxa %g0, [arg1]ASI_ITLB_DEMAP ;\ - b lbl/**/5 ;\ - flush tmp2 ;\ -lbl/**/1: ;\ - set MMU_SCONTEXT, tmp3 ;\ - ldxa [tmp3]ASI_DMMU, tmp4 ;\ - or DEMAP_SECOND | DEMAP_PAGE_TYPE, arg1, arg1 ;\ - cmp tmp4, arg2 ;\ - be,a,pt %icc, lbl/**/4 ;\ - nop ;\ - stxa arg2, [tmp3]ASI_DMMU ;\ -lbl/**/4: ;\ - stxa %g0, [arg1]ASI_DTLB_DEMAP ;\ - stxa %g0, [arg1]ASI_ITLB_DEMAP ;\ - flush tmp2 ;\ - be,a,pt %icc, lbl/**/5 ;\ - nop ;\ - stxa tmp4, [tmp3]ASI_DMMU ;\ - flush tmp2 ;\ -lbl/**/5: ;\ - wrpr %g0, tmp1, %pstate - -/* - * arg1 = dtlb entry - * - Before first compare: - * tmp4 = tte - * tmp5 = vaddr - * tmp6 = cntxnum - */ -#define DTLB_FLUSH_UNLOCKED(lbl, arg1, tmp1, tmp2, tmp3, \ - tmp4, tmp5, tmp6) \ -lbl/**/0: ;\ - sllx arg1, 3, tmp3 ;\ - SF_WORKAROUND(tmp1, tmp2) ;\ - ldxa [tmp3]ASI_DTLB_ACCESS, tmp4 ;\ - srlx tmp4, 6, tmp4 ;\ - andcc tmp4, 1, %g0 ;\ - bnz,pn %xcc, lbl/**/1 ;\ - srlx tmp4, 57, tmp4 ;\ - andcc tmp4, 1, %g0 ;\ - beq,pn %xcc, lbl/**/1 ;\ - nop ;\ - set TAGREAD_CTX_MASK, tmp1 ;\ - ldxa [tmp3]ASI_DTLB_TAGREAD, tmp2 ;\ - and tmp2, tmp1, tmp6 ;\ - andn tmp2, tmp1, tmp5 ;\ - VTAG_FLUSHPAGE(VD, tmp5, tmp6, tmp1, tmp2, tmp3, tmp4) ;\ -lbl/**/1: ;\ - brgz,pt arg1, lbl/**/0 ;\ - sub arg1, 1, arg1 - -/* - * arg1 = itlb entry - * - Before first compare: - * tmp4 = tte - * tmp5 = vaddr - * tmp6 = cntxnum - */ -#define ITLB_FLUSH_UNLOCKED(lbl, arg1, tmp1, tmp2, tmp3, \ - tmp4, tmp5, tmp6) \ -lbl/**/0: ;\ - sllx arg1, 3, tmp3 ;\ - SF_WORKAROUND(tmp1, tmp2) ;\ - ldxa [tmp3]ASI_ITLB_ACCESS, tmp4 ;\ - srlx tmp4, 6, tmp4 ;\ - andcc tmp4, 1, %g0 ;\ - bnz,pn %xcc, lbl/**/1 ;\ - srlx tmp4, 57, tmp4 ;\ - andcc tmp4, 1, %g0 ;\ - beq,pn %xcc, lbl/**/1 ;\ - nop ;\ - set TAGREAD_CTX_MASK, tmp1 ;\ - ldxa [tmp3]ASI_ITLB_TAGREAD, tmp2 ;\ - and tmp2, tmp1, tmp6 ;\ - andn tmp2, tmp1, tmp5 ;\ - VTAG_FLUSHPAGE(VI, tmp5, tmp6, tmp1, tmp2, tmp3, tmp4) ;\ -lbl/**/1: ;\ - brgz,pt arg1, lbl/**/0 ;\ - sub arg1, 1, arg1 - -#define CLEARTL(lvl) \ - wrpr %g0, lvl, %tl ;\ - wrpr %g0, %g0, %tpc ;\ - wrpr %g0, %g0, %tnpc ;\ - wrpr %g0, %g0, %tt - -#define SWITCH_STACK(estk) \ - flushw ;\ - sub estk, SA(KFPUSIZE+GSR_SIZE), estk ;\ - andn estk, 0x3f, estk ;\ - sub estk, SA(MINFRAME) + STACK_BIAS, %sp ;\ - mov estk, %fp - -#endif /* !lint */ - -#if defined(lint) - -/*ARGSUSED*/ -void -drmach_shutdown_asm(uint64_t mbox_addr) -{} - -#else /* lint */ - - ENTRY_NP(drmach_shutdown_asm) - mov %o0, %o5 - - ldxa [%o5]ASI_MEM, %o0 ! get 8-byte estack in o0 - add %o5, 8, %o5 - ldxa [%o5]ASI_MEM, %o1 ! get 8-byte flushaddr in o1 - add %o5, 8, %o5 - lda [%o5]ASI_MEM, %o2 ! get 4-byte size in o2 - srl %o2, 0, %o2 - add %o5, 4, %o5 - lda [%o5]ASI_MEM, %o3 ! get 4-byte linesize in o3 - srl %o3, 0, %o3 - add %o5, 4, %o5 - ldxa [%o5]ASI_MEM, %o4 ! get 8-byte physaddr in o4 - - - ! %o0 = base (va mapping this code in bbsram) - ! %o1 = flushaddr for ecache - ! %o2 = size to use for ecache flush - ! %o3 = ecache linesize - ! %o4 = phys addr of byte to clear when finished - ! - ! output: Stores a zero at [%o4]ASI_MEM - - membar #LoadStore - - ! - ! Switch stack pointer to bbsram - ! - SWITCH_STACK(%o0) - - ! - ! Get some globals - ! - mov %o3, %g1 ! ecache_linesize - mov %o4, %o0 ! physaddr byte to clear - - sethi %hi(dcache_linesize), %g2 - ld [%g2 + %lo(dcache_linesize)], %g2 - - sethi %hi(dcache_size), %g3 - ld [%g3 + %lo(dcache_size)], %g3 - - sethi %hi(icache_linesize), %g4 - ld [%g4 + %lo(icache_linesize)], %g4 - - sethi %hi(icache_size), %g5 - ld [%g5 + %lo(icache_size)], %g5 - - sethi %hi(dtlb_entries), %o5 - ld [%o5 + %lo(dtlb_entries)], %o5 - sllx %o5, 32, %o5 - srlx %o5, 32, %o5 - - sethi %hi(itlb_entries), %o3 - ld [%o3 + %lo(itlb_entries)], %o3 - ! - ! cram Xtlb_entries into a single register (%o5) - ! %o5 upper 32 = itlb_entries - ! lower 32 = dtlb_entries - ! - sllx %o3, 32, %o3 - or %o5, %o3, %o5 - - ! - ! Flush E$ - ! - ECACHE_FLUSHALL(EC, %o1, %o2, %g1, %o3, %o4) - ! - ! %o1 & %o2 now available - ! - - membar #Sync - - ! - ! Flush D$ - ! - DCACHE_FLUSHALL(DC, %g3, %g2, %o3) - - ! - ! Flush I$ - ! - ICACHE_FLUSHALL(IC, %g5, %g4, %o3) - - membar #Sync - - ! - ! Flush dtlb's - ! - srlx %o5, 32, %g5 ! %g5 = itlb_entries - sllx %o5, 32, %o5 - srlx %o5, 32, %g1 - sub %g1, 1, %g1 ! %g1 = dtlb_entries - 1 - - DTLB_FLUSH_UNLOCKED(D, %g1, %g3, %g4, %o2, %o3, %o4, %o5) - - ! - ! Flush itlb's - ! - sub %g5, 1, %g1 ! %g1 = itlb_entries - 1 - - ITLB_FLUSH_UNLOCKED(I, %g1, %g3, %g4, %o2, %o3, %o4, %o5) - - membar #Sync - - ! - ! Clear byte to signal finished. - ! - stba %g0, [%o0]ASI_MEM - membar #Sync - - ! - ! read ensures that last write completed (has left queue in the PC chip) - ! - lduba [%o0]ASI_MEM, %g0 -5: - ba 5b - nop - SET_SIZE(drmach_shutdown_asm) - - .global drmach_shutdown_asm_end - - .skip 2048 - -drmach_shutdown_asm_end: - -#endif /* lint */ diff --git a/usr/src/uts/sun4u/starfire/ml/idn_asm.s b/usr/src/uts/sun4u/starfire/ml/idn_asm.s deleted file mode 100644 index 563fe67286..0000000000 --- a/usr/src/uts/sun4u/starfire/ml/idn_asm.s +++ /dev/null @@ -1,385 +0,0 @@ -/* - * 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 - * or http://www.opensolaris.org/os/licensing. - * See the License for the specific language governing permissions - * and limitations under the License. - * - * When distributing Covered Code, include this CDDL HEADER in each - * file and include the License file at usr/src/OPENSOLARIS.LICENSE. - * If applicable, add the following below this CDDL HEADER, with the - * fields enclosed by brackets "[]" replaced with your own identifying - * information: Portions Copyright [yyyy] [name of copyright owner] - * - * CDDL HEADER END - */ -/* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -#pragma ident "%Z%%M% %I% %E% SMI" - -/* - * This file contains the low-level DMV interrupt - * handler for IDN cross-domain interrupts. - */ - -#if defined(lint) -#include <sys/types.h> -#endif /* lint */ - -#include <sys/asm_linkage.h> -#include <sys/machasi.h> -#include <sys/privregs.h> -#include <sys/intreg.h> -#include <sys/machthread.h> - -#include <sys/idn.h> - -#if !defined(lint) -#include "idn_offsets.h" -#endif /* !lint */ - -#define IDN_MONDO - -/* - * The IDN_DMV_CPU_SHIFT is based on the sizeof (idn_dmv_cpu_t) - * which must be a power of 2 to optimize calculating our - * entry into idn_dmv_cpu[]. - */ -#define IDN_DMV_CPU_SHIFT 4 - -/* - *-------------------------------------------------------- - */ -#if defined(lint) - -/* - * Would be nice to use init_mondo, but unforunately - * it assumes the first arg is 32-bits. - */ -/*ARGSUSED*/ -void -idnxf_init_mondo(uint64_t arg0, uint64_t arg1, uint64_t arg2) -{} - -#else /* lint */ - - .global _idn_dispatch_status_busy -_idn_dispatch_status_busy: - .asciz "ASI_INTR_DISPATCH_STATUS error: busy" - .align 4 - - ENTRY_NP(idnxf_init_mondo) -#ifdef DEBUG - ! - ! IDSR should not be busy at the moment - borrowed from init_mondo - ! - ldxa [%g0]ASI_INTR_DISPATCH_STATUS, %g1 - btst IDSR_BUSY, %g1 - bz,pt %xcc, 1f - mov ASI_INTR_DISPATCH, %asi - sethi %hi(_idn_dispatch_status_busy), %o0 - call panic - or %o0, %lo(_idn_dispatch_status_busy), %o0 -#endif /* DEBUG */ - - mov ASI_INTR_DISPATCH, %asi -1: - stxa %o0, [IDDR_0]%asi ! dmv_word0 - stxa %o1, [IDDR_1]%asi ! dmv_word1 - stxa %o2, [IDDR_2]%asi ! dmv_word2 - - retl - membar #Sync - - SET_SIZE(idnxf_init_mondo) - -#endif /* lint */ -/* - *-------------------------------------------------------- - */ -#if defined(lint) - -/* - * Unfortunately, send_mondo is rather picky about getting - * a result from the cpu it sends an interrupt to. If it - * doesn't get a result within a specific timeframe it - * will panic! For IDN that's not cool since a cpu hungup - * in one could ultimately result in the demise of a cpu - * in another domain. Instead of getting our panties in - * a bind, we simply bail out. - */ -/*ARGSUSED*/ -int -idnxf_send_mondo(int upaid) -{ return (0); } - -#else /* lint */ - - .seg ".data" - - .global _idn_send_mondo_failure -_idn_send_mondo_failure: - .word 0 - - .seg ".text" - ENTRY(idnxf_send_mondo) - ! - ! NOTE: - ! This is stolen from send_mondo. The changes - ! are those ifdef'd with IDN_MONDO - ! - ! construct the interrupt dispatch command register in %g1 - ! also, get the dispatch out as SOON as possible - ! (initial analysis puts the minimum dispatch time at around - ! 30-60 cycles. hence, we try to get the dispatch out quickly - ! and then start the rapid check loop). - ! - rd %tick, %o4 ! baseline tick - sll %o0, IDCR_PID_SHIFT, %g1 ! IDCR<18:14> = upa port id - or %g1, IDCR_OFFSET, %g1 ! IDCR<13:0> = 0x70 - stxa %g0, [%g1]ASI_INTR_DISPATCH ! interrupt vector dispatch -#if defined(SF_ERRATA_54) - membar #Sync ! store must occur before load - mov 0x20, %g3 ! UDBH Control Register Read - ldxa [%g3]ASI_SDB_INTR_R, %g0 -#endif - membar #Sync - clr %o2 ! clear NACK counter - clr %o3 ! clear BUSY counter - - ! - ! how long, in ticks, are we willing to wait completely - ! - sethi %hi(xc_tick_limit), %g2 - ldx [%g2 + %lo(xc_tick_limit)], %g2 - add %g2, %o4, %o5 ! compute the limit value - - ! - ! check the dispatch status - ! -.check_dispatch: - ldxa [%g0]ASI_INTR_DISPATCH_STATUS, %o1 - brz,pn %o1, .dispatch_complete - rd %tick, %g5 - - ! - ! see if we've gone beyond the limit - ! (can tick ever overflow?) - ! -.timeout_primed: - sub %o5, %g5, %g2 ! limit - tick < 0 if timeout - brgez,pt %g2, .check_busy - inc %o3 ! bump the BUSY counter - -#ifdef IDN_MONDO - ! - ! Within the context of IDN we don't want - ! to panic just because we can't send_mondo. - ! Clear the dispatch register and increment - ! our count of failures. - ! - stxa %g0, [%g1]ASI_INTR_DISPATCH - sethi %hi(_idn_send_mondo_failure), %o0 - ld [%o0 + %lo(_idn_send_mondo_failure)], %o1 - inc %o1 - st %o1, [%o0 + %lo(_idn_send_mondo_failure)] - retl - mov -1, %o0 ! return (-1) -#else /* IDN_MONDO */ - ! - ! time to die, see if we are already panicing - ! - mov %o0, %o1 ! save target - sethi %hi(_send_mondo_nack), %o0 - or %o0, %lo(_send_mondo_nack), %o0 - sethi %hi(panicstr), %g2 - ldn [%g2 + %lo(panicstr)], %g2 - brnz %g2, .dispatch_complete ! skip if already in panic - nop - call panic - nop -#endif /* IDN_MONDO */ - -.check_busy: - btst IDSR_BUSY, %o1 ! was it BUSY? - bnz,pt %xcc, .check_dispatch - nop - - ! - ! we weren't busy, we must have been NACK'd - ! wait a while and send again - ! (this might need jitter) - ! - sethi %hi(sys_clock_mhz), %g2 - lduw [%g2 + %lo(sys_clock_mhz)], %g2 - rd %tick, %g4 - add %g2, %g4, %g2 -.delay: - cmp %g2, %g4 - bgu,pt %xcc, .delay - rd %tick, %g4 - - stxa %g0, [%g1]ASI_INTR_DISPATCH ! interrupt vector dispatch -#if defined(SF_ERRATA_54) - membar #Sync ! store must occur before load - ldxa [%g3]ASI_SDB_INTR_R, %g0 -#endif - membar #Sync - clr %o3 ! reset BUSY counter - ba .check_dispatch - inc %o2 ! bump the NACK counter - -.dispatch_complete: -#ifndef IDN_MONDO -#ifdef SEND_MONDO_STATS - ! - ! Increment the appropriate entry in a send_mondo timeout array - ! x_entry[CPU][MSB]++; - sub %g5, %o4, %g5 ! how long did we wait? - clr %o1 ! o1 is now bit counter -1: orcc %g5, %g0, %g0 ! any bits left? - srlx %g5, 1, %g5 ! bits to the right - bne,a,pt %xcc, 1b - add %o1, 4, %o1 ! pointer increment - - ! - ! now compute the base of the x_early entry for our cpu - ! - CPU_INDEX(%o0, %g5) - sll %o0, 8, %o0 ! 64 * 4 - add %o0, %o1, %o1 ! %o0 = &[CPU][delay] - - ! - ! and increment the appropriate value - ! - sethi %hi(x_early), %o0 - or %o0, %lo(x_early), %o0 - ld [%o0 + %o1], %g5 - inc %g5 - st %g5, [%o0 + %o1] -#endif /* SEND_MONDO_STATS */ -#endif /* !IDN_MONDO */ - retl -#ifdef IDN_MONDO - mov %g0, %o0 ! return (0) -#else /* IDN_MONDO */ - nop -#endif /* IDN_MONDO */ - SET_SIZE(idnxf_send_mondo) - -#endif /* lint */ -/* - *-------------------------------------------------------- - */ -#if defined(lint) - -/*ARGSUSED*/ -void -idn_dmv_handler(void *arg) -{} - -#else /* lint */ - - ENTRY_NP(idn_dmv_handler) - ! - ! On entry: - ! g1 = idn_dmv_data - ! g2 = word 0 - ! - ldx [%g1 + IDN_DMV_QBASE], %g4 ! g4 = idn_dmv_qbase - add %g1, IDN_DMV_CPU, %g3 ! g3 = &idn_dmv_cpu[0] - - CPU_INDEX(%g6, %g5) ! g6 = cpuid - - ! - ! g5 = cur = idn_dmv_cpu[cpuid] - ! - sll %g6, IDN_DMV_CPU_SHIFT, %g6 ! g6 = cpuid * 8 - add %g3, IDN_DMV_CURRENT, %g3 - ld [%g6 + %g3], %g5 - ! - ! g5 = idn_dmv_cpu[cpuid].idn_dmv_current - ! offset from idn_dmv_qbase - ! - or %g5, %g0, %g5 ! get to 64-bits - add %g5, %g4, %g5 ! g5 = idn_dmv_current - ! actual address - ldstub [%g5 + IV_INUSE], %g7 ! cur->iv_inuse = 0xff - brz,pt %g7, 1f ! did we get it? - sub %g3, IDN_DMV_CURRENT, %g4 - - ! - ! Queue is FULL. Drop interrupt. - ! - add %g4, IDN_DMV_LOSTINTR, %g3 - ld [%g6 + %g3], %g2 - ! - ! g2 = idn_dmv_cpu[cpuid].idn_iv_lostintr++ - ! - inc %g2 - set dmv_finish_intr, %g4 - st %g2, [%g3 + %g6] - jmp %g4 - mov -1, %g1 - ! - ! not reached - ! - -1: - add %g4, IDN_DMV_ACTIVE, %g7 - ! - ! Move current pointer to next one. - ! idn_dmv_current[cpuid] = cur->iv_next - ! - ld [%g5 + IV_NEXT], %g4 - st %g4, [%g3 + %g6] - - ! - ! Start filling in structure with data. - ! - stx %g2, [%g5 + IV_HEAD] - - mov IRDR_1, %g2 - mov IRDR_2, %g4 - ldxa [%g2]ASI_INTR_RECEIVE, %g2 ! g2 = xargs[0,1] - ldxa [%g4]ASI_INTR_RECEIVE, %g4 ! g4 = xargs[2,3] - - stx %g2, [%g5 + IV_XARGS0] - stx %g4, [%g5 + IV_XARGS2] - - membar #StoreLoad|#StoreStore - - clrb [%g5 + IV_READY] ! cur->iv_ready = 0 (unlocked) - - ! - ! See if we're already active, i.e. have things - ! queued. If so, don't bother generating a soft - ! interrupt. IDN interrupts could exhaust the - ! intr_vec structs for the given cpu and that code - ! doesn't know how to survive with intr_vec structs! - ! - ldstub [%g6 + %g7], %g7 ! idn_dmv_active = 0xff - brz,a,pt %g7, 2f - ldx [%g1 + IDN_SOFT_INUM], %g7 ! g7 = idn_soft_inum - mov -1, %g7 -2: - - ! - ! Setup to cause an IDN soft interrupt to occur, - ! (if necessary). - ! - set dmv_finish_intr, %g3 - jmp %g3 - mov %g7, %g1 - - SET_SIZE(idn_dmv_handler) - -#endif /* lint */ diff --git a/usr/src/uts/sun4u/starfire/ml/idn_offsets.in b/usr/src/uts/sun4u/starfire/ml/idn_offsets.in deleted file mode 100644 index 2a5da76e4b..0000000000 --- a/usr/src/uts/sun4u/starfire/ml/idn_offsets.in +++ /dev/null @@ -1,60 +0,0 @@ -\ -\ 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 -\ or http://www.opensolaris.org/os/licensing. -\ 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 (c) 1999 by Sun Microsystems, Inc. -\ All rights reserved. -\ -\ Based on sun4u/ml/offsets.in. -\ -\ Definitions needed by IDN send-mondo support. -\ -\ Offset definitions for low-level idn_dmv_handler() (assembly code) -\ - -#pragma ident "%Z%%M% %I% %E% SMI" - -#include <sys/types.h> -#include <sys/sysmacros.h> -#include <sys/param.h> -#include <sys/machparam.h> -#include <sys/systm.h> -#include <sys/machsystm.h> -#include <sys/cpuvar.h> - -#include <sys/idn.h> - -idn_dmv_cpu_t IDN_DMV_CPU_SIZE - idn_dmv_current - idn_dmv_active - idn_dmv_lostintr - -idn_dmv_data_t IDN_DMV_DATA_SIZE - idn_soft_inum - idn_dmv_qbase - idn_dmv_cpu - -idn_dmv_msg_t IDN_DMV_MSG_SIZE - iv_next - iv_inuse - iv_ready - iv_head - iv_xargs0 - iv_xargs2 diff --git a/usr/src/uts/sun4u/starfire/ngdr/Makefile b/usr/src/uts/sun4u/starfire/ngdr/Makefile deleted file mode 100644 index 7d68bff634..0000000000 --- a/usr/src/uts/sun4u/starfire/ngdr/Makefile +++ /dev/null @@ -1,95 +0,0 @@ -# -# 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 -# or http://www.opensolaris.org/os/licensing. -# 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 2004 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# - -# -# This makefile drives the production of the ngdr driver module. -# -# sun4u starfire implementation architecture dependent -# - -# -# Path to the base of the uts directory tree (usually /usr/src/uts). -# -UTSBASE = ../../.. - -# -# Define the module and object file sets. -# -MODULE = ngdr -OBJECTS = $(DR_OBJS:%=$(OBJS_DIR)/%) -LINTS = $(DR_OBJS:%.o=$(LINTS_DIR)/%.ln) -ROOTMODULE = $(ROOT_STARFIRE_DRV_DIR)/$(MODULE) -CONF_SRCDIR = $(UTSBASE)/sun4u/starfire/io - -# -# Include common rules. -# -include $(UTSBASE)/sun4u/starfire/Makefile.starfire - -# -# Define targets -# -ALL_TARGET = $(BINARY) $(SRC_CONFFILE) -LINT_TARGET = $(MODULE).lint -INSTALL_TARGET = $(BINARY) $(ROOTMODULE) $(ROOT_CONFFILE) - -# -# lint pass one enforcement -# -CFLAGS += $(CCVERBOSE) -CERRWARN += -_gcc=-Wno-parentheses -CERRWARN += -_gcc=-Wno-uninitialized - -# -# module dependencies -# -LDFLAGS += -dy -Nmisc/ngdrmach - -# -# Default build targets. -# -.KEEP_STATE: - -def: $(DEF_DEPS) - -all: $(ALL_DEPS) - -clean: $(CLEAN_DEPS) - -clobber: $(CLOBBER_DEPS) - -lint: $(LINT_DEPS) - -modlintlib: $(MODLINTLIB_DEPS) - -clean.lint: $(CLEAN_LINT_DEPS) - -install: $(INSTALL_DEPS) - -# -# Include common targets. -# -include $(UTSBASE)/sun4u/starfire/Makefile.targ diff --git a/usr/src/uts/sun4u/starfire/ngdrmach/Makefile b/usr/src/uts/sun4u/starfire/ngdrmach/Makefile deleted file mode 100644 index 181e6cf8a6..0000000000 --- a/usr/src/uts/sun4u/starfire/ngdrmach/Makefile +++ /dev/null @@ -1,92 +0,0 @@ -# -# 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 -# or http://www.opensolaris.org/os/licensing. -# 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 2004 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# Copyright (c) 2011 Bayard G. Bell. All rights reserved. -# -# This makefile drives the production of the ngdrmach loadable module. -# -# sun4u starfire implementation architecture dependent -# - -# -# Path to the base of the uts directory tree (usually /usr/src/uts). -# -UTSBASE = ../../.. - -# -# Define the module and object file sets. -# -MODULE = ngdrmach -OBJECTS = $(NGDRMACH_OBJS:%=$(OBJS_DIR)/%) -LINTS = $(NGDRMACH_OBJS:%.o=$(LINTS_DIR)/%.ln) -ROOTMODULE = $(ROOT_STARFIRE_MISC_DIR)/$(MODULE) - -# -# Include common rules. -# -include $(UTSBASE)/sun4u/starfire/Makefile.starfire - -# -# Define targets -# -ALL_TARGET = $(BINARY) -LINT_TARGET = $(MODULE).lint -INSTALL_TARGET = $(BINARY) $(ROOTMODULE) - -# -# lint pass one enforcement -# -CFLAGS += $(CCVERBOSE) -CERRWARN += -_gcc=-Wno-uninitialized - -# -# Define dependency on cvc -# -LDFLAGS += -dy -N drv/cvc - -# -# Default build targets. -# -.KEEP_STATE: - -def: $(DEF_DEPS) - -all: $(ALL_DEPS) - -clean: $(CLEAN_DEPS) - -clobber: $(CLOBBER_DEPS) - -lint: $(LINT_DEPS) - -modlintlib: $(MODLINTLIB_DEPS) - -clean.lint: $(CLEAN_LINT_DEPS) - -install: $(INSTALL_DEPS) - -# -# Include common targets. -# -include $(UTSBASE)/sun4u/starfire/Makefile.targ diff --git a/usr/src/uts/sun4u/starfire/os/bbus_intr.c b/usr/src/uts/sun4u/starfire/os/bbus_intr.c deleted file mode 100644 index f82d8afc50..0000000000 --- a/usr/src/uts/sun4u/starfire/os/bbus_intr.c +++ /dev/null @@ -1,643 +0,0 @@ -/* - * 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 - * or http://www.opensolaris.org/os/licensing. - * See the License for the specific language governing permissions - * and limitations under the License. - * - * When distributing Covered Code, include this CDDL HEADER in each - * file and include the License file at usr/src/OPENSOLARIS.LICENSE. - * If applicable, add the following below this CDDL HEADER, with the - * fields enclosed by brackets "[]" replaced with your own identifying - * information: Portions Copyright [yyyy] [name of copyright owner] - * - * CDDL HEADER END - */ -/* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -#pragma ident "%Z%%M% %I% %E% SMI" - -#include <sys/types.h> -#include <sys/param.h> -#include <sys/kmem.h> -#include <sys/cpu_sgnblk_defs.h> -#include <vm/seg.h> -#include <sys/iommu.h> -#include <sys/vtrace.h> -#include <sys/intreg.h> -#include <sys/ivintr.h> -#include <sys/cpuvar.h> -#include <sys/systm.h> -#include <sys/machsystm.h> -#include <sys/cyclic.h> -#include <sys/cpu_sgn.h> - -extern cpu_sgnblk_t *cpu_sgnblkp[NCPU]; -extern struct cpu *SIGBCPU; -extern void power_down(const char *); - -uint_t bbus_intr_inum; -uint64_t bbus_poll_inum; - -/* - * Support for sgnblk polling. - */ - -/* Internal function prototypes */ -static void sgnblk_poll_init(); -static uint_t bbus_poll(caddr_t arg1, caddr_t arg2); -static void sgnblk_poll_handler(void *unused); -#ifdef THROTTLE -static void sgnblk_poll_throttle(uint64_t interval); -#endif /* THROTTLE */ - -/* Default sgnblk polling interval is every 5 seconds. */ -#define ONE_SECOND (1000000) /* in usecs */ -#ifdef THROTTLE -#define SGNBLK_POLL_INTERVAL (5 * ONE_SECOND) -#define SGNBLK_POLL_FAST (ONE_SECOND >> 1) -#define SGNBLK_POLL_FAST_WIN ((60 * ONE_SECOND) / \ - SGNBLK_POLL_FAST) -#else /* THROTTLE */ -/* - * Until we can find a way to throttle back to 0.5 second intervals - * we're stuck fixed on 2.5 second intervals. - */ -#define SGNBLK_POLL_INTERVAL ((2 * ONE_SECOND) + (ONE_SECOND >> 1)) -#endif /* THROTTLE */ - -#define MAX_SGNBLK_POLL_CLNT 5 - -void (*pollclntfunc[MAX_SGNBLK_POLL_CLNT])(); -/* - * sgnblk_mutex Protects juggling & sgnblk_poll_refs[]. - * sgnblk_poll_mutex Protects pollclntfunc[]. - */ -kmutex_t sgnblk_mutex; -kmutex_t sgnblk_poll_mutex; -static uint64_t sgnblk_poll_interval = SGNBLK_POLL_INTERVAL; -#ifdef THROTTLE -static uint64_t sgnblk_poll_fast = SGNBLK_POLL_FAST; -static int64_t sgnblk_poll_fast_win = SGNBLK_POLL_FAST_WIN; -#endif /* THROTTLE */ -static processorid_t sgnblk_pollcpu = -1; -/* - * Note that the sigblock polling depends on CY_HIGH_LEVEL - * being higher than PIL_13 since we ultimately need to - * dispatch a PIL_13 soft handler. - * Also, we assume one sgnblk handler for the entire system. - * Once upon a time we had them per-cpu. With the Cyclic stuff - * we would have to bind our cyclic handler to a cpu and doing - * this prevents that cpu from being offlined. Since the Cyclic - * subsystem could indirectly juggle us without us knowing we - * have to assume we're running from any possible cpu and not - * always SIGBCPU. - */ -#ifdef THROTTLE -static cyclic_id_t sgnblk_poll_cycid = CYCLIC_NONE; -#endif /* THROTTLE */ -static cyc_handler_t sgnblk_poll_cychandler = { - sgnblk_poll_handler, - NULL, - CY_HIGH_LEVEL -}; -static cyc_time_t sgnblk_poll_time; - -/* - * Anybody that references the polling (SIGBCPU) can - * register a callback function that will be called if - * the polling cpu is juggled, e.g. during a DR operation. - */ -#define MAX_SGNBLK_POLL_REFS 10 - -struct sgnblk_poll_refs { - void (*callback)(cpu_sgnblk_t *sigbp, void *arg); - void *arg; -} sgnblk_poll_refs[MAX_SGNBLK_POLL_REFS]; - -/* - * Bootbus intr handler: Generic handler for all SSP/CBS - * interrupt requests initiated via the hw bootbus intr - * mechanism. This is similar to the level15 - * interrupt handling for sigb commands in the CS6400. - * Most of these code were stolen from the sigb stuff in - * in CS6400. - */ - -extern struct cpu cpu0; - -/*ARGSUSED*/ -static uint_t -bbus_intr(caddr_t arg) -{ - int cmd = 0; - processorid_t cpu_id = CPU->cpu_id; - int retflag; - int resp = 0; - proc_t *initpp; - - ASSERT(cpu_sgnblkp[cpu_id] != NULL); - - /* - * Check for unsolicited messages in the host's mailbox. - */ - retflag = cpu_sgnblkp[cpu_id]->sigb_host_mbox.flag; - - switch (retflag) { - case CBS_TO_HOST: - retflag = HOST_TO_CBS; - break; - default: - retflag = SIGB_MBOX_EMPTY; - break; - } - if (retflag == SIGB_MBOX_EMPTY) - return (0); /* interrupt not claimed */ - - /* - * We only look for UNSOLICITED messages, i.e. commands. - * Responses to these commands are returned into the same - * mailbox from which the command was received, i.e. host's. - * - * If the host should solicit a message from the SSP, that - * message/command goes into the SSP's mailbox (sigb_ssp_mbox). - * The responses (from the SSP) to these messages will be - * read from the ssp mailbox by whomever solicited it, but - * will NOT be handled through this level 15 interrupt - * mechanism. - * - * Note that use of the flag field of the signature block mailbox - * structure and the mailbox protocol itself, serializes access - * to these mailboxes. - */ - - resp = 0; - - /* - * The first sizeof (uint_t) bytes of the data field - * is the command. - */ - cmd = cpu_sgnblkp[cpu_id]->sigb_host_mbox.cmd; - - switch (cmd) { - case SSP_GOTO_OBP: - /* - * Let's set the mailbox flag to BUSY while we are in OBP - */ - cpu_sgnblkp[cpu_id]->sigb_host_mbox.flag = SIGB_MBOX_BUSY; - - debug_enter("SSP requested (SSP_GOTO_OBP)"); - /* - * This command does NOT require a response. - */ - resp = 0; - break; - - case SSP_GOTO_PANIC: - /* - * Let's reset the mailbox flag before we bail. - */ - cpu_sgnblkp[cpu_id]->sigb_host_mbox.flag = SIGB_MBOX_EMPTY; - - cmn_err(CE_PANIC, "SSP requested (SSP_GOTO_PANIC)\n"); - /* should never reach this point */ - - resp = 0; - break; - case SSP_ENVIRON: - /* - * Environmental Interrupt. - */ - - /* - * Send SIGPWR to init(1) it will run rc0, which will uadmin to - * powerdown. - */ - - mutex_enter(&pidlock); - initpp = prfind(P_INITPID); - mutex_exit(&pidlock); - - /* - * If we're still booting and init(1) isn't set up yet, - * simply halt. - */ - if (initpp == NULL) { - extern void halt(char *); - cmn_err(CE_WARN, "?Environmental Interrupt"); - power_down((char *)NULL); - halt("Power off the System!\n"); /* just in case */ - } - - /* - * else, graceful shutdown with inittab and all getting involved - * - * XXX: Do we Need to modify the init process for the Cray 6400! - */ - psignal(initpp, SIGPWR); - - /* - * XXX: kick off a sanity timeout panic in case the /etc/inittab - * or /etc/rc0 files are hosed. The 6400 needs to hang here - * when we return from psignal. - * - * cmn_err(CE_PANIC, "SSP requested (SSP_ENVIRON)\n"); - * should never reach this point - */ - - resp = 0; - break; - /* - * Could handle more mailbox commands right here. - */ - - default: - resp = SIGB_BAD_MBOX_CMD; - break; - } - - /* - * If resp is non-zero then we'll automatically reset - * the handler_sigb lock once we've sent the response, - * however if no response is needed, then resetlck must - * be set so that the handler_sigb lock is reset. - */ - if (resp != 0) { - /* - * Had some kind of trouble handling the mailbox - * command. Need to send back an error response - * and back out of the cpu_sgnblk handling. - */ - cpu_sgnblkp[cpu_id]->sigb_host_mbox.cmd = resp; - bcopy((caddr_t)&cmd, - (caddr_t)&cpu_sgnblkp[cpu_id]->sigb_host_mbox.data[0], - sizeof (cmd)); - cpu_sgnblkp[cpu_id]->sigb_host_mbox.flag = retflag; - } else { - /* - * No response expected, but we still have to - * reset the flag to empty for the next person. - */ - cpu_sgnblkp[cpu_id]->sigb_host_mbox.flag = SIGB_MBOX_EMPTY; - } - return (1); /* interrupt claimed */ -} - -void -register_bbus_intr() -{ - /* - * Starfire's ASIC have the capability to generate a mondo - * vector. The SSP uses this capability via the Boot Bus to - * send an interrupt to a domain. - * - * The SSP generates a mondo with: - * ign = UPAID_TO_IGN(bootcpu_upaid) - * ino = 0 - * - * An interrupt handler is added for this inum. - */ - bbus_intr_inum = UPAID_TO_IGN(cpu0.cpu_id) * MAX_INO; - VERIFY(add_ivintr(bbus_intr_inum, PIL_13, (intrfunc)bbus_intr, - NULL, NULL, NULL) == 0); - - - /* - * Due to a HW flaw in starfire, liberal use - * of bootbus intrs under heavy system load - * may cause the machine to arbstop. The workaround - * is to provide a polling mechanism thru the signature - * block interface to allow another way for the SSP to - * interrupt the host. Applications like IDN which generate - * a high degree of SSP to host interruptions for - * synchronization will need to use the polling facility - * instead of the hw bootbus interrupt mechanism. - * The HW bootbus intr support is left intact as it - * will still be used by existing SSP applications for system - * recovery in the event of system hangs etc.. In such situations, - * HW bootbus intr is a better mechanism as it is HW generated - * level 15 interrupt that has a better chance of kicking - * a otherwise hung OS into recovery. - * - * Polling is done by scheduling a constant tick timer - * interrupt at a certain predefined interval. - * The handler will do a poll and if there is a - * "intr" request, scheduled a soft level 13 intr - * to handle it. Allocate the inum for the level - * 13 intr here. - */ - bbus_poll_inum = add_softintr(PIL_13, bbus_poll, 0, SOFTINT_ST); -} - -static void -sgnblk_poll_init() -{ - ASSERT(MUTEX_HELD(&sgnblk_mutex)); - - mutex_init(&sgnblk_poll_mutex, NULL, - MUTEX_SPIN, (void *)ipltospl(PIL_14)); - sgnblk_pollcpu = SIGBCPU->cpu_id; - mutex_enter(&cpu_lock); - sgnblk_poll_time.cyt_when = 0ull; - sgnblk_poll_time.cyt_interval = sgnblk_poll_interval * 1000ull; -#ifdef THROTTLE - sgnblk_poll_cycid = cyclic_add(&sgnblk_poll_cychandler, - &sgnblk_poll_time); -#else /* THROTTLE */ - (void) cyclic_add(&sgnblk_poll_cychandler, &sgnblk_poll_time); -#endif /* THROTTLE */ - mutex_exit(&cpu_lock); - ASSERT(sgnblk_pollcpu == SIGBCPU->cpu_id); -} - -int -sgnblk_poll_register(void(*func)(processorid_t cpu_id, - cpu_sgnblk_t *cpu_sgnblkp)) -{ - int i; - - /* - * See if we need to initialize - * sgnblk polling - */ - mutex_enter(&sgnblk_mutex); - if (sgnblk_pollcpu == -1) - sgnblk_poll_init(); - mutex_exit(&sgnblk_mutex); - - mutex_enter(&sgnblk_poll_mutex); - - /* - * Look for a empty slot - */ - for (i = 0; i < MAX_SGNBLK_POLL_CLNT; i++) { - if (pollclntfunc[i] == NULL) { - pollclntfunc[i] = func; - mutex_exit(&sgnblk_poll_mutex); - return (1); - } - } - mutex_exit(&sgnblk_poll_mutex); - return (0); /* failed */ -} - -int -sgnblk_poll_unregister(void(*func)(processorid_t cpu_id, - cpu_sgnblk_t *cpu_sgnblkp)) -{ - int i; - - mutex_enter(&sgnblk_poll_mutex); - - /* - * Look for the slot matching the function passed in. - */ - for (i = 0; i < MAX_SGNBLK_POLL_CLNT; i++) { - if (pollclntfunc[i] == func) { - pollclntfunc[i] = NULL; - mutex_exit(&sgnblk_poll_mutex); - return (1); - } - } - mutex_exit(&sgnblk_poll_mutex); - return (0); /* failed */ -} - - -/* - * For DR support. - * Juggle poll tick client to another cpu - * Assumed to be called single threaded. - */ -void -juggle_sgnblk_poll(struct cpu *cp) -{ - int i; - - mutex_enter(&sgnblk_mutex); - - if (sgnblk_pollcpu == -1 || - (cp != NULL && sgnblk_pollcpu == cp->cpu_id)) { - mutex_exit(&sgnblk_mutex); - return; - } - - /* - * Disable by simply returning here - * Passing a null cp is assumed to be - * sgnpoll disable request. - */ - if (cp == NULL) { - for (i = 0; i < MAX_SGNBLK_POLL_REFS; i++) { - void (*func)(), *arg; - - if ((func = sgnblk_poll_refs[i].callback) != NULL) { - arg = sgnblk_poll_refs[i].arg; - (*func)(NULL, arg); - } - } - mutex_exit(&sgnblk_mutex); - return; - } - - sgnblk_pollcpu = cp->cpu_id; - - for (i = 0; i < MAX_SGNBLK_POLL_REFS; i++) { - void (*func)(), *arg; - - if ((func = sgnblk_poll_refs[i].callback) != NULL) { - arg = sgnblk_poll_refs[i].arg; - (*func)(cpu_sgnblkp[sgnblk_pollcpu], arg); - } - } - - mutex_exit(&sgnblk_mutex); -} - -#ifdef THROTTLE -/*ARGSUSED0*/ -static void -_sgnblk_poll_throttle(void *unused) -{ - mutex_enter(&cpu_lock); - if (sgnblk_poll_cycid != CYCLIC_NONE) { - cyclic_remove(sgnblk_poll_cycid); - sgnblk_poll_cycid = CYCLIC_NONE; - } - - if (sgnblk_poll_time.cyt_interval > 0ull) - sgnblk_poll_cycid = cyclic_add(&sgnblk_poll_cychandler, - &sgnblk_poll_time); - mutex_exit(&cpu_lock); -} - -/* - * We don't want to remove the cyclic within the context of - * the handler so we kick off the throttle in background - * via a timeout call. - */ -static void -sgnblk_poll_throttle(uint64_t new_interval) -{ - mutex_enter(&cpu_lock); - sgnblk_poll_time.cyt_when = 0ull; - sgnblk_poll_time.cyt_interval = new_interval * 1000ull; - mutex_exit(&cpu_lock); - - (void) timeout(_sgnblk_poll_throttle, NULL, (clock_t)0); -} -#endif /* THROTTLE */ - -/* - * High priority interrupt handler (PIL_14) - * for signature block mbox polling. - */ -/*ARGSUSED0*/ -static void -sgnblk_poll_handler(void *unused) -{ - processorid_t cpuid = SIGBCPU->cpu_id; -#ifdef THROTTLE - static int64_t sb_window = -1; - static uint64_t sb_interval = 0; -#endif /* THROTTLE */ - - if (cpu_sgnblkp[cpuid] == NULL) - return; - - /* - * Poll for SSP requests - */ - if (cpu_sgnblkp[cpuid]->sigb_host_mbox.intr == SIGB_INTR_SEND) { - /* reset the flag - sure hope this is atomic */ - cpu_sgnblkp[cpuid]->sigb_host_mbox.intr = SIGB_INTR_OFF; - -#ifdef THROTTLE - /* - * Go into fast poll mode for a short duration - * (SGNBLK_POLL_FAST_WIN) in SGNBLK_POLL_FAST interval. - * The assumption here is that we just got activity - * on the mbox poll, the probability of more coming down - * the pipe is high - so let's look more often. - */ - if ((sb_window < 0) && (sb_interval > sgnblk_poll_fast)) { - sb_interval = sgnblk_poll_fast; - sgnblk_poll_throttle(sb_interval); - } - sb_window = sgnblk_poll_fast_win; -#endif /* THROTTLE */ - - /* schedule poll processing */ - setsoftint(bbus_poll_inum); - -#ifdef THROTTLE - } else if (sb_window >= 0) { - /* Revert to slow polling once fast window ends */ - if ((--sb_window < 0) && - (sb_interval < sgnblk_poll_interval)) { - sb_interval = sgnblk_poll_interval; - sgnblk_poll_throttle(sb_interval); - } -#endif /* THROTTLE */ - } -} - -/*ARGSUSED*/ -static uint_t -bbus_poll(caddr_t arg1, caddr_t arg2) -{ - int i; - processorid_t cpu_id = SIGBCPU->cpu_id; - cpu_sgnblk_t *sgnblkp = cpu_sgnblkp[cpu_id]; - - /* - * Go thru the poll client array and call the - * poll client functions one by one - */ - mutex_enter(&sgnblk_poll_mutex); - - for (i = 0; i < MAX_SGNBLK_POLL_CLNT; i++) { - void (*func)(processorid_t cpuid, cpu_sgnblk_t *sgnblkp); - - if ((func = pollclntfunc[i]) != NULL) { - mutex_exit(&sgnblk_poll_mutex); - (*func)(cpu_id, sgnblkp); - mutex_enter(&sgnblk_poll_mutex); - } - } - mutex_exit(&sgnblk_poll_mutex); - - return (1); -} - -int -sgnblk_poll_reference(void (*callback)(cpu_sgnblk_t *sigb, void *arg), - void *arg) -{ - int i, slot; - cpu_sgnblk_t *sigbp; - - if (callback == NULL) - return (-1); - - mutex_enter(&sgnblk_mutex); - /* - * First verify caller is not already registered. - */ - slot = -1; - for (i = 0; i < MAX_SGNBLK_POLL_REFS; i++) { - if ((slot == -1) && (sgnblk_poll_refs[i].callback == NULL)) { - slot = i; - continue; - } - if (sgnblk_poll_refs[i].callback == callback) { - mutex_exit(&sgnblk_mutex); - return (-1); - } - } - /* - * Now find an empty entry. - */ - if (slot == -1) { - mutex_exit(&sgnblk_mutex); - return (-1); - } - sgnblk_poll_refs[slot].callback = callback; - sgnblk_poll_refs[slot].arg = arg; - - sigbp = (sgnblk_pollcpu != -1) ? cpu_sgnblkp[sgnblk_pollcpu] : NULL; - - (*callback)(sigbp, arg); - - mutex_exit(&sgnblk_mutex); - - return (0); -} - -void -sgnblk_poll_unreference(void (*callback)(cpu_sgnblk_t *sigb, void *arg)) -{ - int i; - - mutex_enter(&sgnblk_mutex); - for (i = 0; i < MAX_SGNBLK_POLL_REFS; i++) { - if (sgnblk_poll_refs[i].callback == callback) { - void *arg; - - arg = sgnblk_poll_refs[i].arg; - (*callback)(NULL, arg); - sgnblk_poll_refs[i].callback = NULL; - sgnblk_poll_refs[i].arg = NULL; - break; - } - } - mutex_exit(&sgnblk_mutex); -} diff --git a/usr/src/uts/sun4u/starfire/os/cpu_sgnblk.c b/usr/src/uts/sun4u/starfire/os/cpu_sgnblk.c deleted file mode 100644 index be505da37b..0000000000 --- a/usr/src/uts/sun4u/starfire/os/cpu_sgnblk.c +++ /dev/null @@ -1,181 +0,0 @@ -/* - * 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 - * or http://www.opensolaris.org/os/licensing. - * 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 2004 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -#pragma ident "%Z%%M% %I% %E% SMI" - -/* - * Following is STARFIRE specific code - */ - -#include <sys/types.h> -#include <sys/systm.h> -#include <sys/archsystm.h> -#include <sys/machsystm.h> -#include <sys/vmem.h> -#include <sys/mman.h> -#include <sys/vm.h> - -#include <sys/cmn_err.h> -#include <sys/cpu_sgnblk_defs.h> -#include <sys/starfire.h> - -#include <vm/seg.h> -#include <vm/seg_kmem.h> -#include <vm/seg_kp.h> -#include <sys/vtrace.h> -#include <sys/cpu_sgn.h> - -/* - * SIGBCPU represents the cpu maintaining the primary - * sigblock (bbsram). This bbsram is used for CVC - * and maintains the post2obp structure. It starts - * out as the bootproc (cpu0). - */ -struct cpu *SIGBCPU = &cpu0; - -cpu_sgnblk_t *cpu_sgnblkp[NCPU]; - -/* - * Mapin the the cpu's signature block. - */ -void -cpu_sgn_mapin(int cpuid) -{ - uint64_t bbsram_physaddr; - uint64_t cpu_sgnblk_physaddr; - uint32_t cpu_sgnblk_offset; - caddr_t cvaddr; - pgcnt_t num_pages; - pfn_t pfn; - - ASSERT(cpu_sgnblkp[cpuid] == NULL); - - /* - * Construct the physical base address of the bbsram - * in PSI space associated with this cpu in question. - */ - cpu_sgnblk_physaddr = bbsram_physaddr = - STARFIRE_UPAID2UPS(cpuid) | STARFIRE_PSI_BASE; - - /* - * The cpu_sgnblk pointer offsets are stored in the - * undefined hardware trap slot 0x7f which is located - * at offset 0xfe0. There are 2 of them since the - * bbsram is shared among the 2 cpus residing on the - * a PC. We need to determine the CPU in question whether - * it is in port 0 or 1. CPU on port 0 has its - * signature blkptr stored in 0xfe0 while the cpu_sgnblk - * ptr of local port 1's CPU is in offset 0xfe8. - */ - if (cpuid & 0x1) { - /* CPU is in local port 1 */ - bbsram_physaddr |= 0xfe8ULL; - } else { - /* CPU is in local port 0 */ - bbsram_physaddr |= 0xfe0ULL; - } - - /* - * Read in the cpu_sgnblk pointer offset. Add it to the bbsram - * base address to get the base address of the cpu_sgnblk. - */ - cpu_sgnblk_offset = ldphysio(bbsram_physaddr); - cpu_sgnblk_physaddr += cpu_sgnblk_offset; - - pfn = (pfn_t)(cpu_sgnblk_physaddr >> MMU_PAGESHIFT); - - num_pages = mmu_btopr(((cpu_sgnblk_physaddr & - MMU_PAGEOFFSET) + sizeof (cpu_sgnblk_t))); - - /* - * Map in the cpu_sgnblk - */ - cvaddr = vmem_alloc(heap_arena, ptob(num_pages), VM_SLEEP); - - hat_devload(kas.a_hat, cvaddr, ptob(num_pages), - pfn, PROT_READ | PROT_WRITE, HAT_LOAD_LOCK); - - cpu_sgnblkp[cpuid] = ((cpu_sgnblk_t *)(cvaddr + - (uint32_t)(cpu_sgnblk_offset & MMU_PAGEOFFSET))); -} - -void -cpu_sgn_mapout(int cpuid) -{ - ulong_t cvaddr, num_pages; - uint32_t cpu_sgnblk_offset; - uint64_t cpu_sgnblk_physaddr; - uint64_t bbsram_physaddr; - - if ((cvaddr = (ulong_t)cpu_sgnblkp[cpuid]) == NULL) { - cmn_err(CE_WARN, "cpu_sgn_mapout: ERROR: " - "cpu_sgnblkp[%d] = NULL\n", cpuid); - } else { - cvaddr &= ~MMU_PAGEOFFSET; - - /* - * Construct the physical base address of the bbsram - * in PSI space associated with this cpu in question. - */ - bbsram_physaddr = STARFIRE_UPAID2UPS(cpuid) | - STARFIRE_PSI_BASE; - cpu_sgnblk_physaddr = bbsram_physaddr; - - /* - * The cpu_sgnblk pointer offsets are stored in the - * undefined hardware trap slot 0x7f which is located - * at offset 0xfe0. There are 2 of them since the - * bbsram is shared among the 2 cpus residing on the - * a PC. We need to determine the CPU in question whether - * it is in port 0 or 1. CPU on port 0 has its - * signature blkptr stored in 0xfe0 while the cpu_sgnblk - * ptr of local port 1's CPU is in offset 0xfe8. - */ - if (cpuid & 0x1) { - /* CPU is in local port 1 */ - bbsram_physaddr |= 0xfe8ULL; - } else { - /* CPU is in local port 0 */ - bbsram_physaddr |= 0xfe0ULL; - } - - /* - * Read in the cpu_sgnblk pointer offset. Add it to the bbsram - * base address to get the base address of the cpu_sgnblk. - */ - cpu_sgnblk_offset = ldphysio(bbsram_physaddr); - cpu_sgnblk_physaddr += cpu_sgnblk_offset; - - num_pages = mmu_btopr(((uint_t)(cpu_sgnblk_physaddr & - MMU_PAGEOFFSET) + sizeof (cpu_sgnblk_t))); - - hat_unload(kas.a_hat, (caddr_t)cvaddr, ptob(num_pages), - HAT_UNLOAD_UNLOCK); - vmem_free(heap_arena, (caddr_t)cvaddr, ptob(num_pages)); - - cpu_sgnblkp[cpuid] = NULL; - } -} diff --git a/usr/src/uts/sun4u/starfire/os/pda.c b/usr/src/uts/sun4u/starfire/os/pda.c deleted file mode 100644 index 5aee0cd542..0000000000 --- a/usr/src/uts/sun4u/starfire/os/pda.c +++ /dev/null @@ -1,623 +0,0 @@ -/* - * 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 - * or http://www.opensolaris.org/os/licensing. - * 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 2004 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - * Copyright (c) 2016 by Delphix. All rights reserved. - */ - -#pragma ident "%Z%%M% %I% %E% SMI" - -/* - * Starfire Post Descriptor Array (post2obp) management. - */ - -#include <sys/debug.h> -#include <sys/types.h> -#include <sys/errno.h> -#include <sys/cpuvar.h> -#include <sys/dditypes.h> -#include <sys/conf.h> -#include <sys/ddi.h> -#include <sys/kmem.h> -#include <sys/sunddi.h> -#include <sys/sunndi.h> -#include <sys/vm.h> -#include <vm/seg.h> -#include <vm/seg_kmem.h> -#include <vm/seg_kp.h> -#include <sys/machsystm.h> -#include <sys/starfire.h> - -#include <sys/cpu_sgnblk_defs.h> -#include <sys/pda.h> -#include <sys/cpu_sgn.h> - -extern struct cpu *SIGBCPU; -extern cpu_sgnblk_t *cpu_sgnblkp[]; - -extern uint64_t mc_get_mem_alignment(); -extern uint64_t mc_asr_to_pa(uint_t mcreg); - -static post2obp_info_t *cpu_p2o_mapin(int cpuid); -static void cpu_p2o_mapout(int cpuid, post2obp_info_t *p2o); -static void p2o_update_checksum(post2obp_info_t *p2o); -static uint_t p2o_calc_checksum(post2obp_info_t *p2o); -static void p2o_mem_sort(post2obp_info_t *p2o); -static void p2o_mem_coalesce(post2obp_info_t *p2o); - -typedef struct { - post2obp_info_t *p2o_ptr; - int p2o_cpuid; -} p2o_info_t; - -/* - * PDA management routines. Should ultimately be made - * accessible to other Starfire subsystems, but for - * now we'll leave it here. - */ -pda_handle_t -pda_open() -{ - p2o_info_t *pip; - - if (SIGBCPU == NULL) { - cmn_err(CE_WARN, "pda_open: SIGBCPU is NULL"); - return (NULL); - } - - pip = (p2o_info_t *)kmem_alloc(sizeof (p2o_info_t), KM_SLEEP); - - pip->p2o_cpuid = (int)SIGBCPU->cpu_id; - pip->p2o_ptr = cpu_p2o_mapin(pip->p2o_cpuid); - - if (pip->p2o_ptr == NULL) { - kmem_free((caddr_t)pip, sizeof (p2o_info_t)); - return ((pda_handle_t)NULL); - } else { - return ((pda_handle_t)pip); - } -} - -void -pda_close(pda_handle_t ph) -{ - p2o_info_t *pip; - - if ((pip = (p2o_info_t *)ph) == NULL) - return; - - cpu_p2o_mapout(pip->p2o_cpuid, pip->p2o_ptr); - - kmem_free((caddr_t)pip, sizeof (p2o_info_t)); -} - -int -pda_board_present(pda_handle_t ph, int boardnum) -{ - ushort_t bda_board; - post2obp_info_t *p2o = ((p2o_info_t *)ph)->p2o_ptr; - - bda_board = p2o->p2o_bdinfo[boardnum].bda_board; - - if ((bda_board & BDAN_MASK) != BDAN_GOOD) - return (0); - else - return (1); -} - -void * -pda_get_board_info(pda_handle_t ph, int boardnum) -{ - post2obp_info_t *p2o = ((p2o_info_t *)ph)->p2o_ptr; - - return ((void *)&(p2o->p2o_bdinfo[boardnum])); -} - -uint_t -pda_get_mem_size(pda_handle_t ph, int boardnum) -{ - int c; - pgcnt_t npages; - uint_t asr; - pfn_t basepfn, endpfn; - uint64_t basepa, endpa; - post2obp_info_t *p2o = ((p2o_info_t *)ph)->p2o_ptr; - - if (boardnum == -1) - return (p2o->p2o_memtotal.Memt_NumPages); - - asr = p2o->p2o_bdminfo[boardnum].bmda_adr; - - basepa = mc_asr_to_pa(asr); - /* - * Put on MC alignment. - */ - endpa = mc_get_mem_alignment(); - basepa &= ~(endpa - 1); - endpa += basepa; - basepfn = (pfn_t)(basepa >> PAGESHIFT); - endpfn = (pfn_t)(endpa >> PAGESHIFT); - - npages = 0; - - for (c = 0; c < p2o->p2o_memtotal.Memt_NumChunks; c++) { - pfn_t c_basepfn, c_endpfn; - - c_basepfn = (pfn_t)p2o->p2o_mchunks[c].Memc_StartAddress - >> (PAGESHIFT - BDA_PAGESHIFT); - c_endpfn = (pfn_t)p2o->p2o_mchunks[c].Memc_Size - >> (PAGESHIFT - BDA_PAGESHIFT); - c_endpfn += c_basepfn; - - if ((endpfn <= c_basepfn) || (basepfn >= c_endpfn)) - continue; - - c_basepfn = MAX(c_basepfn, basepfn); - c_endpfn = MIN(c_endpfn, endpfn); - ASSERT(c_basepfn <= c_endpfn); - - npages += c_endpfn - c_basepfn; - } - - return (npages); -} - -void -pda_mem_add_span(pda_handle_t ph, uint64_t basepa, uint64_t nbytes) -{ - post2obp_info_t *p2o = ((p2o_info_t *)ph)->p2o_ptr; - int c, nchunks; - pfn_t a_pfn, a_npgs; - - ASSERT(p2o); - - nchunks = p2o->p2o_memtotal.Memt_NumChunks; - a_pfn = (pfn_t)(basepa >> BDA_PAGESHIFT); - a_npgs = (pfn_t)(nbytes >> BDA_PAGESHIFT); - - for (c = 0; c < nchunks; c++) { - int cend; - - if (a_pfn <= p2o->p2o_mchunks[c].Memc_StartAddress) { - for (cend = nchunks; cend > c; cend--) - p2o->p2o_mchunks[cend] = - p2o->p2o_mchunks[cend - 1]; - break; - } - } - p2o->p2o_mchunks[c].Memc_StartAddress = a_pfn; - p2o->p2o_mchunks[c].Memc_Size = a_npgs; - nchunks++; - - p2o->p2o_memtotal.Memt_NumChunks = nchunks; - p2o->p2o_memtotal.Memt_NumPages += a_npgs; - - p2o_mem_sort(p2o); - p2o_mem_coalesce(p2o); - p2o_update_checksum(p2o); -} - -void -pda_mem_del_span(pda_handle_t ph, uint64_t basepa, uint64_t nbytes) -{ - post2obp_info_t *p2o = ((p2o_info_t *)ph)->p2o_ptr; - int c, o_nchunks, n_nchunks; - pfn_t d_pfn; - pgcnt_t d_npgs, npages; - MemChunk_t *mp, *endp; - - ASSERT(p2o); - - d_pfn = (pfn_t)(basepa >> BDA_PAGESHIFT); - d_npgs = (pgcnt_t)(nbytes >> BDA_PAGESHIFT); - n_nchunks = o_nchunks = p2o->p2o_memtotal.Memt_NumChunks; - endp = &(p2o->p2o_mchunks[o_nchunks]); - npages = 0; - - for (c = 0; c < o_nchunks; c++) { - uint_t p_pfn, p_npgs; - - p_pfn = p2o->p2o_mchunks[c].Memc_StartAddress; - p_npgs = p2o->p2o_mchunks[c].Memc_Size; - if (p_npgs == 0) - continue; - - if (((d_pfn + d_npgs) <= p_pfn) || - (d_pfn >= (p_pfn + p_npgs))) { - npages += p_npgs; - continue; - } - - if (d_pfn < p_pfn) { - if ((d_pfn + d_npgs) >= (p_pfn + p_npgs)) { - /* - * Entire chunk goes away. - */ - p_pfn = p_npgs = 0; - } else { - p_npgs -= d_pfn + d_npgs - p_pfn; - p_pfn = d_pfn + d_npgs; - } - } else if (d_pfn == p_pfn) { - if ((d_pfn + d_npgs) >= (p_pfn + p_npgs)) { - p_pfn = p_npgs = 0; - } else { - p_npgs -= d_npgs; - p_pfn += d_npgs; - } - } else { - if ((d_pfn + d_npgs) >= (p_pfn + p_npgs)) { - p_npgs = d_pfn - p_pfn; - npages += p_npgs; - } else { - /* - * Ugh, got to split a - * memchunk, we're going to - * need an extra one. It's - * gotten from the end. - */ - endp->Memc_StartAddress = d_pfn + d_npgs; - endp->Memc_Size = (p_pfn + p_npgs) - - (d_pfn + d_npgs); - npages += endp->Memc_Size; - endp++; - n_nchunks++; - p_npgs = d_pfn - p_pfn; - } - } - - p2o->p2o_mchunks[c].Memc_StartAddress = p_pfn; - p2o->p2o_mchunks[c].Memc_Size = p_npgs; - if (p_npgs == 0) - n_nchunks--; - npages += p_npgs; - } - p2o->p2o_memtotal.Memt_NumChunks = n_nchunks; - p2o->p2o_memtotal.Memt_NumPages = npages; - - /* - * There is a possibility we created holes in the memchunk list - * due to memchunks that went away. Before we can sort and - * coalesce we need to "pull up" the end of the memchunk list - * and get rid of any holes. - * endp = points to the last empty memchunk entry. - */ - for (mp = &(p2o->p2o_mchunks[0]); mp < endp; mp++) { - register MemChunk_t *mmp; - - if (mp->Memc_Size) - continue; - - for (mmp = mp; mmp < endp; mmp++) - *mmp = *(mmp + 1); - mp--; - endp--; - } - ASSERT(endp == &(p2o->p2o_mchunks[n_nchunks])); - - p2o_mem_sort(p2o); - p2o_mem_coalesce(p2o); - p2o_update_checksum(p2o); -} - -/* - * Synchonize all memory attributes (currently just MC ADRs [aka ASR]) - * with PDA representative values for the given board. A board value - * of (-1) indicates all boards. - */ -/*ARGSUSED*/ -void -pda_mem_sync(pda_handle_t ph, int board, int unit) -{ - post2obp_info_t *p2o = ((p2o_info_t *)ph)->p2o_ptr; - register int b; - - for (b = 0; b < MAX_SYSBDS; b++) { - if ((board != -1) && (board != b)) - continue; - - if (pda_board_present(ph, b)) { - uint64_t masr; - uint_t masr_value; - - masr = STARFIRE_MC_ASR_ADDR_BOARD(b); - masr_value = ldphysio(masr); - - p2o->p2o_bdminfo[b].bmda_adr = masr_value; - } - - if (board == b) - break; - } - - p2o_update_checksum(p2o); -} - -void -pda_get_busmask(pda_handle_t ph, short *amask, short *dmask) -{ - post2obp_info_t *p2o = ((p2o_info_t *)ph)->p2o_ptr; - - if (amask) - *amask = p2o ? p2o->p2o_abus_mask : 0; - - if (dmask) - *dmask = p2o ? p2o->p2o_dbus_mask : 0; -} - -int -pda_is_valid(pda_handle_t ph) -{ - post2obp_info_t *p2o = ((p2o_info_t *)ph)->p2o_ptr; - uint_t csum; - - if (p2o == NULL) - return (0); - - csum = p2o_calc_checksum(p2o); - - return (csum == p2o->p2o_csum); -} - -/* - * Post2obp support functions below here. Internal to PDA module. - * - * p2o_update_checksum - * - * Calculate checksum for post2obp structure and insert it so - * when POST reads it it'll be happy. - */ -static void -p2o_update_checksum(post2obp_info_t *p2o) -{ - uint_t new_csum; - - ASSERT(p2o); - - new_csum = p2o_calc_checksum(p2o); - p2o->p2o_csum = new_csum; -} - -static uint_t -p2o_calc_checksum(post2obp_info_t *p2o) -{ - int i, nchunks; - uint_t *csumptr; - uint_t p2o_size; - uint_t csum, o_csum; - - ASSERT(p2o != NULL); - - nchunks = p2o->p2o_memtotal.Memt_NumChunks; - p2o_size = sizeof (post2obp_info_t) - + ((nchunks - VAR_ARRAY_LEN) * sizeof (MemChunk_t)); - p2o_size /= sizeof (uint_t); - - o_csum = p2o->p2o_csum; - p2o->p2o_csum = 0; - csum = 0; - for (i = 0, csumptr = (uint_t *)p2o; i < p2o_size; i++) - csum += *csumptr++; - p2o->p2o_csum = o_csum; - - return (-csum); -} - -/* - * Sort the mchunk list in ascending order based on the - * Memc_StartAddress field. - * - * disclosure: This is based on the qsort() library routine. - */ -static void -p2o_mem_sort(post2obp_info_t *p2o) -{ - MemChunk_t *base; - int nchunks; - uint_t c1, c2; - char *min, *max; - register char c, *i, *j, *lo, *hi; - - ASSERT(p2o != NULL); - - nchunks = p2o->p2o_memtotal.Memt_NumChunks; - base = &p2o->p2o_mchunks[0]; - - /* ala qsort() */ - max = (char *)base + nchunks * sizeof (MemChunk_t); - hi = max; - for (j = lo = (char *)base; (lo += sizeof (MemChunk_t)) < hi; ) { - c1 = ((MemChunk_t *)j)->Memc_StartAddress; - c2 = ((MemChunk_t *)lo)->Memc_StartAddress; - if (c1 > c2) - j = lo; - } - if (j != (char *)base) { - for (i = (char *)base, - hi = (char *)base + sizeof (MemChunk_t); - /* CSTYLED */ - i < hi;) { - c = *j; - *j++ = *i; - *i++ = c; - } - } - for (min = (char *)base; - /* CSTYLED */ - (hi = min += sizeof (MemChunk_t)) < max;) { - do { - hi -= sizeof (MemChunk_t); - c1 = ((MemChunk_t *)hi)->Memc_StartAddress; - c2 = ((MemChunk_t *)min)->Memc_StartAddress; - } while (c1 > c2); - if ((hi += sizeof (MemChunk_t)) != min) { - for (lo = min + sizeof (MemChunk_t); - /* CSTYLED */ - --lo >= min;) { - c = *lo; - for (i = j = lo; - (j -= sizeof (MemChunk_t)) >= hi; - i = j) { - *i = *j; - } - *i = c; - } - } - } -} - -static void -p2o_mem_coalesce(post2obp_info_t *p2o) -{ - MemChunk_t *mc; - int nchunks, new_nchunks; - uint_t addr, size, naddr, nsize; - uint_t npages; - register int i, cp, ncp; - - ASSERT(p2o != NULL); - - nchunks = new_nchunks = p2o->p2o_memtotal.Memt_NumChunks; - mc = &p2o->p2o_mchunks[0]; - - for (cp = i = 0; i < (nchunks-1); i++, cp = ncp) { - ncp = cp + 1; - addr = mc[cp].Memc_StartAddress; - size = mc[cp].Memc_Size; - naddr = mc[ncp].Memc_StartAddress; - nsize = mc[ncp].Memc_Size; - - if ((addr + size) >= naddr) { - uint_t overlap; - - overlap = addr + size - naddr; - /* - * if (nsize < overlap) then - * next entry fits within the current - * entry so no need to update size. - */ - if (nsize >= overlap) { - size += nsize - overlap; - mc[cp].Memc_Size = size; - } - bcopy((char *)&mc[ncp+1], - (char *)&mc[ncp], - (nchunks - ncp - 1) * sizeof (MemChunk_t)); - ncp = cp; - new_nchunks--; - } - } - - npages = 0; - for (i = 0; i < new_nchunks; i++) - npages += p2o->p2o_mchunks[i].Memc_Size; - - p2o->p2o_memtotal.Memt_NumChunks = new_nchunks; - p2o->p2o_memtotal.Memt_NumPages = npages; -} - -/* - * Mapin the the cpu's post2obp structure. - */ -static post2obp_info_t * -cpu_p2o_mapin(int cpuid) -{ - uint64_t cpu_p2o_physaddr; - uint32_t cpu_p2o_offset; - caddr_t cvaddr; - uint_t num_pages; - pfn_t pfn; - - ASSERT(cpu_sgnblkp[cpuid] != NULL); - /* - * Construct the physical base address of the bbsram - * in PSI space associated with this cpu in question. - */ - cpu_p2o_offset = (uint32_t)cpu_sgnblkp[cpuid]->sigb_postconfig; - if (cpu_p2o_offset == 0) { - cmn_err(CE_WARN, - "cpu_p2o_mapin:%d: sigb_postconfig == NULL\n", - cpuid); - return (NULL); - } - cpu_p2o_physaddr = (STARFIRE_UPAID2UPS(cpuid) | STARFIRE_PSI_BASE) + - (uint64_t)cpu_p2o_offset; - cpu_p2o_offset = (uint32_t)(cpu_p2o_physaddr & MMU_PAGEOFFSET); - cpu_p2o_physaddr -= (uint64_t)cpu_p2o_offset; - - /* - * cpu_p2o_physaddr = Beginning of page containing p2o. - * cpu_p2o_offset = Offset within page where p2o starts. - */ - - pfn = (pfn_t)(cpu_p2o_physaddr >> MMU_PAGESHIFT); - - num_pages = mmu_btopr(cpu_p2o_offset + sizeof (post2obp_info_t)); - - /* - * Map in the post2obp structure. - */ - cvaddr = vmem_alloc(heap_arena, ptob(num_pages), VM_SLEEP); - - hat_devload(kas.a_hat, cvaddr, ptob(num_pages), - pfn, PROT_READ | PROT_WRITE, HAT_LOAD_LOCK); - - return ((post2obp_info_t *)(cvaddr + (ulong_t)cpu_p2o_offset)); -} - -static void -cpu_p2o_mapout(int cpuid, post2obp_info_t *p2o) -{ - ulong_t cvaddr, num_pages; - uint32_t cpu_p2o_offset; - - ASSERT(cpu_sgnblkp[cpuid] != NULL); - - cpu_p2o_offset = (uint32_t)cpu_sgnblkp[cpuid]->sigb_postconfig; - if (cpu_p2o_offset == 0) { - cmn_err(CE_WARN, - "cpu_p2o_mapout:%d: sigb_postconfig == NULL\n", - cpuid); - return; - } - - cpu_p2o_offset = (uint32_t)(((STARFIRE_UPAID2UPS(cpuid) | - STARFIRE_PSI_BASE) + - (uint64_t)cpu_p2o_offset) & - MMU_PAGEOFFSET); - - num_pages = mmu_btopr(cpu_p2o_offset + sizeof (post2obp_info_t)); - - cvaddr = (ulong_t)p2o - cpu_p2o_offset; - if (cvaddr & MMU_PAGEOFFSET) { - cmn_err(CE_WARN, - "cpu_p2o_mapout:%d: cvaddr (0x%x) not on page " - "boundary\n", - cpuid, (uint_t)cvaddr); - return; - } - - hat_unload(kas.a_hat, (caddr_t)cvaddr, ptob(num_pages), - HAT_UNLOAD_UNLOCK); - vmem_free(heap_arena, (caddr_t)cvaddr, ptob(num_pages)); -} diff --git a/usr/src/uts/sun4u/starfire/os/starfire.c b/usr/src/uts/sun4u/starfire/os/starfire.c deleted file mode 100644 index 2dd0688f4a..0000000000 --- a/usr/src/uts/sun4u/starfire/os/starfire.c +++ /dev/null @@ -1,639 +0,0 @@ -/* - * 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 - * or http://www.opensolaris.org/os/licensing. - * 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/param.h> -#include <sys/systm.h> -#include <sys/sysmacros.h> -#include <sys/sunddi.h> -#include <sys/modctl.h> -#include <sys/promif.h> -#include <sys/machparam.h> -#include <sys/kobj.h> -#include <sys/mem_cage.h> -#include <sys/starfire.h> - -#include <sys/platform_module.h> -#include <sys/errno.h> -#include <vm/page.h> -#include <vm/hat_sfmmu.h> -#include <sys/memnode.h> -#include <vm/vm_dep.h> -#include <sys/cpu_sgnblk_defs.h> -#include <sys/cpu_sgn.h> -#include <sys/kdi_impl.h> -#include <sys/clock_impl.h> - -extern cpu_sgnblk_t *cpu_sgnblkp[]; - -/* Preallocation of spare tsb's for DR - none for now */ -int starfire_tsb_spares = STARFIRE_MAX_BOARDS << 1; - -/* Set the maximum number of boards... for DR */ -int starfire_boards = STARFIRE_MAX_BOARDS; - -/* Maximum number of cpus per board... for DR */ -int starfire_cpu_per_board = 4; - -/* Maximum number of mem-units per board... for DR */ -int starfire_mem_per_board = 1; - -/* Maximum number of io-units (buses) per board... for DR */ -int starfire_io_per_board = 2; - -/* Preferred minimum cage size (expressed in pages)... for DR */ -pgcnt_t starfire_startup_cage_size = 0; - -void sgn_update_all_cpus(ushort_t, uchar_t, uchar_t); - -int -set_platform_max_ncpus(void) -{ - starfire_boards = MIN(starfire_boards, STARFIRE_MAX_BOARDS); - - if (starfire_boards < 1) - starfire_boards = 1; - - return (starfire_boards * starfire_cpu_per_board); -} - -void -startup_platform(void) -{ -} - -int -set_platform_tsb_spares() -{ - return (MIN(starfire_tsb_spares, MAX_UPA)); -} - -void -set_platform_defaults(void) -{ - extern char *tod_module_name; - extern int ts_dispatch_extended; - extern void cpu_sgn_update(ushort_t, uchar_t, uchar_t, int); - - uint32_t revlevel; - char buf[20]; - -#ifdef DEBUG - ce_verbose_memory = 2; - ce_verbose_other = 2; -#endif - - /* - * Check to see if we have the right firmware - * We simply do a prom_test to see if - * "SUNW,UE10000-prom-version" interface exist. - */ - if (prom_test("SUNW,UE10000-prom-version") != 0) { - halt("Firmware upgrade is required to boot this OS!"); - } else { - /* - * Versions 5 to 50 and 150 or above can support this OS - */ - (void) sprintf(buf, "cpu-prom-version swap l!"); - prom_interpret(buf, (uintptr_t)&revlevel, 0, 0, 0, 0); - if ((revlevel < 5) || ((revlevel > 50) && (revlevel < 150))) - halt("Firmware upgrade is required to boot this OS!"); - } - - /* Set the CPU signature function pointer */ - cpu_sgn_func = cpu_sgn_update; - - /* Set appropriate tod module for starfire */ - ASSERT(tod_module_name == NULL); - tod_module_name = "todstarfire"; - - /* - * Use the alternate TS dispatch table, which is better - * tuned for large servers. - */ - if (ts_dispatch_extended == -1) /* use platform default */ - ts_dispatch_extended = 1; -} - -#ifdef DEBUG -pgcnt_t starfire_cage_size_limit; -#endif - -void -set_platform_cage_params(void) -{ - extern pgcnt_t total_pages; - extern struct memlist *phys_avail; - - if (kernel_cage_enable) { - pgcnt_t preferred_cage_size; - - preferred_cage_size = - MAX(starfire_startup_cage_size, total_pages / 256); - -#ifdef DEBUG - if (starfire_cage_size_limit) - preferred_cage_size = starfire_cage_size_limit; -#endif - /* - * Note: we are assuming that post has load the - * whole show in to the high end of memory. Having - * taken this leap, we copy the whole of phys_avail - * the glist and arrange for the cage to grow - * downward (descending pfns). - */ - kcage_range_init(phys_avail, KCAGE_DOWN, preferred_cage_size); - } - - if (kcage_on) - cmn_err(CE_NOTE, "!DR Kernel Cage is ENABLED"); - else - cmn_err(CE_NOTE, "!DR Kernel Cage is DISABLED"); -} - -void -load_platform_drivers(void) -{ - /* load the NGDR driver */ - if (i_ddi_attach_pseudo_node("ngdr") == NULL) { - cmn_err(CE_WARN, "ngdr failed to load"); - } -} - -/* - * Starfire does not support power control of CPUs from the OS. - */ -/*ARGSUSED*/ -int -plat_cpu_poweron(struct cpu *cp) -{ - int (*starfire_cpu_poweron)(struct cpu *) = NULL; - - starfire_cpu_poweron = - (int (*)(struct cpu *))kobj_getsymvalue("drmach_cpu_poweron", 0); - - if (starfire_cpu_poweron == NULL) - return (ENOTSUP); - else - return ((starfire_cpu_poweron)(cp)); -} - -/*ARGSUSED*/ -int -plat_cpu_poweroff(struct cpu *cp) -{ - int (*starfire_cpu_poweroff)(struct cpu *) = NULL; - - starfire_cpu_poweroff = - (int (*)(struct cpu *))kobj_getsymvalue("drmach_cpu_poweroff", 0); - - if (starfire_cpu_poweroff == NULL) - return (ENOTSUP); - else - return ((starfire_cpu_poweroff)(cp)); -} - -void -plat_dmv_params(uint_t *hwint, uint_t *swint) -{ - *hwint = STARFIRE_DMV_HWINT; - *swint = 0; -} - -/* - * The following our currently private to Starfire DR - */ -int -plat_max_boards() -{ - return (starfire_boards); -} - -int -plat_max_cpu_units_per_board() -{ - return (starfire_cpu_per_board); -} - -int -plat_max_mem_units_per_board() -{ - return (starfire_mem_per_board); -} - -int -plat_max_io_units_per_board() -{ - return (starfire_io_per_board); -} - - -/* - * This index is used to associate a given pfn to a place on the freelist. - * This results in dispersing pfn assignment over all the boards in the - * system. - * Choose the index randomly to prevent clustering pages of different - * colors on the same board. - */ -static uint_t random_idx(int ubound); - -#define PFN_2_LBN(pfn) (((pfn) >> (STARFIRE_MC_MEMBOARD_SHIFT - PAGESHIFT)) % \ - STARFIRE_MAX_BOARDS) - -void -plat_freelist_process(int mnode) -{ - page_t *page, **freelist; - page_t *bdlist[STARFIRE_MAX_BOARDS]; - page_t **sortlist[STARFIRE_MAX_BOARDS]; - uint32_t idx, idy, size, color, max_color, lbn; - uint32_t bd_flags, bd_cnt, result, bds; - kmutex_t *pcm; - int mtype; - - /* for each page size */ - for (mtype = 0; mtype < MAX_MEM_TYPES; mtype++) { - for (size = 0; size < mmu_page_sizes; size++) { - - /* - * Compute the maximum # of phys colors based on - * page size. - */ - max_color = page_get_pagecolors(size); - - /* for each color */ - for (color = 0; color < max_color; color++) { - - bd_cnt = 0; - bd_flags = 0; - for (idx = 0; idx < STARFIRE_MAX_BOARDS; - idx++) { - bdlist[idx] = NULL; - sortlist[idx] = NULL; - } - - /* find freelist */ - freelist = &PAGE_FREELISTS(mnode, size, - color, mtype); - - if (*freelist == NULL) - continue; - - /* acquire locks */ - pcm = PC_BIN_MUTEX(mnode, color, PG_FREE_LIST); - mutex_enter(pcm); - - /* - * read freelist & sort pages by logical - * board number - */ - /* grab pages till last one. */ - while (*freelist) { - page = *freelist; - result = page_trylock(page, SE_EXCL); - - ASSERT(result); - - /* Delete from freelist */ - if (size != 0) { - page_vpsub(freelist, page); - } else { - mach_page_sub(freelist, page); - } - - /* detect the lbn */ - lbn = PFN_2_LBN(page->p_pagenum); - - /* add to bdlist[lbn] */ - if (size != 0) { - page_vpadd(&bdlist[lbn], page); - } else { - mach_page_add(&bdlist[lbn], - page); - } - - /* if lbn new */ - if ((bd_flags & (1 << lbn)) == 0) { - bd_flags |= (1 << lbn); - bd_cnt++; - } - page_unlock(page); - } - - /* - * Make the sortlist so - * bd_cnt choices show up - */ - bds = 0; - for (idx = 0; idx < STARFIRE_MAX_BOARDS; - idx++) { - if (bdlist[idx]) - sortlist[bds++] = &bdlist[idx]; - } - - /* - * Set random start. - */ - (void) random_idx(-color); - - /* - * now rebuild the freelist by shuffling - * pages from bd lists - */ - while (bd_cnt) { - - /* - * get "random" index between 0 & - * bd_cnt - */ - - ASSERT(bd_cnt && - (bd_cnt < STARFIRE_MAX_BOARDS+1)); - - idx = random_idx(bd_cnt); - - page = *sortlist[idx]; - result = page_trylock(page, SE_EXCL); - - ASSERT(result); - - /* Delete from sort_list */ - /* & Append to freelist */ - /* Big pages use vp_add - 8k don't */ - if (size != 0) { - page_vpsub(sortlist[idx], page); - page_vpadd(freelist, page); - } else { - mach_page_sub(sortlist[idx], - page); - mach_page_add(freelist, page); - } - - /* needed for indexing tmp lists */ - lbn = PFN_2_LBN(page->p_pagenum); - - /* - * if this was the last page on this - * list? - */ - if (*sortlist[idx] == NULL) { - - /* have to find brd list */ - - /* idx is lbn? -- No! */ - /* sortlist, brdlist */ - /* have diff indexs */ - bd_flags &= ~(1 << lbn); - --bd_cnt; - - /* - * redo the sortlist so only - * bd_cnt choices show up - */ - bds = 0; - for (idy = 0; - idy < STARFIRE_MAX_BOARDS; - idy++) { - if (bdlist[idy]) { - sortlist[bds++] - /* CSTYLED */ - = &bdlist[idy]; - } - } - } - page_unlock(page); - } - mutex_exit(pcm); - } - } - } -} - -/* - * If ubound > 0, will return an int between 0 & ubound - * If ubound < 0, will set "random seed" - */ -static uint_t -random_idx(int ubound) -{ - static int idx = 0; - - if (ubound > 0) { - idx = (idx + 1) % ubound; - return (idx); - } - idx = -ubound; - return (0); -} - -/* - * No platform drivers on this platform - */ -char *platform_module_list[] = { - (char *)0 -}; - -/*ARGSUSED*/ -void -plat_tod_fault(enum tod_fault_type tod_bad) -{ -} - -/* - * Update signature block and the signature ring buffer of a given cpu_id. - */ -void -cpu_sgn_update(ushort_t sgn, uchar_t state, uchar_t sub_state, int cpuid) -{ - uchar_t idx; - cpu_sgnblk_t *cpu_sgnblkptr; - - /* - * cpuid == -1 indicates that the operation applies to all cpus. - */ - if (cpuid < 0) { - sgn_update_all_cpus(sgn, state, sub_state); - return; - } - - if (cpu_sgnblkp[cpuid] == NULL) - return; - - cpu_sgnblkptr = cpu_sgnblkp[cpuid]; - - /* - * Map new generic cpu states to older Starfire states. - */ - switch (state) { - case SIGST_OFFLINE: - state = SIGBST_OFFLINE; - break; - case SIGST_RESUME_INPROGRESS: - state = SIGBST_RESUME_INPROGRESS; - break; - case SIGST_QUIESCE_INPROGRESS: - state = SIGBST_QUIESCE_INPROGRESS; - break; - case SIGST_QUIESCED: - state = SIGBST_QUIESCED; - break; - case SIGST_EXIT: - switch (sub_state) { - case SIGSUBST_DEBUG: - state = SIGBST_RUN; - sub_state = EXIT_NULL; - break; - case SIGSUBST_PANIC_CONT: - state = SIGBST_RUN; - sub_state = EXIT_PANIC2; - break; - case SIGSUBST_DUMP: - state = SIGBST_EXIT; - sub_state = EXIT_PANIC2; - break; - default: - break; - } - break; - default: - break; - } - - cpu_sgnblkptr->sigb_signature.state_t.sig = sgn; - cpu_sgnblkptr->sigb_signature.state_t.state = state; - cpu_sgnblkptr->sigb_signature.state_t.sub_state = sub_state; - - /* Update the ring buffer */ - idx = cpu_sgnblkptr->sigb_ringbuf.wr_ptr; - cpu_sgnblkptr->sigb_ringbuf.ringbuf[idx].state_t.sig = sgn; - cpu_sgnblkptr->sigb_ringbuf.ringbuf[idx].state_t.state = state; - cpu_sgnblkptr->sigb_ringbuf.ringbuf[idx].state_t.sub_state = sub_state; - cpu_sgnblkptr->sigb_ringbuf.wr_ptr += 1; - cpu_sgnblkptr->sigb_ringbuf.wr_ptr &= RB_IDX_MASK; -} - -/* - * Update signature block and the signature ring buffer of all CPUs. - */ -void -sgn_update_all_cpus(ushort_t sgn, uchar_t state, uchar_t sub_state) -{ - int i = 0; - uchar_t cpu_state; - uchar_t cpu_sub_state; - - for (i = 0; i < NCPU; i++) { - cpu_sgnblk_t *sblkp; - - sblkp = cpu_sgnblkp[i]; - cpu_sub_state = sub_state; - - if ((sblkp != NULL) && (cpu[i] != NULL && (cpu[i]->cpu_flags & - (CPU_EXISTS|CPU_QUIESCED)))) { - - if (sub_state == EXIT_REBOOT) { - cpu_sub_state = - sblkp->sigb_signature.state_t.sub_state; - - if ((cpu_sub_state == EXIT_PANIC1) || - (cpu_sub_state == EXIT_PANIC2)) - cpu_sub_state = EXIT_PANIC_REBOOT; - else - cpu_sub_state = EXIT_REBOOT; - } - - /* - * If we get here from an OBP sync after watchdog, - * we need to retain the watchdog sync state so that - * hostmon knows what's going on. So if we're in - * watchdog we don't update the state. - */ - - cpu_state = sblkp->sigb_signature.state_t.state; - if (cpu_state == SIGBST_WATCHDOG_SYNC) - cpu_sgn_update(sgn, SIGBST_WATCHDOG_SYNC, - cpu_sub_state, i); - else if (cpu_state == SIGBST_REDMODE_SYNC) - cpu_sgn_update(sgn, SIGBST_REDMODE_SYNC, - cpu_sub_state, i); - else - cpu_sgn_update(sgn, state, cpu_sub_state, i); - } - } -} - -int -cpu_sgn_exists(int cpuid) -{ - return (cpu_sgnblkp[cpuid] != NULL); -} - -ushort_t -get_cpu_sgn(int cpuid) -{ - if (cpu_sgnblkp[cpuid] == NULL) - return ((ushort_t)-1); - - return (cpu_sgnblkp[cpuid]->sigb_signature.state_t.sig); -} - -uchar_t -get_cpu_sgn_state(int cpuid) -{ - if (cpu_sgnblkp[cpuid] == NULL) - return ((uchar_t)-1); - - return (cpu_sgnblkp[cpuid]->sigb_signature.state_t.state); -} - -/* - * KDI functions - used by the in-situ kernel debugger (kmdb) to perform - * platform-specific operations. These functions execute when the world is - * stopped, and as such cannot make any blocking calls, hold locks, etc. - * promif functions are a special case, and may be used. - */ - -static void -starfire_system_claim(void) -{ - lbolt_debug_entry(); - - prom_interpret("sigb-sig! my-sigb-sig!", OBP_SIG, OBP_SIG, 0, 0, 0); -} - -static void -starfire_system_release(void) -{ - prom_interpret("sigb-sig! my-sigb-sig!", OS_SIG, OS_SIG, 0, 0, 0); - - lbolt_debug_return(); -} - -void -plat_kdi_init(kdi_t *kdi) -{ - kdi->pkdi_system_claim = starfire_system_claim; - kdi->pkdi_system_release = starfire_system_release; -} diff --git a/usr/src/uts/sun4u/starfire/pcipsy/Makefile b/usr/src/uts/sun4u/starfire/pcipsy/Makefile deleted file mode 100644 index 97bb94d9a6..0000000000 --- a/usr/src/uts/sun4u/starfire/pcipsy/Makefile +++ /dev/null @@ -1,95 +0,0 @@ -# -# 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 -# or http://www.opensolaris.org/os/licensing. -# 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 2004 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# -# uts/sun4u/starfire/pcipsy/Makefile -# -# This makefile drives the production of the PCI driver kernel module. -# -# sun4u implementation architecture dependent -# - -# -# Path to the base of the uts directory tree (usually /usr/src/uts). -# -UTSBASE = ../../.. - -# -# Define the module and object file sets. -# -MODULE = pcipsy -OBJECTS = $(PSYCHO_PCI_OBJS:%=$(OBJS_DIR)/%) -LINTS = $(PSYCHO_PCI_OBJS:%.o=$(LINTS_DIR)/%.ln) -ROOTMODULE = $(ROOT_STARFIRE_DRV_DIR)/$(MODULE) - -# -# Include common rules. -# -include $(UTSBASE)/sun4u/starfire/Makefile.starfire - -# -# Define targets -# -ALL_TARGET = $(BINARY) -LINT_TARGET = $(MODULE).lint -INSTALL_TARGET = $(BINARY) $(ROOTMODULE) - -# -# lint pass one enforcement -# -CFLAGS += $(CCVERBOSE) -CERRWARN += -_gcc=-Wno-uninitialized -CERRWARN += -_gcc=-Wno-parentheses -CERRWARN += -_gcc=-Wno-unused-function - -# -# Turn on doubleword alignment for 64 bit registers -# -CFLAGS += -dalign - -# -# Default build targets. -# -.KEEP_STATE: - -def: $(DEF_DEPS) - -all: $(ALL_DEPS) - -clean: $(CLEAN_DEPS) - -clobber: $(CLOBBER_DEPS) - -lint: $(LINT_DEPS) - -modlintlib: $(MODLINTLIB_DEPS) - -clean.lint: $(CLEAN_LINT_DEPS) - -install: $(INSTALL_DEPS) - -# -# Include common targets. -# -include $(UTSBASE)/sun4u/starfire/Makefile.targ diff --git a/usr/src/uts/sun4u/starfire/platmod/Makefile b/usr/src/uts/sun4u/starfire/platmod/Makefile deleted file mode 100644 index 026493c4fb..0000000000 --- a/usr/src/uts/sun4u/starfire/platmod/Makefile +++ /dev/null @@ -1,98 +0,0 @@ -# -# 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 -# or http://www.opensolaris.org/os/licensing. -# 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. -# -# ident "%Z%%M% %I% %E% SMI" -# - -# -# This makefile drives the production of the sun4u starfire platform -# module. -# -# sun4u starfire implementation architecture dependent -# - -# -# Path to the base of the uts directory tree (usually /usr/src/uts). -# -UTSBASE = ../../.. -# -# Define the module and object file sets. -# -MODULE = platmod -OBJECTS = $(STARFIRE_OBJS:%=$(OBJS_DIR)/%) -LINTS = $(STARFIRE_OBJS:%.o=$(LINTS_DIR)/%.ln) -ROOTMODULE = $(ROOT_STARFIRE_MISC_DIR)/$(MODULE) -PLAT_DIR = . - -# -# Include common rules. -# -include $(UTSBASE)/sun4u/starfire/Makefile.starfire - -# -# Override defaults -# -CLEANFILES += $(PLATLIB) - -# -# Define targets -# -ALL_TARGET = $(PLATLIB) -LINT_TARGET = $(MODULE).lint -INSTALL_TARGET = $(BINARY) $(ROOTMODULE) - -# -# lint pass one enforcement -# -CFLAGS += $(CCVERBOSE) - -# -# Default build targets. -# -.KEEP_STATE: - -def: $(DEF_DEPS) - -all: $(ALL_DEPS) - -clean: $(CLEAN_DEPS) - -clobber: $(CLOBBER_DEPS) - -lint: $(LINT_DEPS) - -modlintlib: $(MODLINTLIB_DEPS) - -clean.lint: $(CLEAN_LINT_DEPS) - -install: $(INSTALL_DEPS) - -$(PLATLIB): $(BINARY) - $(BUILD.SO) $(BINARY) - -# -# Include common targets. -# -include $(UTSBASE)/sun4u/starfire/Makefile.targ diff --git a/usr/src/uts/sun4u/starfire/rootnex/Makefile b/usr/src/uts/sun4u/starfire/rootnex/Makefile deleted file mode 100644 index 191a61016c..0000000000 --- a/usr/src/uts/sun4u/starfire/rootnex/Makefile +++ /dev/null @@ -1,97 +0,0 @@ -# -# 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 -# or http://www.opensolaris.org/os/licensing. -# 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 2004 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# -# This makefile drives the production of the rootnex driver -# -# sun4u starfire implementation architecture dependent -# - -# -# Path to the base of the uts directory tree (usually /usr/src/uts). -# -UTSBASE = ../../.. - -# -# Define the module and object file sets. -# -MODULE = rootnex -OBJECTS = $(ROOTNEX_OBJS:%=$(OBJS_DIR)/%) -LINTS = $(ROOTNEX_OBJS:%.o=$(LINTS_DIR)/%.ln) -ROOTMODULE = $(ROOT_STARFIRE_DRV_DIR)/$(MODULE) - -# -# Include common rules. -# -include $(UTSBASE)/sun4u/starfire/Makefile.starfire - -# -# Override defaults to build a unique, local modstubs.o. -# -MODSTUBS_DIR = . -$(MODSTUBS_O) := AS_CPPFLAGS += -DROOTNEX_MODULE - -CLEANFILES += $(MODSTUBS_O) - -# -# Define targets -# -ALL_TARGET = $(BINARY) -LINT_TARGET = $(MODULE).lint -INSTALL_TARGET = $(BINARY) $(ROOTMODULE) - -# -# lint pass one enforcement -# -CFLAGS += $(CCVERBOSE) -CERRWARN += -_gcc=-Wno-parentheses -CERRWARN += -_gcc=-Wno-unused-variable -CERRWARN += -_gcc=-Wno-uninitialized -CERRWARN += -_gcc=-Wno-switch - -# -# Default build targets. -# -.KEEP_STATE: - -def: $(DEF_DEPS) - -all: $(ALL_DEPS) - -clean: $(CLEAN_DEPS) - -clobber: $(CLOBBER_DEPS) - -lint: $(LINT_DEPS) - -modlintlib: $(MODLINTLIB_DEPS) - -clean.lint: $(CLEAN_LINT_DEPS) - -install: $(INSTALL_DEPS) - -# -# Include common targets. -# -include $(UTSBASE)/sun4u/starfire/Makefile.targ diff --git a/usr/src/uts/sun4u/starfire/sbus/Makefile b/usr/src/uts/sun4u/starfire/sbus/Makefile deleted file mode 100644 index 03c6d28bf4..0000000000 --- a/usr/src/uts/sun4u/starfire/sbus/Makefile +++ /dev/null @@ -1,98 +0,0 @@ -# -# 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 -# or http://www.opensolaris.org/os/licensing. -# 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 2004 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# -# uts/sun4u/starfire/sbus/Makefile -# -# This makefile drives the production of the SBus driver kernel module, -# the iommu nexus, and the obio nexus (which really is sbus on sun5). -# -# starfire implementation architecture dependent -# - -# -# Path to the base of the uts directory tree (usually /usr/src/uts). -# -UTSBASE = ../../.. - -# -# Define the module and object file sets. -# -MODULE = sbus -OBJECTS = $(SYSIO_SBUS_OBJS:%=$(OBJS_DIR)/%) -LINTS = $(SYSIO_SBUS_OBJS:%.o=$(LINTS_DIR)/%.ln) -ROOTMODULE = $(ROOT_STARFIRE_DRV_DIR)/$(MODULE) - -# -# Include common rules. -# -include $(UTSBASE)/sun4u/starfire/Makefile.starfire - -# -# Define targets -# -ALL_TARGET = $(BINARY) -LINT_TARGET = $(MODULE).lint -INSTALL_TARGET = $(BINARY) $(ROOTMODULE) - -# Turn this on once compiler understands v9 in it's backend -#INLINES += $(UTSBASE)/sun4u/io/iommu.il - -# -# lint pass one enforcement -# -CFLAGS += $(CCVERBOSE) -CERRWARN += -_gcc=-Wno-type-limits -CERRWARN += -_gcc=-Wno-uninitialized - -# -# Turn on doubleword alignment for 64 bit registers -# -CFLAGS += -dalign - -# -# Default build targets. -# -.KEEP_STATE: - -def: $(DEF_DEPS) - -all: $(ALL_DEPS) - -clean: $(CLEAN_DEPS) - -clobber: $(CLOBBER_DEPS) - -lint: $(LINT_DEPS) - -modlintlib: $(MODLINTLIB_DEPS) - -clean.lint: $(CLEAN_LINT_DEPS) - -install: $(INSTALL_DEPS) - -# -# Include common targets. -# -include $(UTSBASE)/sun4u/starfire/Makefile.targ diff --git a/usr/src/uts/sun4u/starfire/spitfire/Makefile b/usr/src/uts/sun4u/starfire/spitfire/Makefile deleted file mode 100644 index 9db750b1cd..0000000000 --- a/usr/src/uts/sun4u/starfire/spitfire/Makefile +++ /dev/null @@ -1,109 +0,0 @@ -# -# 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 -# or http://www.opensolaris.org/os/licensing. -# 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. -# - -# -# This makefile drives the production of the sun4u UltraSPARC driver module. -# -# sun4u/starfire implementation architecture dependent -# - -# -# Path to the base of the uts directory tree (usually /usr/src/uts). -# -UTSBASE = ../../.. - -# -# Define the module and object file sets. -# -MODULE = SUNW,UltraSPARC-II -OBJECTS = $(SPITFIRE_OBJS:%=$(OBJS_DIR)/%) -LINTS = $(SPITFIRE_OBJS:%.o=$(LINTS_DIR)/%.ln) -ROOTMODULE = $(ROOT_STARFIRE_CPU_DIR)/$(MODULE) - -CPU_DIR = . -HERE = ../spitfire - -# -# Include common rules. -# -include $(UTSBASE)/sun4u/starfire/Makefile.starfire - -# -# Override defaults -# -CLEANFILES += $(CPULIB) $(SYM_MOD) - -# -# Define targets -# -ALL_TARGET = $(SYM_MOD) -LINT_TARGET = $(MODULE).lint -INSTALL_TARGET = def $(BINARY) $(ROOTMODULE) - -# -# lint pass one enforcement -# -CFLAGS += $(CCVERBOSE) -CERRWARN += -_gcc=-Wno-uninitialized - -CPPFLAGS += -DCPU_MODULE -DSPITFIRE -AS_CPPFLAGS += -DCPU_MODULE -DSPITFIRE - -# -# Default build targets. -# -.KEEP_STATE: - -def: $(DEF_DEPS) - -all: $(ALL_DEPS) - -clean: $(CLEAN_DEPS) - -clobber: $(CLOBBER_DEPS) - -lint: $(LINT_DEPS) - -modlintlib: $(MODLINTLIB_DEPS) - -clean.lint: $(CLEAN_LINT_DEPS) - -install: $(INSTALL_DEPS) - -$(CPULIB): $(BINARY) - $(BUILD.SO) $(BINARY) - -$(SYM_MOD): $(UNIX_O) $(CPULIB) - @echo "resolving symbols against unix.o" - @(cd $(UNIX_DIR); pwd; \ - CPU_DIR=$(HERE) SYM_MOD=$(HERE)/$(SYM_MOD) $(MAKE) symcheck) - -$(ROOTSOFTLINKS): $(ROOTMODULE) - $(RM) $@; $(SYMLINK) $(MODULE) $@ - -# Include common targets. -# -include $(UTSBASE)/sun4u/starfire/Makefile.targ diff --git a/usr/src/uts/sun4u/starfire/sys/Makefile b/usr/src/uts/sun4u/starfire/sys/Makefile deleted file mode 100644 index 00f306b5c3..0000000000 --- a/usr/src/uts/sun4u/starfire/sys/Makefile +++ /dev/null @@ -1,68 +0,0 @@ -# -# 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 -# or http://www.opensolaris.org/os/licensing. -# 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. -# -UTSBASE = ../../.. - -# -# include global definitions -# -include ../Makefile.starfire - -# -# Override defaults. -# -FILEMODE = 644 - -HDRS= cvc.h - -STARHDRS= $(UTSBASE)/sun4u/ngdr/sys/dr.h \ - $(UTSBASE)/sun4u/ngdr/sys/dr_util.h - -ROOTHDRS= $(HDRS:%=$(USR_STARFIRE_ISYS_DIR)/%) - -ROOTDIR= $(ROOT)/usr/share/src -ROOTDIRS= $(ROOTDIR)/uts $(ROOTDIR)/uts/$(PLATFORM) - -CHECKHDRS= $(HDRS:%.h=%.check) \ - $(STARHDRS:%.h=%.check) - -.KEEP_STATE: - -.PARALLEL: $(CHECKHDRS) $(ROOTHDRS) - -install_h: $(ROOTDIRS) .WAIT $(ROOTHDRS) $(ROOTLINK) - -check: $(CHECKHDRS) - -# -# install rules -# -$(USR_STARFIRE_ISYS_DIR)/%: % $(USR_STARFIRE_ISYS_DIR) - $(INS.file) - -$(ROOTDIRS): - $(INS.dir) - -FRC: - -include ../Makefile.targ diff --git a/usr/src/uts/sun4u/starfire/sys/cpu_sgn.h b/usr/src/uts/sun4u/starfire/sys/cpu_sgn.h deleted file mode 100644 index 8c14d34f3b..0000000000 --- a/usr/src/uts/sun4u/starfire/sys/cpu_sgn.h +++ /dev/null @@ -1,354 +0,0 @@ -/* - * 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 - * or http://www.opensolaris.org/os/licensing. - * 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 (c) 2000 by Sun Microsystems, Inc. - * All rights reserved. - */ - -#ifndef _CPU_SGN_H -#define _CPU_SGN_H - -#pragma ident "%Z%%M% %I% %E% SMI" - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef _ASM -#include <sys/types.h> -#include <sys/cpuvar.h> -#endif /* _ASM */ - -/* - * BBSRAM virtual address - 64 bits max. - */ -typedef uint64_t vaddr_t; - -/* - * Special type for BBSRAM offsets (rather than pointers). - * This must be a 32 bit value - */ -typedef uint32_t bboff_t; - -/* - * As long as each component of the revision is less than - * 256, this trick will work. So we check for that and generate a - * syntax error if the SID is out of range. - */ -#define SIGB_MBOX_SIZE 64 -/* reserved space - rounds size of sigblock_t to 512 */ -#define SIGB_RESV 16 - -#define BASE_ADDR_T_OFFSET 0xFE0 /* BBSRAM base_addr_t offset */ - -#define CVC_OUT_SIZ 1024 /* cvc output buffer size */ -#define CVC_IN_SIZ 256 /* cvc input buffer size */ - -/* make sure the assembler doesn't see the C code */ -#ifndef _ASM - -/* - * The reserved hardware interrupt 7F is used as a pointer structure - * to the two processors' signature blocks in bbsram. Each trap entry - * is 32 bytes, so this structure is always present at bbsram offset - * 0xFE0. - * Over time, we may discover other items that need pointers, that don't - * logically fit in the sigblocks themselves. This structure declares - * the global use of these 8 words. - * The spare_x words are reserved in case a design change calls for - * using 64-bit virtual addresses instead of offsets. This is - * considered unlikely. - * - * The offsets and this structure are normally created by POST when it - * initially creates the sigblocks. Subsequent programs may move the - * sigblocks in bbsram as they see fit, as long as this structure is changed - * to reflect the new location. - */ - -typedef struct { - bboff_t sigblk_offset_0; /* BBSRAM sig block 0 offset */ - uint32_t spare_0; /* spare word just in case */ - bboff_t sigblk_offset_1; /* BBSRAM sig block 1 offset */ - uint32_t spare_1; /* another just in case */ - uint32_t pad[4]; /* trap is 8 32-bit words long */ -} base_addr_t; - - -/* - * The following are used in the flag field of the mailbox structure. - * They are used to synchronize access with the mailbox between the - * SSP and Host, and indicate direction of the given message. - */ -#define SIGB_MBOX_EMPTY 0 -#define SIGB_MBOX_BUSY 1 -#define HOST_TO_CBS 2 -#define CBS_TO_HOST 3 - -/* for sigblk polling */ -#define SIGB_INTR_OFF 0x00 -#define SIGB_INTR_SEND 0xFF - -typedef short mboxflag_t; - -/* - * BE CAREFUL with modifications. To optimize transfers on the - * bootbus between the kernel and mailbox, try to make sure the data - * field falls on a 16 byte boundary. - */ -typedef struct { -/* 0 */ short intr; -/* 2 */ mboxflag_t flag; -/* 4 */ int32_t len; -/* 8 */ uint32_t cmd; -/* c */ char data[SIGB_MBOX_SIZE]; -} sigbmbox_t; /* sizeof = 76 (0x4c) = 19X */ - -typedef struct { - uchar_t cvc_output_buf[CVC_OUT_SIZ]; - uchar_t cvc_input_buf[CVC_IN_SIZ]; - uchar_t cvc_obp_input_flag; /* !=0 -> OBP wants CVC input */ -} sigb_cvc_t; - -/* - * Every CPU signature, state, or substate transition is captured - * in the ring buffer. OS or OBP will be the writer of the ring buffer - * and control board executive (via JTAG) will be the sole reader. Because of - * space limitation in the BBSRAM, the ring buffer can only be 64 entries big. - * A ring buffer is necessary because of the speed difference between the - * reader and writer, and to prevent race condition. - * - * The ring buffer structure contains two pointers, one for reading and - * one for writing, and the buffer itself. The last 6 bits in each of the - * pointer identify an entry in the buffer. The read pointer represents - * the next entry the reader should read. The write pointer represents the - * next entry the writer is going to write. For the reader, the ring buffer - * contains un-read entries if the read and write pointers are different. - * - * In most situations, the reader should be able to keep up with the - * writer. However, in the case where the writer is transitioning - * rapidly, the reader may not be able to keep up and causes an overflow. - * When an overflow happens, instead of suspending the writer, the - * writer continues to write. - * - * The first transition that causes an overflow has 2 consequences - * because of this continuous write action: - * 1. The ring buffer is flushed, all previous transitions history are lost. - * - * Flushing the ring buffer is acceptable since the reader is not - * able to keep up with rapid transitions, it is better off to start - * from the current transition than trying to catch up. - * - * 2. The new transition is recorded in the ring buffer. However, bcecause of - * the way the write pointer is updated, both the read and write pointers - * will be identical which makes the reader thinks there is no transition to - * read. - * - * Even though the reader does not see the most current signature/state in the - * ring buffer, it can be found in the signature block data structure. - * The reader can do a read in the signature block to obtain the current - * signature/block if the read/write pointers indicate the buffer is empty. - * The problem will go away once the writer starts writing again. - * - * Initial condition: - * rd_ptr = 0 - * wr_ptr = 0 - * - * To write a signature into the ring buffer, the steps are: - * 1. write signature into ringbuf[wr_ptr] - * 2. increment wr_ptr by 1 modulo SIGB_RB_SIZ using RB_IDX_MASK - * - * Note: the writer always writes to the ring buffer and the signature - * field in the signature block data structure. - * - * To read a signature from the ring buffer, the steps are: - * 1. compare rd_ptr and wr_ptr - * 2. if they are not equal then - * read signature ringbuf[rd_ptr] - * increment rd_ptr by 1 modulo SIGB_RB_SIZ using RB_IDX_MASK - * save a copy of the signature locally - * return the signature - * 3. else - * read signature from the signature block data structure - * if signature is not the same as the last signature then - * return the signature - * - */ - -#define SIGB_RB_SIZ 64 /* ring buffer size */ -#define RB_IDX_MASK 0x3f /* mask to determine read/write index */ - -typedef struct { -/* 0 */ uchar_t rd_ptr; /* entry to read */ -/* 1 */ uchar_t wr_ptr; /* next entry to write */ -/* 4 */ sig_state_t ringbuf[SIGB_RB_SIZ]; -} sigb_ringbuf_t; /* sizeof = 260 (0x104) = 65X */ - -typedef struct cpu_sgnblk { -/* 0 */ uint32_t sigb_magic; /* SIGBLOCK_MAGIC */ -/* 4 */ uint32_t sigb_version; /* changes with each SID */ -/* 8 */ uint32_t sigb_flags; /* struct sigblock status */ -/* c */ uint32_t sigb_heartbeat; /* prog's heartbeat */ - -/* 10 */ uint32_t sigb_leds; /* Software LED */ -/* 14 */ sig_state_t sigb_signature; /* Current signature & state */ - - /* - * sigb_ringbuf captures the last SIGB_RB_SIZ signature/state - * transitions. - */ -/* 18 */ sigb_ringbuf_t sigb_ringbuf; - - /* - * sigb_host_mbox is intended for msgs targeted for the Host and - * follows the protocol: - * SSP -> [cmd] -> Host -> [resp] -> SSP. - */ -/* 11c */ sigbmbox_t sigb_host_mbox; - -/* 168 */ char sigb_idn[sizeof (sigbmbox_t)]; - -/* 1b4 */ bboff_t sigb_obp_mbox; /* OBP/DHLP mailbox. */ - -/* 1b8 */ bboff_t sigb_postconfig; /* config info from POST */ - -/* 1bc */ uint32_t sigb_post; /* POST opaque */ - -/* 1c0 */ bboff_t sigb_slavep; /* Slave startup block offset */ - -/* 1c4 */ bboff_t sigb_resetinfo_off; /* Resetinfo offset */ - -/* 1c8 */ bboff_t sigb_cvc_off; /* CVC offset */ - -/* 1cc */ bboff_t sigb_eeprom_off; /* EEPROM offset */ - -/* 1d0 */ vaddr_t sigb_wdog_reset_vec; /* Watchdog Reset Vector */ - -/* 1d8 */ vaddr_t sigb_xir_reset_vec; /* XIR Reset vector */ - -/* 1e0 */ vaddr_t sigb_sir_reset_vec; /* SIR Reset Vector */ - -/* 1e8 */ vaddr_t sigb_red_state_reset_vec; /* RED State Reset Vector */ - -/* 1f0 */ uchar_t sigb_resv_array[SIGB_RESV]; /* reserved space */ -} cpu_sgnblk_t; /* sizeof = 512 (0x200) = 128X */ - -#endif /* _ASM */ - -/* - * Mailbox commands. - * - * The commands are listed here so that they are in a central place - * for all users of the signature block mailbox. Want to be careful - * that some subsystems don't accidently use the same value for a - * command. For this reason we introduce a cookie for each subsystem. - */ - -#define SIGB_HANDLER_BUSY (-2) -#define SIGB_BAD_MBOX_CMD (-1) -#define SSP_CMD ('S' << 8) /* generic SSP */ -#define SSP_CMD_SUCCESS (SSP_CMD | 0x1) -#define SSP_GOTO_OBP (SSP_CMD | 0x2) -#define SSP_GOTO_PANIC (SSP_CMD | 0x3) -#define SSP_ENVIRON (SSP_CMD | 0x4) /* environmental intr */ - -#ifdef _KERNEL - -#ifdef _STARFIRE - -extern void juggle_sgnblk_poll(struct cpu *); -extern int sgnblk_poll_register(void (*)(processorid_t, cpu_sgnblk_t *)); -extern int sgnblk_poll_unregister(void (*)(processorid_t, cpu_sgnblk_t *)); -extern int sgnblk_poll_reference(void (*)(cpu_sgnblk_t *, void *), void *); -extern void sgnblk_poll_unreference(void (*)(cpu_sgnblk_t *, void *)); - -extern cpu_sgnblk_t *cpu_sgnblkp[NCPU]; - -/* - * Starfire specific signatures - */ -#define POST_SIG SIG_BLD('P', 'O') -#define DHLP_SIG SIG_BLD('D', 'H') - -/* - * Starfire specific Sigblock states. - */ -#define SIGBST_NONE 0 /* no state */ -#define SIGBST_RUN 1 /* running */ -#define SIGBST_EXIT 2 /* finished */ -#define SIGBST_PRERUN 3 /* pre-exec */ -#define SIGBST_ARBSTOP 4 /* transient arbstop state */ -#define SIGBST_RESET 5 /* reset */ -#define SIGBST_POWEROFF 6 /* no power */ -#define SIGBST_DETACHED 7 /* spinning in OBP after DR DETACH */ -#define SIGBST_CALLBACK 8 /* kernel calling back into OBP */ -#define SIGBST_WATCHDOG 9 /* OBP running after watchdog */ -#define SIGBST_WATCHDOG_SYNC 10 /* OBP "sync" after watchdog reset */ -#define SIGBST_OFFLINE 11 /* cpu offline */ -#define SIGBST_BOOTING 12 /* booting */ -#define SIGBST_UNKNOWN 13 /* unknown */ -#define SIGBST_XIR 14 /* OBP running after XIR */ -#define SIGBST_XIR_SYNC 15 /* OBP trying "sync" in XIR */ -#define SIGBST_SIR 16 /* OBP running after SIR */ -#define SIGBST_SIR_SYNC 17 /* OBP trying "sync" in SIR */ -#define SIGBST_REDMODE 18 /* OBP running after REDMODE */ -#define SIGBST_REDMODE_SYNC 19 /* OBP trying "sync" in REDMODE */ -#define SIGBST_QUIESCED 20 /* system quiesced */ -#define SIGBST_QUIESCE_INPROGRESS 21 /* system quiesce in-progress */ -#define SIGBST_RESUME_INPROGRESS 22 /* system resume in-progress */ - -/* - * Starfire specific Sigblock sub-states - */ -#define EXIT_NULL 0 -#define EXIT_HALT 1 -#define EXIT_ENVIRON 2 -#define EXIT_REBOOT 3 -#define EXIT_PANIC1 4 -#define EXIT_PANIC2 5 -#define EXIT_HUNG 6 -#define EXIT_WATCH 7 -#define EXIT_PANIC_REBOOT 8 -#define EXIT_WATCHDOG_REBOOT 9 -#define EXIT_SOFT_INIT_RESET 10 /* SIR */ -#define EXIT_EXTERN_INIT_RESET 11 /* XIR */ -#define EXIT_REDMODE_REBOOT 12 /* REDMODE */ -#define EXIT_OBP_RESET 13 /* OBP RESET */ - -#else - -#define REGISTER_BBUS_INTR() -#define CPU_SGN_MAPIN(cpuid) -#define CPU_SGN_MAPOUT(cpuid) -#define CPU_SGN_EXISTS(cpuid) (0) -#define SGN_CPU_IS_OS(cpuid) (0) -#define SGN_CPU_IS_OBP(cpuid) (0) -#define SGN_CPU_STATE_IS_DETACHED(cpuid) (0) - -#endif /* _STARFIRE */ - -#endif /* _KERNEL */ - -#ifdef __cplusplus -} -#endif - -#endif /* _CPU_SGN_H */ diff --git a/usr/src/uts/sun4u/starfire/sys/cvc.h b/usr/src/uts/sun4u/starfire/sys/cvc.h deleted file mode 100644 index 4f36155022..0000000000 --- a/usr/src/uts/sun4u/starfire/sys/cvc.h +++ /dev/null @@ -1,116 +0,0 @@ -/* - * 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 - * or http://www.opensolaris.org/os/licensing. - * 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 2004 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -#ifndef _CVC_H -#define _CVC_H - -#pragma ident "%Z%%M% %I% %E% SMI" - -#ifdef __cplusplus -extern "C" { -#endif - -#define cvc_username "ssp" -#define CVCD_SERVICE "cvc_hostd" -#define CVC_CONN_SERVICE "cvc" -#define MAX_CVC_CONN 100 -#define MAXPKTSZ 4096 - -#define TRUE 1 -#define FALSE 0 - -/* - * Network Redirection driver ioctl to jump into debugger. - */ -#define CVC 'N' -#define CVC_BREAK (CVC<<8) -#define CVC_DISCONNECT ((CVC<<8)|0x1) - -#define CVC_CONN_BREAK 0x1 /* Break to OBP or kmdb */ -#define CVC_CONN_DIS 0x2 /* disconnect */ -#define CVC_CONN_STAT 0x4 /* status of CVC connects */ -#define CVC_CONN_WRITE 0x8 /* ask write permission */ -#define CVC_CONN_RELW 0x10 /* release write permission */ -#define CVC_CONN_WRLK 0x20 /* Lock the Write */ -#define CVC_CONN_PRIVATE 0x40 /* Only one session is allowed */ -#define CVC_CONN_SWITCH 0x41 /* Switch communication path */ - - -#define TCP_DEV "/dev/tcp" -#define CVCREDIR_DEV "/devices/pseudo/cvcredir@0:cvcredir" - -/* - * Layout of BBSRAM input and output buffers: - * - * - * |---------------| - * 0x1f400 | control msg | Receive buffer is reduced by two bytes to - * | 1 byte | accomodate a control msg area in which - * |---------------| information is sent from obp_helper to the - * | send buffer | cvc driver (e.g. break to obp) when - * | | communication is over BBSRAM. - * | 1020 bytes | - * |---------------| - * | send count | - * 0x1f7fe | 2 bytes | - * |---------------| - * | receive buffer| - * | | - * | 1022 bytes | - * |---------------| - * | output count | - * 0x1fbfe | 2 bytes | - * |---------------| - * - */ - -#define BBSRAM_COUNT_SIZE sizeof (short) -#define CVC_IN_SIZE 256 -#define CVC_OUT_SIZE 1024 -#define MAX_XFER_INPUT (CVC_IN_SIZE - BBSRAM_COUNT_SIZE) -#define MAX_XFER_OUTPUT (CVC_OUT_SIZE - BBSRAM_COUNT_SIZE) - -#define BBSRAM_OUTPUT_COUNT_OFF (CVC_OUT_SIZE - BBSRAM_COUNT_SIZE) -#define BBSRAM_INPUT_COUNT_OFF (CVC_OUT_SIZE + CVC_IN_SIZE - BBSRAM_COUNT_SIZE) - -/* - * Control msgs sent across BBSRAM from obp_helper to cvc driver - */ -#define CVC_BBSRAM_BREAK 1 -#define CVC_BBSRAM_DISCONNECT 2 -#define CVC_BBSRAM_VIA_NET 3 -#define CVC_BBSRAM_VIA_BBSRAM 4 -#define CVC_BBSRAM_CLOSE_NET 5 - -#ifdef _KERNEL -extern void cvc_assign_iocpu(int cpu_id); -#endif /* _KERNEL */ - -#ifdef __cplusplus -} -#endif - -#endif /* _CVC_H */ diff --git a/usr/src/uts/sun4u/starfire/sys/drmach.h b/usr/src/uts/sun4u/starfire/sys/drmach.h deleted file mode 100644 index 68b8fcc87e..0000000000 --- a/usr/src/uts/sun4u/starfire/sys/drmach.h +++ /dev/null @@ -1,160 +0,0 @@ -/* - * 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 - * or http://www.opensolaris.org/os/licensing. - * 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. - */ - -#ifndef _SYS_DRMACH_H_ -#define _SYS_DRMACH_H_ - -#pragma ident "%Z%%M% %I% %E% SMI" - -#include <sys/types.h> -#include <sys/memlist.h> -#include <sys/processor.h> -#include <sys/starfire.h> -#include <sys/sbd_ioctl.h> -#include <sys/sysevent.h> - -#ifdef __cplusplus -extern "C" { -#endif - -#define MAX_BOARDS plat_max_boards() -#define MAX_CPU_UNITS_PER_BOARD plat_max_cpu_units_per_board() -#define MAX_MEM_UNITS_PER_BOARD plat_max_mem_units_per_board() -#define MAX_IO_UNITS_PER_BOARD plat_max_io_units_per_board() -#define MAX_CMP_UNITS_PER_BOARD MAX_CPU_UNITS_PER_BOARD -#define MAX_CORES_PER_CMP 1 - -/* flags for drmach_configure() and drmach_unconfigure() */ -#define DRMACH_DEVI_FORCE 1 -#define DRMACH_DEVI_REMOVE 2 - -/* returned with drmach_board_find_devices callback */ -#define DRMACH_DEVTYPE_CPU "cpu" -#define DRMACH_DEVTYPE_MEM "memory" -#define DRMACH_DEVTYPE_PCI "pci" -#define DRMACH_DEVTYPE_SBUS "sbus" - -/* number of bytes in smallest coherency unit of this machine */ -#define DRMACH_COHERENCY_UNIT 64 - -typedef void *drmachid_t; - -typedef struct { - boolean_t assigned; - boolean_t powered; - boolean_t configured; - boolean_t busy; - boolean_t empty; - sbd_cond_t cond; - char type[MAXNAMELEN]; - char info[MAXPATHLEN]; /* TODO: what size? */ -} drmach_status_t; - -typedef struct { - int size; - char *copts; -} drmach_opts_t; - -extern sbd_error_t *drmach_copy_rename_init( - drmachid_t dst_id, uint64_t dst_slice_offset, - drmachid_t src_id, struct memlist *src_copy_ml, - drmachid_t *pgm_id); -extern sbd_error_t *drmach_copy_rename_fini(drmachid_t id); -extern void drmach_copy_rename(drmachid_t id); - -extern sbd_error_t *drmach_pre_op(int cmd, drmachid_t id, - drmach_opts_t *opts); -extern sbd_error_t *drmach_post_op(int cmd, drmachid_t id, - drmach_opts_t *opts); - -extern sbd_error_t *drmach_board_assign(int bnum, drmachid_t *id); -extern sbd_error_t *drmach_board_connect(drmachid_t id, - drmach_opts_t *opts); -extern sbd_error_t *drmach_board_deprobe(drmachid_t id); -extern sbd_error_t *drmach_board_disconnect(drmachid_t id, - drmach_opts_t *opts); -extern sbd_error_t *drmach_board_find_devices(drmachid_t id, void *a, - sbd_error_t *(*found)(void *a, const char *, int, drmachid_t)); -extern int drmach_board_lookup(int bnum, drmachid_t *id); -extern sbd_error_t *drmach_passthru(drmachid_t id, - drmach_opts_t *opts); - -extern sbd_error_t *drmach_board_name(int bnum, char *buf, int buflen); - -extern sbd_error_t *drmach_board_poweroff(drmachid_t id); -extern sbd_error_t *drmach_board_poweron(drmachid_t id); -extern sbd_error_t *drmach_board_test(drmachid_t id, drmach_opts_t *opts, - int force); - -extern sbd_error_t *drmach_board_unassign(drmachid_t id); - -extern sbd_error_t *drmach_configure(drmachid_t id, int flags); - -extern sbd_error_t *drmach_cpu_disconnect(drmachid_t id); -extern sbd_error_t *drmach_cpu_get_id(drmachid_t id, processorid_t *cpuid); -extern sbd_error_t *drmach_cpu_get_impl(drmachid_t id, int *ip); -extern void drmach_cpu_flush_ecache_sync(void); - -extern sbd_error_t *drmach_get_dip(drmachid_t id, dev_info_t **dip); - -extern sbd_error_t *drmach_io_is_attached(drmachid_t id, int *yes); -extern sbd_error_t *drmach_io_post_attach(drmachid_t id); -extern sbd_error_t *drmach_io_post_release(drmachid_t id); -extern sbd_error_t *drmach_io_pre_release(drmachid_t id); -extern sbd_error_t *drmach_io_unrelease(drmachid_t id); - -extern sbd_error_t *drmach_mem_add_span(drmachid_t id, - uint64_t basepa, uint64_t size); -extern sbd_error_t *drmach_mem_del_span(drmachid_t id, - uint64_t basepa, uint64_t size); -extern sbd_error_t *drmach_mem_disable(drmachid_t id); -extern sbd_error_t *drmach_mem_enable(drmachid_t id); -extern sbd_error_t *drmach_mem_get_alignment(drmachid_t id, uint64_t *pa); -extern sbd_error_t *drmach_mem_get_base_physaddr(drmachid_t id, - uint64_t *pa); -extern sbd_error_t *drmach_mem_get_memlist(drmachid_t id, - struct memlist **ml); -extern sbd_error_t *drmach_mem_get_size(drmachid_t id, uint64_t *bytes); -extern sbd_error_t *drmach_mem_get_slice_size(drmachid_t id, - uint64_t *bytes); -extern processorid_t drmach_mem_cpu_affinity(drmachid_t id); -extern int drmach_allow_memrange_modify(drmachid_t id); - -extern sbd_error_t *drmach_release(drmachid_t id); -extern sbd_error_t *drmach_status(drmachid_t id, drmach_status_t *stat); -extern sbd_error_t *drmach_unconfigure(drmachid_t id, int flags); -extern int drmach_log_sysevent(int board, char *hint, int flag, - int verbose); - -extern int drmach_verify_sr(dev_info_t *dip, int sflag); -extern void drmach_suspend_last(); -extern void drmach_resume_first(); - -#ifdef __cplusplus -} -#endif - -#endif /* _SYS_DRMACH_H_ */ diff --git a/usr/src/uts/sun4u/starfire/sys/idn.h b/usr/src/uts/sun4u/starfire/sys/idn.h deleted file mode 100644 index a8ee2ce9b8..0000000000 --- a/usr/src/uts/sun4u/starfire/sys/idn.h +++ /dev/null @@ -1,3886 +0,0 @@ -/* - * 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 - * or http://www.opensolaris.org/os/licensing. - * 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. - * Copyright (c) 2016 by Delphix. All rights reserved. - * - * Inter-Domain Network - */ - -#ifndef _SYS_IDN_H -#define _SYS_IDN_H - -#ifndef _ASM - -#ifdef _KERNEL - -#include <sys/note.h> - -#include <sys/cmn_err.h> -#include <sys/dditypes.h> -#include <sys/stream.h> -#include <sys/machsystm.h> -#include <sys/ethernet.h> -#include <sys/dlpi.h> -#include <sys/time.h> -#include <sys/kmem.h> -#include <sys/atomic.h> -#include <sys/cpuvar.h> - -#include <sys/idn_sigb.h> -#include <sys/idn_smr.h> -#endif /* _KERNEL */ - -#ifdef __cplusplus -extern "C" { -#endif - -typedef const char * const procname_t; - -#define MB2B(m) ((size_t)(m) << 20) /* MBytes to Bytes */ -#define B2MB(b) ((uint_t)((b) >> 20)) /* Bytes to MBytes */ - -#ifdef _KERNEL - -/* - * IDN_PROP_SMRSIZE - User specified size in MBytes. - * IDN_PROP_SMRADDR - OBP's internal physical address of the region. - * - * OBP properties of "memory" node that define the SMR space. - */ -#define IDN_PROP_SMRSIZE "idn-smr-size" -#define IDN_PROP_SMRADDR "idn-smr-addr" - -/* - * IDN_AWOLMSG_INTERVAL (driver.conf) - * - * Number of seconds between AWOL messages on a per-domain basis. - * The purpose is to throttle the frequency at which these - * messages appear. - * - * IDN_MSGWAIT_NEGO (driver.conf) - * IDN_MSGWAIT_CFG - * IDN_MSGWAIT_CON - * IDN_MSGWAIT_FIN - * IDN_MSGWAIT_CMD - * IDN_MSGWAIT_DATA - * - * Number of seconds to wait for response to respective - * message type. - * - * IDN_RETRYFREQ_NEGO (driver.conf) - * IDN_RETRYFREQ_CON - * IDN_RETRYFREQ_FIN - * - * Number of seconds to wait between retries of the respective - * message type. - * - * IDN_SMR_ALIGN (not tunable) - * - * The hardware registers that describe the SMR are based on a 64K - * aligned physical address. - * - * IDN_SMR_SIZE (OBP [only]) - * - * Total size of the SMR (Shared Memory Region) in bytes. - * - * IDN_NWR_SIZE (driver.conf) - * - * Total size of the NWR (NetWork Region) portion of the SMR which - * is actually used to support network activity. The NWR is managed - * as simply a pool of I/O buffers which are distributed by the - * Master domain to the Slaves for the purpose of communicating - * between each other. If not set then the entire SMR is used - * as the NWR. - * Req: IDN_NWR_SIZE <= IDN_SMR_SIZE - * - * IDN_SMR_BUFSIZE (driver.conf) - * - * Size of individual SMR buffers. The SMR is divided into chunks - * of IDN_SMR_BUFSIZE bytes. The IDN_MTU is based on this size - * and thus the IDN_SMR_BUFSIZE should be chosen based on performance. - * - * IDN_DATA_SIZE (NOT tunable) - * - * Portion of IDN_SMR_BUFSIZE that can contain raw non-IDN dependent - * data. We subtract IDN_ALIGNSIZE bytes to allow for fast bcopy - * alignment. - * Req: IDN_DATA_SIZE <= - * (IDN_SMR_BUFSIZE - sizeof (smr_pkthdr_t) - IDN_ALIGNSIZE) - * - * IDN_MTU (indirectly tunable via IDN_SMR_BUFSIZE) - * - * This size represents the portion of an SMR I/O buffers that can - * contain (ethernet headerless) data. - * Req: IDN_MTU <= IDN_DATA_SIZE - sizeof (ether_header) - * - * IDN_WINDOW_MAX (driver.conf) - * - * Maximum number of outstanding packets that are allowed per - * domain. If this value is exceeded for a particular domain - * no further I/Os will be transmitted to that domain until it - * has acknowledged enough of the previous transmission to bring - * down its outstanding I/O count (idn_domain.dio) below this - * value. In addition, if this value is exceeded then a Timer - * is scheduled to check for any response from the remote domain. - * - * IDN_WINDOW_INCR (driver.conf) - * - * As more channels/nets are activated on a particular domain - * the greater the number of possible outstanding data packets - * that can be outstanding to a given domain. Since this natural - * occurence can result in the outstanding-I/O count to a given - * domain to increase we run the risk of dropping into the - * IDN_WINDOW_MAX region even though the receiving domain - * may be fine with handling the load. In order to compensate - * for this increased activity and to not incur unjustified - * slips into the IDN_WINDOW_MAX region, the IDN_WINDOW_MAX - * value is adjusted by IDN_WINDOW_INCR for each channel/net - * that is activated for a given domain. - * - * IDN_WINDOW_EMAX (not tunable) - * - * The effective value of IDN_WINDOW_MAX once it has - * been adjusted by IDN_WINDOW_INCR. - * - * IDN_RECLAIM_MIN (driver.conf) - * - * Minimum number of outstanding packets that our allowed - * before subsequent sends will attempt to reclaim some number - * of outstanding data packets. - * - * IDN_RECLAIM_MAX (driver.conf) - * This value represents the maximum number of outstanding - * packets we will try to reclaim during a send once we've - * passed the IDN_RECLAIM_MIN boundary. - * - * IDN_MODUNLOADABLE (ndd) - * - * By default the IDN driver is unloadable. Setting this - * variable will allow the IDN driver to be unloaded provided - * it's not in use. - * - * IDN_LOWAT/IDN_HIWAT (driver.conf) - * - * Low/High water marks for the STREAM interface to IDN. - * - * IDN_MBOX_PER_NET (driver.conf) - * - * Number of mailbox entries that are allocated per channel/net. - * This value effectively represents the amount of outstanding - * activity that can reside at a domain. Increasing this value - * allows more packets to be in transit to a domain, however - * at some point there are diminishing returns since the receiver - * can only consume packets so fast. - * - * IDN_MAX_NETS (driver.conf) - * - * Maximum number of network interfaces (channels) that IDN - * is currently configured to allow. The absolute max is - * IDN_MAXMAX_NETS. We don't automatically default IDN_MAX_NETS - * to IDN_MAXMAX_NETS because it would mean wasted space in - * the mailbox region having to reserve mailboxes that will - * very likely go unused. The smaller this value the fewer - * the number of mailboxes in the SMR and thus the greater the - * number of possible I/O buffers available. - * Req: IDN_MAX_NETS <= IDN_MAXMAX_NETS - * - * IDN_CHECKSUM (driver.conf) - * - * If enabled, IDN validates the smr_pkthdr_t of incoming packets - * via a checksum, and calculates the checksum for outgoing packets. - * Only the first 3 fields of smr_pkthdr_t are checksummed and - * must be set to their expected values prior to calculating the - * checksum. Turned OFF by default when compiled DEBUG. - * - * IDN_SMR_MAXSIZE (not tunable) - * - * The absolute maximum size of the SMR region that we'll allow. - * Note that the virtual address space comes out kernelmap. - */ -#define IDN_AWOLMSG_INTERVAL 60 /* seconds */ -#define IDN_MSGWAIT_NEGO 20 /* seconds */ -#define IDN_MSGWAIT_CFG 40 -#define IDN_MSGWAIT_CON 20 -#define IDN_MSGWAIT_FIN 40 -#define IDN_MSGWAIT_CMD 40 -#define IDN_MSGWAIT_DATA 30 -#define IDN_RETRYFREQ_NEGO 2 -#define IDN_RETRYFREQ_CON 2 -#define IDN_RETRYFREQ_FIN 3 - -#define IDN_SMR_BUFSIZE_MIN 512 -#define IDN_SMR_BUFSIZE_MAX (512*1024) -#define IDN_SMR_BUFSIZE_DEF (16*1024) - -#define IDN_SMR_SHIFT (16) -#define IDN_SMR_ALIGN (1 << IDN_SMR_SHIFT) /* 64K */ -#define IDN_SMR_SIZE idn_smr_size -#define IDN_NWR_SIZE idn_nwr_size -#define IDN_SMR_BUFSIZE idn_smr_bufsize -#define IDN_DATA_SIZE (IDN_SMR_BUFSIZE \ - - sizeof (smr_pkthdr_t) \ - - IDN_ALIGNSIZE) -#define IDN_MTU (IDN_DATA_SIZE - sizeof (struct ether_header)) -#define IDN_WINDOW_MAX idn_window_max -#define IDN_WINDOW_INCR idn_window_incr -#define IDN_WINDOW_EMAX idn_window_emax -#define IDN_RECLAIM_MIN idn_reclaim_min -#define IDN_RECLAIM_MAX idn_reclaim_max -#define IDN_MODUNLOADABLE idn_modunloadable -#define IDN_LOWAT idn_lowat -#define IDN_HIWAT idn_hiwat -#define IDN_MBOX_PER_NET idn_mbox_per_net -#define IDN_MAX_NETS idn_max_nets -#define IDN_CHECKSUM idn_checksum -#define IDN_SMR_MAXSIZE 96 -#define _IDN_SMR_SIZE 32 /* 32M */ -#define _IDN_NWR_SIZE _IDN_SMR_SIZE /* 32M */ -#define _IDN_SMR_BUFSIZE (16 * 1024) /* 16K */ - - -#define IDN_TUNEVAR_NAME(v) (*(char **)((ulong_t)&(v)+(sizeof (ulong_t)))) -#define IDN_TUNEVAR_VALUE(v) (v) - -/* - * History structure to support problem analysis. - */ -#define IDN_HISTORY_NUM 1024 -#define IDN_HISTORY_LOG(op, d0, d1, d2) \ - if (idn_history) { \ - mutex_enter(&idnhlog.h_mutex); \ - idnhlog.h_log[idnhlog.h_index].e_time = TIMESTAMP(); \ - idnhlog.h_log[idnhlog.h_index].e_op = (ushort_t)(op); \ - idnhlog.h_log[idnhlog.h_index].e_data[0] = (ushort_t)(d0); \ - idnhlog.h_log[idnhlog.h_index].e_data[1] = (ushort_t)(d1); \ - idnhlog.h_log[idnhlog.h_index].e_data[2] = (ushort_t)(d2); \ - idnhlog.h_index++; \ - idnhlog.h_index &= (IDN_HISTORY_NUM - 1); \ - mutex_exit(&idnhlog.h_mutex); \ - } - -#define IDNH_GSTATE 0x0001 /* d0=gstate, d1=, d2= */ -#define IDNH_DSTATE 0x0002 /* d0=domid, d1=dstate, d2=cpuid */ -#define IDNH_AWOL 0x0003 /* d0=domid, d1=dstate, d2=cpuid */ -#define IDNH_MASTERID 0x0004 /* d0=masterid, d1=oldid, d2= */ -#define IDNH_NEGO 0x0005 /* d0=domid, d1=ds_trans_on, d2=ds_connected */ -#define IDNH_FIN 0x0006 /* d0=domid, d1=finstate, d2= */ -#define IDNH_RELINK 0x0007 /* d0=domid, d1=dstate, d2=ds_relink */ - -struct idn_h_entry { - hrtime_t e_time; - ushort_t e_op; - ushort_t e_data[3]; -}; - -struct idn_history { - kmutex_t h_mutex; - int h_index; - struct idn_h_entry h_log[IDN_HISTORY_NUM]; -}; -#endif /* _KERNEL */ - -/* - * IDN_SIGBPIL - Interrupt level at which IDN driver - * wakes up idn_sigbhandler_thread - */ -#define IDN_SIGBPIL PIL_3 - -/* - * Definition of sigbintr.sb_busy values which - * represents state of idn_sigbhandler. - */ -#define IDNSIGB_NOTREADY ((uchar_t)0) -#define IDNSIGB_INACTIVE ((uchar_t)1) -#define IDNSIGB_STARTED ((uchar_t)2) -#define IDNSIGB_ACTIVE ((uchar_t)3) -#define IDNSIGB_DIE ((uchar_t)4) - -/* - * Some Xfire based macros that assume 4 cpus per board. - */ -#define CPUID_TO_BOARDID(c) ((c) >> 2) -#define MAX_CPU_PER_BRD 4 -#define CPUSET_TO_BOARDSET(cset, bset) \ - { \ - register int c, b; \ - (bset) = 0; \ - for (b = 0; b < MAX_BOARDS; b++) \ - for (c = 0; c < MAX_CPU_PER_BRD; c++) \ - if (CPU_IN_SET((cset), \ - (b * MAX_CPU_PER_BRD) + c)) \ - (bset) |= 1 << b; \ - } - -/* - * Macros to manipulate boardset and domainset masks. - */ -typedef ushort_t boardset_t; /* assumes max of 16 boards */ -typedef ushort_t domainset_t; /* assumes max of 16 domains */ - -#define BOARDSET(brd) ((boardset_t)(1 << (brd))) -#define BOARDSET_ALL ((boardset_t)~0) -#define BOARD_IN_SET(set, brd) ((set) & BOARDSET(brd)) -#define BOARDSET_ADD(set, brd) ((set) |= BOARDSET(brd)) -#define BOARDSET_DEL(set, brd) ((set) &= ~BOARDSET(brd)) -#define DOMAINSET(d) ((domainset_t)1 << (d)) -#define DOMAINSET_ALL ((domainset_t)~0) -#define DOMAIN_IN_SET(s, d) ((s) & DOMAINSET(d)) -#define DOMAINSET_ADD(s, d) ((s) |= DOMAINSET(d)) -#define DOMAINSET_DEL(s, d) ((s) &= ~DOMAINSET(d)) - -/* - * PFN_TO_SMADDR macro converts a PFN to a IDN_SMR_ALIGN'ed - * address suitable for the CIC bar/lar registers. - */ -#if (IDN_SMR_SHIFT <= MMU_PAGESHIFT) -#define PFN_TO_SMADDR(pfn) ((pfn) << (MMU_PAGESHIFT - IDN_SMR_SHIFT)) -#else -#define PFN_TO_SMADDR(pfn) ((pfn) >> (IDN_SMR_SHIFT - MMU_PAGESHIFT)) -#endif - -/* - * Translate a physical address to a unique domain identifier. - * IMPORTANT - Assumes each board's memory is configured on a 8GB - * boundary. PA(8G) = PFN(1M). - */ -#define MEM8G_SHIFT 33 /* (1 << 33) == 8G */ -#define PADDR_TO_DOMAINID(paddr) ((int)((paddr) >> MEM8G_SHIFT) & 0xf) - -#define VALID_NWROFFSET(off, align) \ - (((uint_t)(off) >= 0) && \ - ((size_t)(off) < MB2B(IDN_NWR_SIZE)) && \ - !((uint_t)(off) & ((align) - 1))) -#define VALID_NWRADDR(addr, align) \ - (((caddr_t)(addr) >= idn.smr.vaddr) && \ - VALID_NWROFFSET(((caddr_t)(addr) - idn.smr.vaddr), (align))) -#define VALID_DOMAINID(d) (((d) >= 0) && ((d) < MAX_DOMAINS)) -#define VALID_UDOMAINID(d) ((d) < MAX_DOMAINS) -#define VALID_CPUID(c) (((c) >= 0) && ((c) < NCPU)) -#define VALID_CHANNEL(c) (((c) >= 0) && ((c) < IDN_MAX_NETS)) -#define VALID_UCHANNEL(c) ((c) < IDN_MAX_NETS) - -/* - * The following are bit values of idn_debug, currently - * only useful if compiled with DEBUG. - */ -#ifdef DEBUG -#define STRING(sss) char sss[20] -#define INUM2STR(mm, ss) inum2str((mm), (ss)) - -#define IDNDBG_XDC 0x00000001 -#define IDNDBG_XF 0x00000002 -#define IDNDBG_REGS 0x00000004 -#define IDNDBG_SMR 0x00000008 -#define IDNDBG_PROTO 0x00000010 -#define IDNDBG_STR 0x00000020 -#define IDNDBG_DRV 0x00000040 -#define IDNDBG_DATA 0x00000080 -#define IDNDBG_STATE 0x00000100 -#define IDNDBG_DLPI 0x00000200 -#define IDNDBG_KERN 0x00000400 -#define IDNDBG_ALLOC 0x00000800 -#define IDNDBG_REMAP 0x00001000 -#define IDNDBG_TIMER 0x00002000 -#define IDNDBG_CHAN 0x00004000 -#define IDNDBG_AWOL 0x00008000 -#define IDNDBG_SYNC 0x00010000 -#define _IDNDBG_UNUSED0 0x00020000 -#define IDNDBG_HITLIST 0x00040000 -#define IDNDBG_XMON 0x00080000 -#define IDNDBG_TEST 0x80000000 -#define IDNDBG_ALL ((uint_t)-1) - -#define PR_ALL if (idn_debug) printf -#define PR_XDC if (idn_debug & IDNDBG_XDC) printf -#define PR_XF if (idn_debug & IDNDBG_XF) printf -#define PR_REGS if (idn_debug & IDNDBG_REGS) printf -#define PR_SMR if (idn_debug & IDNDBG_SMR) printf -#define PR_PROTO if (idn_debug & IDNDBG_PROTO) printf -#define PR_STR if (idn_debug & IDNDBG_STR) printf -#define PR_DRV if (idn_debug & IDNDBG_DRV) printf -#define PR_DATA if (idn_debug & IDNDBG_DATA) printf -#define PR_STATE if (idn_debug & IDNDBG_STATE) printf -#define PR_DLPI if (idn_debug & IDNDBG_DLPI) printf -#define PR_KERN if (idn_debug & IDNDBG_KERN) printf -#define PR_ALLOC if (idn_debug & IDNDBG_ALLOC) printf -#define PR_REMAP if (idn_debug & (IDNDBG_SMR|IDNDBG_REMAP)) printf -#define PR_TIMER if (idn_debug & IDNDBG_TIMER) printf -#define PR_CHAN if (idn_debug & IDNDBG_CHAN) printf -#define PR_AWOL if (idn_debug & (IDNDBG_PROTO|IDNDBG_AWOL)) printf -#define PR_SYNC if (idn_debug & IDNDBG_SYNC) printf -#define _PR_UNUSED0 if (idn_debug & _IDNDBG_UNUSED0) printf -#define PR_HITLIST if (idn_debug & IDNDBG_HITLIST) printf -#define PR_XMON if (idn_debug & IDNDBG_XMON) printf -#define PR_TEST if (idn_debug & IDNDBG_TEST) printf -#else -#define STRING(sss) char *sss = "" -#define INUM2STR(mm, ss) - -#define PR_ALL if (0) printf -#define PR_XDC PR_ALL -#define PR_XF PR_ALL -#define PR_REGS PR_ALL -#define PR_SMR PR_ALL -#define PR_PROTO PR_ALL -#define PR_STR PR_ALL -#define PR_DRV PR_ALL -#define PR_DATA PR_ALL -#define PR_STATE PR_ALL -#define PR_DLPI PR_ALL -#define PR_KERN PR_ALL -#define PR_ALLOC PR_ALL -#define PR_REMAP PR_ALL -#define PR_TIMER PR_ALL -#define PR_CHAN PR_ALL -#define PR_AWOL PR_ALL -#define PR_SYNC PR_ALL -#define PR_SNOOP PR_ALL -#define PR_HITLIST PR_ALL -#define PR_XMON PR_ALL -#define PR_TEST PR_ALL -#endif /* DEBUG */ - -#ifdef _KERNEL -/* - * IDN drivers fields. - * - * IDNMINPSZ Minimum packet size the IDN supports. - * - * IDNMAXPSZ Maximum packet size that IDN supports from upper - * layers. Is equal to IDN_MTU + ether_header. Note - * that the IDN driver could support larger packets - * however the infrastructure to support fragmentation - * does not (and should not) exist with respect to - * ethernet packet types. - */ -#ifdef DEBUG -#define IDNDESC "Inter-Domain Network (DEBUG)" -#else -#define IDNDESC "Inter-Domain Network" -#endif /* DEBUG */ - -#define IDNIDNUM 8264 -#define IDNNAME "idn" -#define IDNMINPSZ 0 /* set at idnopen() */ -#define IDNMAXPSZ 0 /* set at idnopen() */ - -#endif /* _KERNEL */ - -/* - * IDN Global States. - */ -typedef enum { -/* 0 */ IDNGS_OFFLINE = 0, /* idle */ -/* 1 */ IDNGS_CONNECT, /* connecting initial domain */ -/* 2 */ IDNGS_ONLINE, /* master selected */ -/* 3 */ IDNGS_DISCONNECT, /* local is unlinking */ -/* 4 */ IDNGS_RECONFIG, /* selecting new master */ -/* 5 */ _IDNGS_UNUNSED5, -/* 6 */ _IDNGS_UNUNSED6, -/* 7 */ _IDNGS_UNUNSED7, -/* 8 */ _IDNGS_UNUNSED8, -/* 9 */ _IDNGS_UNUNSED9, -/* 10 */ IDNGS_IGNORE /* ignore requests (fault injection) */ -} idn_gstate_t; - -#ifdef _KERNEL - -#define TIMESTAMP() (gethrtime() / 1000000ull) - -/* - * Spaced defined in: - * sigblkp[cpu0.cpu_id]->sigb_idn.reserved1. - */ -#define IDNSB_GSTATE_NEW 0 -#define IDNSB_GSTATE_OLD 1 -#define IDNSB_MASTERCPU 2 -#define IDNSB_RESERVED 3 - -#define IDNSB_HWCHKPT_MAX 4 - -#define IDNSB_SIZE 72 -/* - * This structure gets overlay onto: - * sigblkp[cpu0.cpu_id]->sigb_idn.reserved1. - * - * This structure must be exactly IDNSB_SIZE bytes. - */ -typedef struct idnsb { - uchar_t id_gstate; - uchar_t id_pgstate; - uchar_t id_master_board; - uchar_t id_pmaster_board; - - uchar_t reserved_DO_NOT_USE[24]; /* idnevent_t field */ - - struct { - uchar_t d_board; - uchar_t d_state; - } id_status[MAX_DOMAINS]; - uint_t id_hwstate; - ushort_t id_hwchkpt[IDNSB_HWCHKPT_MAX]; -} idnsb_t; /* sizeof = 72 (0x48) 18X bytes */ - - -#define IDNSB_DOMAIN_UPDATE(dp) \ - { \ - mutex_enter(&idn.idnsb_mutex); \ - if (idn.idnsb) { \ - int domid = (dp)->domid; \ - if ((dp)->dcpu == IDN_NIL_DCPU) \ - idn.idnsb->id_status[domid].d_board = \ - (uchar_t)0xff; \ - else if ((dp)->dvote.v.board == 0) \ - idn.idnsb->id_status[domid].d_board = \ - (uchar_t)CPUID_TO_BOARDID((dp)->dcpu); \ - else \ - idn.idnsb->id_status[domid].d_board = \ - (uchar_t)(dp)->dvote.v.board; \ - idn.idnsb->id_status[domid].d_state = \ - (uchar_t)(dp)->dstate; \ - } \ - mutex_exit(&idn.idnsb_mutex); \ - } -/* - * The following definitions and macros pertain to the - * id_hwstate and id_hwchkpt[] fields. - * - * id_hwstate (m = mark: 1=open, 2=close) - * 0 1 2 3 4 5 6 7 - * --------------------------------- - * | m | m | m | m | XX unused XXX | - * --------------------------------- - * | | | | - * | | | +- CACHE - * | | +- CHAN - * | +- LINK - * +- SMR - * - * Note that nibble 4 is used in DEBUG for noting cache - * flush progress through idnxf_flushall_ecache(). This - * will override id_hwchkpt[] since it only has room for - * 4 items, however the BBSRAM space is there and - * unofficially available :-o - * - * id_hwchkpt[0] = SMR boardset - * id_hwchkpt[1] = LINK boardset - * id_hwchkpt[2] = CHAN boardset - * id_hwchkpt[3] = CACHE boardset. - */ -#define IDNSB_CHKPT_SMR 0 -#define IDNSB_CHKPT_LINK 1 -#define IDNSB_CHKPT_CHAN 2 -#define IDNSB_CHKPT_CACHE 3 -#define IDNSB_CHKPT_UNUSED 4 /* This is the max you can have */ - -#define _CHKPT_MARKIT(item, mark) \ - { \ - uint_t mk = (((uint_t)((mark) & 0xf)) << \ - (((sizeof (uint_t) << 1) - 1 - (item)) << 2)); \ - uint_t *sp = &idn.idnsb->id_hwstate; \ - ASSERT(idn.idnsb); \ - *sp &= ~(((uint_t)0xf) << (((sizeof (uint_t) << 1) \ - - 1 - (item)) << 2)); \ - *sp |= mk; \ - } - -#define CHECKPOINT_OPENED(item, bset, mark) \ - { \ - mutex_enter(&idn.idnsb_mutex); \ - if (idn.idnsb) { \ - ushort_t *sp = &idn.idnsb->id_hwchkpt[0]; \ - _CHKPT_MARKIT((item), (mark)); \ - sp[item] |= ((ushort_t)(bset)); \ - } \ - mutex_exit(&idn.idnsb_mutex); \ - } - -#define CHECKPOINT_CLOSED(item, bset, mark) \ - { \ - mutex_enter(&idn.idnsb_mutex); \ - if (idn.idnsb) { \ - ushort_t *sp = &idn.idnsb->id_hwchkpt[0]; \ - _CHKPT_MARKIT((item), (mark)); \ - sp[item] &= (ushort_t)~(bset); \ - } \ - mutex_exit(&idn.idnsb_mutex); \ - } - -#define CHECKPOINT_CLEAR(item, mark) \ - { \ - mutex_enter(&idn.idnsb_mutex); \ - if (idn.idnsb) { \ - ushort_t *sp = &idn.idnsb->id_hwchkpt[0]; \ - _CHKPT_MARKIT((item), (mark)); \ - sp[item] = 0; \ - } \ - mutex_exit(&idn.idnsb_mutex); \ - } -#ifdef DEBUG -#define CHECKPOINT_CACHE_CLEAR_DEBUG(mark) \ - CHECKPOINT_CLEAR(IDNSB_CHKPT_UNUSED, (mark)) -#define CHECKPOINT_CACHE_STEP_DEBUG(bset, mark) \ - CHECKPOINT_OPENED(IDNSB_CHKPT_UNUSED, (bset), (mark)) -#else -#define CHECKPOINT_CACHE_CLEAR_DEBUG(mark) -#define CHECKPOINT_CACHE_STEP_DEBUG(bset, mark) -#endif /* DEBUG */ - - -#ifdef DEBUG -#define IDN_GSTATE_TRANSITION(ns) \ - { \ - hrtime_t tstamp; \ - /*LINTED*/ \ - IDN_HISTORY_LOG(IDNH_GSTATE, (ns), 0, 0); \ - tstamp = TIMESTAMP(); \ - ASSERT(IDN_GLOCK_IS_EXCL()); \ - PR_STATE("GSTATE:%ld: (l=%d) %s(%d) -> %s(%d)\n", \ - (uint64_t)tstamp, __LINE__, \ - idngs_str[idn.state], idn.state, \ - idngs_str[ns], (ns)); \ - mutex_enter(&idn.idnsb_mutex); \ - if (idn.idnsb) { \ - idn.idnsb->id_pgstate = (uchar_t)idn.state; \ - idn.idnsb->id_gstate = (uchar_t)(ns); \ - } \ - mutex_exit(&idn.idnsb_mutex); \ - idn.state = (ns); \ - } -#else -#define IDN_GSTATE_TRANSITION(ns) \ - { \ - IDN_HISTORY_LOG(IDNH_GSTATE, (ns), 0, 0); \ - mutex_enter(&idn.idnsb_mutex); \ - if (idn.idnsb) { \ - idn.idnsb->id_pgstate = (uchar_t)idn.state; \ - idn.idnsb->id_gstate = (uchar_t)(ns); \ - } \ - mutex_exit(&idn.idnsb_mutex); \ - idn.state = (ns); \ - } -#endif /* DEBUG */ - -/* - * IDN link/unlink operations occur asynchronously with respect to the - * caller. The following definitions are to support the return of - * success/failure back to the original requesting thread. It's - * unlikely to have multiple outstanding link/unlink requests so we - * just provide a very small cache of waiting list entries. If the - * cache becomes exhausted then additional ones are kmem_alloc'd. - */ -#define IDNOP_CACHE_SIZE 3 -#define IDNOP_IN_CACHE(dwl) \ - (((dwl) >= &idn.dopers->_dop_wcache[0]) && \ - ((dwl) < &idn.dopers->_dop_wcache[IDNOP_CACHE_SIZE])) - -typedef struct dop_waitlist { - struct dop_waitlist *dw_next; - domainset_t dw_reqset; - domainset_t dw_domset; - short dw_op; - domainset_t dw_errset; - idnsb_error_t *dw_idnerr; - short dw_errors[MAX_DOMAINS]; -} dop_waitlist_t; - -typedef uint_t idn_xdcargs_t[4]; -typedef uint_t idn_chanset_t; - -/* - * Types of synchronization zones which a connection - * could be in. - */ -typedef enum { - IDNSYNC_NIL, - IDNSYNC_CONNECT, - IDNSYNC_DISCONNECT -} idn_synccmd_t; - -/* - * Type of sync-registration that is being requested. - */ -typedef enum { - IDNSYNC_REG_REG, - IDNSYNC_REG_NEW, - IDNSYNC_REG_QUERY -} idn_syncreg_t; - -#define IDN_SYNC_NUMZONE 3 -#define IDN_SYNC_GETZONE(s) ((((s) != IDNSYNC_CONNECT) && \ - ((s) != IDNSYNC_DISCONNECT)) ? \ - -1 : (int)(s) - 1) -#define IDN_SYNC_GETTRANS(s) (((s) == IDNSYNC_CONNECT) ? \ - idn.domset.ds_trans_on : \ - ((s) == IDNSYNC_DISCONNECT) ? \ - idn.domset.ds_trans_off : 0) - -/* - * Generic states when in a state transition region. - * These ultimately map to domain states via - * a idn_xphase_t definition. General model: - * - * PEND - * /\ - * / \ - * | | - * V V - * SENT--->RCVD - * \ / - * \ / - * VV - * FINAL - * - * Start these types with PEND = 0 so that they're - * compatible with idnxs_state_table[] and idn_xphase_t - * phases that use the value as an index. - */ -typedef enum { -/* 0 */ IDNXS_PEND = 0, -/* 1 */ IDNXS_SENT, -/* 2 */ IDNXS_RCVD, -/* 3 */ IDNXS_FINAL, -/* 4 */ IDNXS_NIL -} idn_xstate_t; - -/* - * Locking protocol: - * - * Each routine is called with SYNC_LOCK and - * the respective domain's DLOCK(EXCL) held. - * The routines must return with these locks - * still held. - */ -struct idn_msgtype; - -typedef struct { - int t_state; - int (*t_check)(int domid, struct idn_msgtype *mtp, - idn_xdcargs_t xargs); - void (*t_action)(int domid, struct idn_msgtype *mtp, - idn_xdcargs_t xargs); - void (*t_error)(int domid, struct idn_msgtype *mtp, - idn_xdcargs_t xargs); -} idn_trans_t; - -/* - * The callback routines (xt_final & xt_exit) are called with - * DLOCK and SYNC_LOCK held and they are required to return - * with these locks still held. - */ -typedef struct { - uint_t xt_msgtype; - idn_trans_t xt_trans[4]; - void (*xt_final)(int domid); - void (*xt_exit)(int domid, uint_t msgtype); -} idn_xphase_t; - -/* - * Synchronization entry representing the synchronization - * state with respect to a given domain for a given zone. - */ -typedef struct idn_syncop { - struct idn_syncop *s_next; - int s_domid; - idn_synccmd_t s_cmd; - int s_msg; - - domainset_t s_set_exp; - domainset_t s_set_rdy; - int (*s_transfunc)(int domid, void *arg); - void *s_transarg; -#ifdef DEBUG - int s_query[MAX_DOMAINS]; -#endif /* DEBUG */ -} idn_syncop_t; - -#ifdef DEBUG -#define IDN_SYNC_QUERY_INIT(d) \ - (bzero((caddr_t)idn_domain[d].dsync.s_query, \ - sizeof (idn_domain[d].dsync.s_query))) -#define IDN_SYNC_QUERY_UPDATE(md, sd) (idn_domain[md].dsync.s_query[sd]++) -#else /* DEBUG */ -#define IDN_SYNC_QUERY_INIT(d) -#define IDN_SYNC_QUERY_UPDATE(md, sd) -#endif /* DEBUG */ - -typedef struct { - idn_syncop_t *sc_op; - int sc_cnt; -} idn_synczone_t; - -#endif /* _KERNEL */ - -/* - * Vote Ticket used during negotiations and elections. - * - * 31 0 - * ----------------------------------------- - * |m...|....|pppp|....|Cbbb|bccc|cccB|BBB1| - * ----------------------------------------- - * m [31] = master/slave - * . [30:24] = unused - * p [23:20] = priority - * . [19:16] = unused - * C [15] = connected (has master) - * b [14:11] = nmembrds-1 - * c [10:5] = ncpus-1 - * B [4:1] = board_id - * 1 [0] = one - */ -typedef union { - struct { - uint_t master :1; - uint_t unused0 :7; - uint_t priority :4; - uint_t unused1 :4; - uint_t connected :1; - uint_t nmembrds :4; - uint_t ncpus :6; - uint_t board :4; - uint_t one :1; - } v; - uint_t ticket; -} idn_vote_t; - -#define IDNVOTE_PRI_MASK 0xf -#define IDNVOTE_MAXPRI 0xf -#define IDNVOTE_MINPRI 0 -#define IDNVOTE_DEFPRI 1 /* must be larger than MINPRI */ -/* - * Initially: - * vote.v.priority = IDNVOTE_DEFPRI - * vote.v.one = 1 - */ -#define IDNVOTE_INITIAL_TICKET ((IDNVOTE_DEFPRI << 20) | 1) -#define IDNVOTE_PRIVALUE(vvv) \ - ((int)vvv.v.priority + ((int)vvv.v.master ? IDNVOTE_MAXPRI : 0)) - -/* - * During elections we only use the "elect" attributes of the - * election ticket, i.e. those physical attributes pertaining - * to the individual domain (priority, nboards, ncpus, board). - */ -#define IDNVOTE_ELECT_MASK 0x00f07fff -#define IDNVOTE_ELECT(tkt) ((tkt).ticket & IDNVOTE_ELECT_MASK) -#define IDNVOTE_BASICS_MASK 0x00f0ffff -#define IDNVOTE_BASICS(tkt) ((tkt).ticket & IDNVOTE_BASICS_MASK) - -/* - * Values used in idn_select_master(). - */ -#define MASTER_IS_NONE 0 /* index into master_select_table */ -#define MASTER_IS_OTHER 1 -#define MASTER_IS_LOCAL 2 -#define MASTER_IS_REMOTE 3 - -typedef enum { - MASTER_SELECT_VOTE, - MASTER_SELECT_VOTE_RCFG, - MASTER_SELECT_CONNECT, - MASTER_SELECT_REMOTE, - MASTER_SELECT_LOCAL, - MASTER_SELECT_WAIT, - MASTER_SELECT_ERROR -} idn_master_select_t; - -/* - * Used to synchronize completion of link/unlink with respect to - * the original requester (user). Necessary since link establishment - * occurs asynchronously. - */ -typedef enum { -/* 0 */ IDNOP_DISCONNECTED, /* successfully disconnected */ -/* 1 */ IDNOP_CONNECTED, /* successfully established */ -/* 2 */ IDNOP_ERROR /* error trying to link/unlink */ -} idn_opflag_t; - -/* - * IDN Protocol Messages. - * These are IDN version (IDN_VERSION) dependent. - * - * ----- 7, --- 6,5.................0 - * | ack | nack | IDN message type | - * ---------------------------------- - */ -#define IDN_VERSION 1 - -/* - * Must be no more than 6-bits. See DMV private data. - */ -#define IDNP_ACK 0x20 -#define IDNP_NACK 0x10 -#define IDNP_NULL 0x00 -#define IDNP_NEGO 0x01 -#define IDNP_CON 0x02 -#define IDNP_CFG 0x03 -#define IDNP_FIN 0x04 -#define IDNP_CMD 0x05 -#define IDNP_DATA 0x06 - -#define IDN_NUM_MSGTYPES 7 -#define IDNP_ACKNACK_MASK (IDNP_ACK | IDNP_NACK) -#define IDNP_MSGTYPE_MASK 0x0f -#define VALID_MSGTYPE(m) (((m) >= IDNP_NEGO) && ((m) < IDN_NUM_MSGTYPES)) - -typedef struct idn_msgtype { - ushort_t mt_mtype; - ushort_t mt_atype; - ushort_t mt_cookie; -} idn_msgtype_t; - -/* - * IDN private data section of DMV layout (48 bits). - * - * 47......40,39.....34,33.....28,27..24,23......16,15..............0 - * | version | msgtype | acktype | did | cpuid | cookie | - * ------------------------------------------------------------------ - * - * version Local domain's version of IDN software. - * msgtype Type of IDN message, e.g. nego, syn, etc. - * acktype If msgtype is a ACK or NACK, then acktype is the - * type of ack that we're receiving, e.g. ack/nego|ack. - * did Local domain's ID (netid) - system-wide unique. - * cpuid Local domain's CPU->cpu_id that sending message. - * cookie Cookie assigned by remote domain for authentication. - * For NEGO & NEGO+ACK messages, it's the cookie that - * the sender expects the receiver to use in subsequent - * messages. The upper-eight bits represent a timer - * cookie to associate timers with expected messages. - */ -#endif /* !_ASM */ - -#ifdef _KERNEL - -#define _IDNPD_COOKIE_MASK 0xffff -#define _IDNPD_COOKIE_SHIFT 32 -#define _IDNPD_VER_MASK 0xff -#define _IDNPD_VER_SHIFT 24 -#define _IDNPD_MTYPE_MASK 0x3f -#define _IDNPD_MTYPE_SHIFT 18 -#define _IDNPD_ATYPE_MASK 0x3f -#define _IDNPD_ATYPE_SHIFT 12 -#define _IDNPD_DOMID_MASK 0xf -#define _IDNPD_DOMID_SHIFT 8 -#define _IDNPD_CPUID_MASK 0xff -#define _IDNPD_CPUID_SHIFT 0 - -#define _IDNPD_COOKIE_LEN 16 - -#ifndef _ASM - -#define IDN_PD2COOKIE(pdata) \ - (((uint_t)((pdata) >> _IDNPD_COOKIE_SHIFT)) & _IDNPD_COOKIE_MASK) -#define IDN_PD2VER(pdata) \ - (((uint_t)((pdata) >> _IDNPD_VER_SHIFT)) & _IDNPD_VER_MASK) -#define IDN_PD2MTYPE(pdata) \ - (((uint_t)((pdata) >> _IDNPD_MTYPE_SHIFT)) & _IDNPD_MTYPE_MASK) -#define IDN_PD2ATYPE(pdata) \ - (((uint_t)((pdata) >> _IDNPD_ATYPE_SHIFT)) & _IDNPD_ATYPE_MASK) -#define IDN_PD2DOMID(pdata) \ - (((uint_t)((pdata) >> _IDNPD_DOMID_SHIFT)) & _IDNPD_DOMID_MASK) -#define IDN_PD2CPUID(pdata) \ - (((uint_t)((pdata) >> _IDNPD_CPUID_SHIFT)) & _IDNPD_CPUID_MASK) - -#define IDN_MAKE_PDATA(mtype, atype, cookie) \ - ((((uint64_t)(cookie) & UINT64_C(_IDNPD_COOKIE_MASK)) << \ - _IDNPD_COOKIE_SHIFT) | \ - (((uint64_t)idn.version & UINT64_C(_IDNPD_VER_MASK)) << \ - _IDNPD_VER_SHIFT) | \ - (((uint64_t)(mtype) & UINT64_C(_IDNPD_MTYPE_MASK)) << \ - _IDNPD_MTYPE_SHIFT) | \ - (((uint64_t)(atype) & UINT64_C(_IDNPD_ATYPE_MASK)) << \ - _IDNPD_ATYPE_SHIFT) | \ - (((uint64_t)idn.localid & UINT64_C(_IDNPD_DOMID_MASK)) << \ - _IDNPD_DOMID_SHIFT) | \ - (((uint64_t)CPU->cpu_id & UINT64_C(_IDNPD_CPUID_MASK)) << \ - _IDNPD_CPUID_SHIFT)) - -#define IDN_TCOOKIE(ck) (((ck) >> 8) & 0xff) -#define IDN_DCOOKIE(ck) ((ck) & 0xff) -#define IDN_MAKE_COOKIE(d, t) ((((t) & 0xff) << 8) | ((d) & 0xff)) - -/* - * IDNP_NEGO - * - * 127........96,95........64,63........32,31.........0 - * | vote | domainset | - * ---------------------------------------------------- - * vote Local/Remote domain's vote ticket. - * domainset Mask of cpuids of domains to which - * sender is connected. Position in domainset - * designates respective domainid. - * E.g. domainset[6] = 20 -> domainid 6 is - * accessible via cpuid 20. - * The slot for the receiving domain - * contains the masterid of the sending - * domain. If the sending domain does - * not have a master then the entry will - * contain IDNNEG_NO_MASTER. - * - * These macros insert a domainid-cpuid pair into the - * domainset to be subsequently passed in a NEGO message, - * also retrieve the cpuid from the domainset for a - * given domainid. - * - * Usage: - * Sending: - * mask = IDNNEG_DSET_MYMASK(); - * IDNNEG_DSET_INIT(dset, mask) - * for (all domains except self) - * IDNNEG_DSET_SET(dset, domain, cpuid, mask); - * - * Receiving: - * IDNNEG_DSET_GET_MASK(dset, recv_domid, recv_mask); - * for (all domains except recv_domid) - * IDNNEG_DSET_GET(dset, domid, cpuid, recv_mask); - */ -typedef uint_t idnneg_dset_t[3]; - -#define IDNNEG_NO_MASTER 0x3f -#define __IDNNEG_DSET_CLEAR(dset) (bzero((caddr_t)(dset), \ - sizeof (idnneg_dset_t))) -#define IDNNEG_DSET_MYMASK() (idn_domain[idn.localid].dcpu) - -#define IDNNEG_DSET_INIT(dset, mask) \ - { \ - __IDNNEG_DSET_CLEAR(dset); \ - IDNNEG_DSET_SET((dset), idn.localid, (mask), idn.localid); \ - } - -#define IDNNEG_DSET_SET(dset, domid, cpuid, mask) \ - { \ - uint_t _s = ((domid) & 0xf) * 6; \ - int _i = _s >> 5; \ - uint_t _s0 = _s & 0x1f; \ - uint_t _t = ((cpuid) ^ (mask)) & 0x3f; \ - /*LINTED*/ \ - ASSERT(((domid) == idn.localid) ? \ - ((mask) == idn.localid) : ((cpuid) != (mask))); \ - (dset)[_i] |= _t << _s0; \ - if ((_s0 + 6) > 32) \ - (dset)[_i + 1] |= _t >> (32 - _s0); \ - } - -#define __IDNNEG_DSET_GET(dset, domid, cpuid, mask, uncond) \ - { \ - uint_t _s = ((domid) & 0xf) * 6; \ - int _i = _s >> 5; \ - uint_t _s0 = _s & 0x1f; \ - uint_t _s1 = (_s + 6) & 0x1f; \ - (cpuid) = ((dset)[_i] >> _s0) & 0x3f; \ - if ((_s0 + 6) > 32) \ - (cpuid) |= ((dset)[_i + 1] << (6 - _s1)) & 0x3f; \ - if ((cpuid) || (uncond)) \ - (cpuid) ^= (mask) & 0x3f; \ - else \ - (cpuid) = -1; \ - } - -#define IDNNEG_DSET_GET_MASK(dset, domid, mask) \ - __IDNNEG_DSET_GET((dset), (domid), (mask), (domid), 1) - -#define IDNNEG_DSET_GET_MASTER(dset, master) \ - __IDNNEG_DSET_GET((dset), idn.localid, (master), \ - idn.localid+MAX_DOMAINS, 0) - -#define IDNNEG_DSET_SET_MASTER(dset, domid, master) \ - IDNNEG_DSET_SET((dset), (domid), (master), \ - (domid)+MAX_DOMAINS) - -#define IDNNEG_DSET_GET(dset, domid, cpuid, mask) \ - __IDNNEG_DSET_GET((dset), (domid), (cpuid), (mask), 0) - -/* - * IDNP_CFG sub-types. - * - * Format of first 32 bit word in XDC: - * stX = sub-type. - * staX = sub-type arg. - * X = position in idn_cfgsubtype_t.param.p[] array. - * num = number of parameters in this XDC (0-3) - * - * 31...28,27...24,23...20,19...16,15...12,11....8,7.....3,2....0 - * | st0 . sta0 | st1 . sta1 | st2 . sta2 | phase | num | - * -------------------------------------------------------------- - * - * Note that since the first 32-bit word in a (IDNP_CFG) XDC is used - * for a sub-type, subsequent three 32-bits words are used for data that - * pertains to respective sub-type, i.e. first sub-type corresponds - * to first of the 3x32-bit words (pos=0), second sub-type corresponds - * to second of the 3x32-bit words (pos=1), etc. Obviously, a max of - * only three sub-types can be sent per xdc. - */ -#define IDNCFG_BARLAR 0x1 /* SMR base/limit pfn */ -#define IDNCFGARG_BARLAR_BAR 0 /* BAR */ -#define IDNCFGARG_BARLAR_LAR 1 /* LAR */ -#define IDNCFG_MCADR 0x2 /* MC ADR, arg = board number */ -#define IDNCFG_NMCADR 0x3 /* Number of MC ADRs to expect */ -#define IDNCFG_CPUSET 0x4 /* dcpuset of remote domain */ -#define IDNCFGARG_CPUSET_UPPER 0 /* 1st word */ -#define IDNCFGARG_CPUSET_LOWER 1 /* 2nd word */ -#define IDNCFG_NETID 0x5 /* dnetid, arg = 0 */ -#define IDNCFG_BOARDSET 0x6 /* board set, arg = 0 */ -#define IDNCFG_SIZE 0x7 /* SMR size parameters */ -#define IDNCFGARG_SIZE_MTU 0 /* IDN_MTU */ -#define IDNCFGARG_SIZE_BUF 1 /* IDN_SMR_BUFSIZE */ -#define IDNCFGARG_SIZE_SLAB 2 /* IDN_SLAB_BUFCOUNT */ -#define IDNCFGARG_SIZE_NWR 3 /* IDN_NWR_SIZE */ -#define IDNCFG_DATAMBOX 0x8 /* SMR data mailbox info */ -#define IDNCFGARG_DATAMBOX_TABLE 0 /* recvmbox table */ -#define IDNCFGARG_DATAMBOX_DOMAIN 1 /* domain's recvmbox */ -#define IDNCFGARG_DATAMBOX_INDEX 2 /* domain's index into table */ -#define IDNCFG_DATASVR 0x9 /* Data server info */ -#define IDNCFGARG_DATASVR_MAXNETS 0 /* max # of nets/channels */ -#define IDNCFGARG_DATASVR_MBXPERNET 1 /* # mbox per net/channel */ -#define IDNCFG_OPTIONS 0xa /* various options */ -#define IDNCFGARG_CHECKSUM 0 /* IDN_CHECKSUM */ - -#define IDN_CFGPARAM(st, sta) ((uchar_t)((((st) & 0xf) << 4) | ((sta) & 0xf))) -#define IDN_CFGPARAM_TYPE(p) (((p) >> 4) & 0xf) -#define IDN_CFGPARAM_ARG(p) ((p) & 0xf) - -typedef union { - struct { - uchar_t p[3]; - uchar_t _num_phase; /* info.num, info.phase used instead */ - } param; - struct { - uint_t _p : 24; /* param.p[] used instead */ - uint_t num : 2; - uint_t phase : 6; - } info; - uint_t val; -} idn_cfgsubtype_t; - -/* - * IDN_MASTER_NCFGITEMS - * Minimum number of config items expected from master. - * - * IDN_SLAVE_NCFGITEMS - * Number of config items expected from slave. - */ -#define IDN_MASTER_NCFGITEMS 17 /* max = +14 (mcadrs) */ -#define IDN_SLAVE_NCFGITEMS 12 - -/* - * IDNP_CMD sub-types. - */ -typedef enum { -/* 1 */ IDNCMD_SLABALLOC = 1, /* Request to allocate a slab */ -/* 2 */ IDNCMD_SLABFREE, /* Request to free a slab */ -/* 3 */ IDNCMD_SLABREAP, /* Reap any free slabs */ -/* 4 */ IDNCMD_NODENAME /* Query nodename of domain */ -} idn_cmd_t; - -#define VALID_IDNCMD(c) (((int)(c) >= (int)IDNCMD_SLABALLOC) && \ - ((int)(c) <= (int)IDNCMD_NODENAME)) -/* - * IDNP_NACK - */ -typedef enum { -/* 1 */ IDNNACK_NOCONN = 1, -/* 2 */ IDNNACK_BADCHAN, -/* 3 */ IDNNACK_BADCFG, -/* 4 */ IDNNACK_BADCMD, -/* 5 */ IDNNACK_RETRY, -/* 6 */ IDNNACK_DUP, -/* 7 */ IDNNACK_EXIT, -/* 8 */ IDNNACK_RESERVED1, -/* 9 */ IDNNACK_RESERVED2, -/* 10 */ IDNNACK_RESERVED3 -} idn_nack_t; - -/* - * IDNP_CON sub-types. - */ -typedef enum { -/* 0 */ IDNCON_OFF = 0, -/* 1 */ IDNCON_NORMAL, /* regular connect sequence */ -/* 2 */ IDNCON_QUERY /* query for connect info */ -} idn_con_t; - -/* - * IDNP_FIN sub-types. - */ -typedef enum { -/* 0 */ IDNFIN_OFF = 0, /* active, no fin */ -/* 1 */ IDNFIN_NORMAL, /* normal disconnect req */ -/* 2 */ IDNFIN_FORCE_SOFT, /* normal dis, force if goes AWOL */ -/* 3 */ IDNFIN_FORCE_HARD, /* force disconnect of AWOL domain */ -/* 4 */ IDNFIN_QUERY /* query for fin info */ -} idn_fin_t; - -#define VALID_FIN(f) (((int)(f) > 0) && \ - ((int)(f) < (int)IDNFIN_QUERY)) -#define FIN_IS_FORCE(f) (((f) == IDNFIN_FORCE_SOFT) || \ - ((f) == IDNFIN_FORCE_HARD)) - -/* - * FIN ARG types - reasons a FIN was sent. - */ -typedef enum { -/* 0 */ IDNFIN_ARG_NONE = 0, /* no argument */ -/* 1 */ IDNFIN_ARG_SMRBAD, /* SMR is corrupted */ -/* 2 */ IDNFIN_ARG_CPUCFG, /* missing cpu per board */ -/* 3 */ IDNFIN_ARG_HWERR, /* error programming hardware */ -/* 4 */ IDNFIN_ARG_CFGERR_FATAL, /* Fatal error during CONFIG */ -/* 5 */ IDNFIN_ARG_CFGERR_MTU, /* MTU sizes conflict */ -/* 6 */ IDNFIN_ARG_CFGERR_BUF, /* SMR_BUF_SIZE conflicts */ -/* 7 */ IDNFIN_ARG_CFGERR_SLAB, /* SLAB sizes conflict */ -/* 8 */ IDNFIN_ARG_CFGERR_NWR, /* NWR sizes conflict */ -/* 9 */ IDNFIN_ARG_CFGERR_NETS, /* MAX_NETS conflict */ -/* 10 */ IDNFIN_ARG_CFGERR_MBOX, /* MBOX_PER_NET conflict */ -/* 11 */ IDNFIN_ARG_CFGERR_NMCADR, /* NMCADR mismatches actual */ -/* 12 */ IDNFIN_ARG_CFGERR_MCADR, /* missing some MCADRs */ -/* 13 */ IDNFIN_ARG_CFGERR_CKSUM, /* checksum settings conflict */ -/* 14 */ IDNFIN_ARG_CFGERR_SMR /* SMR sizes conflict */ -} idn_finarg_t; - -#define IDNFIN_ARG_IS_FATAL(fa) ((fa) > IDNFIN_ARG_NONE) - -#define SET_FIN_TYPE(x, t) \ - ((x) &= 0xffff, (x) |= (((uint_t)(t) & 0xffff) << 16)) -#define SET_FIN_ARG(x, a) \ - ((x) &= ~0xffff, (x) |= ((uint_t)(a) & 0xffff)) -#define GET_FIN_TYPE(x) ((idn_fin_t)(((x) >> 16) & 0xffff)) -#define GET_FIN_ARG(x) ((idn_finarg_t)((x) & 0xffff)) - -#define FINARG2IDNKERR(fa) \ - (((fa) == IDNFIN_ARG_SMRBAD) ? IDNKERR_SMR_CORRUPTED : \ - ((fa) == IDNFIN_ARG_CPUCFG) ? IDNKERR_CPU_CONFIG : \ - ((fa) == IDNFIN_ARG_HWERR) ? IDNKERR_HW_ERROR : \ - ((fa) == IDNFIN_ARG_CFGERR_FATAL) ? IDNKERR_HW_ERROR : \ - ((fa) == IDNFIN_ARG_CFGERR_MTU) ? IDNKERR_CONFIG_MTU : \ - ((fa) == IDNFIN_ARG_CFGERR_BUF) ? IDNKERR_CONFIG_BUF : \ - ((fa) == IDNFIN_ARG_CFGERR_SLAB) ? IDNKERR_CONFIG_SLAB : \ - ((fa) == IDNFIN_ARG_CFGERR_NWR) ? IDNKERR_CONFIG_NWR : \ - ((fa) == IDNFIN_ARG_CFGERR_NETS) ? IDNKERR_CONFIG_NETS : \ - ((fa) == IDNFIN_ARG_CFGERR_MBOX) ? IDNKERR_CONFIG_MBOX : \ - ((fa) == IDNFIN_ARG_CFGERR_NMCADR) ? IDNKERR_CONFIG_NMCADR : \ - ((fa) == IDNFIN_ARG_CFGERR_MCADR) ? IDNKERR_CONFIG_MCADR : \ - ((fa) == IDNFIN_ARG_CFGERR_CKSUM) ? IDNKERR_CONFIG_CKSUM : \ - ((fa) == IDNFIN_ARG_CFGERR_SMR) ? IDNKERR_CONFIG_SMR : 0) - -/* - * FIN SYNC types. - */ -#define IDNFIN_SYNC_OFF 0 /* not set */ -#define IDNFIN_SYNC_NO 1 /* no-sync necessary */ -#define IDNFIN_SYNC_YES 2 /* do fin synchronously */ - -typedef short idn_finsync_t; - -/* - * IDNP_FIN options. - */ -typedef enum { -/* 0 */ IDNFIN_OPT_NONE = 0, /* none (used w/query) */ -/* 1 */ IDNFIN_OPT_UNLINK, /* normal unlink request */ -/* 2 */ IDNFIN_OPT_RELINK /* disconnect and retry link */ -} idn_finopt_t; - -#define VALID_FINOPT(f) (((f) == IDNFIN_OPT_UNLINK) || \ - ((f) == IDNFIN_OPT_RELINK)) - -#define FIN_MASTER_DOMID(x) (((((x) >> 16) & 0xffff) == 0xffff) ? \ - IDN_NIL_DOMID : (((x) >> 16) & 0xffff)) -#define FIN_MASTER_CPUID(x) ((((x) & 0xffff) == 0xffff) ? \ - IDN_NIL_DCPU : ((x) & 0xfff)) -#define MAKE_FIN_MASTER(d, c) ((((uint_t)(d) & 0xffff) << 16) | \ - ((uint_t)(c) & 0xffff)) -#define NIL_FIN_MASTER MAKE_FIN_MASTER(IDN_NIL_DOMID, IDN_NIL_DCPU) - -#ifdef DEBUG -#define IDN_FSTATE_TRANSITION(dp, ns) \ - { \ - int _id; \ - _id = (dp)->domid; \ - if ((dp)->dfin != (ns)) { \ - hrtime_t tstamp; \ - tstamp = TIMESTAMP(); \ - IDN_HISTORY_LOG(IDNH_FIN, _id, (ns), 0); \ - PR_STATE("FSTATE:%ld:%d: (l=%d, b/p=%d/%d) " \ - "%s(%d) -> %s(%d)\n", \ - (uint64_t)tstamp, _id, \ - __LINE__, \ - ((dp)->dcpu == IDN_NIL_DCPU) ? -1 : \ - CPUID_TO_BOARDID((dp)->dcpu), \ - (dp)->dcpu, \ - idnfin_str[(dp)->dfin], (dp)->dfin, \ - idnfin_str[ns], (ns)); \ - (dp)->dfin = (ns); \ - } \ - } -#else -#define IDN_FSTATE_TRANSITION(dp, ns) \ - { \ - IDN_HISTORY_LOG(IDNH_FIN, (dp)->domid, (ns), 0); \ - (dp)->dfin = (ns); \ - } -#endif /* DEBUG */ - -#endif /* !_ASM */ -#endif /* _KERNEL */ - -#ifndef _ASM -/* - * IDN Per-Domain States. - */ -typedef enum { -/* 0 */ IDNDS_CLOSED, /* idle */ -/* 1 */ IDNDS_NEGO_PEND, /* link initiating */ -/* 2 */ IDNDS_NEGO_SENT, /* link initiated, nego sent */ -/* 3 */ IDNDS_NEGO_RCVD, /* link wanted, nego+ack sent */ -/* 4 */ IDNDS_CONFIG, /* passing config info, prgm hw */ -/* 5 */ IDNDS_CON_PEND, /* connection pending */ -/* 6 */ IDNDS_CON_SENT, /* con sent */ -/* 7 */ IDNDS_CON_RCVD, /* con sent & received */ -/* 8 */ IDNDS_CON_READY, /* ready to establish link */ -/* 9 */ IDNDS_CONNECTED, /* established - linked */ -/* 10 */ IDNDS_FIN_PEND, /* unlink initiating */ -/* 11 */ IDNDS_FIN_SENT, /* unlink initiated, fin sent */ -/* 12 */ IDNDS_FIN_RCVD, /* unlink wanted by remote */ -/* 13 */ IDNDS_DMAP /* deprogramming hw */ -} idn_dstate_t; - -#define IDNDS_IS_CLOSED(dp) (((dp)->dstate == IDNDS_CLOSED) || \ - ((dp)->dstate == IDNDS_DMAP)) -#define IDNDS_IS_CONNECTING(dp) (((dp)->dstate > IDNDS_CLOSED) && \ - ((dp)->dstate < IDNDS_CONNECTED)) -#define IDNDS_IS_DISCONNECTING(dp) ((dp)->dstate > IDNDS_CONNECTED) -#define IDNDS_CONFIG_DONE(dp) (((dp)->dstate == IDNDS_CLOSED) || \ - ((dp)->dstate > IDNDS_CONFIG)) -#define IDNDS_SYNC_TYPE(dp) (((dp)->dfin_sync != IDNFIN_SYNC_OFF) ? \ - (dp)->dfin_sync : \ - ((dp)->dstate < IDNDS_CON_READY) ? \ - IDNFIN_SYNC_NO : IDNFIN_SYNC_YES) - -#endif /* !_ASM */ - -#ifdef _KERNEL -#ifndef _ASM -/* - * --------------------------------------------------------------------- - */ -typedef struct idn_timer { - struct idn_timer *t_forw, - *t_back; - struct idn_timerq *t_q; - - timeout_id_t t_id; - short t_domid; - short t_onq; - ushort_t t_type; - ushort_t t_subtype; - uint_t t_cookie; -#ifdef DEBUG - hrtime_t t_posttime; - hrtime_t t_exectime; -#endif /* DEBUG */ -} idn_timer_t; - -#define IDN_TIMER_PUBLIC_COOKIE 0xf - -#define IDN_TIMERQ_IS_LOCKED(tq) (MUTEX_HELD(&(tq)->tq_mutex)) -#define IDN_TIMERQ_LOCK(tq) (mutex_enter(&(tq)->tq_mutex)) -#define IDN_TIMERQ_UNLOCK(tq) (mutex_exit(&(tq)->tq_mutex)) - -#define IDN_TIMERQ_INIT(tq) (idn_timerq_init(tq)) -#define IDN_TIMERQ_DEINIT(tq) (idn_timerq_deinit(tq)) -#define IDN_TIMER_ALLOC() (idn_timer_alloc()) -#define IDN_TIMER_FREE(tp) (idn_timer_free(tp)) - -#define IDN_TIMER_START(tq, tp, tim) \ - (idn_timer_start((tq), (tp), (tim))) -#define IDN_TIMER_STOP(tq, typ, ck) \ - ((void) idn_timer_stop((tq), (typ), (ck))) -#define IDN_TIMER_STOPALL(tp) \ - ((void) idn_timer_stopall(tp)) -#define IDN_TIMER_GET(tq, typ, tp, ck) \ - { \ - mutex_enter(&((tq)->tq_mutex)); \ - (tp) = idn_timer_get((tq), (typ), (ck)); \ - mutex_exit(&((tq)->tq_mutex)); \ - } -#define IDN_TIMER_DEQUEUE(tq, tp) \ - (idn_timer_dequeue((tq), (tp))) -#ifdef DEBUG -#define IDN_TIMER_POST(tp) \ - ((tp)->t_posttime = gethrtime(), (tp)->t_exectime = 0) -#define IDN_TIMER_EXEC(tp) ((tp)->t_exectime = gethrtime()) -#else /* DEBUG */ -#define IDN_TIMER_POST(tp) -#define IDN_TIMER_EXEC(tp) -#endif /* DEBUG */ - -#define IDN_MSGTIMER_START(domid, typ, subtyp, tim, ckp) \ - { \ - idn_timer_t *_tp; \ - char _str[15]; \ - ushort_t *_ckp = (ckp); \ - inum2str((typ), _str); \ - PR_TIMER("msgtimer:%d: START: type = %s (0x%x)\n", \ - (domid), _str, (typ)); \ - _tp = IDN_TIMER_ALLOC(); \ - _tp->t_type = (ushort_t)(typ); \ - _tp->t_subtype = (ushort_t)(subtyp); \ - _tp->t_domid = (short)(domid); \ - _tp->t_cookie = (_ckp) ? *(_ckp) : 0; \ - IDN_TIMER_POST(_tp); \ - if (_ckp) { \ - *(_ckp) = IDN_TIMER_START(&idn_domain[domid].dtimerq, \ - _tp, (tim)); \ - } else { \ - (void) IDN_TIMER_START(&idn_domain[domid].dtimerq, \ - _tp, (tim)); \ - } \ - } -#define IDN_MSGTIMER_STOP(domid, typ, ck) \ - { \ - char _str[15]; \ - inum2str((typ), _str); \ - PR_TIMER("msgtimer:%d: STOP: type = %s (0x%x), " \ - "cookie = 0x%x\n", \ - (domid), _str, (typ), (ck)); \ - IDN_TIMER_STOP(&idn_domain[domid].dtimerq, (typ), (ck)); \ - } -#define IDN_MSGTIMER_GET(dp, typ, tp, ck) \ - IDN_TIMER_GET(&(dp)->dtimerq, (typ), (tp), (ck)) - -/* - * IDN_SLABALLOC_WAITTIME - * Max wait time in ticks that local domains waits for - * master to respond to a slab allocation request. Has - * to be at least as long as wait time for a response to - * the command. - */ -#define IDN_SLABALLOC_WAITTIME ((3 * idn_msg_waittime[IDNP_CMD]) / 2) - -/* - * Domain state transition macros. - */ -#ifdef DEBUG -#define IDN_DSTATE_TRANSITION(dp, ns) \ - { \ - int id; \ - hrtime_t tstamp; \ - tstamp = TIMESTAMP(); \ - ASSERT(RW_WRITE_HELD(&(dp)->drwlock)); \ - id = (dp)->domid; \ - IDN_HISTORY_LOG(IDNH_DSTATE, id, (ns), \ - (uint_t)(dp)->dcpu); \ - PR_STATE("DSTATE:%ld:%d: (l=%d, b/p=%d/%d) " \ - "%s(%d) -> %s(%d)\n", \ - (uint64_t)tstamp, id, \ - __LINE__, \ - ((dp)->dcpu == IDN_NIL_DCPU) ? \ - -1 : CPUID_TO_BOARDID((dp)->dcpu), \ - (dp)->dcpu, \ - idnds_str[(dp)->dstate], (dp)->dstate, \ - idnds_str[ns], (ns)); \ - (dp)->dstate = (ns); \ - IDNSB_DOMAIN_UPDATE(dp); \ - } -#else -#define IDN_DSTATE_TRANSITION(dp, ns) \ - { \ - IDN_HISTORY_LOG(IDNH_DSTATE, (dp)->domid, \ - (ns), (uint_t)(dp)->dcpu); \ - (dp)->dstate = (ns); \ - IDNSB_DOMAIN_UPDATE(dp); \ - } -#endif /* DEBUG */ - -#define IDN_XSTATE_TRANSITION(dp, xs) \ - { \ - int _xs = (xs); \ - (dp)->dxstate = _xs; \ - if (_xs != IDNXS_NIL) { \ - ASSERT((dp)->dxp); \ - IDN_DSTATE_TRANSITION((dp), \ - (dp)->dxp->xt_trans[_xs].t_state); \ - } \ - } - -/* - * --------------------------------------------------------------------- - * IDN Per-Domain Data - * - * The comment to the right of the respective field represents - * what lock protects that field. If there is no comment then - * no lock is required to access the field. - * --------------------------------------------------------------------- - */ - -#define MAXDNAME 32 - -typedef struct idn_domain { - krwlock_t drwlock; - /* - * Assigned domid for domain. Never - * changes once idn_domain[] is - * initialized. We are guaranteed that - * all domains in IDN will have a - * uniqueue domid in the range (0-15). - */ - int domid; - idn_dstate_t dstate; /* drwlock */ - idn_xstate_t dxstate; /* drwlock */ - /* - * Gotten from uname -n for local - * domain. Remote domains pass - * theirs during Config phase. - */ - char dname[MAXDNAME]; /* drwlock */ - /* - * IDN-wide unique identifier for the - * given domain. This value will be - * the same as the domid. - */ - ushort_t dnetid; /* drwlock */ - idn_vote_t dvote; /* drwlock */ - /* - * Used during FIN sequenece to - * determine what type of shutdown - * (unlink) we're executing with - * respect to the given domain. - */ - idn_fin_t dfin; /* drwlock */ - /* - * A non-zero value for dfin_sync - * indicates that unlink of respective - * domain does not need to be performed - * synchronously among all the IDN - * member domains. - */ - short dfin_sync; /* grwlock */ - /* - * Cookie used to determine the - * proper context in which we're - * receiving messages from the given - * domain. Assigned cookies are exchanged - * during initial NEGO messages. - */ - ushort_t dcookie_send; /* drwlock */ - ushort_t dcookie_recv; /* drwlock */ - short dcookie_err; /* drwlock */ - int dcookie_errcnt; /* drwlock */ - /* - * Primary target cpu for sending - * messages. Can change to help - * distribute interrupts on receiving - * side. - */ - int dcpu; /* drwlock */ - /* - * Used to store dcpu from a previous - * life. Only used when requesting - * a RELINK with a domain we were just - * previously linked with. Thus, it - * does represent a valid cpu in the - * remote domain. - */ - int dcpu_save; /* drwlock */ - /* - * Used to store from which cpu the - * last message was received. - */ - int dcpu_last; - /* - * Transition phase area. This field - * points to the proper phase structure - * depending on what stage the given - * domain is in. - */ - idn_xphase_t *dxp; /* drwlock */ - /* - * Actual synchronization object for - * the given domain. - */ - idn_syncop_t dsync; /* drwlock & idn.sync.sz_mutex */ - /* - * Slab information for given domain. - * If the local domain is a master, - * then this field in each domain is used - * to store which slabs have been assigned - * to given domain. If the local domain - * is a slave, then this information is - * NULL for all remote idn_domain[] - * entries, but for local domain holds - * those slabs assigned to local domain. - */ - smr_slab_t *dslab; /* dslab_rwlock */ - short dnslabs; /* dslab_rwlock */ - short dslab_state; /* dslab_rwlock */ - krwlock_t dslab_rwlock; - /* - * Set of cpus belonging to domain. - */ - cpuset_t dcpuset; /* drwlock */ - - int dncpus; /* drwlock */ - /* - * Index into dcpumap to determine - * which cpu to target next for - * interrupt. Intended to allow fair - * distribution of interrupts on - * remote domain. - */ - uint_t dcpuindex; /* drwlock */ - /* - * Quick look-up map of cpus belonging - * to domain. Used to select next target. - */ - uchar_t *dcpumap; /* drwlock */ - /* - * Non-zero indicates outstanding - * I/O's to given domain. - */ - int dio; /* drwlock */ - int dioerr; /* drwlock */ - /* - * Set when we fail to allocate a buffer - * for a domain. Dictates whether to - * reclaim max buffers or not. - */ - lock_t diowanted; - /* - * Set when remote domain does not - * seem to be picking up messages sent - * to it. Non-zero indicates we have - * an outstanding "ping" to domain. - */ - lock_t diocheck; /* drwlock */ - short dslabsize; /* drwlock */ - uint_t dmtu; /* drwlock */ - - uint_t dbufsize; /* drwlock */ - short dnwrsize; /* drwlock */ - lock_t dreclaim_inprogress; /* drwlock */ - uchar_t dreclaim_index; /* drwlock */ - /* - * The following field is primarily - * used during CFG exchange to keep - * track of certain per-domain information. - */ - union { /* all - drwlock */ - struct { - uint_t _dcfgphase : 6; - uint_t _dcfgsnddone : 1; - uint_t _dcfgrcvdone : 1; - uint_t _dcksum : 2; - uint_t _dmaxnets : 6; - uint_t _dmboxpernet : 9; - uint_t _dncfgitems : 6; - uint_t _drecfg : 1; - } _s; - int _dtmp; - } _u; - /* - * Each domain entry maintains a - * timer queue holding timers for - * messages outstanding to that domain. - */ - struct idn_timerq { - int tq_cookie; /* tq_mutex */ - kmutex_t tq_mutex; - int tq_count; /* tq_mutex */ - idn_timer_t *tq_queue; /* tq_mutex */ - } dtimerq; - /* - * dawol is used to keep - * track of AWOL details for - * given domain when it is - * non-responsive. - */ - struct { - int a_count; /* drwlock */ - clock_t a_time; /* drwlock */ - clock_t a_last; /* drwlock */ - clock_t a_msg; /* drwlock */ - } dawol; - - struct hwconfig { - short dh_nboards; /* drwlock */ - short dh_nmcadr; /* drwlock */ - boardset_t dh_boardset; /* drwlock */ - uint_t dh_mcadr[MAX_BOARDS]; /* drwlock */ - } dhw; - /* - * Mailbox information used to - * send/recv messages to given domain. - */ - struct { - kmutex_t m_mutex; - struct idn_mboxtbl *m_tbl; /* m_mutex */ - struct idn_mainmbox *m_send; /* m_mutex */ - struct idn_mainmbox *m_recv; /* m_mutex */ - } dmbox; -} idn_domain_t; - -typedef struct idn_timerq idn_timerq_t; - -#define dcfgphase _u._s._dcfgphase -#define dcfgsnddone _u._s._dcfgsnddone -#define dcfgrcvdone _u._s._dcfgrcvdone -#define dcksum _u._s._dcksum -#define dmaxnets _u._s._dmaxnets -#define dmboxpernet _u._s._dmboxpernet -#define dncfgitems _u._s._dncfgitems -#define drecfg _u._s._drecfg -#define dbindport _u._dbindport -#define dconnected _u._dconnected -#define dtmp _u._dtmp - -#define IDN_DLOCK_EXCL(dd) (rw_enter(&idn_domain[dd].drwlock, RW_WRITER)) -#define IDN_DLOCK_SHARED(dd) (rw_enter(&idn_domain[dd].drwlock, RW_READER)) -#define IDN_DLOCK_TRY_SHARED(dd) \ - (rw_tryenter(&idn_domain[dd].drwlock, \ - RW_READER)) -#define IDN_DLOCK_DOWNGRADE(dd) (rw_downgrade(&idn_domain[dd].drwlock)) -#define IDN_DUNLOCK(dd) (rw_exit(&idn_domain[dd].drwlock)) -#define IDN_DLOCK_IS_EXCL(dd) (RW_WRITE_HELD(&idn_domain[dd].drwlock)) -#define IDN_DLOCK_IS_SHARED(dd) (RW_READ_HELD(&idn_domain[dd].drwlock)) -#define IDN_DLOCK_IS_HELD(dd) (RW_LOCK_HELD(&idn_domain[dd].drwlock)) - -#define IDN_MBOX_LOCK(dd) (mutex_enter(&idn_domain[dd].dmbox.m_mutex)) -#define IDN_MBOX_UNLOCK(dd) (mutex_exit(&idn_domain[dd].dmbox.m_mutex)) - -#define IDN_RESET_COOKIES(dd) \ - (idn_domain[dd].dcookie_send = idn_domain[dd].dcookie_recv = 0) - -#define DSLAB_STATE_UNKNOWN 0 -#define DSLAB_STATE_LOCAL 1 -#define DSLAB_STATE_REMOTE 2 - -#define DSLAB_READ_HELD(d) RW_READ_HELD(&idn_domain[d].dslab_rwlock) -#define DSLAB_WRITE_HELD(d) RW_WRITE_HELD(&idn_domain[d].dslab_rwlock) - -#define DSLAB_LOCK_EXCL(d) \ - rw_enter(&idn_domain[d].dslab_rwlock, RW_WRITER) -#define DSLAB_LOCK_SHARED(d) \ - rw_enter(&idn_domain[d].dslab_rwlock, RW_READER) -#define DSLAB_LOCK_TRYUPGRADE(d) \ - rw_tryupgrade(&idn_domain[d].dslab_rwlock) -#define DSLAB_UNLOCK(d) rw_exit(&idn_domain[d].dslab_rwlock) - -/* - * --------------------------------------------------------------------- - * Macro to pick another target for the given domain. This hopefully - * improves performance by better distributing the SSI responsibilities - * at the target domain. - * --------------------------------------------------------------------- - */ -#define BUMP_INDEX(set, index) \ - { \ - register int p; \ - for (p = (index)+1; p < NCPU; p++) \ - if (CPU_IN_SET((set), p)) \ - break; \ - if (p >= NCPU) \ - for (p = 0; p <= (index); p++) \ - if (CPU_IN_SET((set), p)) \ - break; \ - if (!CPU_IN_SET((set), p)) { \ - uint_t _u32, _l32; \ - _u32 = UPPER32_CPUMASK(set); \ - _l32 = LOWER32_CPUMASK(set); \ - cmn_err(CE_PANIC, \ - "IDN: cpu %d not in cpuset 0x%x.%0x\n", \ - p, _u32, _l32); \ - } \ - (index) = p; \ - } - -#define IDN_ASSIGN_DCPU(dp, cookie) \ - ((dp)->dcpu = (int)((dp)->dcpumap[(cookie) & (NCPU-1)])) - -/* - * --------------------------------------------------------------------- - * Atomic increment/decrement, swap, compare-swap functions. - * --------------------------------------------------------------------- - */ -#define ATOMIC_INC(v) atomic_inc_32((uint_t *)&(v)) -#define ATOMIC_DEC(v) atomic_dec_32((uint_t *)&(v)) -#define ATOMIC_SUB(v, n) atomic_add_32((uint_t *)&(v), -(n)) -#define ATOMIC_CAS(a, c, n) atomic_cas_32((uint32_t *)(a), (uint32_t)(c), \ - (uint32_t)(n)) -#define ATOMIC_SWAPL(a, v) atomic_swap_32((uint32_t *)(a), (uint32_t)(v)) - -/* - * DMV vector interrupt support. - * - * A fixed-size circular buffer is maintained as a queue of - * incoming interrupts. The low-level idn_dmv_handler() waits - * for an entry to become FREE and will atomically mark it INUSE. - * Once it has filled in the appropriate fields it will be marked - * as READY. The high-level idn_handler() will be invoked and will - * process all messages in the queue that are READY. Each message - * is marked PROCESS, a protojob job created and filled in, and - * then the interrupt message is marked FREE for use in the next - * interrupt. The iv_state field is used to hold the relevant - * state and is updated atomically. - */ -#define IDN_PIL PIL_8 -#define IDN_DMV_PENDING_MAX 128 /* per cpu */ - -#endif /* !_ASM */ - -#ifndef _ASM - -/* - * The size of this structure must be a power of 2 - * so that we can do a simple shift to calculate - * our offset into based on cpuid. - */ -typedef struct idn_dmv_cpu { - uint32_t idn_dmv_current; - int32_t idn_dmv_lostintr; - lock_t idn_dmv_active; - char _padding[(2 * sizeof (uint64_t)) - \ - sizeof (uint32_t) - \ - sizeof (lock_t) - \ - sizeof (int32_t)]; -} idn_dmv_cpu_t; - -typedef struct idn_dmv_data { - uint64_t idn_soft_inum; - uint64_t idn_dmv_qbase; - idn_dmv_cpu_t idn_dmv_cpu[NCPU]; -} idn_dmv_data_t; - -/* - * Requirements of the following data structure: - * - MUST be double-word (8 bytes) aligned. - * - _iv_head field MUST start on double-word boundary. - * - iv_xargs0 MUST start on double-word boundary - * with iv_xargs1 immediately following. - * - iv_xargs2 MUST start on double-word boundary - * with iv_xargs3 immediately following. - */ -typedef struct idn_dmv_msg { - uint32_t iv_next; /* offset */ - uchar_t iv_inuse; - uchar_t iv_ready; - ushort_t _padding; - uint32_t iv_head : 16; - uint32_t iv_cookie : 16; - uint32_t iv_ver : 8; - uint32_t iv_mtype : 6; - uint32_t iv_atype : 6; - uint32_t iv_domid : 4; - uint32_t iv_cpuid : 8; - uint32_t iv_xargs0; - uint32_t iv_xargs1; - uint32_t iv_xargs2; - uint32_t iv_xargs3; -} idn_dmv_msg_t; - -extern uint_t idn_dmv_inum; -extern uint_t idn_soft_inum; - -/* - * An IDN-network address has the following format: - * - * 31......16,15........0 - * | channel | dnetid | - * ---------------------- - * channel - network interface. - * netid - idn_domain[].dnetid - */ -#define IDN_MAXMAX_NETS 32 -#define IDN_BROADCAST_ALLCHAN ((ushort_t)-1) -#define IDN_BROADCAST_ALLNETID ((ushort_t)-1) - -typedef union { - struct { - ushort_t chan; - ushort_t netid; - } net; - uint_t netaddr; -} idn_netaddr_t; - -#define CHANSET_ALL (~((idn_chanset_t)0)) -#define CHANSET(c) \ - ((idn_chanset_t)1 << ((c) & 31)) -#define CHAN_IN_SET(m, c) \ - (((m) & ((idn_chanset_t)1 << ((c) & 31))) != 0) -#define CHANSET_ADD(m, c) \ - ((m) |= ((idn_chanset_t)1 << ((c) & 31))) -#define CHANSET_DEL(m, c) \ - ((m) &= ~((idn_chanset_t)1 << ((c) & 31))) -#define CHANSET_ZERO(m) ((m) = 0) - -typedef enum { -/* 0 */ IDNCHAN_OPEN, -/* 1 */ IDNCHAN_SOFT_CLOSE, -/* 2 */ IDNCHAN_HARD_CLOSE, -/* 3 */ IDNCHAN_OFFLINE, -/* 4 */ IDNCHAN_ONLINE -} idn_chanop_t; - -/* - * Retry support. - */ -#define IDN_RETRY_TOKEN(d, x) ((((d) & 0xf) << 16) | \ - (0xffff & (uint_t)(x))) -#define IDN_RETRY_TOKEN2DOMID(t) ((int)(((t) >> 16) & 0xf)) -#define IDN_RETRY_TOKEN2TYPE(t) ((idn_retry_t)((t) & 0xffff)) -#define IDN_RETRY_TYPEALL ((idn_retry_t)0xffff) -#define IDN_RETRY_INTERVAL hz /* 1 sec */ -#define IDN_RETRY_RECFG_MULTIPLE 10 - -#define IDN_RETRYINTERVAL_NEGO (2 * hz) -#define IDN_RETRYINTERVAL_CON (2 * hz) -#define IDN_RETRYINTERVAL_FIN (2 * hz) - -typedef struct idn_retry_job { - struct idn_retry_job *rj_prev; - struct idn_retry_job *rj_next; - void (*rj_func)(uint_t token, void *arg); - void *rj_arg; - uint_t rj_token; - short rj_onq; - timeout_id_t rj_id; -} idn_retry_job_t; - -#define IDNRETRY_ALLOCJOB() \ - ((idn_retry_job_t *)kmem_cache_alloc(idn.retryqueue.rq_cache, KM_SLEEP)) -#define IDNRETRY_FREEJOB(j) \ - (kmem_cache_free(idn.retryqueue.rq_cache, (void *)(j))) - -typedef enum { -/* 0 */ IDNRETRY_NIL = 0, -/* 1 */ IDNRETRY_NEGO, -/* 2 */ IDNRETRY_CON, -/* 3 */ IDNRETRY_CONQ, /* for CON queries */ -/* 4 */ IDNRETRY_FIN, -/* 5 */ IDNRETRY_FINQ, /* for FIN queries */ -/* 6 */ IDN_NUM_RETRYTYPES -} idn_retry_t; - -/* - * --------------------------------------------------------------------- - */ -typedef struct { - int m_domid; - int m_cpuid; - ushort_t m_msgtype; - ushort_t m_acktype; - ushort_t m_cookie; - idn_xdcargs_t m_xargs; -} idn_protomsg_t; - -typedef struct idn_protojob { - struct idn_protojob *j_next; - int j_cache; - idn_protomsg_t j_msg; -} idn_protojob_t; - -typedef struct idn_protoqueue { - struct idn_protoqueue *q_next; - idn_protojob_t *q_joblist; - idn_protojob_t *q_joblist_tail; - int q_die; - int q_id; - ksema_t *q_morgue; - kthread_id_t q_threadp; - kcondvar_t q_cv; - kmutex_t q_mutex; -} idn_protoqueue_t; - -#define IDN_PROTOCOL_NSERVERS 4 -#define IDN_PROTOCOL_SERVER_HASH(d) ((d) % idn.nservers) -#define IDN_PROTOJOB_CHUNKS (idn.nservers) - -/* - * --------------------------------------------------------------------- - * Data Server definitions. - * - * idn_datasvr_t - Describes data server thread. - * . ds_id - Per-domain identifier for data server. - * . ds_domid - Domain which data server is handling. - * . ds_state - Flag to enable/disable/terminate - * data server. - * . ds_mboxp - Pointer to data server's (local) - * mailbox to be serviced. - * . ds_waittime - cv_timedwait sleep time before - * checking respective mailbox. - * . ds_threadp - Pointer to data server thread. - * . ds_cv - Condvar for sleeping. - * . ds_morguep - Semaphore for terminating thread. - * - * idn_mboxhdr_t - Resides in SMR space (MUST be cache_linesize). - * . mh_svr_active - Non-zero indicates data server is - * actively reading mailbox for messages. - * . mh_svr_ready - Non-zero indicates data server has - * allocated and is ready to accept data. - * . mh_cookie - Identifier primarily for debug purposes. - * - * idn_mboxmsg_t - Entry in the SMR space circular queue use to - * represent a data packet. - * . mm_owner - Non-zero indicates entry is available - * to be processed by receiver's data server. - * . mm_flag - Indicates whether entry needs to be - * reclaimed by the sender. Also holds error - * indications (e.g. bad offset). - * . mm_offset - SMR offset of respective data packet. - * - * idn_mboxtbl_t - Encapsulation of a per-domain mailbox (SMR space). - * . mt_header - Header information for synchronization. - * . mt_queue - Circular queue of idn_mboxmsg_t entries. - * - * idn_mainmbox_t - Encapsulation of main SMR recv/send mailboxes. - * . mm_mutex - Protects mm_* entries, enqueuing, and - * dequeuing of messages. Also protects - * updates to the route table pointed to - * by mm_routetbl. - * . mm_count - send: Current number of messages - * enqueued. - * - recv: Cumulative number of messages - * processed. - * . mm_max_count - send: Maximum number of messages - * enqueued per iteration. - * recv: Maximum number of messages - * dequeued per iteration. - * . mm_smr_mboxp - Pointer to SMR (vaddr) space where - * respective mailbox resides. - * --------------------------------------------------------------------- - */ -#define IDN_MBOXHDR_COOKIE_TOP ((uint_t)0xc0c0) -#define IDN_MAKE_MBOXHDR_COOKIE(pd, sd, ch) \ - ((IDN_MBOXHDR_COOKIE_TOP << 16) \ - | (((uint_t)(pd) & 0xf) << 12) \ - | (((uint_t)(sd) & 0xf) << 8) \ - | ((uint_t)(ch) & 0xf)) -#define IDN_GET_MBOXHDR_COOKIE(mhp) \ - ((mhp)->mh_cookie & ~0xff00) -#define VALID_MBOXHDR(mhp, ch, cksum) \ - ((IDN_GET_MBOXHDR_COOKIE(mhp) == \ - IDN_MAKE_MBOXHDR_COOKIE(0, 0, (ch))) && \ - ((cksum) == (*(mhp)).mh_cksum)) -/* - * The number of entries in a mailbox queue must be chosen so - * that (IDN_MMBOX_NUMENTRIES * sizeof (idn_mboxmsg_t)) is a multiple - * of a cacheline size (64). - */ -#define IDN_MMBOX_NUMENTRIES IDN_MBOX_PER_NET -/* - * We step through the mailboxes in effectively cacheline size - * incremenents so that the source and receiving cpus are not competing - * for the same cacheline when transmitting/receiving messages into/from - * the mailboxes. The hard requirement is that the step value be even - * since the mailbox size will be chosen odd. This allows us to wraparound - * the mailbox uniquely touching each entry until we've exhausted them - * all at which point we'll end up where we initially started and repeat - * again. - */ -#define IDN_MMBOXINDEX_STEP (((64 / sizeof (idn_mboxmsg_t)) + 1) & 0xfffe) -#define IDN_MMBOXINDEX_INC(i) \ - { \ - if (((i) += IDN_MMBOXINDEX_STEP) >= IDN_MMBOX_NUMENTRIES) \ - (i) -= IDN_MMBOX_NUMENTRIES; \ - } - -#define IDN_MMBOXINDEX_DIFF(i, j) \ - (((i) >= (j)) ? (((i) - (j)) / IDN_MMBOXINDEX_STEP) \ - : ((((i) + IDN_MMBOX_NUMENTRIES) - (j)) / IDN_MMBOXINDEX_STEP)) - -/* - * Require IDN_MBOXAREA_SIZE <= IDN_SLAB_SIZE so we don't waste - * slab space. - * - * Each domain maintains a MAX_DOMAIN(16) entry mbox_table. Each - * entry represents a receive mailbox for a possible domain to which - * the given domain may have a connection. The send mailbox for each - * respective domain is given to the local domain at the time of - * connection establishment. - */ - -/* - * --------------------------------------------------------------------- - */ -#define IDN_MBOXTBL_SIZE \ - (IDNROUNDUP(((IDN_MBOX_PER_NET * sizeof (idn_mboxmsg_t)) \ - + sizeof (idn_mboxhdr_t)), IDN_ALIGNSIZE)) - -/* - * --------------------------------------------------------------------- - * Each domain has idn_max_nets worth of possible mailbox tables - * for each domain to which it might possibly be connected. - * --------------------------------------------------------------------- - */ -#define IDN_MBOXAREA_SIZE \ - (IDN_MBOXTBL_SIZE * IDN_MAX_NETS * MAX_DOMAINS * MAX_DOMAINS) -#define IDN_MBOXAREA_OFFSET(d) \ - ((d) * IDN_MBOXTBL_SIZE * IDN_MAX_NETS * MAX_DOMAINS) - -/* - * --------------------------------------------------------------------- - * Return the base of the mailbox area (set of tables) assigned - * to the given domain id. - * --------------------------------------------------------------------- - */ -#define IDN_MBOXAREA_BASE(m, d) \ - ((idn_mboxtbl_t *)(((ulong_t)(m)) + IDN_MBOXAREA_OFFSET(d))) - -/* - * --------------------------------------------------------------------- - * Return the pointer to the respective receive mailbox (table set) - * for the given domain id relative to the given base mailbox table. - * --------------------------------------------------------------------- - */ -#define IDN_MBOXTBL_PTR(t, d) \ - ((idn_mboxtbl_t *)(((ulong_t)(t)) + ((d) * IDN_MBOXTBL_SIZE \ - * IDN_MAX_NETS))) -/* - * --------------------------------------------------------------------- - * Return the pointer to the actual target mailbox based on the - * given channel in the given mailbox table. - * --------------------------------------------------------------------- - */ -#define IDN_MBOXTBL_PTR_CHAN(t, c) \ - ((idn_mboxtbl_t *)(((ulong_t)(t)) + ((c) * IDN_MBOXTBL_SIZE))) - -#define IDN_MBOXTBL_PTR_INC(t) \ - ((t) = (idn_mboxtbl_t *)(((ulong_t)(t)) + IDN_MBOXTBL_SIZE)) - -#define IDN_MBOXCHAN_INC(i) \ - { \ - if (++(i) == IDN_MAX_NETS) \ - (i) = 0; \ - } - -/* - * --------------------------------------------------------------------- - * Return the absolute location within the entire mailbox area - * of the mboxtbl for the given primary and secondary domain and - * channel. Only relevant when done by the master. - * --------------------------------------------------------------------- - */ -#define IDN_MBOXTBL_ABS_PTR(mt, pd, sd, ch) \ - (IDN_MBOXTBL_PTR_CHAN( \ - IDN_MBOXTBL_PTR( \ - IDN_MBOXAREA_BASE((mt), (pd)), \ - (sd)), \ - (ch))) - -#define IDN_BFRAME_SHIFT idn.bframe_shift -#define IDN_BFRAME2OFFSET(bf) ((bf) << IDN_BFRAME_SHIFT) -#define IDN_BFRAME2ADDR(bf) IDN_OFFSET2ADDR(IDN_BFRAME2OFFSET(bf)) -#define IDN_OFFSET2BFRAME(off) (((off) >> IDN_BFRAME_SHIFT) & 0xffffff) -#define IDN_ADDR2BFRAME(addr) IDN_OFFSET2BFRAME(IDN_ADDR2OFFSET(addr)) - -typedef struct idn_mboxmsg { - uint_t ms_owner : 1, - ms_flag : 7, - ms_bframe : 24; -} idn_mboxmsg_t; - -typedef idn_mboxmsg_t idn_mboxq_t[1]; - -#define IDN_CKSUM_MBOX_COUNT (offsetof(idn_mboxhdr_t, mh_svr_ready) / 2) - -#define IDN_CKSUM_MBOX(h) \ - (IDN_CHECKSUM ? \ - idn_cksum((ushort_t *)(h), IDN_CKSUM_MBOX_COUNT) : 0) - -typedef struct idn_mboxhdr { - uint_t mh_cookie; - uint_t mh_svr_ready_ptr; - uint_t mh_svr_active_ptr; - ushort_t mh_svr_ready; - ushort_t mh_svr_active; - - uint_t _padding[(64 - - (4*sizeof (uint_t)) - - (2*sizeof (ushort_t))) / sizeof (uint_t)]; - - uint_t mh_cksum; -} idn_mboxhdr_t; - -typedef struct idn_mboxtbl { - idn_mboxhdr_t mt_header; - idn_mboxq_t mt_queue; -} idn_mboxtbl_t; - -#define IDN_CHAN_DOMAIN_REGISTER(csp, dom) \ - (DOMAINSET_ADD((csp)->ch_reg_domset, (dom))) - -#define IDN_CHAN_DOMAIN_UNREGISTER(csp, dom) \ - (DOMAINSET_DEL((csp)->ch_reg_domset, (dom))) - -#define IDN_CHAN_DOMAIN_IS_REGISTERED(csp, dom) \ - (DOMAIN_IN_SET((csp)->ch_reg_domset, (dom))) - -#define IDN_CHANSVR_SCANSET_ADD_PENDING(csp, dom) \ - { \ - register int _d; \ - register uint64_t _domset; \ - (dom) &= MAX_DOMAINS - 1; /* Assumes power of 2 */ \ - _domset = 0ull; \ - for (_d = 0; _d < (csp)->ch_recv_domcount; _d++) { \ - if ((int)(((csp)->ch_recv_scanset_pending >> \ - (_d * 4)) & 0xf) == (dom)) \ - break; \ - else \ - _domset = (_domset << 4) | 0xfull; \ - } \ - if (_d == (csp)->ch_recv_domcount) { \ - _domset &= (csp)->ch_recv_scanset_pending; \ - _domset |= (uint64_t)(dom) << \ - ((csp)->ch_recv_domcount * 4); \ - (csp)->ch_recv_domcount++; \ - (csp)->ch_recv_scanset_pending = 0ull; \ - for (_d = 0; _d < 16; \ - _d += (csp)->ch_recv_domcount) { \ - (csp)->ch_recv_scanset_pending |= _domset; \ - _domset <<= (csp)->ch_recv_domcount * 4; \ - } \ - } \ - } -#define IDN_CHANSVR_SCANSET_DEL_PENDING(csp, dom) \ - { \ - register int _d; \ - register uint64_t _domset; \ - (dom) &= MAX_DOMAINS - 1; /* Assumes power of 2 */ \ - _domset = 0ull; \ - for (_d = 0; _d < (csp)->ch_recv_domcount; _d++) { \ - if ((int)(((csp)->ch_recv_scanset_pending >> \ - (_d * 4)) & 0xf) == (dom)) \ - break; \ - else \ - _domset = (_domset << 4) | 0xfull; \ - } \ - if (_d < (csp)->ch_recv_domcount) { \ - _domset &= (csp)->ch_recv_scanset_pending; \ - (csp)->ch_recv_scanset_pending >>= 4; \ - (csp)->ch_recv_domcount--; \ - for (; _d < (csp)->ch_recv_domcount; _d++) \ - _domset |= (csp)->ch_recv_scanset_pending &\ - (0xfull << (_d * 4)); \ - (csp)->ch_recv_scanset_pending = 0ull; \ - if ((csp)->ch_recv_domcount) { \ - for (_d = 0; _d < 16; \ - _d += (csp)->ch_recv_domcount) { \ - (csp)->ch_recv_scanset_pending |= \ - _domset; \ - _domset <<= \ - (csp)->ch_recv_domcount * 4; \ - } \ - } \ - } \ - } - -#define IDN_CHAN_TRYLOCK_GLOBAL(csp) \ - mutex_tryenter(&(csp)->ch_mutex) -#define IDN_CHAN_LOCK_GLOBAL(csp) \ - mutex_enter(&(csp)->ch_mutex) -#define IDN_CHAN_UNLOCK_GLOBAL(csp) \ - mutex_exit(&(csp)->ch_mutex) -#define IDN_CHAN_GLOBAL_IS_LOCKED(csp) \ - (MUTEX_HELD(&(csp)->ch_mutex)) - -#define IDN_CHAN_LOCAL_IS_LOCKED(csp) \ - (MUTEX_HELD(&(csp)->ch_send.c_mutex) && \ - MUTEX_HELD(&(csp)->ch_recv.c_mutex)) -#define IDN_CHAN_LOCK_LOCAL(csp) \ - (mutex_enter(&(csp)->ch_recv.c_mutex, \ - mutex_enter(&(csp)->ch_send.c_mutex)) -#define IDN_CHAN_UNLOCK_LOCAL(csp) \ - (mutex_exit(&(csp)->ch_send.c_mutex), \ - mutex_exit(&(csp)->ch_recv.c_mutex)) - -#define IDN_CHAN_RECV_IS_LOCKED(csp) \ - (MUTEX_HELD(&(csp)->ch_recv.c_mutex)) -#define IDN_CHAN_TRYLOCK_RECV(csp) \ - (mutex_tryenter(&(csp)->ch_recv.c_mutex)) -#define IDN_CHAN_LOCK_RECV(csp) \ - (mutex_enter(&(csp)->ch_recv.c_mutex)) -#define IDN_CHAN_UNLOCK_RECV(csp) \ - (mutex_exit(&(csp)->ch_recv.c_mutex)) - -#define IDN_CHAN_SEND_IS_LOCKED(csp) \ - (MUTEX_HELD(&(csp)->ch_send.c_mutex)) -#define IDN_CHAN_TRYLOCK_SEND(csp) \ - (mutex_tryenter(&(csp)->ch_send.c_mutex)) -#define IDN_CHAN_LOCK_SEND(csp) \ - (mutex_enter(&(csp)->ch_send.c_mutex)) -#define IDN_CHAN_UNLOCK_SEND(csp) \ - (mutex_exit(&(csp)->ch_send.c_mutex)) - -/* - * A channel table is an array of pointers to mailboxes - * for the respective domains for the given channel. - * Used a cache for the frequently used items. Respective - * fields in mainmbox are updated just prior to sleeping. - */ - -/* - * Reading c_state requires either c_mutex or ch_mutex. - * Writing c_state requires both c_mutex and ch_mutex in the order: - * ch_mutex - * c_mutex - */ -typedef struct idn_chaninfo { - kmutex_t c_mutex; - uchar_t c_state; /* protected by c_mutex */ - uchar_t c_checkin; /* asynchronous flag */ - kcondvar_t c_cv; - ushort_t c_waiters; /* protected by c_mutex */ - ushort_t c_inprogress; /* protected by c_mutex */ -} idn_chaninfo_t; - -/* - * Reading/Writing ch_state requires ch_mutex. - * When updating both recv and send c_state's for the locks - * must be grabbed in the following order: - * ch_mutex - * ch_recv.c_mutex - * ch_send.c_mutex - * This order is necessary to prevent deadlocks. - * In general ch_state is intended to represent c_state of - * individual send/recv sides. During state transitions the - * ch_state and c_state values may be slightly different, - * but eventually should end up identical. - */ -typedef struct idn_chansvr { - uchar_t ch_id; - uchar_t ch_state; /* protected by ch_mutex */ - lock_t ch_initlck; - lock_t ch_actvlck; - domainset_t ch_reg_domset; - kmutex_t ch_mutex; - - idn_chaninfo_t ch_send; - int _padding2[(64 - - (2*sizeof (uchar_t)) - (2*sizeof (lock_t)) - - sizeof (uint_t) - sizeof (kmutex_t) - - sizeof (idn_chaninfo_t)) / sizeof (int)]; - - idn_chaninfo_t ch_recv; - - uint64_t ch_recv_scanset; - uint64_t ch_recv_scanset_pending; - - domainset_t ch_recv_domset; - domainset_t ch_recv_domset_pending; - short ch_recv_domcount; - kcondvar_t ch_recv_cv; - int ch_recv_waittime; - int ch_recv_changed; - - kthread_id_t ch_recv_threadp; - ksema_t *ch_recv_morguep; - int ch_bound_cpuid; - int ch_bound_cpuid_pending; -} idn_chansvr_t; - -typedef struct idn_mainmbox { - kmutex_t mm_mutex; - short mm_channel; - short mm_domid; - ushort_t mm_flags; - short mm_type; - - idn_chansvr_t *mm_csp; /* non-NULL indicates reg'd */ - int mm_count; - int mm_dropped; - idn_mboxtbl_t *mm_smr_mboxp; /* SMR vaddr */ - - ushort_t *mm_smr_activep; /* SMR pointer */ - ushort_t *mm_smr_readyp; /* SMR pointer */ - int mm_qiget; /* next msg to get */ - int mm_qiput; /* next slot to put msg */ -} idn_mainmbox_t; - -/* - * mm_flags - */ -#define IDNMMBOX_FLAG_CORRUPTED 0x01 -/* - * mm_type - */ -#define IDNMMBOX_TYPE_RECV 0x1 -#define IDNMMBOX_TYPE_SEND 0x2 - -#define IDNMBOX_IS_RECV(m) ((m) == IDNMMBOX_TYPE_RECV) -#define IDNMBOX_IS_SEND(m) ((m) == IDNMMBOX_TYPE_SEND) - -/* - * Period between sending wakeup xdc's to remote domain. - */ -#define IDN_CHANNEL_WAKEUP_PERIOD (hz >> 1) -/* - * ms_flag bit values. - */ -#define IDN_MBOXMSG_FLAG_RECLAIM 0x1 /* needs to be reclaimed */ -#define IDN_MBOXMSG_FLAG_INPROCESS 0x2 -#define IDN_MBOXMSG_FLAG_ERR_BADOFFSET 0x4 -#define IDN_MBOXMSG_FLAG_ERR_NOMBOX 0x8 -#define IDN_MBOXMSG_FLAG_ERRMASK 0xc -/* - * ch_state/c_state bit values. - */ -#define IDN_CHANSVC_STATE_ATTACHED 0x01 -#define IDN_CHANSVC_STATE_ENABLED 0x02 -#define IDN_CHANSVC_STATE_ACTIVE 0x04 -#define IDN_CHANSVC_STATE_FLUSH 0x10 -#define IDN_CHANSVC_STATE_CORRUPTED 0x20 -#define IDN_CHANSVC_STATE_MASK 0x07 /* ATTACHED/ENABLED/ACTIVE */ - -#define IDN_CHANSVC_PENDING_BITS (IDN_CHANSVC_STATE_ATTACHED | \ - IDN_CHANSVC_STATE_ENABLED) - -/* - * GLOBAL - */ -#define IDN_CHANNEL_IS_ATTACHED(csp) \ - ((csp)->ch_state & IDN_CHANSVC_STATE_ATTACHED) -#define IDN_CHANNEL_IS_DETACHED(csp) \ - (!IDN_CHANNEL_IS_ATTACHED(csp)) -#define IDN_CHANNEL_IS_PENDING(csp) \ - (((csp)->ch_state & IDN_CHANSVC_STATE_MASK) == \ - IDN_CHANSVC_PENDING_BITS) -#define IDN_CHANNEL_IS_ACTIVE(csp) \ - ((csp)->ch_state & IDN_CHANSVC_STATE_ACTIVE) -#define IDN_CHANNEL_IS_ENABLED(csp) \ - ((csp)->ch_state & IDN_CHANSVC_STATE_ENABLED) -/* - * SEND - */ -#define IDN_CHANNEL_IS_SEND_ACTIVE(csp) \ - ((csp)->ch_send.c_state & IDN_CHANSVC_STATE_ACTIVE) -/* - * RECV - */ -#define IDN_CHANNEL_IS_RECV_ACTIVE(csp) \ - ((csp)->ch_recv.c_state & IDN_CHANSVC_STATE_ACTIVE) -#define IDN_CHANNEL_IS_RECV_CORRUPTED(csp) \ - ((csp)->ch_recv.c_state & IDN_CHANSVC_STATE_CORRUPTED) - - -#define IDN_CHAN_SEND_INPROGRESS(csp) ((csp)->ch_send.c_inprogress++) -#define IDN_CHAN_SEND_DONE(csp) \ - { \ - ASSERT((csp)->ch_send.c_inprogress > 0); \ - if ((--((csp)->ch_send.c_inprogress) == 0) && \ - ((csp)->ch_send.c_waiters != 0)) \ - cv_broadcast(&(csp)->ch_send.c_cv); \ - } -#define IDN_CHAN_RECV_INPROGRESS(csp) ((csp)->ch_recv.c_inprogress++) -#define IDN_CHAN_RECV_DONE(csp) \ - { \ - ASSERT((csp)->ch_recv.c_inprogress > 0); \ - if ((--((csp)->ch_recv.c_inprogress) == 0) && \ - ((csp)->ch_recv.c_waiters != 0)) \ - cv_broadcast(&(csp)->ch_recv.c_cv); \ - } - -#define IDN_CHANSVC_MARK_ATTACHED(csp) \ - ((csp)->ch_state = IDN_CHANSVC_STATE_ATTACHED) -#define IDN_CHANSVC_MARK_DETACHED(csp) \ - ((csp)->ch_state = 0) -#define IDN_CHANSVC_MARK_PENDING(csp) \ - ((csp)->ch_state |= IDN_CHANSVC_STATE_ENABLED) -#define IDN_CHANSVC_MARK_DISABLED(csp) \ - ((csp)->ch_state &= ~IDN_CHANSVC_STATE_ENABLED) -#define IDN_CHANSVC_MARK_ACTIVE(csp) \ - ((csp)->ch_state |= IDN_CHANSVC_STATE_ACTIVE) -#define IDN_CHANSVC_MARK_IDLE(csp) \ - ((csp)->ch_state &= ~IDN_CHANSVC_STATE_ACTIVE) - -#define IDN_CHANSVC_MARK_RECV_ACTIVE(csp) \ - ((csp)->ch_recv.c_state |= IDN_CHANSVC_STATE_ACTIVE) -#define IDN_CHANSVC_MARK_RECV_CORRUPTED(csp) \ - ((csp)->ch_recv.c_state |= IDN_CHANSVC_STATE_CORRUPTED) -#define IDN_CHANSVC_MARK_SEND_ACTIVE(csp) \ - ((csp)->ch_send.c_state |= IDN_CHANSVC_STATE_ACTIVE) - -typedef enum { - IDNCHAN_ACTION_DETACH, /* DETACH (ATTACHED = 0) */ - IDNCHAN_ACTION_STOP, /* DISABLE (ENABLED = 0) */ - IDNCHAN_ACTION_SUSPEND, /* IDLE (ACTIVE = 0) */ - IDNCHAN_ACTION_RESUME, - IDNCHAN_ACTION_RESTART, - IDNCHAN_ACTION_ATTACH -} idn_chanaction_t; - -#define IDN_CHANNEL_SUSPEND(c, w) \ - (idn_chan_action((c), IDNCHAN_ACTION_SUSPEND, (w))) -#define IDN_CHANNEL_RESUME(c) \ - (idn_chan_action((c), IDNCHAN_ACTION_RESUME, 0)) -#define IDN_CHANNEL_STOP(c, w) \ - (idn_chan_action((c), IDNCHAN_ACTION_STOP, (w))) -#define IDN_CHANNEL_RESTART(c) \ - (idn_chan_action((c), IDNCHAN_ACTION_RESTART, 0)) -#define IDN_CHANNEL_DETACH(c, w) \ - (idn_chan_action((c), IDNCHAN_ACTION_DETACH, (w))) -#define IDN_CHANNEL_ATTACH(c) \ - (idn_chan_action((c), IDNCHAN_ACTION_ATTACH, 0)) - -/* - * ds_waittime range values. - * When a packet arrives the waittime starts at MIN and gradually - * shifts up to MAX until another packet arrives. If still no - * packet arrives then we go to a hard sleep - */ -#define IDN_NETSVR_SPIN_COUNT idn_netsvr_spin_count -#define IDN_NETSVR_WAIT_MIN idn_netsvr_wait_min -#define IDN_NETSVR_WAIT_MAX idn_netsvr_wait_max -#define IDN_NETSVR_WAIT_SHIFT idn_netsvr_wait_shift - -/* - * --------------------------------------------------------------------- - * IDN Global Data - * - * The comment to the right of the respective field represents - * what lock protects that field. If there is no comment then - * no lock is required to access the field. - * --------------------------------------------------------------------- - */ -typedef struct idn_global { /* protected by... */ - krwlock_t grwlock; - /* - * Global state of IDN w.r.t. - * the local domain. - */ - idn_gstate_t state; /* grwlock */ - /* - * Version of the IDN driver. - * Is passed in DMV header so that - * other domains can validate they - * support protocol used by local - * domain. - */ - int version; - /* - * Set to 1 if SMR region properly - * allocated and available. - */ - int enabled; - /* - * Local domains "domain id". - */ - int localid; - /* - * Domain id of the Master domain. - * Set to IDN_NIL_DOMID if none - * currently exists. - */ - int masterid; /* grwlock */ - /* - * Primarily used during Reconfiguration - * to track the expected new Master. - * Once the current IDN is dismantled - * the local domain will attempt to - * connect to this new domain. - */ - int new_masterid; /* grwlock */ - /* - * Number of protocol servers configured. - */ - int nservers; - - dev_info_t *dip; - - struct { - /* - * dmv_inum - * Interrupt number assigned by - * DMV subsystem to IDN's DMV - * handler. - * soft_inum - * Soft interrupt number assigned - * by OS (add_softintr) for Soft - * interrupt dispatched by DMV - * handler. - */ - uint_t dmv_inum; - uint64_t soft_inum; - caddr_t dmv_data; - size_t dmv_data_len; - } intr; - /* - * first_swlink - * Used as synchronization to - * know whether channels need - * to be activated or not. - * first_hwlink - * Used as mechanism to determine - * whether local domain needs - * to publicize its SMR, assuming - * it is the Master. - * first_hwmaster - * Domainid of the domain that - * was the master at the time - * the hardware was programmed. - * We need to keep this so that - * we deprogram with respect to - * the correct domain that the - * hardware was originally - * programmed to. - */ - lock_t first_swlink; - lock_t first_hwlink; - short first_hwmasterid; - /* - * The xmit* fields are used to set-up a background - * thread to monitor when a channel is ready to be - * enabled again. This is necessary since IDN - * can't rely on hardware to interrupt it when - * things are ready to go. We need this ability - * to wakeup our STREAMS queues. - * Criteria for reenabling queues. - * gstate == IDNGS_ONLINE - * channel = !check-in - * buffers are available - * - * xmit_chanset_wanted - * Indicates which channels wish to have - * their queues reenabled when ready. - * xmit_tid - * Timeout-id of monitor. - */ - kmutex_t xmit_lock; - idn_chanset_t xmit_chanset_wanted; /* xmit_lock */ - timeout_id_t xmit_tid; /* xmit_lock */ - - struct { - /* - * ready - * Indicates SMR region allocated - * and available from OBP. - * vaddr - * Virtual address assigned to SMR. - * locpfn - * Page Frame Number associated - * with local domain's SMR. - * rempfn - * Page Frame Number associated - * with remote (Master) domain's SMR. - * rempfnlim - * PFN past end of remote domain's - * SMR. - * prom_paddr/prom_size - * Physical address and size of - * SMR that were assigned by OBP. - */ - int ready; - caddr_t vaddr; - pfn_t locpfn; - pfn_t rempfn; /* grwlock */ - - pfn_t rempfnlim; /* grwlock */ - uint64_t prom_paddr; - - uint64_t prom_size; - } smr; - - /* - * idnsb_mutex - * Protects access to IDN's - * sigblock area. - * idnsb_eventp - * IDN's private area in sigblock - * used for signaling events - * regarding IDN state to SSP. - * idnsb - * Area within IDN's private - * sigblock area used for tracking - * certain IDN state which might - * be useful during arbstop - * conditions (if caused by IDN!). - */ - kmutex_t idnsb_mutex; - idnsb_event_t *idnsb_eventp; - idnsb_t *idnsb; - - struct sigbintr { - /* - * sb_mutex - * Protects sigbintr elements - * to synchronize execution of - * sigblock (IDN) mailbox handling. - * sb_cpuid - * Cpu whose sigblock mailbox - * originally received IDN request - * from SSP. Necessary to know - * where to put response. - * sb_busy - * Flag indicating state of - * sigblock handler thread. - * Synchronize activity between - * SSP and current IDN requests that - * are in progress. - * sb_cv - * Condition variable for sigblock - * handler thread to wait on. - * sb_inum - * Soft interrupt number assigned - * by OS to handle soft interrupt - * request make by low-level (IDN) - * sigblock handler to dispatch actual - * processing of sigblock (mailbox) - * request. - */ - kmutex_t sb_mutex; - uchar_t sb_cpuid; /* sigbintr.sb_mutex */ - uchar_t sb_busy; /* sigbintr.sb_mutex */ - kcondvar_t sb_cv; /* sigbintr.sb_mutex */ - uint64_t sb_inum; /* sigbintr.sb_mutex */ - } sigbintr; - - /* - * struprwlock, strup, sip, siplock - * Standard network streams - * handling structures to manage - * instances of IDN driver. - */ - krwlock_t struprwlock; - struct idnstr *strup; /* struprwlock */ - - struct idn *sip; /* siplock */ - kmutex_t sipwenlock; - kmutex_t siplock; - - /* - * Area where IDN maintains its kstats. - */ - kstat_t *ksp; - /* - * Number of domains that local domain - * has "open". - */ - int ndomains; /* grwlock */ - /* - * Number of domains that local domain - * has registered as non-responsive. - */ - int nawols; /* grwlock */ - /* - * Number of network channels (interfaces) - * which are currently active. - */ - int nchannels; /* grwlock */ - /* - * Bitmask representing channels - * that are currently active. - */ - idn_chanset_t chanset; /* grwlock */ - /* - * Array of channel (network/data) servers - * that have been created. Not necessarily - * all active. - */ - idn_chansvr_t *chan_servers; /* elmts = ch_mutex */ - /* - * Pointer to sigblock handler thread - * which ultimately processes SSP - * IDN requests. - */ - kthread_id_t sigb_threadp; - /* - * Pointer to area used by Master - * to hold mailbox structures. - * Actual memory is in SMR. - */ - idn_mboxtbl_t *mboxarea; /* grwlock */ - - struct { - /* - * IDN_SYNC_LOCK - Provides serialization - * mechanism when performing synchronous - * operations across domains. - */ - kmutex_t sz_mutex; - /* - * Actual synchronization zones for - * CONNECT/DISCONNECT phases. - */ - idn_synczone_t sz_zone[IDN_SYNC_NUMZONE]; - } sync; /* sz_mutex */ - - struct { - /* - * ds_trans_on - * Set of domains which are trying - * to establish a link w/local. - * ds_ready_on - * Set of domains which local knows - * are ready for linking, but has - * not yet confirmed w/peers. - * ds_connected - * Set of domains that local has - * confirmed as being ready. - * ds_trans_off - * Set of domains which are trying - * to unlink from local. - * ds_ready_off - * Set of domains which local knows - * are ready for unlink, but has - * not yet confirmed w/peers. - * ds_relink - * Set of domains we're expecting - * to relink with subsequent to - * a RECONFIG (new master selection). - * ds_hwlinked - * Set of domains for which local - * has programmed its hardware. - * ds_flush - * Set of domains requiring that - * local flush its ecache prior - * to unlinking. - * ds_awol - * Set of domains believed to be - * AWOL - haven't responded to - * any queries. - * ds_hitlist - * Set of domains which local domain - * is unlinking from and wishes to ignore - * any extraneous indirect link requests - * from other domains, e.g. during a - * Reconfig. - */ - domainset_t ds_trans_on; /* sz_mutex */ - domainset_t ds_ready_on; /* sz_mutex */ - - domainset_t ds_connected; /* sz_mutex */ - domainset_t ds_trans_off; /* sz_mutex */ - - domainset_t ds_ready_off; /* sz_mutex */ - domainset_t ds_relink; /* sz_mutex */ - - domainset_t ds_hwlinked; /* sz_mutex */ - domainset_t ds_flush; /* sz_mutex */ - - domainset_t ds_awol; /* sz_mutex */ - domainset_t ds_hitlist; /* sz_mutex */ - } domset; - /* - * Bitmask identifying all cpus in - * the local IDN. - */ - cpuset_t dc_cpuset; - /* - * Bitmask identifying all boards in - * the local IDN. - */ - boardset_t dc_boardset; - - struct dopers { - /* - * Waiting area for IDN requests, - * i.e. link & unlinks. IDN requests - * are performed asynchronously so - * we need a place to wait until the - * operation has completed. - * - * dop_domset - * Identifies which domains the - * current waiter is interested in. - * dop_waitcount - * Number of waiters in the room. - * dop_waitlist - * Actual waiting area. - * dop_freelist - * Freelist (small cache) of - * structs for waiting area. - */ - kmutex_t dop_mutex; - kcondvar_t dop_cv; /* dop_mutex */ - domainset_t dop_domset; /* dop_mutex */ - int dop_waitcount; /* dop_mutex */ - dop_waitlist_t *dop_waitlist; /* dop_mutex */ - dop_waitlist_t *dop_freelist; /* dop_mutex */ - /* dop_mutex */ - dop_waitlist_t _dop_wcache[IDNOP_CACHE_SIZE]; - } *dopers; - - struct { - /* - * Protocol Server: - * - * p_server - * Linked list of queues - * describing protocol - * servers in use. - * p_jobpool - * Kmem cache of structs - * used to enqueue protocol - * jobs for protocol servers. - * p_morgue - * Synchronization (check-in) - * area used when terminating - * protocol servers (threads). - */ - struct idn_protoqueue *p_serverq; - kmem_cache_t *p_jobpool; - ksema_t p_morgue; - } protocol; - - struct idn_retry_queue { - /* - * rq_jobs - * Queue of Retry jobs - * that are outstanding. - * rq_count - * Number of jobs on retry - * queue. - * rq_cache - * Kmem cache for structs - * used to describe retry - * jobs. - */ - idn_retry_job_t *rq_jobs; /* rq_mutex */ - int rq_count; /* rq_mutex */ - kmutex_t rq_mutex; /* rq_mutex */ - - kcondvar_t rq_cv; /* rq_mutex */ - kmem_cache_t *rq_cache; - } retryqueue; - - struct slabpool { - /* - * Slabpool: - * - * ntotslabs - * Total number of slabs - * in SMR (free & in-use). - * npools - * Number of pools available - * in list. One smr_slabtbl - * exists for each pool. - */ - int ntotslabs; - int npools; - struct smr_slabtbl { - /* - * sarray - * Array of slab structs - * representing slabs in SMR. - * nfree - * Number of slabs actually - * available in sarray. - * nslabs - * Number of slabs represented - * in sarray (free & in-use). - */ - smr_slab_t *sarray; - int nfree; - int nslabs; - } *pool; - /* - * Holds array of smr_slab_t structs kmem_alloc'd - * for slabpool. - */ - smr_slab_t *savep; - } *slabpool; - - struct slabwaiter { - /* - * Waiting area for threads - * requesting slab allocations. - * Used by Slaves for all requests, - * but used by Master only for - * redundant requests, i.e. multiple - * requests on behalf of the same - * domain. One slabwaiter area - * exist for each possible domain. - * - * w_nwaiters - * Number of threads waiting - * in waiting area. - * w_done - * Flag to indicate that - * allocation request has - * completed. - * w_serrno - * Non-zero indicates an - * errno value to represent - * error that occurred during - * attempt to allocate slab. - * w_closed - * Indicates that waiting area is - * closed and won't allow any new - * waiters. This occurs during - * the small window where we're - * trying to suspend a channel. - * w_cv - * Condvar for waiting on. - * w_sp - * Holds slab structure of - * successfully allocated slab. - */ - kmutex_t w_mutex; - short w_nwaiters; /* w_mutex */ - short w_done; /* w_mutex */ - short w_serrno; /* w_mutex */ - short w_closed; /* w_mutex */ - kcondvar_t w_cv; /* w_mutex */ - smr_slab_t *w_sp; /* w_mutex */ - } *slabwaiter; - /* - * Kmem cache used for allocating - * timer structures for outstanding - * IDN requests. - */ - kmem_cache_t *timer_cache; - /* - * Effectively constant used in - * translating buffer frames in - * mailbox message frames to - * offsets within SMR. - */ - int bframe_shift; -} idn_global_t; - -typedef struct idn_retry_queue idn_retry_queue_t; - -#define IDN_GET_MASTERID() (idn.masterid) -#define IDN_SET_MASTERID(mid) \ - { \ - int _mid = (mid); \ - mutex_enter(&idn.idnsb_mutex); \ - if (idn.idnsb) { \ - idn.idnsb->id_pmaster_board = \ - idn.idnsb->id_master_board; \ - if (_mid == IDN_NIL_DOMID) \ - idn.idnsb->id_master_board = (uchar_t)0xff; \ - else \ - idn.idnsb->id_master_board = \ - (uchar_t)idn_domain[_mid].dvote.v.board; \ - } \ - mutex_exit(&idn.idnsb_mutex); \ - IDN_HISTORY_LOG(IDNH_MASTERID, _mid, idn.masterid, 0); \ - PR_STATE("%d: MASTERID %d -> %d\n", __LINE__, \ - idn.masterid, _mid); \ - idn.masterid = _mid; \ - } -#define IDN_GET_NEW_MASTERID() (idn.new_masterid) -#define IDN_SET_NEW_MASTERID(mid) \ - { \ - PR_STATE("%d: NEW MASTERID %d -> %d\n", __LINE__, \ - idn.new_masterid, (mid)); \ - idn.new_masterid = (mid); \ - } - -#define IDN_GLOCK_EXCL() (rw_enter(&idn.grwlock, RW_WRITER)) -#define IDN_GLOCK_SHARED() (rw_enter(&idn.grwlock, RW_READER)) -#define IDN_GLOCK_TRY_SHARED() (rw_tryenter(&idn.grwlock, RW_READER)) -#define IDN_GLOCK_DOWNGRADE() (rw_downgrade(&idn.grwlock)) -#define IDN_GUNLOCK() (rw_exit(&idn.grwlock)) -#define IDN_GLOCK_IS_EXCL() (RW_WRITE_HELD(&idn.grwlock)) -#define IDN_GLOCK_IS_SHARED() (RW_READ_HELD(&idn.grwlock)) -#define IDN_GLOCK_IS_HELD() (RW_LOCK_HELD(&idn.grwlock)) - -#define IDN_SYNC_LOCK() (mutex_enter(&idn.sync.sz_mutex)) -#define IDN_SYNC_TRYLOCK() (mutex_tryenter(&idn.sync.sz_mutex)) -#define IDN_SYNC_UNLOCK() (mutex_exit(&idn.sync.sz_mutex)) -#define IDN_SYNC_IS_LOCKED() (MUTEX_HELD(&idn.sync.sz_mutex)) - -/* - * Macro to reset some globals necessary in preparing - * for initialization of HW for IDN. - */ -#define IDN_PREP_HWINIT() \ - { \ - ASSERT(IDN_GLOCK_IS_EXCL()); \ - lock_clear(&idn.first_swlink); \ - lock_clear(&idn.first_hwlink); \ - idn.first_hwmasterid = (short)IDN_NIL_DOMID; \ - } - -/* - * Return values of idn_send_data. - */ -#define IDNXMIT_OKAY 0 /* xmit successful */ -#define IDNXMIT_LOOP 1 /* loopback */ -#define IDNXMIT_DROP 2 /* drop packet */ -#define IDNXMIT_RETRY 3 /* retry packet (requeue and qenable) */ -#define IDNXMIT_REQUEUE 4 /* requeue packet, but don't qenable */ - -/* - * --------------------------------------------------------------------- - * ss_rwlock must be acquired _before_ any idn_domain locks are - * acquired if both structs need to be accessed. - * idn.struprwlock is acquired when traversing IDN's strup list - * and when adding or deleting entries. - * - * ss_nextp Linked list of streams. - * ss_rq Respective read queue. - * ss_sip Attached device. - * ss_state Current DL state. - * ss_sap Bound SAP. - * ss_flags Misc. flags. - * ss_mccount # enabled multicast addrs. - * ss_mctab Table of multicast addrs. - * ss_minor Minor device number. - * ss_rwlock Protects ss_linkup fields and DLPI state machine. - * ss_linkup Boolean flag indicating whether particular (domain) link - * is up. - * --------------------------------------------------------------------- - */ -struct idnstr { /* gets shoved into q_ptr */ - struct idnstr *ss_nextp; - queue_t *ss_rq; - struct idn *ss_sip; - t_uscalar_t ss_state; - t_uscalar_t ss_sap; - uint_t ss_flags; - uint_t ss_mccount; - struct ether_addr *ss_mctab; - minor_t ss_minor; - krwlock_t ss_rwlock; -}; - -/* - * idnstr.ss_flags - Per-stream flags - */ -#define IDNSFAST 0x01 /* "M_DATA fastpath" mode */ -#define IDNSRAW 0x02 /* M_DATA plain raw mode */ -#define IDNSALLPHYS 0x04 /* "promiscuous mode" */ -#define IDNSALLMULTI 0x08 /* enable all multicast addresses */ -#define IDNSALLSAP 0x10 /* enable all ether type values */ - -/* - * Maximum number of multicast address per stream. - */ -#define IDNMAXMC 64 -#define IDNMCALLOC (IDNMAXMC * sizeof (struct ether_addr)) - -/* - * Full DLSAP address length (in struct dladdr format). - */ -#define IDNADDRL (ETHERADDRL + sizeof (ushort_t)) - -struct idndladdr { - struct ether_addr dl_phys; - ushort_t dl_sap; -}; - -#define IDNHEADROOM 64 -#define IDNROUNDUP(a, n) (((a) + ((n) - 1)) & ~((n) - 1)) - -/* - * Respective interpretation of bytes in 6 byte ethernet address. - */ -#define IDNETHER_ZERO 0 -#define IDNETHER_COOKIE1 1 -#define IDNETHER_COOKIE1_VAL 0xe5 -#define IDNETHER_COOKIE2 2 -#define IDNETHER_COOKIE2_VAL 0x82 -#define IDNETHER_NETID 3 -#define IDNETHER_CHANNEL 4 -#define IDNETHER_RESERVED 5 -#define IDNETHER_RESERVED_VAL 0x64 - -/* - * IDN driver supports multliple instances, however they - * still all refer to the same "physical" device. Multiple - * instances are supported primarily to allow increased - * STREAMs bandwidth since each instance has it's own IP queue. - * This structure is primarily defined to be consistent with - * other network drivers and also to hold the kernel stats. - */ -struct idn_kstat { - ulong_t si_ipackets; /* # packets received */ - ulong_t si_ierrors; /* # total input errors */ - ulong_t si_opackets; /* # packets sent */ - ulong_t si_oerrors; /* # total output errors */ - - ulong_t si_txcoll; /* # xmit collisions */ - ulong_t si_rxcoll; /* # recv collisions */ - ulong_t si_crc; /* # recv crc errors */ - ulong_t si_buff; /* # recv pkt sz > buf sz */ - - ulong_t si_nolink; /* # loss of connection */ - ulong_t si_linkdown; /* # link is down */ - ulong_t si_inits; /* # driver inits */ - ulong_t si_nocanput; /* # canput() failures */ - - ulong_t si_allocbfail; /* # allocb() failures */ - ulong_t si_notbufs; /* # out of xmit buffers */ - ulong_t si_reclaim; /* # reclaim failures */ - ulong_t si_smraddr; /* # bad SMR addrs */ - - ulong_t si_txmax; /* # xmit over limit */ - ulong_t si_txfull; /* # xmit mbox full */ - ulong_t si_xdcall; /* # xdcalls sent */ - ulong_t si_sigsvr; /* # data server wakeups */ - - ulong_t si_mboxcrc; /* # send mbox crc errors */ - /* - * MIB II kstat variables - */ - ulong_t si_rcvbytes; /* # bytes received */ - ulong_t si_xmtbytes; /* # bytes transmitted */ - ulong_t si_multircv; /* # multicast packets received */ - - ulong_t si_multixmt; /* # multicast packets for xmit */ - ulong_t si_brdcstrcv; /* # broadcast packets received */ - ulong_t si_brdcstxmt; /* # broadcast packets for xmit */ - ulong_t si_norcvbuf; /* # rcv packets discarded */ - - ulong_t si_noxmtbuf; /* # xmit packets discarded */ - /* - * PSARC 1997/198 : 64 bit kstats - */ - uint64_t si_ipackets64; /* # packets received */ - uint64_t si_opackets64; /* # packets transmitted */ - uint64_t si_rbytes64; /* # bytes received */ - uint64_t si_obytes64; /* # bytes transmitted */ - /* - * PSARC 1997/247 : RFC 1643 dot3Stats... - */ - ulong_t si_fcs_errors; /* FCSErrors */ - ulong_t si_macxmt_errors; /* InternalMacTransmitErrors */ - ulong_t si_toolong_errors; /* FrameTooLongs */ - ulong_t si_macrcv_errors; /* InternalMacReceiveErrors */ -}; - -/* - * Per logical interface private data structure. - */ -struct idn { - struct idn *si_nextp; /* linked instances */ - dev_info_t *si_dip; /* assoc. dev_info */ - struct ether_addr si_ouraddr; /* enet address */ - - uint_t si_flags; /* misc. flags */ - uint_t si_wantw; /* xmit: out of res. */ - queue_t *si_ip4q; /* ip (v4) read queue */ - queue_t *si_ip6q; /* ip (v6) read queue */ - - kstat_t *si_ksp; /* kstat pointer */ - struct idn_kstat si_kstat; /* per-inst kstat */ -}; - -struct idn_gkstat { - ulong_t gk_reconfigs; /* # reconfigs */ - ulong_t gk_reconfig_last; /* timestamep */ - ulong_t gk_reaps; /* # of reap request */ - ulong_t gk_reap_last; /* timestamep */ - - ulong_t gk_links; /* # of IDN links */ - ulong_t gk_link_last; /* timestamep */ - ulong_t gk_unlinks; /* # of IDN unlinks */ - ulong_t gk_unlink_last; /* timestamep */ - - ulong_t gk_buffail; /* # bad bufalloc */ - ulong_t gk_buffail_last; /* timestamp */ - ulong_t gk_slabfail; /* # bad slaballoc */ - ulong_t gk_slabfail_last; /* timestamp */ - - ulong_t gk_reap_count; /* # of slabs reaped */ - ulong_t gk_dropped_intrs; /* dropped intrs */ -}; - -extern struct idn_gkstat sg_kstat; - -#ifdef IDN_NO_KSTAT - -#define IDN_KSTAT_INC(s, i) -#define IDN_KSTAT_ADD(s, i, n) -#define IDN_GKSTAT_INC(i) -#define IDN_GKSTAT_ADD(vvv, iii) -#define IDN_GKSTAT_GLOBAL_EVENT(vvv, nnn) - -#else /* IDN_NO_KSTAT */ - -#define IDN_KSTAT_INC(sss, vvv) \ - ((((struct idn *)(sss))->si_kstat.vvv)++) -#define IDN_KSTAT_ADD(sss, vvv, nnn) \ - ((((struct idn *)(sss))->si_kstat.vvv) += (nnn)) -#define IDN_GKSTAT_INC(vvv) ((sg_kstat.vvv)++) -#define IDN_GKSTAT_ADD(vvv, iii) ((sg_kstat.vvv) += (iii)) -#define IDN_GKSTAT_GLOBAL_EVENT(vvv, ttt) \ - ((sg_kstat.vvv)++, ((sg_kstat.ttt) = ddi_get_lbolt())) - -#endif /* IDN_NO_KSTAT */ - -/* - * idn.si_flags - */ -#define IDNRUNNING 0x01 /* IDNnet is UP */ -#define IDNPROMISC 0x02 /* promiscuous mode enabled */ -#define IDNSUSPENDED 0x04 /* suspended (DR) */ - -typedef struct kstat_named kstate_named_t; - -struct idn_kstat_named { - kstat_named_t sk_ipackets; /* # packets received */ - kstat_named_t sk_ierrors; /* # total input errors */ - kstat_named_t sk_opackets; /* # packets sent */ - kstat_named_t sk_oerrors; /* # total output errors */ - - kstat_named_t sk_txcoll; /* # xmit collisions */ - kstat_named_t sk_rxcoll; /* # recv collisions */ - kstat_named_t sk_crc; /* # recv crc errors */ - kstat_named_t sk_buff; /* # recv pkt sz > buf sz */ - - kstat_named_t sk_nolink; /* # loss of connection */ - kstat_named_t sk_linkdown; /* # link is down */ - kstat_named_t sk_inits; /* # driver inits */ - kstat_named_t sk_nocanput; /* # canput() failures */ - - kstat_named_t sk_allocbfail; /* # allocb() failures */ - kstat_named_t sk_notbufs; /* # out of xmit buffers */ - kstat_named_t sk_reclaim; /* # reclaim failures */ - kstat_named_t sk_smraddr; /* # bad SMR addrs */ - - kstat_named_t sk_txmax; /* # xmit over limit */ - kstat_named_t sk_txfull; /* # xmit mbox full */ - kstat_named_t sk_xdcall; /* # xdcalls sent */ - kstat_named_t sk_sigsvr; /* # data server wakeups */ - - kstat_named_t sk_mboxcrc; /* # send mbox crc errors */ - /* - * MIB II kstat variables - */ - kstat_named_t sk_rcvbytes; /* # bytes received */ - kstat_named_t sk_xmtbytes; /* # bytes transmitted */ - kstat_named_t sk_multircv; /* # multicast packets received */ - - kstat_named_t sk_multixmt; /* # multicast packets for xmit */ - kstat_named_t sk_brdcstrcv; /* # broadcast packets received */ - kstat_named_t sk_brdcstxmt; /* # broadcast packets for xmit */ - kstat_named_t sk_norcvbuf; /* # rcv packets discarded */ - - kstat_named_t sk_noxmtbuf; /* # xmit packets discarded */ - /* - * PSARC 1997/198 : 64bit kstats - */ - kstat_named_t sk_ipackets64; /* # packets received */ - kstat_named_t sk_opackets64; /* # packets transmitted */ - kstat_named_t sk_rbytes64; /* # bytes received */ - kstat_named_t sk_obytes64; /* # bytes transmitted */ - /* - * PSARC 1997/247 : RFC 1643 dot3Stats... - */ - kstat_named_t sk_fcs_errors; /* FCSErr */ - kstat_named_t sk_macxmt_errors; /* InternalMacXmtErr */ - kstat_named_t sk_toolong_errors; /* FrameTooLongs */ - kstat_named_t sk_macrcv_errors; /* InternalMacRcvErr */ -}; - -/* - * Stats for global events of interest (non-counters). - */ -struct idn_gkstat_named { - kstat_named_t sk_curtime; /* current time */ - kstat_named_t sk_reconfigs; /* # master recfgs */ - kstat_named_t sk_reconfig_last; /* timestamp */ - kstat_named_t sk_reaps; /* # of reap req */ - kstat_named_t sk_reap_last; /* timestamp */ - kstat_named_t sk_links; /* # of links */ - kstat_named_t sk_link_last; /* timestamp */ - kstat_named_t sk_unlinks; /* # of unlinks */ - kstat_named_t sk_unlink_last; /* timestamp */ - kstat_named_t sk_buffail; /* # bad buf alloc */ - kstat_named_t sk_buffail_last; /* timestamp */ - kstat_named_t sk_slabfail; /* # bad buf alloc */ - kstat_named_t sk_slabfail_last; /* timestamp */ - kstat_named_t sk_reap_count; /* # slabs reaped */ - kstat_named_t sk_dropped_intrs; /* intrs dropped */ -}; - -/* - * --------------------------------------------------------------------- - */ -#ifdef DEBUG -#define IDNXDC(d, mt, a1, a2, a3, a4) \ - ((void) debug_idnxdc("idnxdc", (int)(d), (mt), \ - (uint_t)(a1), (uint_t)(a2), (uint_t)(a3), (uint_t)(a4))) -#else /* DEBUG */ -#define IDNXDC(d, mt, a1, a2, a3, a4) \ - (idnxdc((int)(d), (mt), \ - (uint_t)(a1), (uint_t)(a2), (uint_t)(a3), (uint_t)(a4))) -#endif /* DEBUG */ -#define IDNXDC_BROADCAST(ds, mt, a1, a2, a3, a4) \ - (idnxdc_broadcast((domainset_t)(ds), (mt), \ - (uint_t)(a1), (uint_t)(a2), (uint_t)(a3), (uint_t)(a4))) - -/* - * --------------------------------------------------------------------- - */ -#define SET_XARGS(x, a0, a1, a2, a3) \ - ((x)[0] = (uint_t)(a0), (x)[1] = (uint_t)(a1), \ - (x)[2] = (uint_t)(a2), (x)[3] = (uint_t)(a3)) - -#define GET_XARGS(x, a0, a1, a2, a3) \ - ((*(uint_t *)(a0) = (x)[0]), \ - (*(uint_t *)(a1) = (x)[1]), \ - (*(uint_t *)(a2) = (x)[2]), \ - (*(uint_t *)(a3) = (x)[3])) - -#define CLR_XARGS(x) \ - ((x)[0] = (x)[1] = (x)[2] = (x)[3] = 0) - -#define GET_XARGS_NEGO_TICKET(x) ((uint_t)(x)[0]) -#define GET_XARGS_NEGO_DSET(x, d) \ - ((d)[0] = (x)[1], (d)[1] = (x)[2], (d)[2] = (x)[3]) -#define SET_XARGS_NEGO_TICKET(x, t) ((x)[0] = (uint_t)(t)) -#define SET_XARGS_NEGO_DSET(x, d) \ - ((x)[1] = (uint_t)(d)[0], \ - (x)[2] = (uint_t)(d)[1], \ - (x)[3] = (uint_t)(d)[2]) - -#define GET_XARGS_CON_TYPE(x) ((idn_con_t)(x)[0]) -#define GET_XARGS_CON_DOMSET(x) ((domainset_t)(x)[1]) -#define SET_XARGS_CON_TYPE(x, t) ((x)[0] = (uint_t)(t)) -#define SET_XARGS_CON_DOMSET(x, s) ((x)[1] = (uint_t)(s)) - -#define GET_XARGS_FIN_TYPE(x) GET_FIN_TYPE((x)[0]) -#define GET_XARGS_FIN_ARG(x) GET_FIN_ARG((x)[0]) -#define GET_XARGS_FIN_DOMSET(x) ((domainset_t)(x)[1]) -#define GET_XARGS_FIN_OPT(x) ((idn_finopt_t)(x)[2]) -#define GET_XARGS_FIN_MASTER(x) ((uint_t)(x)[3]) -#define SET_XARGS_FIN_TYPE(x, t) SET_FIN_TYPE((x)[0], (t)) -#define SET_XARGS_FIN_ARG(x, a) SET_FIN_ARG((x)[0], (a)) -#define SET_XARGS_FIN_DOMSET(x, s) ((x)[1] = (uint_t)(s)) -#define SET_XARGS_FIN_OPT(x, o) ((x)[2] = (uint_t)(o)) -#define SET_XARGS_FIN_MASTER(x, m) ((x)[3] = (uint_t)(m)) - -#define GET_XARGS_NACK_TYPE(x) ((idn_nack_t)(x)[0]) -#define GET_XARGS_NACK_ARG1(x) ((x)[1]) -#define GET_XARGS_NACK_ARG2(x) ((x)[2]) -#define SET_XARGS_NACK_TYPE(x, t) ((x)[0] = (uint_t)(t)) -#define SET_XARGS_NACK_ARG1(x, a1) ((x)[1] = (uint_t)(a1)) -#define SET_XARGS_NACK_ARG2(x, a2) ((x)[2] = (uint_t)(a2)) - -#define GET_XARGS_CFG_PHASE(x) ((int)(x)[0]) -#define SET_XARGS_CFG_PHASE(x, p) ((x)[0] = (uint_t)(p)) - -/* - * --------------------------------------------------------------------- - */ -/* - * Device instance to SIP (IDN instance pointer). - */ -#ifdef DEBUG -#define IDN_INST2SIP(i) \ - (ASSERT(((i) >= 0) && ((i) < (IDN_MAXMAX_NETS << 1))), \ - idn_i2s_table[i]) -#else /* DEBUG */ -#define IDN_INST2SIP(i) (idn_i2s_table[i]) -#endif /* DEBUG */ - -#define IDN_SET_INST2SIP(i, s) \ - { \ - ASSERT(((i) >= 0) && ((i) < (IDN_MAXMAX_NETS << 1))); \ - idn_i2s_table[i] = (s); \ - } - -#define IDN_NETID2DOMID(n) (VALID_UDOMAINID(n) ? \ - ((int)(n)) : IDN_NIL_DOMID) -#define IDN_DOMID2NETID(d) ((ushort_t)(d)) - -#ifdef DEBUG -#define IDNDL_ETHER2DOMAIN(eap) \ - (_idndl_ether2domain(eap)) -#define IDNDL_ETHER2SIP(eap) \ - (_idndl_ether2sip(eap)) -#else -/* - * The following values can be returned from IDNDL_ETHER2DOMAIN: - * IDN_NIL_DOMID - * Ether address is broadcast (0xff) or domain doesn't exist. - * domid Domain id with drwlock(reader) held. - */ -#define IDNDL_ETHER2DOMAIN(eap) \ - (IDN_NETID2DOMID((eap)->ether_addr_octet[IDNETHER_NETID])) -#define IDNDL_ETHER2SIP(eap) \ - (((eap)->ether_addr_octet[IDNETHER_CHANNEL] == 0xff) ? NULL : \ - IDN_INST2SIP((int)(eap)->ether_addr_octet[IDNETHER_CHANNEL])) -#endif /* DEBUG */ - -#define UPPER32_CPUMASK(s) _upper32cpumask(s) -#define LOWER32_CPUMASK(s) _lower32cpumask(s) -#define MAKE64_CPUMASK(s, u, l) _make64cpumask(&(s), (u), (l)) - -#ifdef DEBUG -extern caddr_t _idn_getstruct(char *structname, int size); -extern void _idn_freestruct(caddr_t ptr, char *structname, int size); - -#define GETSTRUCT(structure, num) \ - ((structure *)_idn_getstruct("structure", sizeof (structure)*(num))) -#define FREESTRUCT(ptr, structure, num) \ - (_idn_freestruct((caddr_t)ptr, "structure", sizeof (structure)*(num))) -#else /* DEBUG */ -#define GETSTRUCT(structure, num) \ - ((structure *)kmem_zalloc((uint_t)(sizeof (structure) * (num)), \ - KM_SLEEP)) -#define FREESTRUCT(ptr, structure, num) \ - (kmem_free((caddr_t)(ptr), sizeof (structure) * (num))) -#endif /* DEBUG */ - -extern int idn_debug; -extern idn_global_t idn; -extern idn_domain_t idn_domain[]; -extern struct idn *idn_i2s_table[]; -extern int idn_history; -extern struct idn_history idnhlog; - -extern int idn_smr_size; -extern int idn_nwr_size; -extern int idn_protocol_nservers; -extern int idn_awolmsg_interval; -extern int idn_smr_bufsize; -extern int idn_slab_bufcount; -extern int idn_slab_prealloc; -extern int idn_slab_mintotal; -extern int idn_window_max; -extern int idn_window_incr; -extern int idn_reclaim_min; -extern int idn_reclaim_max; -extern int idn_mbox_per_net; -extern int idn_max_nets; - -extern int idn_netsvr_spin_count; -extern int idn_netsvr_wait_min; -extern int idn_netsvr_wait_max; -extern int idn_netsvr_wait_shift; - -extern int idn_checksum; - -extern int idn_msgwait_nego; -extern int idn_msgwait_cfg; -extern int idn_msgwait_con; -extern int idn_msgwait_fin; -extern int idn_msgwait_cmd; -extern int idn_msgwait_data; - -extern int idn_retryfreq_nego; -extern int idn_retryfreq_con; -extern int idn_retryfreq_fin; - -extern int idn_window_emax; /* calculated */ -extern int idn_slab_maxperdomain; /* calculated */ - -/* - * --------------------------------------------------------------------- - * io/idn.c - * --------------------------------------------------------------------- - */ -extern int board_to_ready_cpu(int board, cpuset_t cpuset); -extern int idn_open_domain(int domid, int cpuid, uint_t ticket); -extern void idn_close_domain(int domid); -extern void inum2str(uint_t inum, char str[]); -extern idn_timer_t *idn_timer_alloc(); -extern void idn_timer_free(idn_timer_t *tp); -extern void idn_timerq_init(idn_timerq_t *tq); -extern void idn_timerq_deinit(idn_timerq_t *tq); -extern void idn_timerq_free(idn_timerq_t *tq); -extern ushort_t idn_timer_start(idn_timerq_t *tq, idn_timer_t *tp, - clock_t tval); -extern int idn_timer_stopall(idn_timer_t *tp); -extern void idn_timer_dequeue(idn_timerq_t *tq, idn_timer_t *tp); -extern void idn_timer_stop(idn_timerq_t *tq, int subtype, ushort_t tcookie); -extern idn_timer_t *idn_timer_get(idn_timerq_t *tq, int subtype, - ushort_t tcookie); -extern void idn_domain_resetentry(idn_domain_t *dp); -extern void idn_strlinks_enable(uint_t netaddr, int domid); -extern void idn_strlinks_disable(uint_t domset, uint_t netaddr, - int disconnect); -extern void idn_dopcache_init(); -extern void idn_dopcache_deinit(); -extern void *idn_init_op(idn_opflag_t opflag, boardset_t boardset, - idnsb_error_t *sep); -extern void idn_add_op(idn_opflag_t opflag, domainset_t domset); -extern void idn_update_op(idn_opflag_t opflag, domainset_t domset, - idnsb_error_t *sep); -extern void idn_deinit_op(void *cookie); -extern int idn_wait_op(void *cookie, boardset_t *domsetp, - int wait_timeout); -extern int idn_wakeup_op(boardset_t boardset, uint_t domset, - idn_opflag_t opflag, int error); -extern void idn_error_op(uint_t domset, boardset_t boardset, int error); -extern void cpuset2str(cpuset_t cset, char buffer[]); -extern void domainset2str(domainset_t dset, char buffer[]); -extern void boardset2str(boardset_t bset, char buffer[]); -extern void mask2str(uint_t mask, char buffer[], int maxnum); -extern int idnxdc(int domid, idn_msgtype_t *mtp, - uint_t arg1, uint_t arg2, - uint_t arg3, uint_t arg4); -extern void idnxdc_broadcast(domainset_t domset, idn_msgtype_t *mtp, - uint_t arg1, uint_t arg2, - uint_t arg3, uint_t arg4); -extern void idn_awol_event_set(boardset_t boardset); -extern void idn_awol_event_clear(boardset_t boardset); -#ifdef DEBUG -extern int debug_idnxdc(char *f, int domid, idn_msgtype_t *mtp, - uint_t arg1, uint_t arg2, - uint_t arg3, uint_t arg4); -#endif /* DEBUG */ -extern boardset_t cpuset2boardset(cpuset_t portset); -extern uint_t _upper32cpumask(cpuset_t cset); -extern uint_t _lower32cpumask(cpuset_t cset); -extern void _make64cpumask(cpuset_t *csetp, uint_t upper, uint_t lower); - -/* - * --------------------------------------------------------------------- - * io/idn_proto.c - * --------------------------------------------------------------------- - */ -extern void idn_assign_cookie(int domid); -extern int idn_rput_data(queue_t *q, mblk_t *mp, int isput); -extern int idn_wput_data(queue_t *q, mblk_t *mp, int isput); -extern int idn_send_data(int dst_domid, idn_netaddr_t dst_netaddr, - queue_t *wq, mblk_t *mp); -extern void idn_recv_signal(mblk_t *mp); -extern int idn_link(int domid, int cpuid, int pri, int waittime, - idnsb_error_t *sep); -extern int idn_unlink(int domid, boardset_t idnset, idn_fin_t fintype, - idn_finopt_t finopt, int waittime, - idnsb_error_t *sep); -extern int idnh_recv_dataack(int domid, int src_proc, - uint_t acknack, idn_xdcargs_t xargs); -extern int idnh_recv_other(int sourceid, int src_proc, int dst_proc, - uint_t inum, uint_t acknack, - idn_xdcargs_t xargs); -extern void idn_send_cmd(int domid, idn_cmd_t cmdtype, - uint_t arg1, uint_t arg2, uint_t arg3); -extern void idn_send_cmdresp(int domid, idn_msgtype_t *mtp, - idn_cmd_t cmdtype, uint_t arg1, - uint_t arg2, uint_t cerrno); -extern void idn_broadcast_cmd(idn_cmd_t cmdtype, - uint_t arg1, uint_t arg2, uint_t arg3); -extern int idn_reclaim_mboxdata(int domid, int channel, int nbufs); -extern void idn_clear_awol(int domid); -extern int idn_protocol_init(int nservers); -extern void idn_protocol_deinit(); -extern void idn_timer_expired(void *arg); -extern int idn_open_channel(int channel); -extern void idn_close_channel(int channel, idn_chanop_t chanop); -extern idn_mainmbox_t *idn_mainmbox_init(int domid, int mbx); -extern void idn_mainmbox_deinit(int domid, idn_mainmbox_t *mmp); -extern void idn_signal_data_server(int domid, ushort_t channel); -extern int idn_chanservers_init(); -extern void idn_chanservers_deinit(); -extern void idn_chanserver_bind(int net, int cpuid); -extern int idn_retry_terminate(uint_t token); -extern idn_protojob_t *idn_protojob_alloc(int kmflag); -extern void idn_protojob_submit(int cookie, idn_protojob_t *jp); -extern int idn_domain_is_registered(int domid, int channel, - idn_chanset_t *chansetp); -extern void idn_xmit_monitor_kickoff(int chan_wanted); -extern void idn_sync_exit(int domid, idn_synccmd_t cmd); -/* - * --------------------------------------------------------------------- - * io/idn_xf.c - * --------------------------------------------------------------------- - */ -extern void idnxf_flushall_ecache(); -extern int idnxf_shmem_add(int is_master, boardset_t boardset, - pfn_t pfnbase, pfn_t pfnlimit, - uint_t *mcadr); -extern int idnxf_shmem_sub(int is_master, boardset_t boardset); -extern int idn_cpu_per_board(void *p2o, cpuset_t cset, - struct hwconfig *hwp); -/* - * --------------------------------------------------------------------- - * io/idn_dlpi.c - * --------------------------------------------------------------------- - */ -extern int idndl_init(struct idn *sip); -extern void idndl_uninit(struct idn *sip); -extern void idndl_statinit(struct idn *sip); -extern void idndl_dodetach(struct idnstr *); -extern int idnioc_dlpi(queue_t *wq, mblk_t *mp, int *argsize); -extern void idndl_localetheraddr(struct idn *sip, struct ether_addr *eap); -extern int idndl_domain_etheraddr(int domid, int instance, - struct ether_addr *eap); -extern void idndl_dlpi_init(); -extern int idndl_start(queue_t *wq, mblk_t *mp, struct idn *sip); -extern void idndl_read(struct idn *sip, mblk_t *mp); -extern void idndl_proto(queue_t *wq, mblk_t *mp); -extern void idndl_sendup(struct idn *, mblk_t *, struct idnstr *(*)()); -extern struct idnstr *idndl_accept(struct idnstr *, struct idn *, int, - struct ether_addr *); -extern struct idnstr *idndl_paccept(struct idnstr *, struct idn *, int, - struct ether_addr *); -extern void idndl_wenable(struct idn *); -/* - * --------------------------------------------------------------------- - * io/idn_smr.c - * --------------------------------------------------------------------- - */ -extern void smr_slabwaiter_open(domainset_t domset); -extern void smr_slabwaiter_close(domainset_t domset); -/* - * --------------------------------------------------------------------- - */ -extern void idn_smrsize_init(); -extern void idn_init_autolink(); -extern void idn_deinit_autolink(); - -extern void idn_dmv_handler(void *arg); -extern void idnxf_init_mondo(uint64_t dmv_word0, - uint64_t dmv_word1, uint64_t dmv_word2); -extern int idnxf_send_mondo(int upaid); - -extern clock_t idn_msg_waittime[]; -extern clock_t idn_msg_retrytime[]; - -#endif /* !_ASM */ -#endif /* _KERNEL */ - -#ifndef _ASM -/* - * --------------------------------------------------------------------- - */ -#define IDN_NIL_DOMID -1 -#define IDN_NIL_DCPU -1 - -/* - * --------------------------------------------------------------------- - */ - -/* - * IOCTL Interface - * - * Commands must stay in the range (1 - 4096) since only 12 bits - * are allotted. - */ -#define _IDN(n) (('I' << 20) | ('D' << 12) | (n)) -#define IDNIOC_LINK _IDN(1) /* domain_link */ -#define IDNIOC_UNLINK _IDN(2) /* domain_unlink */ -#define IDNIOC_unused0 _IDN(3) -#define IDNIOC_unused1 _IDN(4) -#define IDNIOC_unused2 _IDN(5) -#define IDNIOC_unused3 _IDN(6) -#define IDNIOC_unused4 _IDN(7) -#define IDNIOC_DLPI_ON _IDN(8) /* Turn ON DLPI on str */ -#define IDNIOC_DLPI_OFF _IDN(9) /* Turn OFF DLPI on str */ -#define IDNIOC_PING _IDN(10) /* For latency testing */ -#define IDNIOC_PING_INIT _IDN(11) -#define IDNIOC_PING_DEINIT _IDN(12) -#define IDNIOC_MEM_RW _IDN(13) /* Random R/W of SMR */ - - -#define VALID_NDOP(op) (((op) == ND_SET) || ((op) == ND_GET)) - -#define VALID_DLPIOP(op) (((op) == DLIOCRAW) || \ - ((op) == DL_IOC_HDR_INFO)) - -#define VALID_IDNOP(op) (((op) >= _IDN(1)) && ((op) <= _IDN(13))) - -#define VALID_IDNIOCTL(op) (VALID_IDNOP(op) || \ - VALID_NDOP(op) || \ - VALID_DLPIOP(op)) - -typedef union idnop { - struct { - int domid; /* input */ - int cpuid; /* input */ - int master; /* input */ - int wait; /* input */ - } link; - struct { - int domid; /* input */ - int cpuid; /* input */ - int force; /* input */ - int wait; /* input */ - } unlink; - struct { - int domid; /* input */ - int cpuid; /* input */ - } ping; - struct { - uint_t lo_off; /* input */ - uint_t hi_off; /* input */ - int blksize; /* input */ - int num; /* input */ - int rw; /* input */ - int goawol; /* input */ - } rwmem; -} idnop_t; - -#ifdef _KERNEL -/* - * ndd support for IDN tunables. - */ -typedef struct idnparam { - ulong_t sp_min; - ulong_t sp_max; - ulong_t sp_val; - char *sp_name; -} idnparam_t; - -extern idnparam_t idn_param_arr[]; - -#define idn_modunloadable idn_param_arr[0].sp_val -#ifdef IDN_PERF -#define _LP 0 -#define _xxx_tbd idn_param_arr[_LP+1].sp_val -#endif /* IDN_PERF */ - -/* - * ===================================================================== - */ - -/* - * Some junk to pretty print board lists and cpu lists in - * log/console messages. Length is big enough to display 64 double - * digit cpus separated by a command and single space. (Board list - * is similar, but only 16 entries possible. - */ -#define _DSTRLEN 400 -#define ALLOC_DISPSTRING() ((char *)kmem_alloc(_DSTRLEN, KM_NOSLEEP)) -#define FREE_DISPSTRING(b) (kmem_free((void *)(b), _DSTRLEN)) - -/* - * These are declared in idn.c. - */ -extern const char *idnds_str[]; -extern const char *idnxs_str[]; -extern const char *idngs_str[]; -extern const char *idncmd_str[]; -extern const char *idncon_str[]; -extern const char *idnfin_str[]; -extern const char *idnfinarg_str[]; -extern const char *idnfinopt_str[]; -extern const char *idnreg_str[]; -extern const char *idnnack_str[]; -extern const char *idnop_str[]; -extern const char *idnsync_str[]; -extern const char *chanop_str[]; -extern const char *chanaction_str[]; -extern const char *inum_str[]; -extern const int inum_bump; -extern const int inum_max; -extern const int acknack_shift; - -extern const char *timer_str[]; -extern const char *res_str[]; - -#endif /* _KERNEL */ -#endif /* !_ASM */ - -#ifdef __cplusplus -} -#endif - -#endif /* _SYS_IDN_H */ diff --git a/usr/src/uts/sun4u/starfire/sys/idn_sigb.h b/usr/src/uts/sun4u/starfire/sys/idn_sigb.h deleted file mode 100644 index 9e1d256d9a..0000000000 --- a/usr/src/uts/sun4u/starfire/sys/idn_sigb.h +++ /dev/null @@ -1,401 +0,0 @@ -/* - * 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 - * or http://www.opensolaris.org/os/licensing. - * 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 (c) 1999-2000 by Sun Microsystems, Inc. - * All rights reserved. - * - * Inter-Domain Network Sigblock Interface. - * - * ****************************************************** - * ****************************************************** - * IMPORTANT: THE DEFINITIONS HERE ARE DUPLICATES OF - * THE cbe_idn_sigb.h FILE IN cbe/cbutils. - * ANY CHANGES THERE MUST BE RELECTED - * HERE AND VICE VERSA. WE CANNOT INCLUDE - * THIS HEADER IN THE BUILD OF CBE. - * ****************************************************** - * ****************************************************** - */ - -#ifndef _SYS_IDN_SIGB_H -#define _SYS_IDN_SIGB_H - -#pragma ident "%Z%%M% %I% %E% SMI" - -#include <sys/types.h> - -#ifdef __cplusplus -extern "C" { -#endif - -#ifdef _SSP -#include <domain_config.h> -#include <sigblock.h> -#define _MAX_DOMAINS MAX_DOMAINS_PER_MACH -#else /* _SSP */ -#include <sys/starfire.h> -#include <sys/cpu_sgnblk_defs.h> -#include <sys/cpu_sgn.h> -#define MAX_BOARDS STARFIRE_MAX_BOARDS -#define MAX_DOMAINS MAX_BOARDS -#define _MAX_DOMAINS MAX_DOMAINS -#endif /* _SSP */ - -#define SSI_LINK (('I' << 8) | 0x01) -#define SSI_UNLINK (('I' << 8) | 0x02) -#define SSI_INFO (('I' << 8) | 0x03) -#define SSI_ACK 0x10 - -#define VALID_IDNSIGBCMD(c) ((((c) & ~SSI_ACK) == SSI_LINK) || \ - (((c) & ~SSI_ACK) == SSI_UNLINK) || \ - (((c) & ~SSI_ACK) == SSI_INFO)) - -/* - * SSI_LINK - * timeout field must be first. - */ -typedef struct { - int32_t timeout; /* seconds */ - int32_t cpuid; - int32_t domid; - int32_t master_pri; -} idnsb_link_t; - - -/* - * SSI_UNLINK - * timeout field must be first. - * - * If both cpuid and domid are specified then they must match the - * correct domain from the local domain's perspective. The cpuid - * and/or domid have precedence over the boardset parameter. - * The boardset parameter is provided if the caller is unable to - * determine the cpuid/domid of the target domain. This may happen - * if the target domain is currently down. - * - * idnsb_unlink_t.force values. - */ -#define SSIFORCE_OFF 0 -#define SSIFORCE_SOFT 1 -#define SSIFORCE_HARD 2 - -typedef struct { - int32_t timeout; /* seconds */ - int32_t cpuid; - int32_t domid; - ushort_t boardset; - short force; - ushort_t idnset; -} idnsb_unlink_t; - - -/* - * SSI_INFO - * Assumes max of 16 boards/domain. - * - * idnsb_info_t.idn_active values. - */ -#define SSISTATE_INACTIVE 0 -#define SSISTATE_BUSY 1 -#define SSISTATE_ACTIVE 2 - -typedef struct { - ushort_t domain_boardset[_MAX_DOMAINS]; - uchar_t idn_active; - uchar_t idn_state; /* same as GSTATE */ - uchar_t local_index; - uchar_t local_cpuid; - uchar_t master_index; - uchar_t master_cpuid; - ushort_t awol_domset; - ushort_t conn_domset; - ushort_t _filler; -} idnsb_info_t; - -#define INIT_IDNKERR(ep) \ - (bzero((caddr_t)(ep), sizeof (idnsb_error_t))) -#define SET_IDNKERR_ERRNO(ep, err) ((ep)->k_errno = (int)(err)) -#define SET_IDNKERR_IDNERR(ep, err) ((ep)->k_idnerr = (int)(err)) -#define SET_IDNKERR_PARAM0(ep, p0) ((ep)->k_param[0] = (uint_t)(p0)) -#define SET_IDNKERR_PARAM1(ep, p1) ((ep)->k_param[1] = (uint_t)(p1)) -#define SET_IDNKERR_PARAM2(ep, p2) ((ep)->k_param[2] = (uint_t)(p2)) -#define GET_IDNKERR_ERRNO(ep) ((ep)->k_errno) -#define GET_IDNKERR_IDNERR(ep) ((ep)->k_idnerr) -#define GET_IDNKERR_PARAM0(ep) ((ep)->k_param[0]) -#define GET_IDNKERR_PARAM1(ep) ((ep)->k_param[1]) -#define GET_IDNKERR_PARAM2(ep) ((ep)->k_param[2]) - -#define IDNKERR_DRV_DISABLED 0x100 /* IDN driver disabled */ - /* param=none */ -#define IDNKERR_DATA_LEN 0x101 /* invalid length of idnsb_data_t */ - /* p0=length */ -#define IDNKERR_INFO_FAILED 0x102 /* SSI_INFO failed */ - /* param=none */ -#define IDNKERR_INVALID_DOMAIN 0x103 /* invalid domain specified */ - /* p0=domid, p1=cpuid */ -#define IDNKERR_INVALID_FORCE 0x104 /* invalid force option specified */ - /* p0=force */ -#define IDNKERR_INVALID_CMD 0x105 /* invalid IDN/SSI command req */ - /* p0=cmd */ -#define IDNKERR_INVALID_WTIME 0x106 /* invalid waittime specified */ - /* p0=waittime */ -#define IDNKERR_SMR_CORRUPTED 0x107 /* SMR memory is corrupted */ - /* p0=domid (against who detected) */ -#define IDNKERR_CPU_CONFIG 0x108 /* missing a cpu per board */ - /* p0=domid */ -#define IDNKERR_HW_ERROR 0x109 /* error programming hardware */ - /* p0=domid */ -#define IDNKERR_SIGBINTR_LOCKED 0x10a /* sigbintr is locked */ -#define IDNKERR_SIGBINTR_BUSY 0x10b /* sigbintr is busy working */ -#define IDNKERR_SIGBINTR_NOTRDY 0x10c /* sigbintr thread not ready */ -#define IDNKERR_CONFIG_FATAL 0x10d /* fatal error during config */ -#define IDNKERR_CONFIG_MULTIPLE 0x10e /* multiple config conflicts */ - /* p0=domid, p1=count */ - /* - * For all CONFIG errors: - * p0=domid, p1=expected, p2=actual. - */ -#define IDNKERR_CONFIG_MTU 0x10f /* MTU configs conflict */ -#define IDNKERR_CONFIG_BUF 0x110 /* SMR_BUF_SIZE conflicts */ -#define IDNKERR_CONFIG_SLAB 0x111 /* slab-size conflicts */ -#define IDNKERR_CONFIG_NWR 0x112 /* NWR sizes conflict */ -#define IDNKERR_CONFIG_NETS 0x113 /* MAX_NETS conflict */ -#define IDNKERR_CONFIG_MBOX 0x114 /* MBOX_PER_NETS conflict */ -#define IDNKERR_CONFIG_NMCADR 0x115 /* Number of MCADRS conflicts */ -#define IDNKERR_CONFIG_MCADR 0x116 /* Missing MCADR */ -#define IDNKERR_CONFIG_CKSUM 0x117 /* checksum setting conflicts */ -#define IDNKERR_CONFIG_SMR 0x118 /* master's SMR too large */ - -typedef struct { - int k_errno; - int k_idnerr; - uint_t k_param[3]; -} idnsb_error_t; - -typedef struct { - union { - int _ssb_timeout; /* link & unlink only (secs) */ - idnsb_link_t _ssb_link; - idnsb_unlink_t _ssb_unlink; - idnsb_info_t _ssb_info; - } _u; - idnsb_error_t ssb_error; -} idnsb_data_t; - -#define ssb_timeout _u._ssb_timeout -#define ssb_link _u._ssb_link -#define ssb_unlink _u._ssb_unlink -#define ssb_info _u._ssb_info - - -/* - * Boot information set by IDN driver when loaded. - * SSIEVENT_BOOT Indicates IDN driver is ready for linking. - * If this nibble is cleared (0) it - * indicates domain has halted. - * SSIEVENT_AWOL Indicates local IDN has reported - * some domains (boards) have gone AWOL. - * (event_handled) is primarily used by SSP/CB applications for - * synchronization with respect to handling event triggered in (event). - * The respective bits from (event) are set in (event_handled) - * when the event has been successfully processed by IDNevent(SSP). - * It is cleared by CBE based TCL scripts (mon_signatures.tcl, idn.tcl) - * when event is detected and needs processing. - * SSIEVENT_VERSION represents the version of the SSP side of - * the IDN software. While idnsb_event_t.version represents the - * version of the OS side of the IDN software. - * - * Protocol: Host SSP - * ---- --- - * event - * - 1 -> evt[].e_handled - * - X -> evt[].e_event - * - Y -> evt[].e_event_data - * - 0 -> evt[].e_handled - * (!evt[].e_handled) - * ...process(evt[].e_event) - * - evt[].e_handled_data = - * evt[].e_event_data - * - evt[].e_handled = 1 - */ -#define SSIEVENT_COOKIE "IDN" -#define SSIEVENT_COOKIE_LEN 3 -#define SSIEVENT_VERSION 1 - -#define SSIEVENT_BOOT 0 /* index to evt[] */ -#define _SSIEVENT_BOOT_VAL 0xb -#define _SSIEVENT_BOOT_SHIFT (SSIEVENT_BOOT << 2) -#define _SSIEVENT_BOOT_MASK (_SSIEVENT_BOOT_VAL << _SSIEVENT_BOOT_SHIFT) - -#define SSIEVENT_AWOL 1 -#define _SSIEVENT_AWOL_VAL 0xa -#define _SSIEVENT_AWOL_SHIFT (SSIEVENT_AWOL << 2) -#define _SSIEVENT_AWOL_MASK (_SSIEVENT_AWOL_VAL << _SSIEVENT_AWOL_SHIFT) - -#define SSIEVENT_NUM 2 /* actual max simultaneous events */ -#define SSIEVENT_MAXNUM 3 /* last one in reserve */ - -#define _SSIEVENT_VALUE(i) \ - ((i == 0) ? _SSIEVENT_BOOT_VAL : ((i == 1) ? _SSIEVENT_AWOL_VAL : 0)) - -#define _SSIEVENT_MASKS(i) \ - ((i == 0) ? _SSIEVENT_BOOT_MASK : ((i == 1) ? _SSIEVENT_AWOL_MASK : 0)) -/* - * Get a bitmask of the current "state". - */ -#define SSIEVENT_GET_STATE_MASK(s) \ - (((s).idn_evt[SSIEVENT_BOOT].e_event ? _SSIEVENT_BOOT_MASK : 0) \ - | ((s).idn_evt[SSIEVENT_AWOL].e_event ? _SSIEVENT_AWOL_MASK : 0)) - -#define SSIEVENT_GET_STATE(s, e) \ - ((s).idn_evt[e].e_event ? _SSIEVENT_VALUE(e) : 0) -#define SSIEVENT_CLR_STATE(s, e) \ - ((s).idn_evt[e].e_event = 0) -#define SSIEVENT_SET_STATE(s, e) \ - ((s).idn_evt[e].e_event = _SSIEVENT_VALUE(e)) - -/* - * Get a bitmask of the currently handled states. - */ -#define SSIEVENT_GET_HANDLED_MASK(s) \ - (((s).idn_evt[SSIEVENT_BOOT].e_handled ? _SSIEVENT_BOOT_MASK : 0) \ - | ((s).idn_evt[SSIEVENT_AWOL].e_handled ? _SSIEVENT_AWOL_MASK : 0)) - -#define SSIEVENT_GET_HANDLED(s, e) \ - ((s).idn_evt[e].e_handled ? _SSIEVENT_VALUE(e) : 0) -#define SSIEVENT_CLR_HANDLED(s, e) \ - ((s).idn_evt[e].e_handled = 0) -#define SSIEVENT_SET_HANDLED(s, e) \ - ((s).idn_evt[e].e_handled = _SSIEVENT_VALUE(e)) -#define SSIEVENT_SET_HANDLED_DATA(s, e, d) \ - ((s).idn_evt[e].e_handled_data = (ushort_t)(d)) -#define SSIEVENT_GET_HANDLED_EVT(i, e) \ - ((i).e_handled ? _SSIEVENT_VALUE(e) : 0) -#define SSIEVENT_CLR_HANDLED_EVT(i) ((i).e_handled = 0) -#define SSIEVENT_SET_HANDLED_EVT(i, e) ((i).e_handled = _SSIEVENT_VALUE(e)) - -/* - * Check for the state of a particular event within a state bitmask. - */ -#define SSIEVENT_CHK_STATE_MASK(m, e) \ - ((((m) & (0xf << ((e) << 2))) == _SSIEVENT_MASKS(e)) ? 1 : 0) -#define SSIEVENT_CHK_HANDLED_MASK(m, e) SSIEVENT_CHK_STATE_MASK((m), (e)) - -/* - * Build the state mask managed in the cbe to represent the state - * of the respective events above. - */ -#define SSIEVENT_DEL_STATE_MASK(m, e) ((m) &= ~(0xf << ((e) << 2))) -#define SSIEVENT_ADD_STATE_MASK(m, e) \ - (SSIEVENT_DEL_STATE_MASK((m), (e)), \ - ((m) |= _SSIEVENT_MASKS(e))) -#define SSIEVENT_STATE_MASK (_SSIEVENT_BOOT_MASK | _SSIEVENT_AWOL_MASK) -#define SSIEVENT_STATE_NIL 0 - -#ifdef _KERNEL -#define SSIEVENT_SET(s, e, d) { \ - SSIEVENT_SET_HANDLED(*(s), (e)); \ - membar_stst_stld(); \ - SSIEVENT_SET_STATE(*(s), (e)); \ - (s)->idn_evt[e].e_event_data = (ushort_t)(d); \ - membar_stst_stld(); \ - SSIEVENT_CLR_HANDLED(*(s), (e)); \ -} -#define SSIEVENT_CLEAR(s, e, d) { \ - SSIEVENT_SET_HANDLED(*(s), (e)); \ - membar_stst_stld(); \ - SSIEVENT_CLR_STATE(*(s), (e)); \ - (s)->idn_evt[e].e_event_data &= (ushort_t)~(d); \ - membar_stst_stld(); \ - SSIEVENT_CLR_HANDLED(*(s), (e)); \ -} -#define SSIEVENT_ADD(s, e, d) { \ - SSIEVENT_SET_HANDLED(*(s), (e)); \ - membar_stst_stld(); \ - SSIEVENT_SET_STATE(*(s), (e)); \ - (s)->idn_evt[e].e_event_data |= (ushort_t)(d); \ - membar_stst_stld(); \ - SSIEVENT_CLR_HANDLED(*(s), (e)); \ -} -#define SSIEVENT_DEL(s, e, d) { \ - SSIEVENT_SET_HANDLED(*(s), (e)); \ - membar_stst_stld(); \ - (s)->idn_evt[e].e_event_data &= (ushort_t)~(d); \ - if ((s)->idn_evt[e].e_event_data != 0) { \ - SSIEVENT_SET_STATE(*(s), (e)); \ - membar_stst_stld(); \ - SSIEVENT_CLR_HANDLED(*(s), (e)); \ - } else { \ - membar_stst_stld(); \ - SSIEVENT_CLR_STATE(*(s), (e)); \ - } \ -} -#endif /* _KERNEL */ - -typedef struct idnevent { - uchar_t e_event; - uchar_t e_handled; - ushort_t e_event_data; - ushort_t e_handled_data; - ushort_t reserved; -} idnevent_t; - -/* - * IMPORTANT: This data structure must be the size of a sigbmbox_t - * so that it fits in the space it steals in the sigblock. - * Also, any changes to this structure must be cross-checked - * with (struct idnsb) in <sun4u1/sys/idn.h> with respect - * the area from reserved1 on down. - */ -#define IDNSB_EVENT_SIZE (sizeof (sigbmbox_t)) -typedef struct { - struct _idnsb_event { - union { - struct { - char _cookie[SSIEVENT_COOKIE_LEN]; - uchar_t _version; - } _ss; - struct { - uint_t _cookie : 24; - uint_t _version : 8; - } _sn; - } _u; - uint_t _reserved1; /* reserved for IDN driver */ - idnevent_t _evt[SSIEVENT_MAXNUM]; - } _s; - - /* reserved for IDN driver */ - char reserved2[IDNSB_EVENT_SIZE - sizeof (struct _idnsb_event)]; -} idnsb_event_t; - -#define idn_evt _s._evt -#define idn_reserved1 _s._reserved1 -#define idn_cookie_str _s._u._ss._cookie -#define idn_version_byte _s._u._ss._version -#define idn_cookie _s._u._sn._cookie -#define idn_version _s._u._sn._version - -#ifdef __cplusplus -} -#endif - -#endif /* _SYS_IDN_SIGB_H */ diff --git a/usr/src/uts/sun4u/starfire/sys/idn_smr.h b/usr/src/uts/sun4u/starfire/sys/idn_smr.h deleted file mode 100644 index 8a0e4cddb2..0000000000 --- a/usr/src/uts/sun4u/starfire/sys/idn_smr.h +++ /dev/null @@ -1,230 +0,0 @@ -/* - * 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 - * or http://www.opensolaris.org/os/licensing. - * 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 (c) 1999 by Sun Microsystems, Inc. - * All rights reserved. - * - * Inter-Domain Network - SMR support. - */ - -#ifndef _SYS_IDN_SMR_H -#define _SYS_IDN_SMR_H - -#include <sys/sysmacros.h> - -#ifdef __cplusplus -extern "C" { -#endif - -typedef uint_t smr_offset_t; - -#define IDN_NIL_SMROFFSET ((smr_offset_t)-1) - -/* - * --------------------------------------------------------------------- - * Data in the SMR is automatically aligned on 64 byte boundaries due - * to the large IDN_SMR_BUFSIZE, however the streams buffers may not be - * so we bump them in order to allow us to align appropriately and thus - * maximize bcopy performance. - * --------------------------------------------------------------------- - */ -#define IDN_ALIGNSIZE 64 -/* - * Align the pointer "p" to the same relative offset as the reference - * pointer "r" within IDN_ALIGNSIZE bytes. - */ -#define IDN_ALIGNPTR(p, r) ((uintptr_t)(p) + (((uintptr_t)(r) - \ - (uintptr_t)(p)) & \ - (uintptr_t)(IDN_ALIGNSIZE - 1))) - -#define IDN_OFFSET2ADDR(off) ((caddr_t)((uintptr_t)(off) + \ - (uintptr_t)idn.smr.vaddr)) -#define IDN_ADDR2OFFSET(va) ((smr_offset_t)((caddr_t)(va) - idn.smr.vaddr)) -#define IDN_BUF2DATA(b, o) ((caddr_t)((uintptr_t)(b) + (uintptr_t)(o))) -#define IDN_BUF2HDR(b) ((smr_pkthdr_t *)(b)) - -#define IDN_CKSUM_PKT_COUNT (offsetof(smr_pkthdr_t, b_cksum) / 2) - -#define IDN_CKSUM_PKT(h) \ - (IDN_CHECKSUM ? \ - idn_cksum((ushort_t *)(h), IDN_CKSUM_PKT_COUNT) : 0) - -typedef struct smr_pkthdr { - uint_t b_netaddr; - uint_t b_netports; - smr_offset_t b_offset; - int b_length; - - ushort_t b_rawio; - ushort_t b_cksum; - smr_offset_t b_next; /* used during reclamation */ -} smr_pkthdr_t; - -/* - * --------------------------------------------------------------------- - * IDN Slab related definitions. - * - * Domains are allocated SMR buffers in slabs. Slaves keep track of - * their own slabs in their respective idn_domain entry. The Master - * keeps track of slave slabs via their respective idn_domain entry. - * The global slab pools representing all of the SMR and managed by - * the master are maintained in the idn_global structure. - * - * The minimum number of slabs is chosen so that there is at least - * one slab available for every possible domain that might be attached. - * - * NOTE: idn_slab_bufcount * idn_smr_bufsize should be on a 64-byte - * (IDN_ALIGNSIZE) boundary for maximum bcopy performance. - * --------------------------------------------------------------------- - */ -#define IDN_SLAB_BUFCOUNT idn_slab_bufcount -#define IDN_SLAB_SIZE (IDN_SLAB_BUFCOUNT * IDN_SMR_BUFSIZE) -#define IDN_SLAB_MAXNUM (idn.slabpool->ntotslabs) -#define IDN_SLAB_MINPERPOOL 3 -#define IDN_SLAB_MINTOTAL idn_slab_mintotal -#define IDN_SLAB_PREALLOC idn_slab_prealloc - -/* - * --------------------------------------------------------------------- - * Maximum number of slabs per domain the master will - * allow to be allocated. Further requests simply result - * in a failed allocation. - * Nominal value is 1/6 of the total available (~10). - * Maximum number of bufs a domain can expect based on - * IDN_SLAB_MAXPERDOMAIN. - * --------------------------------------------------------------------- - */ -#define IDN_SLAB_MAXPERDOMAIN idn_slab_maxperdomain -#define IDN_BUF_MAXPERDOMAIN (IDN_SLAB_MAXPERDOMAIN * IDN_SLAB_BUFCOUNT) -/* - * --------------------------------------------------------------------- - * If the total number of available slabs managed by the master - * goes below this minimum total threshold, then the master kicks - * off a reap request to all domains to check for free slabs and - * to give them up. For performance reasons, domains do not - * automatically flush out free slabs. They rely on the master - * to tell them to look for some. - * --------------------------------------------------------------------- - */ -#define IDN_SLAB_THRESHOLD MIN(MAX_DOMAINS, \ - (IDN_SLAB_MINTOTAL + \ - (IDN_SLAB_MINTOTAL / 5))) -#define IDN_REAP_INTERVAL (2 * hz) - -#define SMR_SLABPOOL_HASH(d) ((d) % idn.slabpool->npools) -#define SMR_SLABPOOL_HASHSTEP(p) (((p)+4) % idn.slabpool->npools) -#define SMR_SLAB_HASH(p, d) \ - ((d) % idn.slabpool->pool[p].nslabs) -#define SMR_SLAB_HASHSTEP(p, s) \ - (((s)+1) % idn.slabpool->pool[p].nslabs) - -/* - * --------------------------------------------------------------------- - * There is one smr_slabbuf for each buffer in the respective slab. - * - * sb_domid Domainid currently owning respective buffer. - * Local domains use this field to determine what buffers - * are outstanding at which domains. The master uses this - * field to know which domain owns given slab. - * sb_bufp Actual pointer to (VA) buffer. - * sb_next Used to manage free and in-use lists. - * --------------------------------------------------------------------- - */ -typedef struct smr_slabbuf { - int sb_domid; - caddr_t sb_bufp; - struct smr_slabbuf *sb_next; -} smr_slabbuf_t; - -/* - * --------------------------------------------------------------------- - * There is one smr_slab per slab of buffers. - * - * sl_next List of slabs allocated to same requester. - * sl_start Base virtual address (SMR) of slab. - * sl_end Points to byte immediately following end of slab. - * sl_lock Atomic lock used to manage free/inuse lists. - * sl_domid Used by Master to indicate which slave owns - * respective slab. - * sl_free Freelist of available buffers. - * sl_inuse List of buffers currently allocated and in-use. - * sl_head Pointer to memory allocated to hold smr_slabbuf_t's. - * --------------------------------------------------------------------- - */ -typedef struct smr_slab { - struct smr_slab *sl_next; - caddr_t sl_start, - sl_end; - lock_t sl_lock; - - union { - int _sl_domid; - struct { - smr_slabbuf_t *_sl_free; - smr_slabbuf_t *_sl_inuse; - smr_slabbuf_t *_sl_head; - } _s; - } _u; -} smr_slab_t; - -#define sl_domid _u._sl_domid -#define sl_free _u._s._sl_free -#define sl_inuse _u._s._sl_inuse -#define sl_head _u._s._sl_head - -/* - * --------------------------------------------------------------------- - * io/idn_smr.c - * --------------------------------------------------------------------- - */ -extern void smr_slab_reap(int domid, int *nslabs); -extern int smr_slab_alloc(int domid, smr_slab_t **spp); -extern void smr_slab_free(int domid, smr_slab_t *sp); -extern void smr_slab_garbage_collection(smr_slab_t *sp); -extern int smr_slab_busy(smr_slab_t *sp); -extern int smr_buf_alloc(int domid, uint_t len, caddr_t *bufpp); -extern int smr_buf_free(int domid, caddr_t bufp, uint_t len); -extern int smr_buf_free_locked(int domid, caddr_t bufp, uint_t len); -extern int smr_buf_free_all(int domid); -extern int smr_buf_reclaim(int domid, int nbufs); -extern int smr_slaballoc_put(int domid, smr_slab_t *sp, int forceflag, - int serrno); -extern void smr_alloc_buflist(smr_slab_t *sp); -extern void smr_free_buflist(smr_slab_t *sp); -extern int smr_slabwaiter_init(); -extern void smr_slabwaiter_deinit(); -extern int smr_slabwaiter_abort(int domid, int serrno); -extern smr_slab_t *smr_slaballoc_get(int domid, caddr_t bufp, - caddr_t ebufp); -extern int smr_slabpool_init(size_t reserved_size, - caddr_t *reserved_area); -extern void smr_slabpool_deinit(); -extern void smr_remap(struct as *as, register caddr_t vaddr, - register pfn_t new_pfn, uint_t mblen); - -extern int idn_slab_prealloc; - -#ifdef __cplusplus -} -#endif - -#endif /* _SYS_IDN_SMR_H */ diff --git a/usr/src/uts/sun4u/starfire/sys/idn_xf.h b/usr/src/uts/sun4u/starfire/sys/idn_xf.h deleted file mode 100644 index e23b9005d3..0000000000 --- a/usr/src/uts/sun4u/starfire/sys/idn_xf.h +++ /dev/null @@ -1,133 +0,0 @@ -/* - * 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 - * or http://www.opensolaris.org/os/licensing. - * 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 (c) 1999 by Sun Microsystems, Inc. - * All rights reserved. - * - * Inter-Domain Network - Xfire specifics. - */ - -#ifndef _SYS_IDN_XF_H -#define _SYS_IDN_XF_H - -#pragma ident "%Z%%M% %I% %E% SMI" - -#include <sys/pda.h> -#include <sys/cpu_sgnblk_defs.h> -#include <sys/idn_sigb.h> -#include <sys/starfire.h> - -#include <sys/idn.h> - -#ifdef __cplusplus -extern "C" { -#endif - -/* - * These address bits fit into PA[17:9]. - */ -#define CIC_CONFIG0_ADDR 0x002 -#define CIC_CONFIG1_ADDR 0x003 -#define CIC_DOMAIN_MASK_ADDR 0x004 -#define CIC_SM_MASK_ADDR 0x005 -#define CIC_SM_BAR_LSB_ADDR 0x006 -#define CIC_SM_BAR_MSB_ADDR 0x007 -#define CIC_SM_LAR_LSB_ADDR 0x008 -#define CIC_SM_LAR_MSB_ADDR 0x009 - -#define CIC_CONFIG0_BUSMODE_MASK 0x3 -#define CIC_CONFIG0_BUSMODE_SHIFT 2 -#define CIC_CONFIG0_BUSMODE(c) \ - (((c) >> CIC_CONFIG0_BUSMODE_SHIFT) & CIC_CONFIG0_BUSMODE_MASK) -#define CIC_CONFIG1_SMMASK_MASK 0x1 -#define CIC_CONFIG1_SMMASK_SHIFT 1 -#define CIC_CONFIG1_SMMASK_BIT(c) \ - (((c) >> CIC_CONFIG1_SMMASK_SHIFT) & CIC_CONFIG1_SMMASK_MASK) - -#define CIC_CSR_ADDR_MASK 0x1ff -#define CIC_CSR_ADDR_SHIFT 9 -#define CSR_TYPE_CIC 0xe - -#define CSR_BOARD_MASK 0xf /* PA[39:36] */ -#define CSR_BOARD_SHIFT 36 - -#define CSR_TYPE_MASK 0xf /* PA[35:32] */ -#define CSR_TYPE_SHIFT 32 - -#define CSR_BUS_MASK 0x3 -#define CSR_BUS_SHIFT 6 /* XXX - depends on config/shuffle */ - - /* bd=board, t=type, a=addr, bs=bus */ -#define MAKE_CIC_CSR_PA(bd, t, a, bs) \ - (((u_longlong_t)1 << 40) \ - | ((u_longlong_t)((bd) & CSR_BOARD_MASK) \ - << CSR_BOARD_SHIFT) \ - | ((u_longlong_t)((t) & CSR_TYPE_MASK) \ - << CSR_TYPE_SHIFT) \ - | ((u_longlong_t)((a) & CIC_CSR_ADDR_MASK) \ - << CIC_CSR_ADDR_SHIFT) \ - | ((u_longlong_t)((bs) & CSR_BUS_MASK) \ - << CSR_BUS_SHIFT)) - -#define STARFIRE_PC_MADR_VALIDBIT 0x80000000 - -/* - * Macro to calculate address of CIC prep buffer - * that resides in PC. - * This macro really belongs in <sys/starfire.h> - */ -#define STARFIRE_PC_CICBUF_ADDR(bb, p) \ - (STARFIRE_BRD_TO_PSI(bb) | \ - ((uint64_t)(p) << STARFIRE_UPS_MID_SHIFT) | \ - STARFIRE_PSI_PCREG_OFF | \ - STARFIRE_PC_CIC_WRITE_DATA) - -/* - * --------------------------------------------------------------------- - */ - -extern cpu_t cpu0; - -extern int get_hw_config(struct hwconfig *loc_hw); -extern int update_local_hw_config(idn_domain_t *ldp, - struct hwconfig *loc_hw); -extern boardset_t cic_read_domain_mask(int board, int bus); -extern boardset_t cic_read_sm_mask(int board, int bus); -extern uint_t cic_read_sm_bar(int board, int bus); -extern uint_t cic_read_sm_lar(int board, int bus); -extern void pc_read_madr(pda_handle_t ph, int lboard, - uint_t mc_adr[], int local_only); -extern void mc_get_adr_all(pda_handle_t ph, uint_t mc_adr[], - int *nmcadr); -extern int post2obp_valid(post2obp_info_t *p2o); - -extern uint_t xf_physio_rdword(u_longlong_t physaddr); -extern void xf_physio_wrword(u_longlong_t physaddr, uint_t value); -extern ushort_t xf_physio_rdhword(u_longlong_t physaddr); -extern void xf_physio_wrhword(u_longlong_t physaddr, ushort_t value); - - -#ifdef __cplusplus -} -#endif - -#endif /* _SYS_IDN_XF_H */ diff --git a/usr/src/uts/sun4u/starfire/sys/pda.h b/usr/src/uts/sun4u/starfire/sys/pda.h deleted file mode 100644 index 0725f45347..0000000000 --- a/usr/src/uts/sun4u/starfire/sys/pda.h +++ /dev/null @@ -1,226 +0,0 @@ -/* - * 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 - * or http://www.opensolaris.org/os/licensing. - * 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 1998-2003 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -#ifndef _SYS_PDA_H -#define _SYS_PDA_H - -#pragma ident "%Z%%M% %I% %E% SMI" - -#ifdef __cplusplus -extern "C" { -#endif - -#include <sys/types.h> - -/* - * Contains definitions used for PDA (Post Descriptor Array) [post2obp] - * support. - * - * XXX - These data structures is defined in SSP-land in: - * src/post/export/xf_postif.h. It is not anticipated - * that any future changes will be made to this data - * structure so we'll allow this hack on this go around. - */ - -#define MAX_ABUSES 4 /* Address buses */ -#define MAX_DBUSES 2 /* Data buses */ - -#define MAX_SYSBDS 16 /* no more than 16 system boards */ -#define MAX_PROCMODS 4 /* Per system board */ -#define MAX_PC 3 /* Per system board */ -#define MAX_XDB 4 /* Per system board */ -#define MAX_CIC 4 /* Per system board */ -#define MAX_MGROUPS 4 /* Per MC and system board */ -#define MAX_IOCS 2 /* Per system board */ -#define MAX_SLOTS_PER_IOC 4 /* Per ioc */ - -typedef struct { - ushort_t bda_board; /* BDAN 0|Anyred|mem|Board */ - ushort_t bda_proc; /* BDAN Processor 3:0 */ - ushort_t bda_pc; /* BDAN PC asic 2:0 */ - ushort_t bda_xdb; /* BDAN XDB asic 3:0 */ - ushort_t bda_cic; /* BDAN CIC asic 3:0 */ - ushort_t bda_ldpath; /* BDAN 0|0| ldpath [dbus] */ - ushort_t bda_ioc; /* BDAN 0|0| ioc 1:0 */ - ushort_t bda_ios[MAX_IOCS]; /* BDAN Scard 3:0 */ - ushort_t bda_mgroup; /* BDAN memory group 3:0 */ -} board_desc_t; - -typedef struct { - ushort_t bada_proc [MAX_PROCMODS]; /* Extra status on procs */ - uchar_t bada_iom_type; /* I/O module type. */ - uchar_t bada_fill[3]; - ushort_t bada_ioc[MAX_IOCS]; /* Extra status on iocs */ -} board_auxdesc_t; - -/* - * The three lsb of bada_proc holds the ecache size of that proc - * module, as (log-base-2 - 19), so 1/2 MB is 0, 1 MB is 1, ... - * 32 MB is 6. 7 is a bogus value. - */ -#define BADA_PROC_GET_ECL2M19(bada_proc) ((bada_proc) & 0x7) - -typedef struct { - uint32_t bmda_adr; /* MC ADR */ - uint32_t bmda_gab_bank_sel; /* MC gab bank sel reg */ - ushort_t bmda_bank_setup; /* MC gab bank setup reg */ - ushort_t bmda_filler; - int32_t bmda_badpage[MAX_MGROUPS]; - /* - * One bad page offset per - * mgroup is allowed. No - * bad page if < 0. - */ -} board_mdesc_t; - -/* - * BDA nibble status definitions: - * These are ordered in terms of preserving interesting information - * in POST displays where all configurations are displayed in a - * single value. The highest value for a resource over all - * configurations is shown. - * Of course, this is just for help to engineers/technicians in - * understanding what happened; for the most part, everything - * except "GOOD" is just different flavors of "BAD". - * Note the special macro SET_BDA_NBL_CRUNCH below which requires - * that BDAN_CRUNCH be 0. - */ -#define BDAN_CRUNCH 0x0 /* Unusable by implication */ -#define BDAN_UNDEFINED 0x1 /* Architecturally Missing */ -#define BDAN_MISS 0x2 /* Missing */ -#define BDAN_FAIL 0x3 /* Tested and failed */ -#define BDAN_BLACK 0x4 /* Blacklisted */ -#define BDAN_RED 0x5 /* Redlisted */ -#define BDAN_EXCLUDED 0x6 /* Board is not in this domain */ -#define BDAN_UNCONFIG 0x7 /* Good, but not in config. */ -#define BDAN_GOOD 0x8 /* Like it says. */ -#define BDAN_MASK 0xF - - -/* Macros for accessing BDA nibbles */ -#define BDA_NBL(shrt, nibix) \ - (((shrt) >> ((nibix) << 2)) & BDAN_MASK) -#define SET_BDA_NBL(shrt, nibix, val) \ -{ \ - shrt &= ~(BDAN_MASK << ((nibix) << 2)); \ - shrt |= (val) << ((nibix) << 2); \ -} - -/* - * This exists to keep lint from complaining about statements with - * null efect when we OR in a constant 0 in SET_BDA_NBL. It's a pain, - * but it does save the code optimizer some work. ;-{ - */ -#define SET_BDA_NBL_CRUNCH(shrt, nibix) \ - (shrt &= ~(BDAN_MASK << ((nibix) << 2))) - -/* Definitions for nibbles in the bda_board element: */ -#define BDA_GEN_NBL 0 /* Overall state of the board */ -#define BDA_MC_NBL 1 /* State of the memory. */ -/* - * BDAN_RED if anything red on board, or board is BDAN_EXCLUDED; - * otherwise BDAN_GOOD - */ -#define BDA_ANYRED_NBL 2 -/* - * Macro BDA_PAGESHIFT hides Solaris page size to Starfire POST, as POST - * assumes Solaris basic page size as 8K. - * Note: Only BDA_PAGESHIFT is used, BDA_PAGESIZE is added for readability. - */ -#define BDA_PAGESHIFT 13 -#define BDA_PAGESIZE (1<<BDA_PAGESHIFT) - -typedef struct { /* Memory Total Descriptor */ - int32_t Memt_NumPages; /* 8 KB each */ - int32_t Memt_NumChunks; -} MemoryTotal_t; - -typedef struct { /* Chunk Descriptor */ - uint32_t Memc_StartAddress; /* In 8 KB pages */ - int32_t Memc_Size; /* In 8 KB pages */ -} MemChunk_t; - - -#define P2OBP_MAGIC "XFPOST_2OBP" -#define VAR_ARRAY_LEN 1 - -typedef struct { - char p2o_magic[12]; /* magic cookie = P2OBP_MAGIC */ - int32_t p2o_struct_version; /* equal to P2OBP_VERSION */ - uint32_t p2o_csum; /* sum(uint[]) */ - uint32_t p2o_post_time; /* creation time */ - uint32_t p2o_post_pid; /* pid of sequencer on SSP */ - uint32_t p2o_post_level; /* level at which hpost ran */ - short p2o_abus_mask; /* [3:0] = Valid PA buses */ - /* [5:4] = bus shuffle mode */ - short p2o_dbus_mask; /* Valid physdata buses */ - uint32_t p2o_intercon_freq; /* hz */ - uint32_t p2o_procssor_freq; /* hz */ - int32_t p2o_post_private; - uint32_t p2o_flags; /* See P2OFLAG_XXX */ - uchar_t p2o_procint_intx_freq_ratio; /* 0 if not known */ - uchar_t p2o_fill_byte[3]; - uint_t p2o_filler[6]; /* for expansion */ - board_desc_t p2o_bdinfo[MAX_SYSBDS]; - board_mdesc_t p2o_bdminfo[MAX_SYSBDS]; - board_auxdesc_t p2o_auxinfo[MAX_SYSBDS]; - MemoryTotal_t p2o_memtotal; - /* - * Array of descriptors of existing memory. - * Number of descriptors is given in memtotal.NumChunks. - */ - MemChunk_t p2o_mchunks[VAR_ARRAY_LEN]; -} post2obp_info_t; - -#ifdef _KERNEL -/* - * Following definitions in support of DR. - */ -typedef void *pda_handle_t; - -extern pda_handle_t pda_open(); -extern void pda_close(pda_handle_t ph); -extern int pda_board_present(pda_handle_t ph, int boardnum); -extern void *pda_get_board_info(pda_handle_t ph, int boardnum); -extern uint_t pda_get_mem_size(pda_handle_t ph, int boardnum); -extern void pda_mem_add_span(pda_handle_t ph, - uint64_t basepa, - uint64_t nbytes); -extern void pda_mem_del_span(pda_handle_t ph, - uint64_t basepa, - uint64_t nbytes); -extern void pda_mem_sync(pda_handle_t ph, int board, int unit); -extern void pda_get_busmask(pda_handle_t ph, - short *amask, short *dmask); -extern int pda_is_valid(pda_handle_t ph); - -#endif /* _KERNEL */ - -#ifdef __cplusplus -} -#endif - -#endif /* _SYS_PDA_H */ diff --git a/usr/src/uts/sun4u/starfire/unix/Makefile b/usr/src/uts/sun4u/starfire/unix/Makefile deleted file mode 100644 index e474a9fe90..0000000000 --- a/usr/src/uts/sun4u/starfire/unix/Makefile +++ /dev/null @@ -1,189 +0,0 @@ -# -# 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 -# or http://www.opensolaris.org/os/licensing. -# 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. -# - -# -# This makefile drives the production of unix (and unix.o). -# -# sun4u starfire implementation architecture dependent -# - -# -# Path to the base of the uts directory tree (usually /usr/src/uts). -# -UTSBASE = ../../.. - -# -# Define the module and object file sets. -# -UNIX = unix -OBJECTS = $(SPECIAL_OBJS:%=$(OBJS_DIR)/%) \ - $(CORE_OBJS:%=$(OBJS_DIR)/%) \ - $(MACH_NOT_YET_KMODS:%=$(OBJS_DIR)/%) -LINTS = $(SPECIAL_OBJS:%.o=$(LINTS_DIR)/%.ln) \ - $(CORE_OBJS:%.o=$(LINTS_DIR)/%.ln) \ - $(MACH_NOT_YET_KMODS:%.o=$(LINTS_DIR)/%.ln) \ - $(LINTS_DIR)/vers.ln \ - $(LINTS_DIR)/modstubs.ln - -KRTLD_MAPFILE = $(UTSBASE)/sparc/krtld/mapfile -KRTLD_OBJECTS = $(KRTLD_OBJS:%=$(OBJS_DIR)/%) -KRTLD_O = $(OBJS_DIR)/krtld.o - -ROOTMODULE = $(ROOT_STARFIRE_KERN_DIR)/$(UNIX) -UNIX32_LINK = $(ROOT_STARFIRE_KERN_DIR_32)/$(UNIX) -UNIX_BIN = $(OBJS_DIR)/$(UNIX) - -LIBS = $(GENLIB) $(PLATLIB) $(CPULIB) - -GENUNIX = genunix -GENUNIX_DIR = ../../$(GENUNIX) -GENOPTS = -L $(GENUNIX_DIR)/$(OBJS_DIR) -l $(GENUNIX) - -CPU_DIR = . -CPUOPTS = -L $(CPU_DIR)/$(OBJS_DIR) -l $(CPUNAME) - -PLAT_DIR = ../../platmod -PLATOPTS = -L $(PLAT_DIR)/$(OBJS_DIR) -l $(PLATMOD) - -LIBOPTS = $(GENOPTS) $(PLATOPTS) $(CPUOPTS) - -CTFEXTRAOBJS = $(OBJS_DIR)/vers.o - -# -# Include common rules. -# -include $(UTSBASE)/sun4u/starfire/Makefile.starfire - -# -# Define targets -# -ALL_TARGET = $(UNIX_BIN) -LINT_TARGET = $(LINT_LIB) -INSTALL_TARGET = $(UNIX_BIN) $(ROOTMODULE) $(UNIX32_LINK) - -# -# This is UNIX_DIR. Use a short path. -# -UNIX_DIR = . - -# -# Overrides -# -CLEANFILES += $(UNIX_O) $(MODSTUBS_O) $(KRTLD_O) $(KRTLD_OBJECTS) \ - $(OBJS_DIR)/vers.c $(OBJS_DIR)/vers.o \ - $(CPU_OBJ) $(CPULIB) \ - $(DTRACESTUBS_O) $(DTRACESTUBS) - -CLOBBERFILES = $(CLEANFILES) $(UNIX_BIN) -CLEANLINTFILES += $(LINT_LIB) - -# -# lint pass one enforcement -# Turn on doubleword alignment for 64 bit counter timer registers -# -CFLAGS += $(CCVERBOSE) -dalign - -CERRWARN += -_gcc=-Wno-parentheses -CERRWARN += -_gcc=-Wno-uninitialized -CERRWARN += -_gcc=-Wno-char-subscripts -CERRWARN += -_gcc=-Wno-unused-variable -CERRWARN += -_gcc=-Wno-unused-function -CERRWARN += -_gcc=-Wno-unused-label -CERRWARN += -_gcc=-Wno-type-limits -CERRWARN += -_gcc=-Wno-clobbered -CERRWARN += -_gcc=-Wno-empty-body -CERRWARN += -_gcc=-Wno-unused-value -CERRWARN += -_gcc=-Wno-switch - -# -# Default build targets. -# -.KEEP_STATE: - -def: $(DEF_DEPS) - -all: $(ALL_DEPS) - -clean: $(CLEAN_DEPS) - -clobber: $(CLOBBER_DEPS) - -lint: $(LINT_DEPS) - -clean.lint: $(CLEAN_LINT_DEPS) - -install: $(INSTALL_DEPS) - -$(UNIX_BIN): $(UNIX_O) $(KRTLD_O) $(MODSTUBS_O) $(MAPFILE) $(LIBS) \ - $(DTRACESTUBS) - $(LD) -dy -b -o $@ -e _start -M $(MAPFILE) \ - $(UNIX_O) $(KRTLD_O) $(MODSTUBS_O) $(LIBOPTS) $(DTRACESTUBS) - $(CTFMERGE_UNIQUIFY_AGAINST_GENUNIX) - $(POST_PROCESS) - $(CHK4UBINARY) - -$(UNIX32_LINK): $(ROOT_PSM_KERN_DIR_32) $(UNIX_BIN) - -$(RM) $@; ln -s $(SUBDIR64)/$(UNIX) $@ - -symcheck: $(UNIX_O) $(KRTLD_O) $(MODSTUBS_O) $(LIBS) - $(LD) -dy -b -o $(SYM_MOD) -M $(MAPFILE) \ - $(UNIX_O) $(KRTLD_O) $(MODSTUBS_O) $(LIBOPTS) $(DTRACESTUBS) - -$(UNIX_O): $(OBJECTS) $(OBJS_DIR)/vers.o - $(LD) -r -o $@ $(OBJECTS) $(OBJS_DIR)/vers.o - -$(KRTLD_O): $(KRTLD_OBJECTS) - $(LD) -r -o $@ -M$(KRTLD_MAPFILE) $(KRTLD_OBJECTS) - -# -# CPU_OBJ now comprises of 2 object files which come from sun4 common -# and from architecture dependent code. OBJS_DIR is prepended where -# CPU_OBJ is defined to allow for building multiple CPU_OBJ's -# -$(CPULIB): $(CPU_OBJ) - $(BUILD.SO) $(CPU_OBJ) - -# -# The global lint target builds the kernel lint library (llib-lunix.ln) -# which is equivalent to a lint of /unix.o. Then all kernel modules for -# this architecture are linted against the kernel lint library. -# -# Note: lint errors in the kernel lint library will be repeated for -# each module. It is important that the kernel lint library -# be clean to keep the textual output to a reasonable level. -# - -$(LINT_LIB): $(LINT_LIB_DIR) $(LINTS) - @-$(ECHO) "\n$(UNIX): (library construction):" - @$(LINT) -o $(UNIX) $(LINTFLAGS) $(LINTS) - @$(MV) $(@F) $@ - -lintlib: $(LINT_DEPS) - -# -# Include common targets. -# -include $(UTSBASE)/sun4u/starfire/Makefile.targ diff --git a/usr/src/uts/sun4u/sys/Makefile b/usr/src/uts/sun4u/sys/Makefile index 8e73425995..612e09ecb8 100644 --- a/usr/src/uts/sun4u/sys/Makefile +++ b/usr/src/uts/sun4u/sys/Makefile @@ -20,6 +20,7 @@ # # Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. +# Copyright 2019 Peter Tribble. # # uts/sun4u/sys/Makefile # @@ -90,7 +91,6 @@ HDRS= \ pte.h \ sbd_ioctl.h \ spitregs.h \ - starfire.h \ sysioerr.h \ sysiosbus.h \ todmostek.h \ diff --git a/usr/src/uts/sun4u/sys/machintreg.h b/usr/src/uts/sun4u/sys/machintreg.h index 2ca8a37b46..1610f9148a 100644 --- a/usr/src/uts/sun4u/sys/machintreg.h +++ b/usr/src/uts/sun4u/sys/machintreg.h @@ -23,12 +23,13 @@ * Copyright 2005 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ +/* + * Copyright 2019 Peter Tribble. + */ #ifndef _SYS_MACHINTREG_H #define _SYS_MACHINTREG_H -#pragma ident "%Z%%M% %I% %E% SMI" - #ifdef __cplusplus extern "C" { #endif @@ -150,16 +151,6 @@ extern "C" { #define INR_EN_SHIFT 31 #define INR_PID_SHIFT 26 #define INR_PID_MASK (IRSR_PID_MASK << (INR_PID_SHIFT)) -#ifdef _STARFIRE -/* - * Starfire interrupt group number is 7 bits - * Starfire's IGN (inter group #) is not the same as upaid - */ -#define IGN_SIZE 7 /* Interrupt Group Number bit size */ -#define UPAID_TO_IGN(upaid) ((((upaid & 0x3C) >> 1) | (upaid & 0x1)) | \ - (((upaid & 0x2) << 4) | \ - ((upaid & 0x40) ^ 0x40))) -#else /* * IGN_SIZE can be defined in a platform's makefile. If it is not defined, * use a default of 5. @@ -168,7 +159,6 @@ extern "C" { #define IGN_SIZE 5 /* Interrupt Group Number bit size */ #endif #define UPAID_TO_IGN(upaid) (upaid) -#endif /* _STARFIRE */ #define IR_CPU_CLEAR 0x4 /* clear pending register for cpu */ #define IR_MASK_OFFSET 0x4 diff --git a/usr/src/uts/sun4u/sys/machparam.h b/usr/src/uts/sun4u/sys/machparam.h index b0130af21f..a205b21be1 100644 --- a/usr/src/uts/sun4u/sys/machparam.h +++ b/usr/src/uts/sun4u/sys/machparam.h @@ -19,6 +19,9 @@ * CDDL HEADER END */ /* + * Copyright 2019 Peter Tribble. + */ +/* * Copyright (c) 1993, 2010, Oracle and/or its affiliates. All rights reserved. */ @@ -54,28 +57,17 @@ extern "C" { * The maximum possible number of UPA devices in a system. * MAX_UPA maybe defined in a platform's makefile. */ -#ifdef _STARFIRE -/* - * We have a 7 bit id space for UPA devices in Xfire - */ -#define MAX_UPA 128 -#else #ifndef MAX_UPA #define MAX_UPA 32 #endif -#endif /* _STARFIRE */ /* * Maximum cpuid value that we support. NCPU can be defined in a platform's * makefile. */ -#if (defined(_STARFIRE) && !defined(lint)) -#define NCPU 64 -#else #ifndef NCPU #define NCPU 32 #endif -#endif /* _STARFIRE && !lint */ #if (NCPU <= 1) #define NCPU_LOG2 0 @@ -323,11 +315,7 @@ extern "C" { #define PFN_TO_BUSTYPE(pfn) (((pfn) >> 19) & 0x1FF) #define IO_BUSTYPE(pfn) ((PFN_TO_BUSTYPE(pfn) & 0x100) >> 8) -#ifdef _STARFIRE -#define PFN_TO_UPAID(pfn) BUSTYPE_TO_UPAID(PFN_TO_BUSTYPE(pfn)) -#else #define PFN_TO_UPAID(pfn) (((pfn) >> 20) & 0x1F) -#endif /* _STARFIRE */ /* * Defines used for the ptl1_panic parameter, which is passed to the diff --git a/usr/src/uts/sun4u/sys/machthread.h b/usr/src/uts/sun4u/sys/machthread.h index 7b844bea44..d72dc7c91a 100644 --- a/usr/src/uts/sun4u/sys/machthread.h +++ b/usr/src/uts/sun4u/sys/machthread.h @@ -22,12 +22,13 @@ * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ +/* + * Copyright 2019 Peter Tribble. + */ #ifndef _SYS_MACHTHREAD_H #define _SYS_MACHTHREAD_H -#pragma ident "%Z%%M% %I% %E% SMI" - #include <sys/asi.h> #include <sys/sun4asi.h> #include <sys/machasi.h> @@ -51,31 +52,7 @@ extern "C" { sll out, 16, out; \ srl out, 16, out; -#ifdef _STARFIRE -/* - * CPU_INDEX(r, scr) - * Returns cpu id in r. - * On Starfire, this is read from the Port Controller's Port ID - * register in local space. - * - * Need to load the 64 bit address of the PC's PortID reg - * using only one register. Kludge the 41 bits address constant to - * be 32bits by shifting it 12 bits to the right first. - */ -#define LOCAL_PC_PORTID_ADDR_SRL12 0x1FFF4000 -#define PC_PORT_ID 0xD0 - -#define CPU_INDEX(r, scr) \ - rdpr %pstate, scr; \ - andn scr, PSTATE_IE | PSTATE_AM, r; \ - wrpr r, 0, %pstate; \ - set LOCAL_PC_PORTID_ADDR_SRL12, r; \ - sllx r, 12, r; \ - or r, PC_PORT_ID, r; \ - lduwa [r]ASI_IO, r; \ - wrpr scr, 0, %pstate - -#elif defined(_OPL) +#ifdef _OPL /* * For OPL platform, we get CPU_INDEX from ASI_EIDR. */ @@ -84,7 +61,7 @@ extern "C" { and r, 0xfff, r -#else /* _STARFIRE */ +#else /* _OPL */ /* * UPA supports up to 32 devices while Safari supports up to @@ -112,7 +89,7 @@ extern "C" { srlx r, 17, r; \ and r, CPU_MASK, r -#endif /* _STARFIRE */ +#endif /* _OPL */ /* * Given a cpu id extract the appropriate word diff --git a/usr/src/uts/sun4u/sys/pci/pci_cb.h b/usr/src/uts/sun4u/sys/pci/pci_cb.h index 6907fc3b4f..8584e5cf31 100644 --- a/usr/src/uts/sun4u/sys/pci/pci_cb.h +++ b/usr/src/uts/sun4u/sys/pci/pci_cb.h @@ -23,12 +23,13 @@ * Copyright 2004 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ +/* + * Copyright 2019 Peter Tribble. + */ #ifndef _SYS_PCI_CB_H #define _SYS_PCI_CB_H -#pragma ident "%Z%%M% %I% %E% SMI" - #ifdef __cplusplus extern "C" { #endif @@ -78,10 +79,6 @@ struct cb { uint64_t cb_obsta_pa; /* 1st-attached-side sta reg base PA */ uint64_t *cb_imr_save; - -#ifdef _STARFIRE - caddr_t cb_ittrans_cookie; /* intr tgt translation */ -#endif }; #define CB_INO_TO_MONDO(cb_p, ino) ((cb_p)->cb_ign << PCI_INO_BITS | (ino)) diff --git a/usr/src/uts/sun4u/sys/pci/pci_ib.h b/usr/src/uts/sun4u/sys/pci/pci_ib.h index c85f972a8a..b034043ced 100644 --- a/usr/src/uts/sun4u/sys/pci/pci_ib.h +++ b/usr/src/uts/sun4u/sys/pci/pci_ib.h @@ -22,6 +22,9 @@ * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ +/* + * Copyright 2019 Peter Tribble. + */ #ifndef _SYS_PCI_IB_H #define _SYS_PCI_IB_H @@ -178,17 +181,6 @@ struct ib_ino_info { #define IB_IS_OBIO_INO(ino) (ino & 0x20) -#ifdef _STARFIRE -/* - * returns a uniq ino per interrupt mapping register - * For on board devices, inos are not shared. But for plugin devices, - * return the 1st ino of the 4 that are sharing the same mapping register. - */ -#define IB_GET_MAPREG_INO(ino) \ - ((volatile uint64_t *)(uintptr_t)((ino & 0x20) ? \ - ino : ((ino >> 2) << 2))) -#endif /* _STARFIRE */ - #define IB_IGN_TO_MONDO(ign, ino) (((ign) << PCI_INO_BITS) | (ino)) #define IB_INO_TO_MONDO(ib_p, ino) IB_IGN_TO_MONDO((ib_p)->ib_ign, ino) diff --git a/usr/src/uts/sun4u/sys/pci/pci_regs.h b/usr/src/uts/sun4u/sys/pci/pci_regs.h index 74aa47a6aa..724cdb3cfb 100644 --- a/usr/src/uts/sun4u/sys/pci/pci_regs.h +++ b/usr/src/uts/sun4u/sys/pci/pci_regs.h @@ -22,12 +22,13 @@ * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ +/* + * Copyright 2019 Peter Tribble. + */ #ifndef _SYS_PCI_REGS_H #define _SYS_PCI_REGS_H -#pragma ident "%Z%%M% %I% %E% SMI" - #ifdef __cplusplus extern "C" { #endif @@ -65,8 +66,6 @@ extern "C" { /* * (psycho and schizo) control register bit definitions: */ -#define COMMON_CB_CONTROL_STATUS_IGN 0x0007c00000000000ull -#define COMMON_CB_CONTROL_STATUS_IGN_SHIFT 46 #define COMMON_CB_CONTROL_STATUS_APCKEN 0x0000000000000008ull #define COMMON_CB_CONTROL_STATUS_APERR 0x0000000000000004ull #define COMMON_CB_CONTROL_STATUS_IAP 0x0000000000000002ull diff --git a/usr/src/uts/sun4u/sys/prom_plat.h b/usr/src/uts/sun4u/sys/prom_plat.h index 66ea55b2c1..39616187ca 100644 --- a/usr/src/uts/sun4u/sys/prom_plat.h +++ b/usr/src/uts/sun4u/sys/prom_plat.h @@ -22,12 +22,13 @@ * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ +/* + * Copyright 2019 Peter Tribble. + */ #ifndef _SYS_PROM_PLAT_H #define _SYS_PROM_PLAT_H -#pragma ident "%Z%%M% %I% %E% SMI" - #include <sys/feature_tests.h> #include <sys/cpuvar.h> @@ -262,16 +263,6 @@ extern int prom_starcat_iosram_write(uint32_t key, uint32_t offset, uint32_t len, caddr_t buf); /* - * Starfire-specific routines - */ -extern int prom_starfire_add_brd(uint_t cpuid); -extern int prom_starfire_rm_brd(uint_t brdnum); -extern void prom_starfire_add_cpu(uint_t cpuid); -extern void prom_starfire_rm_cpu(uint_t cpuid); -extern int prom_starfire_move_cpu0(uint_t cpuid); -extern void prom_starfire_init_console(uint_t cpuid); - -/* * OPL-specific routines */ extern void prom_opl_get_tod(time_t *time, int64_t *stickval); diff --git a/usr/src/uts/sun4u/sys/sbd_ioctl.h b/usr/src/uts/sun4u/sys/sbd_ioctl.h index 16efc10bd7..e8c8ca1e2b 100644 --- a/usr/src/uts/sun4u/sys/sbd_ioctl.h +++ b/usr/src/uts/sun4u/sys/sbd_ioctl.h @@ -22,6 +22,9 @@ * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ +/* + * Copyright 2019 Peter Tribble. + */ #ifndef _SBD_IOCTL_H #define _SBD_IOCTL_H @@ -505,34 +508,6 @@ typedef struct { #define ESTC_NWSWITCH 1037 /* Cannot unconfigure I/O board: network switch failed */ -/* Starfire error codes */ - -#define ESTF_NONE 2000 /* No error */ -#define ESTF_GETPROP 2001 /* Cannot read property value */ -#define ESTF_GETPROPLEN 2002 /* Cannot determine property length */ -#define ESTF_BNUM 2003 /* Invalid board number */ -#define ESTF_CONFIGBUSY 2004 - /* Cannot proceed; Board is configured or busy */ -#define ESTF_NOCPUID 2005 /* No CPU specified for connect */ -#define ESTF_PROBE 2006 /* Firmware probe failed */ -#define ESTF_DEPROBE 2007 /* Firmware deprobe failed */ -#define ESTF_MOVESIGB 2008 /* Firmware move-cpu0 failed */ -#define ESTF_JUGGLE 2009 /* Cannot move SIGB assignment */ -#define ESTF_HASSIGB 2010 - /* Cannot disconnect CPU; SIGB is currently assigned */ -#define ESTF_SUPPORT 2011 /* Operation not supported */ -#define ESTF_DRVFAIL 2012 /* Device driver failure */ -#define ESTF_SETCPUVAL 2013 - /* Must specify a CPU on the given board */ -#define ESTF_NODEV 2014 /* No such device */ -#define ESTF_INTERBOARD 2015 - /* Memory configured with inter-board interleaving */ -#define ESTF_UNKPTCMD 2016 /* Unrecognized platform command */ -#define ESTF_NOTID 2017 /* drmach parameter is not a valid ID */ -#define ESTF_INAPPROP 2018 - /* drmach parameter is inappropriate for operation */ -#define ESTF_INTERNAL 2019 /* Unexpected internal condition */ - /* Daktari error codes */ #define EDAK_NONE 3000 /* no error */ diff --git a/usr/src/uts/sun4u/sys/spitregs.h b/usr/src/uts/sun4u/sys/spitregs.h index 492990c720..1c246f1446 100644 --- a/usr/src/uts/sun4u/sys/spitregs.h +++ b/usr/src/uts/sun4u/sys/spitregs.h @@ -23,12 +23,13 @@ * Copyright 2004 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ +/* + * Copyright 2019 Peter Tribble. + */ #ifndef _SYS_SPITREGS_H #define _SYS_SPITREGS_H -#pragma ident "%Z%%M% %I% %E% SMI" - #ifdef __cplusplus extern "C" { #endif @@ -37,24 +38,11 @@ extern "C" { * This file is cpu dependent. */ -#ifdef _STARFIRE -/* - * Starfire's cpu upaids are not the same - * as cpuids. - * XXX - our obp took the liberty of - * converting cpu upaids into cpuids when - * presenting it as upa-portid property. - */ -#define CPUID_TO_UPAID(upaid) (((upaid & 0x3C) << 1) | \ - ((upaid & 0x40) >> 4) | \ - (upaid &0x3)) -#else /* * The mid is the same as the cpu id. * We might want to change this later */ #define CPUID_TO_UPAID(cpuid) (cpuid) -#endif /* _STARFIRE */ /* * LSU Control Register diff --git a/usr/src/uts/sun4u/sys/starfire.h b/usr/src/uts/sun4u/sys/starfire.h deleted file mode 100644 index 038f0b3c0e..0000000000 --- a/usr/src/uts/sun4u/sys/starfire.h +++ /dev/null @@ -1,248 +0,0 @@ -/* - * 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 - * or http://www.opensolaris.org/os/licensing. - * 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 (c) 1996-2000 by Sun Microsystems, Inc. - * All rights reserved. - */ - -#ifndef _STARFIRE_H -#define _STARFIRE_H - -#pragma ident "%Z%%M% %I% %E% SMI" - -#ifdef __cplusplus -extern "C" { -#endif - -/* I/O space definitions */ -#define STARFIRE_IO_BASE 0x10000000000ULL - -/* UPA Port Space (UPS) definitions */ -#define STARFIRE_UPS_MID_SHIFT 33 /* MID is 7 bits */ -#define STARFIRE_UPS_BRD_SHIFT 36 -#define STARFIRE_UPS_BUS_SHIFT 6 - -/* Starfire Interconnect Space (IS) definitions */ -#define STARFIRE_IS_MC_BASE 0x10e80000000ULL /* MC Register Space */ - - -/* Port Specific Interconnect Space (PSI) */ -#define STARFIRE_PSI_BASE \ - 0x100f8000000ULL /* put mid in [39:33] */ -#define STARFIRE_PSI_PCREG_OFF \ - 0x4000000ULL /* PSI offset for PC regs */ -#define STARFIRE_BRD_TO_PSI(board) \ - (STARFIRE_PSI_BASE | \ - (((uint64_t)board) << STARFIRE_UPS_BRD_SHIFT)) - - -/* Starfire BootBus Space (BS) definitions */ -#define STARFIRE_PSI_BS_BASE \ - STARFIRE_PSI_BASE /* BS at start of PSI Space */ - -#define STARFIRE_UPAID2PSI_BS(upaid) \ - (STARFIRE_PSI_BS_BASE | \ - ((u_longlong_t)STARFIRE_UPAID2HWMID(upaid) << \ - STARFIRE_UPS_MID_SHIFT)) - -#define STARFIRE_DEV2UPAID(b, p, i) \ - ((((i) & 0x1) << 6) | \ - (((b) & 0xf) << 2) | \ - ((p) & 0x3)) - -/* Starfire Port Controller Register offsets */ -#define STARFIRE_PC_CONF 0x000000UL /* Configuration Reg */ -#define STARFIRE_PC_COMP_ID 0x000010UL /* Component ID Reg */ -#define STARFIRE_PC_BUS_CONF 0x000020UL /* Bus Configuration Reg */ -#define STARFIRE_PC_TO_HOLD_CONF 0x000030UL /* Timeout/Hold Config Reg */ -#define STARFIRE_PC_CIC_WRITE_DATA 0x000040UL /* CIC Write Data Reg */ -#define STARFIRE_PC_FORCE_PARITY_ERR 0x000050UL /* Force Parity Err Reg */ -#define STARFIRE_PC_ERR_0_MASK 0x000060UL /* Err 0 Mask Reg */ -#define STARFIRE_PC_ERR_1_MASK 0x000070UL /* Err 1 Mask Reg */ -#define STARFIRE_PC_ERR_0 0x000080UL /* Err 0 Reg */ -#define STARFIRE_PC_ERR_1 0x000090UL /* Err 1 Reg */ -#define STARFIRE_PC_ERR_DATA_SRC 0x0000a0UL /* Err Data Src Reg */ -#define STARFIRE_PC_ERR_DATA_LOW 0x0000b0UL /* Err Data Lower Reg */ -#define STARFIRE_PC_ERR_DATA_HI 0x0000c0UL /* Err Data Upper Reg */ -#define STARFIRE_PC_PORT_ID 0x0000d0UL -#define STARFIRE_PC_PERF_COUNT_0 0x0000e0UL -#define STARFIRE_PC_PERF_COUNT_1 0x0000f0UL -#define STARFIRE_PC_PERF_COUNT_CNTRL 0x000100UL -#define STARFIRE_PC_BLOCK 0x0001c0UL /* 512 Byte scr area */ -#define STARFIRE_PC_INT_MAP 0x000200UL /* 32 regs 00.0200-00.03f0 */ -#define STARFIRE_PC_MADR 0x000400UL /* 16 regs 00.0400-00.04f0 */ - -/* Starfire PC definitions/macros */ -#define STARFIRE_PC_MADR_BOARD_SHIFT 4 -#define STARFIRE_PC_MADR_ADDR(bb, rb, p) \ - (STARFIRE_BRD_TO_PSI(bb) | \ - ((uint64_t)(p) << STARFIRE_UPS_MID_SHIFT) | \ - ((uint64_t)(rb) << STARFIRE_PC_MADR_BOARD_SHIFT) | \ - STARFIRE_PSI_PCREG_OFF | \ - STARFIRE_PC_MADR) - -/* Starfire BB (BootBus) definitions/macros */ -#define STARFIRE_BB_SYSRESET_CNTRL 0x800000ULL -#define STARFIRE_BB_PAUSE_FLUSH 0x800016ULL - -#define STARFIRE_BB_PC_PAUSE(i) ((uchar_t)(1 << (i))) -#define STARFIRE_BB_PC_FLUSH(i) ((uchar_t)(1 << ((i)+2))) -#define STARFIRE_BB_PC_IDLE(i) ((uchar_t)(1 << ((i)+4))) - -#define STARFIRE_BB_SYSRESET(i) ((uchar_t)(1 << (i))) - -#define STARFIRE_BB_PC_ADDR(bb, p, io) \ - (STARFIRE_UPAID2PSI_BS(STARFIRE_DEV2UPAID((bb), (p), (io))) | \ - STARFIRE_BB_PAUSE_FLUSH) -#define STARFIRE_BB_RESET_ADDR(bb, p) \ - (STARFIRE_UPAID2PSI_BS(STARFIRE_DEV2UPAID((bb), (p), 0)) | \ - STARFIRE_BB_SYSRESET_CNTRL) - -/* Starfire Memory Controller Register offsets */ -#define STARFIRE_MC_ASR 0x000400U /* Addr Select Reg */ -#define STARFIRE_MC_DIMMTYPE 0x00c800U /* DIMM Type Code Reg */ -#define STARFIRE_MC_IDLE 0x00cc00U /* Idle MC Reg */ - -/* Starfire MC definitions/macros */ -#define STARFIRE_MC_MEM_PRESENT_MASK 0x80000000U -#define STARFIRE_MC_MEM_BASEADDR_MASK 0x7fff0000U -#define STARFIRE_MC_IDLE_MASK 0x00008000U -#define STARFIRE_MC_MASK_MASK 0x00007f00U -#define STARFIRE_MC_DIMMSIZE_MASK 0x0000001fU -#define STARFIRE_MC_INTERLEAVE_MASK 0x00000001U -#define STARFIRE_MC_MASK_SHIFT 18 -#define STARFIRE_MC_BASE_SHIFT 10 -#define STARFIRE_MC_ADDR_HIBITS 0x1fe00000000ULL -#define STARFIRE_MC_ASR_ADDR(reg) ((reg) | (uint64_t)STARFIRE_MC_ASR) -#define STARFIRE_MC_IDLE_ADDR(reg) ((reg) | (uint64_t)STARFIRE_MC_IDLE) -#define STARFIRE_MC_DIMMTYPE_ADDR(reg) ((reg) | (uint64_t)STARFIRE_MC_DIMMTYPE) -#define STARFIRE_MC_ASR_ADDR_BOARD(b) \ - (((uint64_t)(b) << STARFIRE_UPS_BRD_SHIFT) | \ - STARFIRE_IS_MC_BASE | \ - (uint64_t)STARFIRE_MC_ASR) - -/* - * Memory boards on Starfire are aligned on 8GB - * boundaries, i.e. the physical address space - * is not physically contiguous. - */ -#define STARFIRE_MC_MEMBOARD_SHIFT 33 -#define STARFIRE_MC_MEMBOARD_ALIGNMENT \ - (UINT64_C(1) << STARFIRE_MC_MEMBOARD_SHIFT) - -/* - * Starfire has a special regspec for the "reg" property of the - * mem-unit node since this node is homegrown. - */ -struct sf_memunit_regspec { - uint_t regspec_addr_hi; - uint_t regspec_addr_lo; - uint_t regspec_size_hi; - uint_t regspec_size_lo; -}; - -/* - * Conversion macros - */ - -/* - * Starfire hardware version of the upaid (commonly known as - * HWMID) is different from the software version (also known as upaid). - * HW version BBBBIPp == SW version IBBBBPp - */ -#define STARFIRE_UPAID2HWMID(upaid) (((upaid & 0x3C) << 1) | \ - ((upaid & 0x40) >> 4) | (upaid & 0x3)) - - -/* Xfire UPA ID to UPA Port Specific Space */ -#define STARFIRE_UPAID2UPS(upaid) \ - (((u_longlong_t)STARFIRE_UPAID2HWMID(upaid) << \ - STARFIRE_UPS_MID_SHIFT) | STARFIRE_IO_BASE) - -/* - * Macro to convert our 7 bits HW MID to 7 bits SW MID - * That is "BBBBIPp" to "IBBBBPp". - */ -#define STARFIRE_HWMID2SWMID(mid) ((mid & 0x3) | ((mid & 0x78) >> 1) | \ - ((mid & 0x4) << 4)) - -/* - * Macro to convert our 7 bits UPAid to Sun's 5 bit HW Interrupt - * group number required in some hardware registers (sysios). - * That is "IBBBBPp" to "BBBBp", where "BBBB" is the board number, - * "IP" is the PC id and "p" is the port number. - */ -#define STARFIRE_UPAID2HWIGN(upaid) \ - (((upaid & 0x3C) >> 1) | (upaid & 0x1)) - -/* - * Macro to convert our UPAid to a 7 bit Starfire version of the - * interrupt group number. This so-called IGN is part of - * the interrupt vector number read by the CPU serving this interrupt. - * Thanks to the warp minds of our hardware guys, it is in this - * convoluted weird format. Note that the interrupt vector number is - * then used to index into the interrupt dispatch table to get its - * interrupt handler. - * Convert "IBBBBPp" to "XPBBBBp" where "BBBB" is the 4bit board #, - * "IP" is the 2 bit PC id, "p" is the port # and "X" is ~I. - */ -#define STARFIRE_UPAID2IGN(upaid) (STARFIRE_UPAID2HWIGN(upaid) | \ - ((upaid & 0x2) << 4) | \ - ((upaid & 0x40) ^ 0x40)) - -/* - * Starfire platform specific routines currently only defined - * in starfire.c and referenced by DR. - */ -extern int plat_max_boards(); -extern int plat_max_cpu_units_per_board(); -extern int plat_max_mem_units_per_board(); -extern int plat_max_io_units_per_board(); - -/* - * Starfire platform specific interrupt translation routines - */ -extern void pc_ittrans_init(int, caddr_t *); -extern void pc_ittrans_uninit(caddr_t); -extern int pc_translate_tgtid(caddr_t, int, volatile uint64_t *); -extern void pc_ittrans_cleanup(caddr_t, volatile uint64_t *); - -/* - * Maximum number of system boards supported in a Starfire. - */ -#define STARFIRE_MAX_BOARDS 16 - -/* - * We reserve some "fake" DMV values for Starfire IDN. These are treated - * as hardware interrupt numbers, but they don't correspond to an actual UPA - * port; they can thus be allocated as "well-known" numbers for IDN purposes. - */ -#define STARFIRE_DMV_EXTRA 4 -#define STARFIRE_DMV_HWINT (MAX_UPA+STARFIRE_DMV_EXTRA) -#define STARFIRE_DMV_IDN_BASE (MAX_UPA) - - -#ifdef __cplusplus -} -#endif - -#endif /* _STARFIRE_H */ diff --git a/usr/src/uts/sun4u/sys/sysiosbus.h b/usr/src/uts/sun4u/sys/sysiosbus.h index d72c1c0aa3..05029e9fb8 100644 --- a/usr/src/uts/sun4u/sys/sysiosbus.h +++ b/usr/src/uts/sun4u/sys/sysiosbus.h @@ -23,12 +23,13 @@ * Copyright 2005 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ +/* + * Copyright 2019 Peter Tribble. + */ #ifndef _SYS_SYSIOSBUS_H #define _SYS_SYSIOSBUS_H -#pragma ident "%Z%%M% %I% %E% SMI" - #ifndef _ASM #include <sys/avintr.h> #include <sys/vmem.h> @@ -319,9 +320,6 @@ struct sbus_soft_state { pfn_t sbus_io_hi_pfn; struct iophyslist *sbus_io_ranges; int intr_mapping_ign; /* placeholder for the IGN */ -#ifdef _STARFIRE - caddr_t ittrans_cookie; /* starfire intr target translation */ -#endif /* _STARFIRE */ #ifdef DEBUG kmutex_t iomemlock; /* Memory usage lock (debug only) */ struct io_mem_list *iomem; /* Memory usage list (debug only) */ diff --git a/usr/src/uts/sun4u/todstarfire/Makefile b/usr/src/uts/sun4u/todstarfire/Makefile deleted file mode 100644 index cbaee6f875..0000000000 --- a/usr/src/uts/sun4u/todstarfire/Makefile +++ /dev/null @@ -1,87 +0,0 @@ -# -# 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 -# or http://www.opensolaris.org/os/licensing. -# 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 -# -# -# uts/sun4u/todmostek/Makefile -# Copyright 2004 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# -#ident "%Z%%M% %I% %E% SMI" -# -# This makefile drives the production of the todstarfire -# kernel module. -# - -# -# Path to the base of the uts directory tree (usually /usr/src/uts). -# -UTSBASE = ../.. - -# -# Define the module and object file sets. -# -MODULE = todstarfire -OBJECTS = $(TODSTARFIRE_OBJS:%=$(OBJS_DIR)/%) -LINTS = $(TODSTARFIRE_OBJS:%.o=$(LINTS_DIR)/%.ln) -ROOTMODULE = $(ROOT_PSM_TOD_DIR)/$(MODULE) - -# -# Include common rules. -# -include $(UTSBASE)/sun4u/Makefile.sun4u - -# -# Define targets -# -ALL_TARGET = $(BINARY) -LINT_TARGET = $(MODULE).lint -INSTALL_TARGET = $(BINARY) $(ROOTMODULE) - -# -# lint pass one enforcement -# -CFLAGS += $(CCVERBOSE) - -# -# Default build targets. -# -.KEEP_STATE: - -def: $(DEF_DEPS) - -all: $(ALL_DEPS) - -clean: $(CLEAN_DEPS) - -clobber: $(CLOBBER_DEPS) - -lint: $(LINT_DEPS) - -modlintlib: $(MODLINTLIB_DEPS) - -clean.lint: $(CLEAN_LINT_DEPS) - -install: $(INSTALL_DEPS) - -# -# Include common targets. -# -include $(UTSBASE)/sun4u/Makefile.targ diff --git a/usr/src/uts/sun4v/os/mach_mp_startup.c b/usr/src/uts/sun4v/os/mach_mp_startup.c index 06a6f59279..a0c3928a2f 100644 --- a/usr/src/uts/sun4v/os/mach_mp_startup.c +++ b/usr/src/uts/sun4v/os/mach_mp_startup.c @@ -23,6 +23,10 @@ * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. */ +/* + * Copyright 2019 Peter Tribble. + */ + #include <sys/machsystm.h> #include <sys/cpu_module.h> #include <sys/dtrace.h> @@ -70,11 +74,6 @@ init_cpu_info(struct cpu *cp) (void) strcpy(pi->pi_fputypes, "sparcv9"); /* - * StarFire requires the signature block stuff setup here - */ - CPU_SGN_MAPIN(cpuid); - - /* * cpu0 is always initialized at boot time, but it can be initialized * again if it is dynamically removed and then re-added. We check if * we are booting by verifying cpu_list. During boot, cpu0 is already |
