/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* MonteCarlo HotSwap Controller functionality
*/
#include <sys/mct_topology.h>
#include <sys/scsbioctl.h>
/* TUNABLE PARAMETERS. Some are Debug Only. Please take care when using. */
/*
* Set this flag to 1, to enable full hotswap mode at boot time.
* Since HPS is threaded, it is not recommended that we set this flag
* to 1 because enabling full hotswap interrupt can invoke the ENUM
* event handler accessing the slot data structure which may have not
* been initialized in the hotplug framework since the HPS may not yet
* have called the slot registration function with the bus nexus.
*/
static int scsb_hsc_enable_fhs = 0;
/*
* Every time a slot is registered with the hotswap framework, the
* framework calls back. This variable keeps a count on how many
* callbacks are done.
*/
static int scsb_hsc_numReg = 0;
/*
* When this flag is set, the board is taken offline (put in reset) after
* a unconfigure operation, in Basic Hotswap mode.
*/
/*
* When this flag is set, we take the board to reset after unconfigure
* operation when operating in full hotswap mode.
*/
/*
* Implementation of this counter will work only on Montecarlo since
* the ENUM# Interrupt line is not shared with other interrupts.
* When the hardware routing changes, then there may be need to remove
* or change this functionality.
* This functionality is provided so that a bad or non friendly full hotswap
* board does not hang the system in full hotswap mode. Atleast the
* intent is that! Eventually Solaris kernel will provide similar support
* for recovering from a stuck interrupt line. Till then, lets do this.
*/
/*
* following flag can be used for imitating that behaviour.
* Currently we can set this flag and use the remove op to remove the
* interrupt handler from the system. Care must be taken when using this
* function since trying to remove the interrupt handler when the interrupts
* are pending may hang the system permanently.
* Since the hardware does not support this functionality, we adopt this
* approach for debugs.
*/
static int scsb_hsc_enum_switch = 0;
/*
* When the board loses Healthy# at runtime (with the board being configured),
* cPCI specs states that a Reset has to be asserted immediately.
* We dont do this currently, until satellite processor support is given
* and the implications of such a act is fully understood.
* To adopt the cPCI specs recommendation, set this flag to 1.
*/
static int scsb_hsc_healthy_reset = 0;
/*
* According to PCI 2.2 specification, once a board comes out of PCI_RST#,
* it may take upto 2^25 clock cycles to respond to config cycles. For
* montecarlo using a 33MHz cPCI bus, it's around 1.024 s. The variable
* will specify the time in ms to wait before attempting config access.
*/
/*
* slot map property for MC should be
*
* hsc-slot-map="/pci@1f,0/pci@1/pci@1","15","2",
* "/pci@1f,0/pci@1/pci@1","14","3",
* "/pci@1f,0/pci@1/pci@1","13","4",
* "/pci@1f,0/pci@1/pci@1","12","5"
* "/pci@1f,0/pci@1/pci@1","11","6"
* "/pci@1f,0/pci@1/pci@1","10","7"
* "/pci@1f,0/pci@1/pci@1","8","8";
*
* slot map property for Tonga should be
* hsc-slot-map="/pci@1f,0/pci@1/pci@1","8","1"
* "/pci@1f,0/pci@1/pci@1", "15", "2"
* "/pci@1f,0/pci@1/pci@1", "14", "4"
* "/pci@1f,0/pci@1/pci@1", "13", "5"
*
* Please note that the CPU slot number is 3 for Tonga.
*/
/*
* Services we require from the SCSB
*/
extern int scsb_get_slot_state(void *, int, int *);
extern int scsb_connect_slot(void *, int, int);
extern int scsb_disconnect_slot(void *, int, int);
static void *hsc_state;
static uint_t hsc_enum_intr(char *);
static int scsb_enable_enum(hsc_state_t *);
static int scsb_disable_enum(hsc_state_t *, int);
static int atoi(const char *);
static int isdigit(int);
static hsc_slot_t *hsc_find_slot(int);
static int scsb_hsc_disable_slot(hsc_slot_t *);
static int scsb_hsc_enable_slot(hsc_slot_t *);
#ifndef lint
static int hsc_clear_all_enum(hsc_state_t *);
#endif
static int hsc_slot_unregister(int);
static int hsc_slot_autoconnect(hsc_slot_t *);
/*
* This mutex protects the following variables:
* hsc_slot_list
*/
/* ARGSUSED */
static int
{
return (HPC_ERR_FAILED);
/* if SCB hotswapped, do not allow connect operations */
return (HPC_ERR_FAILED);
/*
* if previous occupant stayed configured, do not allow another
* occupant to be connected.
* This behaviour is an indication that the slot state
* is not clean.
*/
/*
* In the current implementation, we turn both fault
* and active LEDs to ON state in this situation.
*/
return (HPC_ERR_FAILED);
}
/*
* Get the actual status from the i2c bus
*/
&rstate);
if (rc != DDI_SUCCESS)
return (HPC_ERR_FAILED);
#ifdef DEBUG
"?hsc_connect: slot %d is empty\n",
#endif
return (HPC_ERR_FAILED);
}
return (HPC_SUCCESS);
rc = HPC_SUCCESS;
/*
* call scsb to connect the slot. This also makes sure board is healthy
*/
DEBUG1("hsc_connect: slot %d connection failed",
rc = HPC_ERR_FAILED;
} else {
return (HPC_ERR_FAILED);
}
return (HPC_ERR_FAILED);
}
/*
* Unresetting a board may have caused an interrupt
* burst in case of non friendly boards. So it is
* important to make sure that the ISR has not
* put this board back to disconnect state.
*/
delay(1);
return (HPC_ERR_FAILED);
}
DEBUG1("hsc_connect: slot %d connected",
rc = HPC_SUCCESS;
}
}
/*
* PCI 2.2 specs recommend that the probe software wait
* for upto 2^25 PCI clock cycles after deassertion of
* PCI_RST# before the board is able to respond to config
* cycles. So, before we return, we wait for ~1 sec.
*/
return (rc);
}
/* ARGSUSED */
static int
{
#ifdef DEBUG
#endif
if (hsp->hs_board_configured) {
#ifdef DEBUG
"%s: cannot disconnect configured board in slot %d",
#endif
return (HPC_ERR_FAILED);
}
#ifdef DEBUG
#endif
return (HPC_SUCCESS);
}
/*
* if already disconnected, just return success
* Duplicate disconnect messages should not be failed!
*/
return (HPC_SUCCESS);
}
/* if SCB hotswapped, do not allow disconnect operations */
return (HPC_ERR_FAILED);
/* call scsb to disconnect the slot */
!= DDI_SUCCESS)
return (HPC_ERR_FAILED);
return (HPC_SUCCESS);
}
/*
* In the cPCI world, this operation is not applicable.
* However, we use this function to enable full hotswap mode in debug mode.
*/
/* ARGSUSED */
static int
{
if (scsb_hsc_enum_switch &&
return (HPC_SUCCESS);
}
return (HPC_ERR_NOTSUPPORTED);
}
/*
* In the cPCI world, this operation is not applicable.
* However, we use this function to disable full hotswap mode in debug mode.
*/
/* ARGSUSED */
static int
{
if (scsb_hsc_enum_switch &&
== DDI_SUCCESS)) {
return (HPC_SUCCESS);
}
return (HPC_ERR_NOTSUPPORTED);
}
static void
{
}
static int
{
int res;
DEBUG3("hsc_led_state: slot %d, led %x, state %x",
/*
* We ignore operations on LEDs that we don't support
*/
case HPC_FAULT_LED:
break;
case HPC_ACTIVE_LED:
break;
default:
return (HPC_ERR_NOTSUPPORTED);
}
case HPC_LED_BLINK:
return (HPC_ERR_NOTSUPPORTED);
break;
case HPC_LED_ON:
break;
case HPC_LED_OFF:
break;
default:
break;
}
switch (cmd) {
case HPC_CTRL_SET_LED_STATE:
if (res != 0)
return (HPC_ERR_FAILED);
break;
case HPC_CTRL_GET_LED_STATE:
if (res)
return (HPC_ERR_FAILED);
/* hlip->state = sunit.unit_state; */
break;
default:
return (HPC_ERR_INVALID);
}
return (HPC_SUCCESS);
}
static int
{
int rstate = 0;
int rc;
#ifdef DEBUG
#endif
&rstate);
if (rc != DDI_SUCCESS)
return (HPC_ERR_FAILED);
#ifdef DEBUG
#endif
switch (hsp->hs_slot_state) {
case HPC_SLOT_EMPTY:
DEBUG0("empty");
break;
case HPC_SLOT_CONNECTED:
DEBUG0("connected");
break;
case HPC_SLOT_DISCONNECTED:
DEBUG0("disconnected");
break;
}
/* doing get-state above may have caused a freeze operation */
(rstate == HPC_SLOT_DISCONNECTED)) {
/* freeze puts disconnected boards to connected state */
#if 0
/* in FHS, deassertion of reset may have configured the board */
}
#endif
}
#ifdef DEBUG
/* a SCB hotswap may have forced a state change on the receptacle */
}
#endif
return (HPC_SUCCESS);
}
static int
{
switch (cmd) {
case HPC_CTRL_DEV_CONFIGURED:
/*
* Closing of the Ejector switch in configured/busy state can
* cause duplicate CONFIGURED messages to come down.
* Make sure our LED states are fine.
*/
break;
}
/* LED must be OFF on the occupant. */
else
break;
HSC_AUTOCFG)) {
}
}
break;
break;
break;
break;
default:
return (HPC_ERR_INVALID);
}
if (cmd != HPC_CTRL_DEV_CONFIG_START &&
/*
* If the callback is invoked for all registered slots,
* enable ENUM.
*/
#ifdef DEBUG
":%d non-empty slots\n",
#endif
"Full Hotswap",
return (HPC_ERR_FAILED);
}
}
}
}
return (HPC_SUCCESS);
}
/*ARGSUSED*/
static int
{
return (HPC_SUCCESS);
}
/* ARGSUSED */
static int
{
if (cmd == HPC_CTRL_ENABLE_AUTOCFG) {
slotautocfg_prop, "enabled");
}
} else {
slotautocfg_prop, "disabled");
for (i = 0; i < hsc->slot_table_size; i++) {
int slotnum;
"No Slot Info for slot %d",
slotnum);
continue;
}
break;
}
}
if (enum_disable == B_TRUE)
(void) scsb_disable_enum(hsc,
}
}
return (res);
}
/*
*/
/* ARGSUSED */
#ifndef lint
static int
{
int res;
if (enabled)
else
if (res == 0)
return (HPC_SUCCESS);
return (HPC_ERR_INVALID);
else
return (HPC_ERR_FAILED);
}
#endif
/*ARGSUSED*/
static int
{
switch (request) {
case HPC_CTRL_GET_LED_STATE:
return (hsc_led_state(hsp,
case HPC_CTRL_SET_LED_STATE:
return (hsc_led_state(hsp,
case HPC_CTRL_GET_SLOT_STATE:
case HPC_CTRL_DEV_CONFIGURED:
return (hsc_set_config_state(hsp,
case HPC_CTRL_GET_BOARD_TYPE:
case HPC_CTRL_DISABLE_AUTOCFG:
case HPC_CTRL_ENABLE_AUTOCFG:
case HPC_CTRL_DISABLE_SLOT:
/*
* No hardware support for disabling the slot.
* Just imitate a disable_autoconfig operation for now
*/
return (HPC_ERR_FAILED);
rc = HPC_ERR_FAILED;
return (rc);
case HPC_CTRL_ENABLE_SLOT:
rc = HPC_ERR_FAILED;
return (rc);
case HPC_CTRL_ENABLE_ENUM:
case HPC_CTRL_DISABLE_ENUM:
default:
return (HPC_ERR_INVALID);
}
}
static int
{
int rc;
if (rc == DDI_SUCCESS) {
slot_disable_prop, "disabled");
} else
rc = DDI_FAILURE;
return (rc);
}
static int
{
int rc;
if (rc == DDI_SUCCESS) {
} else
rc = HPC_ERR_FAILED;
return (rc);
}
static hsc_slot_t *
int slot_number,
{
"hsc_alloc_slot: allocation failed for slot %d",
return (NULL);
}
hsip->pci_slot_capabilities = 0;
/*
* Note: the name *must* be 'pci' so that the correct cfgadm plug-in
* library is selected
*/
/*
* We assume that the following LED settings reflect
* the hardware state.
* After we register the slot, we will be invoked by the nexus
* if the slot is occupied, and we will turn on the LED then.
*/
/*
* we should just set this to connected,
* as MC slots are always connected.
*/
if (board_in_slot)
else
return (hsp);
}
static void
{
DEBUG0("hsc_free_slot");
}
/*
* This function is invoked to register a slot
*/
static int
char *bus_path, /* PCI nexus pathname */
{
DEBUG2("hsc_slot_register: slot number %d, device number %d",
#ifdef DEBUG
#endif
return (HPC_ERR_FAILED);
}
if (rc != DDI_SUCCESS)
return (HPC_ERR_FAILED);
/* slot autoconfiguration by default. */
else
/*
* Append to our list
*/
hsc_slot_list = hsp;
0);
if (rc != HPC_SUCCESS) {
return (rc);
}
DEBUG0("hsc_slot_register: hpc_slot_register successful");
return (rc);
}
static int
{
else
break;
}
}
}
return (0);
}
return (1);
}
static int
{
if (rc != DDI_SUCCESS)
return (DDI_FAILURE);
/*
* Set the healthy status for this slot
*/
switch (rstate) {
case HPC_SLOT_EMPTY:
/*
* this will clear any state differences between
* SCB Freeze operations.
*/
/* slot empty. */
break;
case HPC_SLOT_DISCONNECTED:
/*
* this will clear any state differences between
* SCB Freeze operations.
*/
/* check recovery from SCB freeze */
/*
* Force a disconnect just in case there are
* differences between healthy and reset states.
*/
/*
* Slot in reset. OBP has not probed this
* device. Hence it is ok to remove this board.
*/
break;
}
/*FALLTHROUGH*/
case HPC_SLOT_CONNECTED:
/*
* this will clear any state differences between
* SCB Freeze operations.
*/
/*
* OBP should have probed this device, unless
* it was plugged in during the boot operation
* before the driver was loaded. In any case,
* no assumption is made and hence we take
* the conservative approach by keeping fault
* led off so board removal is not allowed.
*/
else
/*
* Netra ct alarm card hotswap support
*/
DEBUG0("Xscsb_hsc_init_slot_state: "
"set HSC_ALARM_CARD_PRES");
}
break;
default:
break;
}
return (rc);
}
static hsc_slot_t *
{
int i;
for (i = 0; i < hsc->slot_table_size; i++) {
return ((hsc_slot_t *)hsc_find_slot(
}
return (NULL);
}
static hsc_slot_t *
{
break;
}
return (hsp);
}
/*
* This function is invoked by the SCSB when an interrupt
* happens to indicate that a board has been inserted-in/removed-from
* the specified slot.
*/
int
{
DEBUG4("hsc_slot_occupancy: slot %d %s, ac=%d, healthy=%d",
"%s: cannot map slot number %d to a hsc_slot_t",
func, slot_number);
return (DDI_FAILURE);
}
if (occupied) {
/*
* A board was just inserted. We are disconnected at this point.
*/
if (flags == ALARM_CARD_ON_SLOT) {
DEBUG0("Xhsc_slot_occupancy: set HSC_ALARM_CARD_PRES");
}
/*
* if previous occupant stayed configured, do not allow another
* occupant to be connected.
* So as soon as the board is plugged in, we turn both LEDs On.
* This behaviour is an indication that the slot state
* is not clean.
*/
return (DDI_SUCCESS);
}
/* Do not allow connect if slot is disabled */
return (DDI_SUCCESS);
/* if no healthy, we stay disconnected. */
return (DDI_SUCCESS);
}
} else {
/*
* A board was just removed
*/
DEBUG0("Xhsc_slot_occupancy:clear HSC_ALARM_CARD_PRES");
}
" on Slot %d, Occupant Online!!",
" Inconsistent State! Slot disabled. Halt!",
/* Slot in reset and disabled */
(void) scsb_hsc_disable_slot(hsp);
/* the following works for P1.0 only. */
} else {
}
}
return (rc);
}
/*
* This function is invoked by the SCSB when the health status of
* a board changes.
*/
/*ARGSUSED*/
int
{
return (DDI_FAILURE);
}
#ifdef DEBUG
#endif
return (DDI_FAILURE);
}
DEBUG2("healthy %s on disconnected slot %d\n",
/*
* Connect the slot if board healthy and in autoconfig mode.
*/
return (hsc_slot_autoconnect(hsp));
}
/*
* the board is connected. The result could be seviour depending
* on the occupant state.
*/
/* Regained HEALTHY# at Run Time...!!! */
"%s, Regained HEALTHY#!",
"configured" : "Unconfigured");
}
} else {
/* Lost HEALTHY# at Run Time...Serious Condition. */
" on Slot %d, Occupant %s",
"Online!!!" : "Offline");
}
slot_number, SCSB_RESET_SLOT) == 0) {
/* signal Ok to remove board. */
"successfully taken offline",
}
}
}
return (DDI_SUCCESS);
}
static int
{
/*
* Keep slot in reset unless autoconfiguration is enabled
* Ie. for Basic Hotswap mode, we stay disconnected at
* insertion. For full hotswap mode, we automatically
* go into connected state at insertion, so that occupant
* autoconfiguration is possible.
*/
/* this statement must be here before unreset. */
} else {
rc = DDI_FAILURE;
}
}
return (rc);
}
/*
* The SCSB code should invoke this function from its _init() function.
*/
int
hsc_init()
{
int rc;
if (rc != 0)
return (rc);
return (DDI_SUCCESS);
}
/*
* The SCSB code should invoke this function from its _fini() function.
*/
int
hsc_fini()
{
if (hsc_slotops != NULL) {
hsc_slotops = NULL;
}
return (DDI_SUCCESS);
}
static int
{
DEBUG0("hsc: Enable ENUM#\n");
return (DDI_SUCCESS);
return (DDI_FAILURE);
return (DDI_FAILURE);
}
HOTSWAP_MODE_PROP, "full");
return (DDI_SUCCESS);
}
/*ARGSUSED*/
static int
{
DEBUG0("hsc: Disable ENUM#\n");
if (op == SCSB_HSC_FORCE_REMOVE) {
/*
* Clear all pending interrupts before unregistering
* the interrupt. Otherwise the system will hang.
*
* Due to the hang problem, we'll not turn off or disable
* interrupts because if there's a non-friendly full hotswap
* device out there, the ENUM# will be kept asserted and
* hence hsc_clear_all_enum() can never deassert ENUM#.
* So the system will hang.
*/
/* hsc_clear_all_enum(hsc); */
"Basic Hotswap Mode\n",
}
HOTSWAP_MODE_PROP, "basic");
return (DDI_SUCCESS);
} else
return (HPC_ERR_NOTSUPPORTED);
}
#ifndef lint
static int
{
int i, rc;
for (i = 0; i < hsc->slot_table_size; i++) {
continue;
if (rc == HPC_EVENT_UNCLAIMED)
break; /* no pending interrupts across the bus */
DEBUG1("Pending Intr on slot %d\n",
}
return (0);
}
#endif
int
{
int i, n, prop_len;
int rc;
char *hotswap_model;
int hpc_slot_table_size;
int rstate;
DEBUG0("hsc_attach: enter\n");
/*
* To get the slot information,
* The OBP defines the 'slot-table' property. But the OS
* can override it with 'hsc-slot-map' property
* through the .conf file.
* Since the formats are different, 2 different property names
* are chosen.
* The OBP property format is
* <phandle>,<pci-devno>,<phys-slotno>,<ga-bits>
* The OS property format is (ga-bits is not used however)
* <busnexus-path>,<pci-devno>,<phys-slotno>,<ga-bits>
*/
if (rc != DDI_PROP_SUCCESS) {
prom_prop = 1;
if (rc != DDI_PROP_SUCCESS) {
return (DDI_FAILURE);
}
}
if (rc != DDI_SUCCESS)
return (DDI_FAILURE);
hsc->n_registered_occupants = 0;
/* hsc->slot_info = hsc_slot_list; */
/*
* Check whether the system should be in basic or full
* hotswap mode. The PROM property always says full, so
* look at the .conf file property whether this is "full"
*/
if (scsb_hsc_enable_fhs) {
} else {
}
if (rc == DDI_PROP_SUCCESS) {
}
}
/*
* Determine the size of the slot table from the property and
* allocate the slot table arrary..Decoding is different for
* OS and PROM property.
*/
if (!prom_prop) { /* OS .conf property */
for (i = 0, n = 0; i < hpc_slot_table_size; i++) {
if (hpc_slot_table_data[i] == 0) {
n++;
}
}
/* There should be four elements per entry */
if (n % 4) {
ddi_get_instance(dip), n);
return (DDI_FAILURE);
}
} else {
sizeof (hsc_prom_slot_table_t);
n = hpc_slot_table_size % sizeof (hsc_prom_slot_table_t);
if (n) {
return (DDI_FAILURE);
}
}
/*
* Netract800 FTC (formerly known as CFTM) workaround.
* Leave Slot 2 out of the HS table if FTC is present in Slot 2
*/
}
/*
* Create enough space for each slot table entry
* based on how many entries in the property
*/
sizeof (hsc_slot_table_t), KM_SLEEP);
if (!prom_prop) {
s = hpc_slot_table_data;
for (i = 0; i < hsc->slot_table_size; i++) {
/* Pick off pointer to nexus path or PROM handle */
nexus = s;
while (*s != NULL)
s++;
s++;
/* Pick off pointer to the pci device number */
pcidev = s;
while (*s != NULL)
s++;
s++;
/* Pick off physical slot no */
phys_slotname = s;
while (*s != NULL)
s++;
s++;
/* Pick off GA bits which we dont use for now. */
ga = s;
while (*s != NULL)
s++;
s++;
--i;
continue;
}
}
} else {
--i;
continue;
}
== -1) {
(hsc->slot_table_size *
sizeof (hsc_slot_table_t)));
return (DDI_FAILURE);
}
}
}
/* keep healthy register cache uptodate before reading slot state */
if (scsb_read_bhealthy(scsb_handle) != 0) {
(hsc->slot_table_size *
sizeof (hsc_slot_table_t)));
return (DDI_FAILURE);
}
/*
* Before we start registering the slots, calculate how many
* slots are occupied.
*/
for (i = 0; i < hsc->slot_table_size; i++) {
return (rc);
if (rstate != HPC_SLOT_EMPTY)
}
for (i = 0; i < hsc->slot_table_size; i++) {
DEBUG2("Registering on nexus [%s] cPCI device [%d]\n",
HPC_SUCCESS) {
while (i) {
i--;
if (hsc_slot_unregister(n) != 0) {
"%s#%d: failed to unregister"
" slot %d",
ddi_get_instance(dip), n);
}
}
sizeof (hsc_slot_table_t)));
return (DDI_FAILURE);
}
}
hsc->hsc_intr_counter = 0;
HOTSWAP_MODE_PROP, "basic");
/*
* We enable full hotswap right here if all the slots are empty.
*/
}
}
}
return (DDI_SUCCESS);
}
/*ARGSUSED*/
int
{
int i = 0;
DEBUG0("hsc_detach: enter\n");
DEBUG2("%s#%d: hsc_detach: Soft state NULL",
return (DDI_FAILURE);
}
return (DDI_FAILURE);
/*
* let's unregister the hotpluggable slots with hotplug service.
*/
for (i = 0; i < hsc->slot_table_size; i++) {
} else {
&aledinfo);
&fledinfo);
}
!= 0) {
return (DDI_FAILURE);
}
}
sizeof (hsc_slot_table_t)));
}
return (DDI_SUCCESS);
}
/*
* The following function is called when the SCSB is hot extracted from
* the system.
*/
int
{
int i;
DEBUG2("%s#%d: Soft state NULL",
return (DDI_SUCCESS);
}
return (DDI_SUCCESS);
for (i = 0; i < hsc->slot_table_size; i++) {
" Cannot map slot number %d to a hsc_slot_t",
continue;
}
/*
* Since reset lines are pulled low, lets mark these
* slots and not allow a connect operation.
* Note that we still keep the slot as slot disconnected,
* although it is connected from the hardware standpoint.
* As soon as the SCB is plugged back in, we check these
* states and put the hardware state back to its original
* state.
*/
}
}
return (DDI_SUCCESS);
}
/*
* The following function is called when the SCSB is hot inserted from
* the system. We must update the LED status and set the RST# registers
* again.
*/
int
{
int i;
DEBUG2("%s#%d: Soft state NULL",
return (DDI_SUCCESS);
}
return (DDI_SUCCESS);
for (i = 0; i < hsc->slot_table_size; i++) {
" Cannot map slot number %d to a hsc_slot_t",
continue;
}
SCSB_RESET_SLOT) != 0) {
" Cannot reset disconnected slot %d",
}
}
" slot%d state",
}
}
return (DDI_SUCCESS);
}
#ifndef lint
int
{
DEBUG2("%s#%d: Soft state NULL",
return (DDI_SUCCESS);
}
return (DDI_SUCCESS);
return (DDI_SUCCESS);
}
#endif
/*
*/
void
{
return;
}
return;
}
switch (op) {
case SCSB_HSC_AC_UNCONFIGURE :
/*
* If ENUM# is enabled, then action is pending on
* this slot, just send a event.
*/
(void) hpc_slot_event_notify(
break;
case SCSB_HSC_AC_GET_SLOT_INFO :
break;
default :
break;
}
}
static uint_t
{
int rc;
DEBUG0("!E!");
return (DDI_INTR_UNCLAIMED);
return (DDI_INTR_UNCLAIMED);
/*
* The following must be done to clear interrupt (synchronous event).
* To process the interrupt, we send an asynchronous event.
*/
if (rc == HPC_EVENT_UNCLAIMED) {
/*
* possible support for handling insertion of non friendly
* full hotswap boards, otherwise the system hangs due
* to uncleared interrupt bursts.
*/
DEBUG2("!E>counter %d, last op@slot %lx\n",
hsc->hsc_intr_counter ++;
" No Last Board Insertion Info.",
hsc->hsc_intr_counter = 0;
return (DDI_INTR_UNCLAIMED);
}
"in Slot %d ? Taking it Offline.",
/*
* this should put just inserted board back in
* reset, thus deasserting the ENUM# and the
* system hang.
*/
SCSB_RESET_SLOT) == 0) {
/* Enumeration failed on this board */
" now in Inconsistent State."
" Halt!",
}
hsc->hsc_intr_counter = 0;
}
return (DDI_INTR_UNCLAIMED);
}
hsc->hsc_intr_counter = 0;
/*
* if interrupt success, rc denotes the PCI device number which
* generated the ENUM# interrupt.
*/
return (DDI_INTR_CLAIMED); /* interrupt already cleared */
}
/* if this is Alarm Card and if it is busy, dont process event */
SCSB_HSC_AC_BUSY) == B_TRUE) {
/*
* Busy means we need to inform (envmond)alarmcard.so
* that it should save the AC configuration, stop the
* heartbeat, and shutdown the RSC link.
*/
return (DDI_INTR_CLAIMED);
}
}
/*
* If SCB was swapped out, dont process ENUM#. We put this slot
* back in reset after SCB is inserted.
*/
return (DDI_INTR_CLAIMED);
return (DDI_INTR_CLAIMED);
}
/*
* A routine to convert a number (represented as a string) to
* the integer value it represents.
*/
static int
{
}
static int
atoi(const char *p)
{
int n;
int c, neg = 0;
if (!isdigit(c = *p)) {
while (isspace(c))
c = *++p;
switch (c) {
case '-':
neg++;
/* FALLTHROUGH */
case '+':
c = *++p;
}
if (!isdigit(c))
return (0);
}
for (n = '0' - c; isdigit(c = *++p); ) {
n *= 10; /* two steps to avoid unnecessary overflow */
n += '0' - c; /* accum neg to avoid surprises at MAX */
}
return (neg ? n : -n);
}