103831d35Sstevel /*
203831d35Sstevel * CDDL HEADER START
303831d35Sstevel *
403831d35Sstevel * The contents of this file are subject to the terms of the
503831d35Sstevel * Common Development and Distribution License (the "License").
603831d35Sstevel * You may not use this file except in compliance with the License.
703831d35Sstevel *
803831d35Sstevel * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
903831d35Sstevel * or http://www.opensolaris.org/os/licensing.
1003831d35Sstevel * See the License for the specific language governing permissions
1103831d35Sstevel * and limitations under the License.
1203831d35Sstevel *
1303831d35Sstevel * When distributing Covered Code, include this CDDL HEADER in each
1403831d35Sstevel * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1503831d35Sstevel * If applicable, add the following below this CDDL HEADER, with the
1603831d35Sstevel * fields enclosed by brackets "[]" replaced with your own identifying
1703831d35Sstevel * information: Portions Copyright [yyyy] [name of copyright owner]
1803831d35Sstevel *
1903831d35Sstevel * CDDL HEADER END
2003831d35Sstevel */
2103831d35Sstevel
2203831d35Sstevel /*
2307d06da5SSurya Prakki * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
2403831d35Sstevel * Use is subject to license terms.
2503831d35Sstevel */
2603831d35Sstevel
2703831d35Sstevel
2803831d35Sstevel /*
2903831d35Sstevel *
3003831d35Sstevel * Serengeti CompactPCI Hot Swap Controller Driver.
3103831d35Sstevel *
3203831d35Sstevel */
3303831d35Sstevel
3403831d35Sstevel #include <sys/types.h>
3503831d35Sstevel #include <sys/cmn_err.h>
3603831d35Sstevel #include <sys/kmem.h>
3703831d35Sstevel #include <sys/errno.h>
3803831d35Sstevel #include <sys/cpuvar.h>
3903831d35Sstevel #include <sys/open.h>
4003831d35Sstevel #include <sys/stat.h>
4103831d35Sstevel #include <sys/conf.h>
4203831d35Sstevel #include <sys/ddi.h>
4303831d35Sstevel #include <sys/sunddi.h>
4403831d35Sstevel #include <sys/modctl.h>
4503831d35Sstevel #include <sys/ksynch.h>
4603831d35Sstevel #include <sys/pci.h>
4703831d35Sstevel #include <sys/serengeti.h>
4803831d35Sstevel #include <sys/sghsc.h>
4903831d35Sstevel #include <sys/promif.h>
5003831d35Sstevel
5103831d35Sstevel /*
5203831d35Sstevel * Debug flags
5303831d35Sstevel */
5403831d35Sstevel
5503831d35Sstevel int sghsc_configure_ack = 0;
5603831d35Sstevel int cpci_enable = 1;
5703831d35Sstevel #ifdef DEBUG
5803831d35Sstevel #define SGHSC_DEBUG
5903831d35Sstevel #endif
6003831d35Sstevel
6103831d35Sstevel #ifdef SGHSC_DEBUG
6203831d35Sstevel int sghsc_debug = 0;
6303831d35Sstevel #define DEBUGF(level, args) \
6403831d35Sstevel { if (sghsc_debug >= (level)) cmn_err args; }
6503831d35Sstevel #define DEBUGON sghsc_debug = 3
6603831d35Sstevel #define DEBUGOFF sghsc_debug = 0
6703831d35Sstevel #else
6803831d35Sstevel #define DEBUGF(level, args) /* nothing */
6903831d35Sstevel #define DEBUGON
7003831d35Sstevel #define DEBUGOFF
7103831d35Sstevel #endif
7203831d35Sstevel
7303831d35Sstevel /*
7403831d35Sstevel * Global data
7503831d35Sstevel */
7603831d35Sstevel static void *sghsc_state; /* soft state */
7703831d35Sstevel static sghsc_rb_head_t sghsc_rb_header; /* ring buffer header */
7803831d35Sstevel
7903831d35Sstevel /*
8003831d35Sstevel * Definitions for events thread (outside interrupt context), mutex and
8103831d35Sstevel * condition variable.
8203831d35Sstevel */
8303831d35Sstevel static kthread_t *sghsc_event_thread;
8403831d35Sstevel static kmutex_t sghsc_event_thread_mutex;
8503831d35Sstevel static kcondvar_t sghsc_event_thread_cv;
8603831d35Sstevel static boolean_t sghsc_event_thread_exit = B_FALSE;
8703831d35Sstevel
8803831d35Sstevel static struct cb_ops sghsc_cb_ops = {
8903831d35Sstevel nodev, /* open */
9003831d35Sstevel nodev, /* close */
9103831d35Sstevel nodev, /* strategy */
9203831d35Sstevel nodev, /* print */
9303831d35Sstevel nodev, /* dump */
9403831d35Sstevel nodev, /* read */
9503831d35Sstevel nodev, /* write */
9603831d35Sstevel nodev, /* ioctl */
9703831d35Sstevel nodev, /* devmap */
9803831d35Sstevel nodev, /* mmap */
9903831d35Sstevel nodev, /* segmap */
10003831d35Sstevel nochpoll, /* poll */
10103831d35Sstevel ddi_prop_op, /* prop_op */
10203831d35Sstevel 0, /* streamtab */
10303831d35Sstevel D_NEW | D_MP, /* Driver compatibility flag */
10403831d35Sstevel CB_REV, /* rev */
10503831d35Sstevel nodev, /* int (*cb_aread)() */
10603831d35Sstevel nodev /* int (*cb_awrite)() */
10703831d35Sstevel };
10803831d35Sstevel
10903831d35Sstevel /*
11003831d35Sstevel * Function prototype for dev_ops
11103831d35Sstevel */
11203831d35Sstevel
11303831d35Sstevel static int sghsc_attach(dev_info_t *, ddi_attach_cmd_t);
11403831d35Sstevel static int sghsc_detach(dev_info_t *, ddi_detach_cmd_t);
11503831d35Sstevel
11603831d35Sstevel static struct dev_ops sghsc_dev_ops = {
11703831d35Sstevel DEVO_REV, /* devo_rev, */
11803831d35Sstevel 0, /* refcnt */
11903831d35Sstevel nulldev, /* get_dev_info */
12003831d35Sstevel nulldev, /* identify */
12103831d35Sstevel nulldev, /* probe */
12203831d35Sstevel sghsc_attach, /* attach */
12303831d35Sstevel sghsc_detach, /* detach */
12403831d35Sstevel nodev, /* reset */
12503831d35Sstevel &sghsc_cb_ops, /* driver operations */
12619397407SSherry Moore (struct bus_ops *)0, /* no bus operations */
12719397407SSherry Moore NULL, /* power */
12819397407SSherry Moore ddi_quiesce_not_needed, /* quiesce */
12903831d35Sstevel };
13003831d35Sstevel
13103831d35Sstevel static struct modldrv modldrv = {
13203831d35Sstevel &mod_driverops,
13319397407SSherry Moore "Serengeti CompactPCI HSC",
13403831d35Sstevel &sghsc_dev_ops,
13503831d35Sstevel };
13603831d35Sstevel
13703831d35Sstevel static struct modlinkage modlinkage = {
13803831d35Sstevel MODREV_1,
13903831d35Sstevel &modldrv,
14003831d35Sstevel NULL
14103831d35Sstevel };
14203831d35Sstevel
14303831d35Sstevel /*
14403831d35Sstevel * Function prototype for HP support
14503831d35Sstevel */
14603831d35Sstevel static int sghsc_connect(caddr_t, hpc_slot_t slot, void *, uint_t);
14703831d35Sstevel static int sghsc_disconnect(caddr_t, hpc_slot_t, void *, uint_t);
14803831d35Sstevel static int sghsc_control(caddr_t, hpc_slot_t, int, caddr_t);
14903831d35Sstevel
15003831d35Sstevel /*
15103831d35Sstevel * Function prototypes for internal functions
15203831d35Sstevel */
15303831d35Sstevel static int sghsc_register_slots(sghsc_t *, int);
15403831d35Sstevel static int sghsc_get_slotnum(sghsc_t *, hpc_slot_t);
15503831d35Sstevel static int sghsc_scctl(int, int, int, int, int *);
15603831d35Sstevel static void sghsc_freemem(sghsc_t *);
15703831d35Sstevel static hpc_slot_t sghsc_find_sloth(int, int, int);
15803831d35Sstevel static sghsc_t *sghsc_find_softstate(int, int, int);
15903831d35Sstevel static int sghsc_led_state(sghsc_t *, hpc_slot_t, int, hpc_led_info_t *);
16003831d35Sstevel static void sghsc_rb_setup(sghsc_rb_head_t *);
16103831d35Sstevel static void sghsc_rb_teardown(sghsc_rb_head_t *);
16203831d35Sstevel static int sghsc_rb_get(sghsc_rb_head_t *, sghsc_event_t *);
16303831d35Sstevel static int sghsc_rb_put(sghsc_rb_head_t *, sghsc_event_t *);
16403831d35Sstevel
16503831d35Sstevel /*
16603831d35Sstevel * Patchable timeout value
16703831d35Sstevel */
16803831d35Sstevel int sghsc_mbx_timeout = SGHSC_MBX_TIMEOUT;
16903831d35Sstevel
17003831d35Sstevel /*
17103831d35Sstevel * Data for self-identification. This will help enumerate all soft states.
17203831d35Sstevel */
17303831d35Sstevel static int sghsc_maxinst;
17403831d35Sstevel
17503831d35Sstevel /*
17603831d35Sstevel * Six slot boat and four slot boats are different in topology (slot to
17703831d35Sstevel * bus assignment) and here we should have 2 separate maps (the first 3
17803831d35Sstevel * slots have the same topology). The map is in the "delta" form. Logical
17903831d35Sstevel * slots correspond to indexes in the map.
18003831d35Sstevel */
18103831d35Sstevel static sdesc_t four_slot_wib_bd[] = {
18203831d35Sstevel 0, 6, 1, HPC_SLOT_TYPE_CPCI, /* logical/physical slot 0 - Schizo0/A */
18303831d35Sstevel 1, 0, 2, 0, /* logical/physical slot 1 - paroli2 */
18403831d35Sstevel 1, 0, 0, 0, /* logical/physical slot 2 - paroli0 */
18503831d35Sstevel 0, 7, 1, HPC_SLOT_TYPE_CPCI /* logical/physical slot 3 - Schizo0/B */
18603831d35Sstevel };
18703831d35Sstevel static sdesc_t four_slot_bd[] = {
18803831d35Sstevel 0, 6, 1, HPC_SLOT_TYPE_CPCI, /* logical/physical slot 0 - Schizo0/A */
18903831d35Sstevel 1, 6, 1, HPC_SLOT_TYPE_CPCI, /* logical/physical slot 1 - Schizo1/A */
19003831d35Sstevel 0, 7, 1, HPC_SLOT_TYPE_CPCI, /* logical/physical slot 2 - Schizo0/B */
19103831d35Sstevel 1, 7, 1, HPC_SLOT_TYPE_CPCI /* logical/physical slot 3 - Schizo1/B */
19203831d35Sstevel };
19303831d35Sstevel static sdesc_t six_slot_wib_bd[] = {
19403831d35Sstevel 0, 6, 1, HPC_SLOT_TYPE_CPCI, /* logical/physical slot 0 - Schizo0/A */
19503831d35Sstevel 1, 0, 2, 0, /* logical/physical slot 1 - paroli2 */
19603831d35Sstevel 1, 0, 0, 0, /* logical/physical slot 2 - paroli0 */
19703831d35Sstevel 0, 7, 1, HPC_SLOT_TYPE_CPCI, /* logical/physical slot 3 - Schizo0/B */
19803831d35Sstevel 0, 7, 2, HPC_SLOT_TYPE_CPCI, /* logical/physical slot 4 - Schizo0/B */
19903831d35Sstevel 0, 7, 3, HPC_SLOT_TYPE_CPCI /* logical/physical slot 5 - Schizo0/B */
20003831d35Sstevel };
20103831d35Sstevel static sdesc_t six_slot_bd[] = {
20203831d35Sstevel 0, 6, 1, HPC_SLOT_TYPE_CPCI, /* logical/physical slot 0 - Schizo0/A */
20303831d35Sstevel 1, 6, 1, HPC_SLOT_TYPE_CPCI, /* logical/physical slot 1 - Schizo1/A */
20403831d35Sstevel 0, 7, 1, HPC_SLOT_TYPE_CPCI, /* logical/physical slot 2 - Schizo0/B */
20503831d35Sstevel 0, 7, 2, HPC_SLOT_TYPE_CPCI, /* logical/physical slot 3 - Schizo0/B */
20603831d35Sstevel 1, 7, 1, HPC_SLOT_TYPE_CPCI, /* logical/physical slot 4 - Schizo1/B */
20703831d35Sstevel 1, 7, 2, HPC_SLOT_TYPE_CPCI /* logical/physical slot 5 - Schizo1/B */
20803831d35Sstevel };
20903831d35Sstevel
21003831d35Sstevel /*
21103831d35Sstevel * DR event handlers
21203831d35Sstevel * We want to register the event handlers once for all instances. In the
21303831d35Sstevel * other hand we have register them after the sghsc has been attached.
21403831d35Sstevel * event_initialize gives us the logic of only registering the events only
21503831d35Sstevel * once. The event thread will do all the work when called from interrupts.
21603831d35Sstevel */
21703831d35Sstevel int sghsc_event_init = 0;
21803831d35Sstevel static uint_t sghsc_event_handler(char *);
21903831d35Sstevel static void sghsc_event_thread_code(void);
22003831d35Sstevel
22103831d35Sstevel /*
22203831d35Sstevel * DR event msg and payload
22303831d35Sstevel */
22403831d35Sstevel static sbbc_msg_t event_msg;
22503831d35Sstevel static sghsc_event_t payload;
22603831d35Sstevel
22703831d35Sstevel /*
22803831d35Sstevel * Event lock and state
22903831d35Sstevel */
23003831d35Sstevel static kmutex_t sghsc_event_lock;
23103831d35Sstevel int sghsc_event_state;
23203831d35Sstevel
23303831d35Sstevel int
_init(void)23403831d35Sstevel _init(void)
23503831d35Sstevel {
23603831d35Sstevel int error;
23703831d35Sstevel
23803831d35Sstevel sghsc_maxinst = 0;
23903831d35Sstevel
24003831d35Sstevel if ((error = ddi_soft_state_init(&sghsc_state,
24103831d35Sstevel sizeof (sghsc_t), 1)) != 0)
24203831d35Sstevel return (error);
24303831d35Sstevel
24403831d35Sstevel if ((error = mod_install(&modlinkage)) != 0) {
24503831d35Sstevel ddi_soft_state_fini(&sghsc_state);
24603831d35Sstevel return (error);
24703831d35Sstevel }
24803831d35Sstevel
24903831d35Sstevel sghsc_rb_header.buf = NULL;
25003831d35Sstevel
25103831d35Sstevel mutex_init(&sghsc_event_thread_mutex, NULL, MUTEX_DRIVER, NULL);
25203831d35Sstevel cv_init(&sghsc_event_thread_cv, NULL, CV_DRIVER, NULL);
25303831d35Sstevel
25403831d35Sstevel return (error);
25503831d35Sstevel }
25603831d35Sstevel
25703831d35Sstevel int
_fini(void)25803831d35Sstevel _fini(void)
25903831d35Sstevel {
26003831d35Sstevel int error;
26103831d35Sstevel
26203831d35Sstevel if ((error = mod_remove(&modlinkage)) != 0)
26303831d35Sstevel return (error);
26403831d35Sstevel /*
26503831d35Sstevel * Unregister the event handler
26603831d35Sstevel */
26707d06da5SSurya Prakki (void) sbbc_mbox_unreg_intr(MBOX_EVENT_CPCI_ENUM, sghsc_event_handler);
26803831d35Sstevel mutex_destroy(&sghsc_event_lock);
26903831d35Sstevel
27003831d35Sstevel /*
27103831d35Sstevel * Kill the event thread if it is running.
27203831d35Sstevel */
27303831d35Sstevel if (sghsc_event_thread != NULL) {
27403831d35Sstevel mutex_enter(&sghsc_event_thread_mutex);
27503831d35Sstevel sghsc_event_thread_exit = B_TRUE;
27603831d35Sstevel /*
27703831d35Sstevel * Goes to the thread at once.
27803831d35Sstevel */
27903831d35Sstevel cv_signal(&sghsc_event_thread_cv);
28003831d35Sstevel /*
28103831d35Sstevel * Waiting for the response from the thread.
28203831d35Sstevel */
28303831d35Sstevel cv_wait(&sghsc_event_thread_cv, &sghsc_event_thread_mutex);
28403831d35Sstevel mutex_exit(&sghsc_event_thread_mutex);
28503831d35Sstevel sghsc_event_thread = NULL;
28603831d35Sstevel }
28703831d35Sstevel mutex_destroy(&sghsc_event_thread_mutex);
28803831d35Sstevel cv_destroy(&sghsc_event_thread_cv);
28903831d35Sstevel
29003831d35Sstevel /*
29103831d35Sstevel * tear down shared, global ring buffer now that it is safe to
29203831d35Sstevel * do so because sghsc_event_handler has been unregistered and
29303831d35Sstevel * sghsc_event_thread_code has exited
29403831d35Sstevel */
29503831d35Sstevel sghsc_rb_teardown(&sghsc_rb_header);
29603831d35Sstevel
29703831d35Sstevel sghsc_maxinst = 0;
29803831d35Sstevel ddi_soft_state_fini(&sghsc_state);
29903831d35Sstevel
30003831d35Sstevel return (0);
30103831d35Sstevel }
30203831d35Sstevel
30303831d35Sstevel int
_info(struct modinfo * modinfop)30403831d35Sstevel _info(struct modinfo *modinfop)
30503831d35Sstevel {
30603831d35Sstevel return (mod_info(&modlinkage, modinfop));
30703831d35Sstevel }
30803831d35Sstevel
30903831d35Sstevel /*
31003831d35Sstevel * sghsc_attach()
31103831d35Sstevel */
31203831d35Sstevel /* ARGSUSED */
31303831d35Sstevel static int
sghsc_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)31403831d35Sstevel sghsc_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
31503831d35Sstevel {
31603831d35Sstevel sghsc_t *sghsc;
31703831d35Sstevel uint_t instance;
31803831d35Sstevel uint_t portid;
31903831d35Sstevel int rc;
32003831d35Sstevel int board_type = 0;
32103831d35Sstevel
32203831d35Sstevel instance = ddi_get_instance(dip);
32303831d35Sstevel
32403831d35Sstevel switch (cmd) {
32503831d35Sstevel case DDI_RESUME:
32603831d35Sstevel return (DDI_SUCCESS);
32703831d35Sstevel
32803831d35Sstevel case DDI_ATTACH:
32903831d35Sstevel break;
33003831d35Sstevel default:
33103831d35Sstevel cmn_err(CE_WARN, "sghsc%d: unsupported cmd %d",
33203831d35Sstevel instance, cmd);
33303831d35Sstevel return (DDI_FAILURE);
33403831d35Sstevel }
33503831d35Sstevel
33603831d35Sstevel DEBUGF(1, (CE_NOTE, "attach sghsc driver. "));
33703831d35Sstevel
33803831d35Sstevel /* Fetch Safari Extended Agent ID of this device. */
33903831d35Sstevel portid = (uint_t)ddi_getprop(DDI_DEV_T_ANY, dip,
34003831d35Sstevel DDI_PROP_DONTPASS, "portid", -1);
34103831d35Sstevel
34203831d35Sstevel if (!SG_PORTID_IS_IO_TYPE(portid)) {
34303831d35Sstevel cmn_err(CE_WARN, "sghsc%d: property %s out of bounds %d\n",
34403831d35Sstevel instance, "portid", portid);
34503831d35Sstevel return (DDI_FAILURE);
34603831d35Sstevel }
34703831d35Sstevel
34803831d35Sstevel if (ddi_soft_state_zalloc(sghsc_state, instance) != DDI_SUCCESS)
34903831d35Sstevel return (DDI_FAILURE);
35003831d35Sstevel
35103831d35Sstevel sghsc = (sghsc_t *)ddi_get_soft_state(sghsc_state, instance);
35203831d35Sstevel
35303831d35Sstevel sghsc->sghsc_dip = dip;
35403831d35Sstevel sghsc->sghsc_instance = instance;
35503831d35Sstevel sghsc->sghsc_board = SG_PORTID_TO_BOARD_NUM(portid);
35603831d35Sstevel sghsc->sghsc_node_id = SG_PORTID_TO_NODEID(portid);
35703831d35Sstevel sghsc->sghsc_portid = portid;
35803831d35Sstevel
35903831d35Sstevel ddi_set_driver_private(dip, sghsc);
36003831d35Sstevel
36103831d35Sstevel mutex_init(SGHSC_MUTEX(sghsc), NULL, MUTEX_DRIVER, NULL);
36203831d35Sstevel
36303831d35Sstevel rc = sghsc_scctl(SGHSC_GET_NUM_SLOTS, sghsc->sghsc_node_id,
36403831d35Sstevel sghsc->sghsc_board, 0, (int *)&sghsc->sghsc_num_slots);
36503831d35Sstevel
36603831d35Sstevel if (rc) {
36703831d35Sstevel cmn_err(CE_WARN, "sghsc%d: unable to size node %d / board %d",
36803831d35Sstevel instance, sghsc->sghsc_node_id, sghsc->sghsc_board);
36903831d35Sstevel goto cleanup_stage2;
37003831d35Sstevel }
37103831d35Sstevel
37203831d35Sstevel DEBUGF(1, (CE_NOTE, "sghsc%d: node %d / board %d has %d slots",
37303831d35Sstevel instance, sghsc->sghsc_node_id, sghsc->sghsc_board,
37403831d35Sstevel sghsc->sghsc_num_slots));
37503831d35Sstevel
37603831d35Sstevel switch (sghsc->sghsc_num_slots) {
37703831d35Sstevel case 4:
37803831d35Sstevel case 6:
37903831d35Sstevel rc = 0;
38003831d35Sstevel break;
38103831d35Sstevel default:
38203831d35Sstevel rc = -1;
38303831d35Sstevel break;
38403831d35Sstevel }
38503831d35Sstevel
38603831d35Sstevel if (rc) {
38703831d35Sstevel cmn_err(CE_WARN, "sghsc%d: wrong num of slots %d for node %d"
38803831d35Sstevel " / board %d", instance, sghsc->sghsc_num_slots,
38903831d35Sstevel sghsc->sghsc_node_id, sghsc->sghsc_board);
39003831d35Sstevel goto cleanup_stage2;
39103831d35Sstevel }
39203831d35Sstevel
39303831d35Sstevel rc = sghsc_scctl(SGHSC_GET_CPCI_BOARD_TYPE, sghsc->sghsc_node_id,
39403831d35Sstevel sghsc->sghsc_board, 0, &board_type);
39503831d35Sstevel
39603831d35Sstevel DEBUGF(1, (CE_NOTE, "sghsc%d: node %d / board %d is type %d",
39703831d35Sstevel instance, sghsc->sghsc_node_id, sghsc->sghsc_board, board_type));
39803831d35Sstevel
39903831d35Sstevel sghsc->sghsc_slot_table = (sghsc_slot_t *)kmem_zalloc((size_t)
40003831d35Sstevel (sghsc->sghsc_num_slots * sizeof (sghsc_slot_t)), KM_SLEEP);
40103831d35Sstevel
40203831d35Sstevel
40303831d35Sstevel if (sghsc_register_slots(sghsc, board_type) != DDI_SUCCESS) {
40403831d35Sstevel DEBUGF(1, (CE_NOTE, "sghsc%d: sghsc_register_slots"
40503831d35Sstevel " failed for node %d / board %d",
40603831d35Sstevel instance, sghsc->sghsc_node_id, sghsc->sghsc_board));
40703831d35Sstevel goto cleanup;
40803831d35Sstevel }
40903831d35Sstevel
41003831d35Sstevel if (sghsc_connect((caddr_t)sghsc, 0, 0, SGHSC_ALL_SLOTS_ENABLE)
41103831d35Sstevel != HPC_SUCCESS) {
41203831d35Sstevel DEBUGF(1, (CE_NOTE, "sghsc%d: sghsc_connect failed for"
41303831d35Sstevel " node %d / board %d", instance, sghsc->sghsc_node_id,
41403831d35Sstevel sghsc->sghsc_board));
41503831d35Sstevel goto cleanup;
41603831d35Sstevel }
41703831d35Sstevel
41803831d35Sstevel
41903831d35Sstevel if (sghsc_event_init == 0) {
42003831d35Sstevel
42103831d35Sstevel /*
42203831d35Sstevel * allocate shared, global ring buffer before registering
42303831d35Sstevel * sghsc_event_handler and before starting
42403831d35Sstevel * sghsc_event_thread_code
42503831d35Sstevel */
42603831d35Sstevel sghsc_rb_setup(&sghsc_rb_header);
42703831d35Sstevel
42803831d35Sstevel /*
42903831d35Sstevel * Regiter cpci DR event handler
43003831d35Sstevel *
43103831d35Sstevel */
43203831d35Sstevel mutex_init(&sghsc_event_lock, NULL, MUTEX_DRIVER, NULL);
43303831d35Sstevel event_msg.msg_buf = (caddr_t)&payload;
43403831d35Sstevel event_msg.msg_len = sizeof (payload);
43503831d35Sstevel rc = sbbc_mbox_reg_intr(MBOX_EVENT_CPCI_ENUM,
43603831d35Sstevel sghsc_event_handler, &event_msg,
43703831d35Sstevel (uint_t *)&sghsc_event_state, &sghsc_event_lock);
43803831d35Sstevel
43903831d35Sstevel if (rc != 0)
44003831d35Sstevel cmn_err(CE_WARN, "sghsc%d: failed to register events"
44103831d35Sstevel " for node %d", instance, sghsc->sghsc_node_id);
44203831d35Sstevel
44303831d35Sstevel sghsc_event_init = 1;
44403831d35Sstevel
44503831d35Sstevel /*
44603831d35Sstevel * Create the event thread if it is not already created.
44703831d35Sstevel */
44803831d35Sstevel if (sghsc_event_thread == NULL) {
44903831d35Sstevel DEBUGF(1, (CE_NOTE, "sghsc: creating event thread"
45003831d35Sstevel "for node %d", sghsc->sghsc_node_id));
45103831d35Sstevel sghsc_event_thread = thread_create(NULL, 0,
45203831d35Sstevel sghsc_event_thread_code, NULL, 0, &p0,
45303831d35Sstevel TS_RUN, minclsyspri);
45403831d35Sstevel }
45503831d35Sstevel }
45603831d35Sstevel
45703831d35Sstevel ddi_report_dev(dip);
45803831d35Sstevel
45903831d35Sstevel /*
46003831d35Sstevel * Grossly bump up the instance counter. We may have holes inside.
46103831d35Sstevel */
46203831d35Sstevel sghsc_maxinst++;
46303831d35Sstevel sghsc->sghsc_valid = 1;
46403831d35Sstevel
46503831d35Sstevel return (DDI_SUCCESS);
46603831d35Sstevel
46703831d35Sstevel cleanup:
46803831d35Sstevel /*
46903831d35Sstevel * Free up allocated resources and return error
47003831d35Sstevel * sghsc_register_slots => unregister all slots
47103831d35Sstevel */
47203831d35Sstevel sghsc_freemem(sghsc);
47303831d35Sstevel
47403831d35Sstevel cleanup_stage2:
47503831d35Sstevel DEBUGF(1, (CE_NOTE, "sghsc%d: attach failed for node %d",
47603831d35Sstevel instance, sghsc->sghsc_node_id));
47703831d35Sstevel mutex_destroy(SGHSC_MUTEX(sghsc));
47803831d35Sstevel ddi_set_driver_private(dip, NULL);
47903831d35Sstevel ddi_soft_state_free(sghsc_state, instance);
48003831d35Sstevel return (DDI_FAILURE);
48103831d35Sstevel }
48203831d35Sstevel
48303831d35Sstevel /*
48403831d35Sstevel * detach(9E)
48503831d35Sstevel */
48603831d35Sstevel /* ARGSUSED */
48703831d35Sstevel static int
sghsc_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)48803831d35Sstevel sghsc_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
48903831d35Sstevel {
49003831d35Sstevel sghsc_t *sghsc;
49103831d35Sstevel int instance;
49203831d35Sstevel int i;
49303831d35Sstevel
49403831d35Sstevel instance = ddi_get_instance(dip);
49503831d35Sstevel sghsc = (sghsc_t *)ddi_get_soft_state(sghsc_state, instance);
49603831d35Sstevel
49703831d35Sstevel if (sghsc == NULL)
49803831d35Sstevel return (DDI_FAILURE);
49903831d35Sstevel
50003831d35Sstevel switch (cmd) {
50103831d35Sstevel case DDI_DETACH:
50203831d35Sstevel /*
50303831d35Sstevel * We don't allow to detach in case the pci nexus
50403831d35Sstevel * didn't run pcihp_uninit(). The buses should be
50503831d35Sstevel * unregistered by now, otherwise slot info will be
50603831d35Sstevel * corrupted on the next 'cfgadm'.
50703831d35Sstevel */
50803831d35Sstevel for (i = 0; i < sghsc->sghsc_num_slots; i++) {
50903831d35Sstevel if (sghsc->sghsc_slot_table[i].handle &&
51003831d35Sstevel hpc_bus_registered(
51103831d35Sstevel sghsc->sghsc_slot_table[i].handle)) {
51203831d35Sstevel cmn_err(CE_WARN,
51303831d35Sstevel "sghsc: must detach buses first");
51403831d35Sstevel return (DDI_FAILURE);
51503831d35Sstevel }
51603831d35Sstevel }
51703831d35Sstevel
51803831d35Sstevel if (mutex_tryenter(&sghsc_event_thread_mutex) == 0)
51903831d35Sstevel return (EBUSY);
52003831d35Sstevel
52103831d35Sstevel sghsc->sghsc_valid = 0;
52203831d35Sstevel sghsc_freemem(sghsc);
52303831d35Sstevel mutex_destroy(SGHSC_MUTEX(sghsc));
52403831d35Sstevel ddi_set_driver_private(dip, NULL);
52503831d35Sstevel ddi_soft_state_free(sghsc_state, instance);
52603831d35Sstevel
52703831d35Sstevel /*
52803831d35Sstevel * Grossly decrement the counter. We may have holes inside.
52903831d35Sstevel */
53003831d35Sstevel if (instance == (sghsc_maxinst - 1))
53103831d35Sstevel sghsc_maxinst--;
53203831d35Sstevel mutex_exit(&sghsc_event_thread_mutex);
53303831d35Sstevel return (DDI_SUCCESS);
53403831d35Sstevel
53503831d35Sstevel case DDI_SUSPEND:
53603831d35Sstevel return (DDI_SUCCESS);
53703831d35Sstevel
53803831d35Sstevel default:
53903831d35Sstevel return (DDI_FAILURE);
54003831d35Sstevel }
54103831d35Sstevel }
54203831d35Sstevel
54303831d35Sstevel
54403831d35Sstevel /*
54503831d35Sstevel * Set up and register slot 0 to num_slots with hotplug
54603831d35Sstevel * framework
54703831d35Sstevel * Assume SGHSC_MUTEX is held
54803831d35Sstevel *
54903831d35Sstevel * Return val: DDI_SUCCESS
55003831d35Sstevel * DDI_FAILURE
55103831d35Sstevel */
55203831d35Sstevel static int
sghsc_register_slots(sghsc_t * sghsc,int board_type)55303831d35Sstevel sghsc_register_slots(sghsc_t *sghsc, int board_type)
55403831d35Sstevel {
55503831d35Sstevel int i;
55603831d35Sstevel dev_info_t *dip = sghsc->sghsc_dip;
55703831d35Sstevel hpc_slot_ops_t *slot_ops = NULL;
55803831d35Sstevel sdesc_t *slot2bus;
55903831d35Sstevel
56003831d35Sstevel
56103831d35Sstevel DEBUGF(1, (CE_NOTE, "sghsc%d: slot table has %d entries for "
56203831d35Sstevel "node %d / board %d", sghsc->sghsc_instance, sghsc->sghsc_num_slots,
56303831d35Sstevel sghsc->sghsc_node_id, sghsc->sghsc_board));
56403831d35Sstevel
56503831d35Sstevel if ((cpci_enable == 0) || (sg_prom_cpci_dr_check() != 0))
56603831d35Sstevel return (DDI_SUCCESS);
56703831d35Sstevel
56803831d35Sstevel if (sghsc->sghsc_slot_table == NULL)
56903831d35Sstevel return (DDI_FAILURE);
57003831d35Sstevel
57103831d35Sstevel switch (board_type) {
57203831d35Sstevel /*
57303831d35Sstevel * If the GET_CPCI_BOARD_TYPE request failed, board type
57403831d35Sstevel * will be NO_BOARD_TYPE. In that case, assume it is an
57503831d35Sstevel * io boat and make board type determination based on the
57603831d35Sstevel * number of slots.
57703831d35Sstevel */
57803831d35Sstevel case NO_BOARD_TYPE:
57903831d35Sstevel case CPCI_BOARD:
58003831d35Sstevel case SP_CPCI_BOARD:
58103831d35Sstevel switch (sghsc->sghsc_num_slots) {
58203831d35Sstevel case 4:
58303831d35Sstevel slot2bus = four_slot_bd;
58403831d35Sstevel break;
58503831d35Sstevel case 6:
58603831d35Sstevel slot2bus = six_slot_bd;
58703831d35Sstevel break;
58803831d35Sstevel default:
58903831d35Sstevel cmn_err(CE_WARN, "sghsc%d: unknown size %d for"
59003831d35Sstevel " node %d / board %d",
59103831d35Sstevel sghsc->sghsc_instance,
59203831d35Sstevel sghsc->sghsc_num_slots,
59303831d35Sstevel sghsc->sghsc_node_id, sghsc->sghsc_board);
59403831d35Sstevel break;
59503831d35Sstevel }
59603831d35Sstevel break;
59703831d35Sstevel case WCI_CPCI_BOARD:
59803831d35Sstevel slot2bus = four_slot_wib_bd;
59903831d35Sstevel break;
60003831d35Sstevel case WCI_SP_CPCI_BOARD:
60103831d35Sstevel slot2bus = six_slot_wib_bd;
60203831d35Sstevel break;
60303831d35Sstevel default:
60403831d35Sstevel cmn_err(CE_WARN, "sghsc%d: unknown type %d for"
60503831d35Sstevel " node %d / board %d", sghsc->sghsc_instance,
60603831d35Sstevel board_type, sghsc->sghsc_node_id,
60703831d35Sstevel sghsc->sghsc_board);
60803831d35Sstevel return (DDI_FAILURE);
60903831d35Sstevel }
61003831d35Sstevel
61103831d35Sstevel /*
61203831d35Sstevel * constructing the slot table array and register the
61303831d35Sstevel * slot with the HPS
61403831d35Sstevel * we don't depend on the .conf file
61503831d35Sstevel */
61603831d35Sstevel for (i = 0; i < sghsc->sghsc_num_slots; i++) {
61703831d35Sstevel char *nexuspath;
61803831d35Sstevel hpc_slot_info_t *slot_info;
61903831d35Sstevel uint32_t base_id;
62003831d35Sstevel
62103831d35Sstevel /*
62203831d35Sstevel * Some kind of black list may be needed
62303831d35Sstevel */
62403831d35Sstevel
62503831d35Sstevel /*
62603831d35Sstevel * Need to talk to SC and get slot info and set slot state:
62703831d35Sstevel * 1. slot status
62803831d35Sstevel * 2. slot capabilities
62903831d35Sstevel * 3. LED status
63003831d35Sstevel * 4. get bus num
63103831d35Sstevel */
63203831d35Sstevel
63303831d35Sstevel /*
63403831d35Sstevel * fill up nexuspath, extended id is used instead of the
63503831d35Sstevel * local one, the node id is encoded in the path twice.
63603831d35Sstevel */
63703831d35Sstevel base_id = sghsc->sghsc_portid & SGHSC_SAFARI_ID_EVEN;
63803831d35Sstevel nexuspath = sghsc->sghsc_slot_table[i].nexus_path;
63903831d35Sstevel
64007d06da5SSurya Prakki (void) sprintf(nexuspath, SGHSC_PATH, sghsc->sghsc_node_id,
64103831d35Sstevel (base_id + slot2bus[i].agent_delta), slot2bus[i].off);
64203831d35Sstevel sghsc->sghsc_slot_table[i].pci_device_num =
64303831d35Sstevel slot2bus[i].pcidev;
64403831d35Sstevel
64503831d35Sstevel /*
64603831d35Sstevel * fill up slot_info
64703831d35Sstevel */
64803831d35Sstevel slot_info = &sghsc->sghsc_slot_table[i].slot_info;
64903831d35Sstevel
65003831d35Sstevel slot_info->version = HPC_SLOT_INFO_VERSION;
65103831d35Sstevel slot_info->slot_type = slot2bus[i].slot_type;
65203831d35Sstevel /* capabilities need to be discovered via SC */
65303831d35Sstevel slot_info->pci_slot_capabilities = HPC_SLOT_64BITS;
65403831d35Sstevel slot_info->pci_dev_num = slot2bus[i].pcidev;
65503831d35Sstevel
65607d06da5SSurya Prakki (void) sprintf(slot_info->pci_slot_name,
65703831d35Sstevel "sg%dslot%d", sghsc->sghsc_board, i);
65803831d35Sstevel DEBUGF(1, (CE_NOTE, "pci_slot_name is %s at pci_dev_num %d"
65903831d35Sstevel " on node %d / board %d", slot_info->pci_slot_name,
66003831d35Sstevel slot_info->pci_dev_num, sghsc->sghsc_node_id,
66103831d35Sstevel sghsc->sghsc_board));
66203831d35Sstevel
66303831d35Sstevel /*
66403831d35Sstevel * allocate and fill up slot_ops
66503831d35Sstevel */
66603831d35Sstevel slot_ops = hpc_alloc_slot_ops(KM_SLEEP);
66703831d35Sstevel sghsc->sghsc_slot_table[i].slot_ops = slot_ops;
66803831d35Sstevel
66903831d35Sstevel /* assign slot ops for HPS */
67003831d35Sstevel slot_ops->hpc_version = HPC_SLOT_OPS_VERSION;
67103831d35Sstevel slot_ops->hpc_op_connect = sghsc_connect;
67203831d35Sstevel slot_ops->hpc_op_disconnect = sghsc_disconnect;
67303831d35Sstevel slot_ops->hpc_op_insert = nodev;
67403831d35Sstevel slot_ops->hpc_op_remove = nodev;
67503831d35Sstevel slot_ops->hpc_op_control = sghsc_control;
67603831d35Sstevel
67703831d35Sstevel /*
67803831d35Sstevel * HA (Full Hot Swap) is the default mode of operation
67903831d35Sstevel * but the type of the board is set conservstively as
68003831d35Sstevel * sghsc has no way of knowing it. The HP Framwork will
68103831d35Sstevel * overwrite the value set at boot time.
68203831d35Sstevel */
68303831d35Sstevel sghsc->sghsc_slot_table[i].flags = SGHSC_SLOT_AUTO_CFG_EN;
68403831d35Sstevel sghsc->sghsc_slot_table[i].board_type = HPC_BOARD_UNKNOWN;
68503831d35Sstevel
68603831d35Sstevel /* Only register CPCI slots */
68703831d35Sstevel if (slot_info->slot_type != HPC_SLOT_TYPE_CPCI) {
68803831d35Sstevel DEBUGF(1, (CE_NOTE, "sghsc_register_slots: "
68903831d35Sstevel "slot %d is non-cpci", i));
69003831d35Sstevel continue;
69103831d35Sstevel }
69203831d35Sstevel
69303831d35Sstevel /*
69403831d35Sstevel * register slots
69503831d35Sstevel */
69603831d35Sstevel if ((hpc_slot_register(dip, nexuspath, slot_info,
69703831d35Sstevel &sghsc->sghsc_slot_table[i].handle,
69803831d35Sstevel slot_ops, (caddr_t)sghsc, 0)) != 0) {
69903831d35Sstevel
70003831d35Sstevel /*
70103831d35Sstevel * return failure and let attach()
70203831d35Sstevel * do the cleanup
70303831d35Sstevel */
70403831d35Sstevel cmn_err(CE_WARN, "sghsc%d: Slot <%s> failed during HPS"
70503831d35Sstevel " registration process for node %d / board %d",
70603831d35Sstevel sghsc->sghsc_instance, slot_info->pci_slot_name,
70703831d35Sstevel sghsc->sghsc_node_id, sghsc->sghsc_board);
70803831d35Sstevel return (DDI_FAILURE);
70903831d35Sstevel }
71003831d35Sstevel
71103831d35Sstevel }
71203831d35Sstevel DEBUGF(1, (CE_NOTE, "sghsc registered successfully for"
71303831d35Sstevel " node %d / board %d", sghsc->sghsc_node_id, sghsc->sghsc_board));
71403831d35Sstevel return (DDI_SUCCESS);
71503831d35Sstevel }
71603831d35Sstevel
71703831d35Sstevel /*
71803831d35Sstevel * Connecting a slot or all slots
71903831d35Sstevel * State Diagram:
72003831d35Sstevel * states
72103831d35Sstevel * hw bits EMPTY DISCONNECT CONNECT
72203831d35Sstevel * slot_enable NO NO YES
72303831d35Sstevel * card_present NO YES YES
72403831d35Sstevel * slot_switch N/A NO/YES YES
72503831d35Sstevel *
72603831d35Sstevel * Return val: HPC_SUCCESS if the slot(s) are enabled
72703831d35Sstevel * HPC_ERR_FAILED if the slot can't be enabled
72803831d35Sstevel */
72903831d35Sstevel /* ARGSUSED */
73003831d35Sstevel static int
sghsc_connect(caddr_t op_arg,hpc_slot_t sloth,void * data,uint_t flag)73103831d35Sstevel sghsc_connect(caddr_t op_arg, hpc_slot_t sloth, void *data,
73203831d35Sstevel uint_t flag)
73303831d35Sstevel {
73403831d35Sstevel int i = 0;
73503831d35Sstevel sghsc_t *sghsc = (sghsc_t *)op_arg;
73603831d35Sstevel int rc;
73703831d35Sstevel int result;
73803831d35Sstevel int slot_num = sghsc_get_slotnum(sghsc, sloth);
73903831d35Sstevel
74003831d35Sstevel switch (flag) {
74103831d35Sstevel
74203831d35Sstevel case SGHSC_ALL_SLOTS_ENABLE:
74303831d35Sstevel for (i = 0; i < sghsc->sghsc_num_slots; i++) {
74403831d35Sstevel /*
74503831d35Sstevel * All slots will be marked 'empty' as HP Framework
74603831d35Sstevel * will try to connect those which have no kernel node.
74703831d35Sstevel */
74803831d35Sstevel sghsc->sghsc_slot_table[i].slot_status =
74903831d35Sstevel HPC_SLOT_EMPTY;
75003831d35Sstevel }
75103831d35Sstevel
75203831d35Sstevel return (HPC_SUCCESS);
75303831d35Sstevel }
75403831d35Sstevel
75503831d35Sstevel if (slot_num == -1)
75603831d35Sstevel return (HPC_ERR_INVALID);
75703831d35Sstevel
75803831d35Sstevel SGHSC_MUTEX_ENTER(sghsc);
75903831d35Sstevel
76003831d35Sstevel DEBUGF(1, (CE_NOTE, "sghsc%d: connecting logical slot%d for"
76103831d35Sstevel " node %d / board %d", sghsc->sghsc_instance, slot_num,
76203831d35Sstevel sghsc->sghsc_node_id, sghsc->sghsc_board));
76303831d35Sstevel
76403831d35Sstevel /*
76503831d35Sstevel * Powering an empty slot is highly illegal so far
76603831d35Sstevel * (before SC implemented a constant poll). Otherwise
76703831d35Sstevel * it breaks ddi framework and HP. The workaround
76803831d35Sstevel * is to check for a card first.
76903831d35Sstevel */
77003831d35Sstevel rc = sghsc_scctl(SGHSC_GET_SLOT_STATUS, sghsc->sghsc_node_id,
77103831d35Sstevel sghsc->sghsc_board, slot_num, &result);
77203831d35Sstevel
77303831d35Sstevel if (rc == ETIMEDOUT) {
77403831d35Sstevel SGHSC_MUTEX_EXIT(sghsc);
77503831d35Sstevel return (HPC_ERR_FAILED);
77603831d35Sstevel }
77703831d35Sstevel
77803831d35Sstevel if (rc) {
77903831d35Sstevel cmn_err(CE_NOTE, "sghsc%d: unable to stat slot %d for"
78003831d35Sstevel " node %d / board %d", sghsc->sghsc_instance, slot_num,
78103831d35Sstevel sghsc->sghsc_node_id, sghsc->sghsc_board);
78203831d35Sstevel sghsc->sghsc_slot_table[i].slot_status = HPC_SLOT_UNKNOWN;
78303831d35Sstevel SGHSC_MUTEX_EXIT(sghsc);
78403831d35Sstevel return (HPC_ERR_FAILED);
78503831d35Sstevel }
78603831d35Sstevel
78703831d35Sstevel
78803831d35Sstevel if ((result >> CPCI_STAT_SLOT_EMPTY_SHIFT) & ONE_BIT) {
78903831d35Sstevel sghsc->sghsc_slot_table[i].slot_status = HPC_SLOT_EMPTY;
79003831d35Sstevel SGHSC_MUTEX_EXIT(sghsc);
79103831d35Sstevel return (HPC_ERR_FAILED);
79203831d35Sstevel }
79303831d35Sstevel
79403831d35Sstevel rc = sghsc_scctl(SGHSC_SET_SLOT_POWER_ON, sghsc->sghsc_node_id,
79503831d35Sstevel sghsc->sghsc_board, slot_num, &result);
79603831d35Sstevel if (rc) {
79703831d35Sstevel cmn_err(CE_WARN, "sghsc%d: unable to poweron slot %d for"
79803831d35Sstevel " node %d / board %d", sghsc->sghsc_instance,
79903831d35Sstevel slot_num, sghsc->sghsc_node_id, sghsc->sghsc_board);
80003831d35Sstevel SGHSC_MUTEX_EXIT(sghsc);
80103831d35Sstevel return (HPC_ERR_FAILED);
80203831d35Sstevel } else {
80303831d35Sstevel sghsc->sghsc_slot_table[slot_num].slot_status =
80403831d35Sstevel HPC_SLOT_CONNECTED;
80503831d35Sstevel }
80603831d35Sstevel
80703831d35Sstevel SGHSC_MUTEX_EXIT(sghsc);
80803831d35Sstevel
80903831d35Sstevel return (HPC_SUCCESS);
81003831d35Sstevel }
81103831d35Sstevel
81203831d35Sstevel
81303831d35Sstevel /*
81403831d35Sstevel * Disconnecting a slot or slots
81503831d35Sstevel *
81603831d35Sstevel * return: HPC_SUCCESS if slot(s) are successfully disconnected
81703831d35Sstevel * HPC_ERR_FAILED if slot(s) can't be disconnected
81803831d35Sstevel *
81903831d35Sstevel */
82003831d35Sstevel /* ARGSUSED */
82103831d35Sstevel static int
sghsc_disconnect(caddr_t op_arg,hpc_slot_t sloth,void * data,uint_t flag)82203831d35Sstevel sghsc_disconnect(caddr_t op_arg, hpc_slot_t sloth, void *data,
82303831d35Sstevel uint_t flag)
82403831d35Sstevel {
82503831d35Sstevel sghsc_t *sghsc = (sghsc_t *)op_arg;
82603831d35Sstevel int rc;
82703831d35Sstevel int result;
82803831d35Sstevel int slot_num = sghsc_get_slotnum(sghsc, sloth);
82903831d35Sstevel
83003831d35Sstevel switch (flag) {
83103831d35Sstevel case SGHSC_ALL_SLOTS_DISABLE:
83203831d35Sstevel return (HPC_SUCCESS);
83303831d35Sstevel
83403831d35Sstevel }
83503831d35Sstevel
83603831d35Sstevel if (slot_num == -1)
83703831d35Sstevel return (HPC_ERR_INVALID);
83803831d35Sstevel
83903831d35Sstevel SGHSC_MUTEX_ENTER(sghsc);
84003831d35Sstevel
84103831d35Sstevel /*
84203831d35Sstevel * Disconnecting an empty or disconnected slot
84303831d35Sstevel * does't make sense.
84403831d35Sstevel */
84503831d35Sstevel if (sghsc->sghsc_slot_table[slot_num].slot_status !=
84603831d35Sstevel HPC_SLOT_CONNECTED) {
84703831d35Sstevel SGHSC_MUTEX_EXIT(sghsc);
84803831d35Sstevel return (HPC_SUCCESS);
84903831d35Sstevel }
85003831d35Sstevel
85103831d35Sstevel rc = sghsc_scctl(SGHSC_SET_SLOT_POWER_OFF, sghsc->sghsc_node_id,
85203831d35Sstevel sghsc->sghsc_board, slot_num, &result);
85303831d35Sstevel if (rc) {
85403831d35Sstevel cmn_err(CE_WARN, "sghsc%d: unable to poweroff slot %d for"
85503831d35Sstevel " node %d / board %d", sghsc->sghsc_instance,
85603831d35Sstevel slot_num, sghsc->sghsc_node_id, sghsc->sghsc_board);
85703831d35Sstevel SGHSC_MUTEX_EXIT(sghsc);
85803831d35Sstevel return (HPC_ERR_FAILED);
85903831d35Sstevel } else {
86003831d35Sstevel sghsc->sghsc_slot_table[slot_num].slot_status =
86103831d35Sstevel HPC_SLOT_DISCONNECTED;
86203831d35Sstevel }
86303831d35Sstevel
86403831d35Sstevel SGHSC_MUTEX_EXIT(sghsc);
86503831d35Sstevel
86603831d35Sstevel return (HPC_SUCCESS);
86703831d35Sstevel }
86803831d35Sstevel
86903831d35Sstevel /*
87003831d35Sstevel * Entry point from the hotplug framework to do
87103831d35Sstevel * the main hotplug operations
87203831d35Sstevel * Return val: HPC_SUCCESS success on ops
87303831d35Sstevel * HPC_NOT_SUPPORTED not supported feature
87403831d35Sstevel * HPC_ERR_FAILED ops failed
87503831d35Sstevel */
87603831d35Sstevel /*ARGSUSED*/
87703831d35Sstevel static int
sghsc_control(caddr_t op_arg,hpc_slot_t sloth,int request,caddr_t arg)87803831d35Sstevel sghsc_control(caddr_t op_arg, hpc_slot_t sloth, int request,
87903831d35Sstevel caddr_t arg)
88003831d35Sstevel {
88103831d35Sstevel sghsc_t *sghsc = (sghsc_t *)op_arg;
88203831d35Sstevel int slot = sghsc_get_slotnum(sghsc, sloth);
88303831d35Sstevel int error = HPC_SUCCESS;
88403831d35Sstevel int rc;
88503831d35Sstevel int result;
88603831d35Sstevel
88703831d35Sstevel if ((sghsc == NULL) || (slot < 0) ||
88803831d35Sstevel (slot >= sghsc->sghsc_num_slots)) {
88903831d35Sstevel cmn_err(CE_WARN, "sghsc%d: sghsc_control fails with slot = %d"
89003831d35Sstevel " max = %d, sloth = 0x%p for node %d / board %d",
89103831d35Sstevel sghsc->sghsc_instance, slot, sghsc->sghsc_num_slots,
89203831d35Sstevel sloth, sghsc->sghsc_node_id, sghsc->sghsc_board);
89303831d35Sstevel return (HPC_ERR_INVALID);
89403831d35Sstevel }
89503831d35Sstevel
89603831d35Sstevel SGHSC_MUTEX_ENTER(sghsc);
89703831d35Sstevel
89803831d35Sstevel switch (request) {
89903831d35Sstevel case HPC_CTRL_GET_LED_STATE: {
90003831d35Sstevel /* arg == hpc_led_info_t */
90103831d35Sstevel
90203831d35Sstevel hpc_led_info_t *ledinfo;
90303831d35Sstevel
90403831d35Sstevel ledinfo = (hpc_led_info_t *)arg;
90503831d35Sstevel
90603831d35Sstevel DEBUGF(1, (CE_NOTE, "sghsc%d: sghsc_control"
90703831d35Sstevel " HPC_CTRL_GET_LED_STATE for node %d / board %d slot %d",
90803831d35Sstevel sghsc->sghsc_instance, sghsc->sghsc_node_id,
90903831d35Sstevel sghsc->sghsc_board, slot));
91003831d35Sstevel
91103831d35Sstevel switch (ledinfo->led) {
91203831d35Sstevel case HPC_POWER_LED:
91303831d35Sstevel case HPC_ATTN_LED:
91403831d35Sstevel case HPC_FAULT_LED:
91503831d35Sstevel case HPC_ACTIVE_LED:
91603831d35Sstevel error = sghsc_led_state(sghsc, sloth,
91703831d35Sstevel HPC_CTRL_GET_LED_STATE, ledinfo);
91803831d35Sstevel break;
91903831d35Sstevel default:
92003831d35Sstevel cmn_err(CE_WARN, "sghsc%d: sghsc_control"
92103831d35Sstevel " HPC_CTRL_GET_LED_STATE "
92203831d35Sstevel " unknown led state %d for node %d / board %d"
92303831d35Sstevel " slot handle 0x%p", sghsc->sghsc_instance,
92403831d35Sstevel ledinfo->led, sghsc->sghsc_node_id,
92503831d35Sstevel sghsc->sghsc_board, sloth);
92603831d35Sstevel error = HPC_ERR_NOTSUPPORTED;
92703831d35Sstevel break;
92803831d35Sstevel }
92903831d35Sstevel
93003831d35Sstevel break;
93103831d35Sstevel }
93203831d35Sstevel
93303831d35Sstevel case HPC_CTRL_SET_LED_STATE: {
93403831d35Sstevel /* arg == hpc_led_info_t */
93503831d35Sstevel hpc_led_info_t *ledinfo;
93603831d35Sstevel
93703831d35Sstevel ledinfo = (hpc_led_info_t *)arg;
93803831d35Sstevel
93903831d35Sstevel DEBUGF(1, (CE_NOTE, "sghsc%d: sghsc_control"
94003831d35Sstevel " HPC_CTRL_SET_LED_STATE for node %d / board %d slot %d",
94103831d35Sstevel sghsc->sghsc_instance, sghsc->sghsc_node_id,
94203831d35Sstevel sghsc->sghsc_board, slot));
94303831d35Sstevel
94403831d35Sstevel switch (ledinfo->led) {
94503831d35Sstevel case HPC_POWER_LED:
94603831d35Sstevel case HPC_ATTN_LED:
94703831d35Sstevel case HPC_FAULT_LED:
94803831d35Sstevel case HPC_ACTIVE_LED:
94903831d35Sstevel DEBUGF(1, (CE_NOTE, "sghsc:"
95003831d35Sstevel " LED writing not supported "));
95103831d35Sstevel break;
95203831d35Sstevel
95303831d35Sstevel default:
95403831d35Sstevel DEBUGF(1, (CE_NOTE, "sghsc:"
95503831d35Sstevel " LED not supported "));
95603831d35Sstevel error = HPC_ERR_NOTSUPPORTED;
95703831d35Sstevel }
95803831d35Sstevel break;
95903831d35Sstevel }
96003831d35Sstevel
96103831d35Sstevel case HPC_CTRL_GET_SLOT_STATE: {
96203831d35Sstevel DEBUGF(1, (CE_NOTE, "sghsc%d: sghsc_control"
96303831d35Sstevel " HPC_CTRL_GET_SLOT_STATE for node %d / board %d slot %d",
96403831d35Sstevel sghsc->sghsc_instance, sghsc->sghsc_node_id,
96503831d35Sstevel sghsc->sghsc_board, slot));
96603831d35Sstevel
96703831d35Sstevel /*
96803831d35Sstevel * Send mailbox cmd to SC to query the latest state
96903831d35Sstevel */
97003831d35Sstevel rc = sghsc_scctl(SGHSC_GET_SLOT_STATUS, sghsc->sghsc_node_id,
97103831d35Sstevel sghsc->sghsc_board, slot, &result);
97203831d35Sstevel
97303831d35Sstevel if (rc == ETIMEDOUT) {
97403831d35Sstevel error = HPC_ERR_FAILED;
97503831d35Sstevel break;
97603831d35Sstevel }
97703831d35Sstevel
97803831d35Sstevel if (rc) {
97903831d35Sstevel cmn_err(CE_NOTE, "sghsc%d: unable to stat slot %d for "
98003831d35Sstevel "node %d / board %d", sghsc->sghsc_instance, slot,
98103831d35Sstevel sghsc->sghsc_node_id, sghsc->sghsc_board);
98203831d35Sstevel sghsc->sghsc_slot_table[slot].slot_status =
98303831d35Sstevel HPC_SLOT_UNKNOWN;
98403831d35Sstevel *(hpc_slot_state_t *)arg = HPC_SLOT_UNKNOWN;
98503831d35Sstevel break;
98603831d35Sstevel }
98703831d35Sstevel
98803831d35Sstevel /*
98903831d35Sstevel * Update the cached state if needed. Initally all
99003831d35Sstevel * slots are marked as empty for the Hot Plug Framwork.
99103831d35Sstevel */
99203831d35Sstevel if ((result >> CPCI_STAT_SLOT_EMPTY_SHIFT) & ONE_BIT) {
99303831d35Sstevel sghsc->sghsc_slot_table[slot].slot_status =
99403831d35Sstevel HPC_SLOT_EMPTY;
99503831d35Sstevel } else if ((result >> CPCI_STAT_POWER_ON_SHIFT) & ONE_BIT) {
99603831d35Sstevel sghsc->sghsc_slot_table[slot].slot_status =
99703831d35Sstevel HPC_SLOT_CONNECTED;
99803831d35Sstevel } else if (sghsc->sghsc_slot_table[slot].slot_status ==
99903831d35Sstevel HPC_SLOT_EMPTY ||
100003831d35Sstevel sghsc->sghsc_slot_table[slot].slot_status ==
100103831d35Sstevel HPC_SLOT_UNKNOWN) {
100203831d35Sstevel sghsc->sghsc_slot_table[slot].slot_status =
100303831d35Sstevel HPC_SLOT_DISCONNECTED;
100403831d35Sstevel }
100503831d35Sstevel /*
100603831d35Sstevel * No change
100703831d35Sstevel */
100803831d35Sstevel *(hpc_slot_state_t *)arg =
100903831d35Sstevel sghsc->sghsc_slot_table[slot].slot_status;
101003831d35Sstevel
101103831d35Sstevel break;
101203831d35Sstevel }
101303831d35Sstevel
101403831d35Sstevel case HPC_CTRL_DEV_CONFIGURED:
101503831d35Sstevel DEBUGF(1, (CE_NOTE, "sghsc%d: sghsc_control"
101603831d35Sstevel " HPC_CTRL_DEV_CONFIGURED for node %d / board %d slot %d",
101703831d35Sstevel sghsc->sghsc_instance, sghsc->sghsc_node_id,
101803831d35Sstevel sghsc->sghsc_board, slot));
101903831d35Sstevel
102003831d35Sstevel if (sghsc_configure_ack)
102103831d35Sstevel cmn_err(CE_NOTE, "sghsc%d:"
102203831d35Sstevel " node %d / board %d slot %d configured",
102303831d35Sstevel sghsc->sghsc_instance, sghsc->sghsc_node_id,
102403831d35Sstevel sghsc->sghsc_board, slot);
102503831d35Sstevel /*
102603831d35Sstevel * This is important to tell SC:
102703831d35Sstevel * "start looking for ENUMs"
102803831d35Sstevel */
102903831d35Sstevel if (sghsc->sghsc_slot_table[slot].flags &
103003831d35Sstevel SGHSC_SLOT_AUTO_CFG_EN)
103103831d35Sstevel (void) sghsc_scctl(SGHSC_SET_ENUM_CLEARED,
103203831d35Sstevel sghsc->sghsc_node_id, sghsc->sghsc_board,
103303831d35Sstevel slot, &result);
103403831d35Sstevel
103503831d35Sstevel break;
103603831d35Sstevel
103703831d35Sstevel case HPC_CTRL_DEV_UNCONFIGURED:
103803831d35Sstevel /*
103903831d35Sstevel * due to unclean drivers, unconfigure may leave
104003831d35Sstevel * some state on card, configure may actually
104103831d35Sstevel * use these invalid values. therefore, may force
104203831d35Sstevel * disconnect.
104303831d35Sstevel */
104403831d35Sstevel
104503831d35Sstevel DEBUGF(1, (CE_NOTE, "sghsc%d: sghsc_control "
104603831d35Sstevel "HPC_CTRL_DEV_UNCONFIGURED for node %d / board %d slot %d",
104703831d35Sstevel sghsc->sghsc_instance, sghsc->sghsc_node_id,
104803831d35Sstevel sghsc->sghsc_board, slot));
104903831d35Sstevel
105003831d35Sstevel SGHSC_MUTEX_EXIT(sghsc);
105103831d35Sstevel if (sghsc_disconnect(op_arg, sloth, 0,
105203831d35Sstevel 0) != HPC_SUCCESS) {
105303831d35Sstevel DEBUGF(1, (CE_NOTE, "sghsc_control: "
105403831d35Sstevel "disconnect failed"));
105503831d35Sstevel error = HPC_ERR_FAILED;
105603831d35Sstevel }
105703831d35Sstevel
105803831d35Sstevel cmn_err(CE_NOTE, "sghsc%d: node %d / board %d "
105903831d35Sstevel "slot %d unconfigured", sghsc->sghsc_instance,
106003831d35Sstevel sghsc->sghsc_node_id, sghsc->sghsc_board, slot);
106103831d35Sstevel return (error);
106203831d35Sstevel
106303831d35Sstevel
106403831d35Sstevel case HPC_CTRL_GET_BOARD_TYPE: {
106503831d35Sstevel /* arg = hpc_board_type_t */
106603831d35Sstevel
106703831d35Sstevel DEBUGF(1, (CE_NOTE, "sghsc%d: sghsc_control"
106803831d35Sstevel " HPC_CTRL_GET_BOARD_TYPE for node %d / board %d slot %d",
106903831d35Sstevel sghsc->sghsc_instance, sghsc->sghsc_node_id,
107003831d35Sstevel sghsc->sghsc_board, slot));
107103831d35Sstevel
107203831d35Sstevel *(hpc_board_type_t *)arg =
107303831d35Sstevel sghsc->sghsc_slot_table[slot].board_type;
107403831d35Sstevel
107503831d35Sstevel break;
107603831d35Sstevel }
107703831d35Sstevel
107803831d35Sstevel case HPC_CTRL_ENABLE_AUTOCFG:
107903831d35Sstevel DEBUGF(1, (CE_NOTE, "sghsc%d: sghsc_control"
108003831d35Sstevel " HPC_CTRL_ENABLE_AUTOCFG for node %d / board %d slot %d",
108103831d35Sstevel sghsc->sghsc_instance, sghsc->sghsc_node_id,
108203831d35Sstevel sghsc->sghsc_board, slot));
108303831d35Sstevel
108403831d35Sstevel sghsc->sghsc_slot_table[slot].flags |= SGHSC_SLOT_AUTO_CFG_EN;
108503831d35Sstevel (void) hpc_slot_event_notify(sloth, HPC_EVENT_ENABLE_ENUM,
108603831d35Sstevel HPC_EVENT_NORMAL);
108703831d35Sstevel
108803831d35Sstevel /*
108903831d35Sstevel * Tell SC to start looking for ENUMs on this slot.
109003831d35Sstevel */
109103831d35Sstevel rc = sghsc_scctl(SGHSC_SET_ENUM_CLEARED, sghsc->sghsc_node_id,
109203831d35Sstevel sghsc->sghsc_board, slot, &result);
109303831d35Sstevel
109403831d35Sstevel if (rc)
109503831d35Sstevel cmn_err(CE_WARN, "sghsc%d: unable to arm ENUM for"
109603831d35Sstevel " node %d / board %d, slot %d",
109703831d35Sstevel sghsc->sghsc_instance, sghsc->sghsc_node_id,
109803831d35Sstevel sghsc->sghsc_board, slot);
109903831d35Sstevel break;
110003831d35Sstevel
110103831d35Sstevel case HPC_CTRL_DISABLE_AUTOCFG:
110203831d35Sstevel DEBUGF(1, (CE_NOTE, "sghsc%d: sghsc_control"
110303831d35Sstevel " HPC_CTRL_DISABLE_AUTOCFG for node %d / board %d slot %d",
110403831d35Sstevel sghsc->sghsc_instance, sghsc->sghsc_node_id,
110503831d35Sstevel sghsc->sghsc_board, slot));
110603831d35Sstevel
110703831d35Sstevel sghsc->sghsc_slot_table[slot].flags &= ~SGHSC_SLOT_AUTO_CFG_EN;
110803831d35Sstevel (void) hpc_slot_event_notify(sloth, HPC_EVENT_DISABLE_ENUM,
110903831d35Sstevel HPC_EVENT_NORMAL);
111003831d35Sstevel break;
111103831d35Sstevel
111203831d35Sstevel case HPC_CTRL_DISABLE_SLOT:
111303831d35Sstevel case HPC_CTRL_ENABLE_SLOT:
111403831d35Sstevel break;
111503831d35Sstevel
111603831d35Sstevel /* need to add support for enable/disable_ENUM */
111703831d35Sstevel case HPC_CTRL_DISABLE_ENUM:
111803831d35Sstevel case HPC_CTRL_ENABLE_ENUM:
111903831d35Sstevel default:
112003831d35Sstevel DEBUGF(1, (CE_CONT, "sghsc%d: sghsc_control "
112103831d35Sstevel "request (0x%x) not supported", sghsc->sghsc_instance,
112203831d35Sstevel request));
112303831d35Sstevel
112403831d35Sstevel /* invalid request */
112503831d35Sstevel error = HPC_ERR_NOTSUPPORTED;
112603831d35Sstevel }
112703831d35Sstevel
112803831d35Sstevel SGHSC_MUTEX_EXIT(sghsc);
112903831d35Sstevel
113003831d35Sstevel return (error);
113103831d35Sstevel }
113203831d35Sstevel
113303831d35Sstevel /*
113403831d35Sstevel * Read/write slot's led
113503831d35Sstevel * Assume MUTEX_HELD
113603831d35Sstevel *
113703831d35Sstevel * return: HPC_SUCCESS if the led's status is avaiable,
113803831d35Sstevel * SC return status otherwise.
113903831d35Sstevel */
114003831d35Sstevel static int
sghsc_led_state(sghsc_t * sghsc,hpc_slot_t sloth,int op,hpc_led_info_t * ledinfo)114103831d35Sstevel sghsc_led_state(sghsc_t *sghsc, hpc_slot_t sloth, int op,
114203831d35Sstevel hpc_led_info_t *ledinfo)
114303831d35Sstevel {
114403831d35Sstevel int rval;
114503831d35Sstevel int slot_num;
114603831d35Sstevel int result;
114703831d35Sstevel
114803831d35Sstevel slot_num = sghsc_get_slotnum(sghsc, sloth);
114903831d35Sstevel rval = sghsc_scctl(SGHSC_GET_SLOT_STATUS, sghsc->sghsc_node_id,
115003831d35Sstevel sghsc->sghsc_board, slot_num, &result);
115103831d35Sstevel if (rval != HPC_SUCCESS)
115203831d35Sstevel return (rval);
115303831d35Sstevel
115403831d35Sstevel switch (op) {
115503831d35Sstevel case HPC_CTRL_GET_LED_STATE:
115603831d35Sstevel switch (ledinfo->led) {
115703831d35Sstevel case HPC_POWER_LED:
115803831d35Sstevel if ((result >> CPCI_STAT_LED_POWER_SHIFT) & ONE_BIT)
115903831d35Sstevel ledinfo->state = HPC_LED_ON;
116003831d35Sstevel else
116103831d35Sstevel ledinfo->state = HPC_LED_OFF;
116203831d35Sstevel break;
116303831d35Sstevel
116403831d35Sstevel case HPC_ATTN_LED:
116503831d35Sstevel case HPC_FAULT_LED:
116603831d35Sstevel if ((result >> CPCI_STAT_LED_FAULT_SHIFT) & ONE_BIT)
116703831d35Sstevel ledinfo->state = HPC_LED_ON;
116803831d35Sstevel else
116903831d35Sstevel ledinfo->state = HPC_LED_OFF;
117003831d35Sstevel break;
117103831d35Sstevel
117203831d35Sstevel case HPC_ACTIVE_LED:
117303831d35Sstevel if ((result >> CPCI_STAT_LED_HP_SHIFT) & ONE_BIT)
117403831d35Sstevel ledinfo->state = HPC_LED_ON;
117503831d35Sstevel else
117603831d35Sstevel ledinfo->state = HPC_LED_OFF;
117703831d35Sstevel break;
117803831d35Sstevel }
117903831d35Sstevel
118003831d35Sstevel break;
118103831d35Sstevel
118203831d35Sstevel case HPC_CTRL_SET_LED_STATE:
118303831d35Sstevel return (HPC_ERR_NOTSUPPORTED);
118403831d35Sstevel }
118503831d35Sstevel
118603831d35Sstevel return (HPC_SUCCESS);
118703831d35Sstevel }
118803831d35Sstevel
118903831d35Sstevel /*
119003831d35Sstevel * sghsc_get_slotnum()
119103831d35Sstevel * get slot number from the slot handle
119203831d35Sstevel * returns non-negative value to indicate slot number
119303831d35Sstevel * -1 for failure
119403831d35Sstevel */
119503831d35Sstevel static int
sghsc_get_slotnum(sghsc_t * sghsc,hpc_slot_t sloth)119603831d35Sstevel sghsc_get_slotnum(sghsc_t *sghsc, hpc_slot_t sloth)
119703831d35Sstevel {
119803831d35Sstevel int i;
119903831d35Sstevel
120003831d35Sstevel if (sloth == NULL || sghsc == NULL)
120103831d35Sstevel return (-1);
120203831d35Sstevel
120303831d35Sstevel for (i = 0; i < sghsc->sghsc_num_slots; i++) {
120403831d35Sstevel
120503831d35Sstevel if (sghsc->sghsc_slot_table[i].handle == sloth)
120603831d35Sstevel return (i);
120703831d35Sstevel }
120803831d35Sstevel
120903831d35Sstevel return (-1);
121003831d35Sstevel
121103831d35Sstevel }
121203831d35Sstevel
121303831d35Sstevel /*
121403831d35Sstevel * sghsc_scctl()
121503831d35Sstevel * mailbox interface
121603831d35Sstevel *
121703831d35Sstevel * return result code from mailbox operation
121803831d35Sstevel */
121903831d35Sstevel static int
sghsc_scctl(int cmd,int node_id,int board,int slot,int * resultp)122003831d35Sstevel sghsc_scctl(int cmd, int node_id, int board, int slot, int *resultp)
122103831d35Sstevel {
122203831d35Sstevel int ret = 0xbee;
122303831d35Sstevel bitcmd_info_t cmd_info, *cmd_infop = &cmd_info;
122403831d35Sstevel bitcmd_resp_t cmd_info_r, *cmd_info_r_p = &cmd_info_r;
122503831d35Sstevel sbbc_msg_t request, *reqp = &request;
122603831d35Sstevel sbbc_msg_t response, *resp = &response;
122703831d35Sstevel
122803831d35Sstevel cmd_infop->cmd_id = 0x01234567;
122903831d35Sstevel cmd_infop->node_id = node_id;
123003831d35Sstevel cmd_infop->board = board;
123103831d35Sstevel cmd_infop->slot = slot;
123203831d35Sstevel
123303831d35Sstevel reqp->msg_type.type = CPCI_MBOX;
123403831d35Sstevel reqp->msg_status = 0xeeeeffff;
123503831d35Sstevel reqp->msg_len = sizeof (cmd_info);
123603831d35Sstevel reqp->msg_bytes = 8;
123703831d35Sstevel reqp->msg_buf = (caddr_t)cmd_infop;
123803831d35Sstevel reqp->msg_data[0] = 0;
123903831d35Sstevel reqp->msg_data[1] = 0;
124003831d35Sstevel
124103831d35Sstevel bzero(resp, sizeof (*resp));
124203831d35Sstevel bzero(cmd_info_r_p, sizeof (*cmd_info_r_p));
124303831d35Sstevel
124403831d35Sstevel resp->msg_buf = (caddr_t)cmd_info_r_p;
124503831d35Sstevel resp->msg_len = sizeof (cmd_info_r);
124603831d35Sstevel
124703831d35Sstevel resp->msg_type.type = CPCI_MBOX;
124803831d35Sstevel resp->msg_bytes = 8;
124903831d35Sstevel resp->msg_status = 0xddddffff;
125003831d35Sstevel
125103831d35Sstevel switch (cmd) {
125203831d35Sstevel case SGHSC_GET_SLOT_STATUS:
125303831d35Sstevel reqp->msg_type.sub_type = CPCI_GET_SLOT_STATUS;
125403831d35Sstevel resp->msg_type.sub_type = CPCI_GET_SLOT_STATUS;
125503831d35Sstevel reqp->msg_len -= 4;
125603831d35Sstevel break;
125703831d35Sstevel case SGHSC_GET_NUM_SLOTS:
125803831d35Sstevel reqp->msg_type.sub_type = CPCI_GET_NUM_SLOTS;
125903831d35Sstevel resp->msg_type.sub_type = CPCI_GET_NUM_SLOTS;
126003831d35Sstevel reqp->msg_len -= 8;
126103831d35Sstevel break;
126203831d35Sstevel case SGHSC_SET_SLOT_STATUS_RESET:
126303831d35Sstevel reqp->msg_type.sub_type = CPCI_SET_SLOT_STATUS;
126403831d35Sstevel resp->msg_type.sub_type = CPCI_SET_SLOT_STATUS;
126503831d35Sstevel cmd_infop->info = CPCI_SET_STATUS_SLOT_RESET;
126603831d35Sstevel break;
126703831d35Sstevel case SGHSC_SET_SLOT_STATUS_READY:
126803831d35Sstevel reqp->msg_type.sub_type = CPCI_SET_SLOT_STATUS;
126903831d35Sstevel resp->msg_type.sub_type = CPCI_SET_SLOT_STATUS;
127003831d35Sstevel cmd_infop->info = CPCI_SET_STATUS_SLOT_READY;
127103831d35Sstevel break;
127203831d35Sstevel case SGHSC_SET_SLOT_FAULT_LED_ON:
127303831d35Sstevel reqp->msg_type.sub_type = CPCI_SET_SLOT_FAULT_LED;
127403831d35Sstevel resp->msg_type.sub_type = CPCI_SET_SLOT_FAULT_LED;
127503831d35Sstevel cmd_infop->info = CPCI_SET_FAULT_LED_ON;
127603831d35Sstevel break;
127703831d35Sstevel case SGHSC_SET_SLOT_FAULT_LED_OFF:
127803831d35Sstevel reqp->msg_type.sub_type = CPCI_SET_SLOT_FAULT_LED;
127903831d35Sstevel resp->msg_type.sub_type = CPCI_SET_SLOT_FAULT_LED;
128003831d35Sstevel cmd_infop->info = CPCI_SET_FAULT_LED_OFF;
128103831d35Sstevel break;
128203831d35Sstevel case SGHSC_SET_SLOT_FAULT_LED_KEEP:
128303831d35Sstevel reqp->msg_type.sub_type = CPCI_SET_SLOT_FAULT_LED;
128403831d35Sstevel resp->msg_type.sub_type = CPCI_SET_SLOT_FAULT_LED;
128503831d35Sstevel cmd_infop->info = CPCI_SET_FAULT_LED_KEEP;
128603831d35Sstevel break;
128703831d35Sstevel case SGHSC_SET_SLOT_FAULT_LED_TOGGLE:
128803831d35Sstevel reqp->msg_type.sub_type = CPCI_SET_SLOT_FAULT_LED;
128903831d35Sstevel resp->msg_type.sub_type = CPCI_SET_SLOT_FAULT_LED;
129003831d35Sstevel cmd_infop->info = CPCI_SET_FAULT_LED_TOGGLE;
129103831d35Sstevel break;
129203831d35Sstevel case SGHSC_SET_SLOT_POWER_OFF:
129303831d35Sstevel reqp->msg_type.sub_type = CPCI_SET_SLOT_POWER;
129403831d35Sstevel resp->msg_type.sub_type = CPCI_SET_SLOT_POWER;
129503831d35Sstevel cmd_infop->info = CPCI_POWER_OFF;
129603831d35Sstevel break;
129703831d35Sstevel case SGHSC_SET_SLOT_POWER_ON:
129803831d35Sstevel reqp->msg_type.sub_type = CPCI_SET_SLOT_POWER;
129903831d35Sstevel resp->msg_type.sub_type = CPCI_SET_SLOT_POWER;
130003831d35Sstevel cmd_infop->info = CPCI_POWER_ON;
130103831d35Sstevel break;
130203831d35Sstevel case SGHSC_GET_CPCI_BOARD_TYPE:
130303831d35Sstevel reqp->msg_type.sub_type = CPCI_BOARD_TYPE;
130403831d35Sstevel resp->msg_type.sub_type = CPCI_BOARD_TYPE;
130503831d35Sstevel reqp->msg_len -= 8;
130603831d35Sstevel break;
130703831d35Sstevel case SGHSC_SET_ENUM_CLEARED:
130803831d35Sstevel reqp->msg_type.sub_type = CPCI_SET_ENUM_CLEARED;
130903831d35Sstevel resp->msg_type.sub_type = CPCI_SET_ENUM_CLEARED;
131003831d35Sstevel break;
131103831d35Sstevel default:
131203831d35Sstevel cmn_err(CE_WARN, "sghsc: unrecognized action code 0x%x\n",
131303831d35Sstevel cmd);
131403831d35Sstevel }
131503831d35Sstevel
131603831d35Sstevel DEBUGF(1, (CE_NOTE,
131703831d35Sstevel "sghsc: sending mbox command type=%d subtype=0x%x size=%d buf=%p",
131803831d35Sstevel reqp->msg_type.type, reqp->msg_type.sub_type,
131907d06da5SSurya Prakki reqp->msg_len, (void *)reqp->msg_buf));
132003831d35Sstevel
132103831d35Sstevel DEBUGF(1, (CE_NOTE,
132203831d35Sstevel "sghsc: sending buf cmd_id=0x%x node_id=0x%x board=0x%x "
132303831d35Sstevel "slot=0x%x info=0x%x", cmd_infop->cmd_id, cmd_infop->node_id,
132403831d35Sstevel cmd_infop->board, cmd_infop->slot, cmd_infop->info));
132503831d35Sstevel
132603831d35Sstevel
132703831d35Sstevel ret = sbbc_mbox_request_response(reqp, resp, sghsc_mbx_timeout);
132803831d35Sstevel
132903831d35Sstevel /*
133003831d35Sstevel * The resp->msg_status field may contain an SC error or a common
133103831d35Sstevel * error such as ETIMEDOUT.
133203831d35Sstevel */
133303831d35Sstevel if ((ret != 0) || (resp->msg_status != SG_MBOX_STATUS_SUCCESS)) {
133403831d35Sstevel DEBUGF(1, (CE_NOTE, "sghsc: mailbox command error = 0x%x, "
133503831d35Sstevel "status = 0x%x", ret, resp->msg_status));
133603831d35Sstevel return (-1);
133703831d35Sstevel }
133803831d35Sstevel
133903831d35Sstevel DEBUGF(1, (CE_NOTE, "sghsc: reply request status=0x%x",
134003831d35Sstevel reqp->msg_status));
134103831d35Sstevel DEBUGF(1, (CE_NOTE, "sghsc: reply resp status=0x%x",
134203831d35Sstevel resp->msg_status));
134303831d35Sstevel DEBUGF(1, (CE_NOTE, "sghsc: reply buf cmd_id=0x%x result=0x%x\n",
134403831d35Sstevel cmd_info_r_p->cmd_id, cmd_info_r_p->result));
134503831d35Sstevel
134603831d35Sstevel #ifdef DEBUG_EXTENDED
134703831d35Sstevel if (cmd == SGHSC_GET_NUM_SLOTS) {
134803831d35Sstevel DEBUGF(1, (CE_NOTE, "sghsc: node %d / board %d has %d slots",
134919397407SSherry Moore cmd_infop->node_id, cmd_infop->board,
135019397407SSherry Moore cmd_info_r_p->result));
135103831d35Sstevel *resultp = cmd_info_r_p->result;
135203831d35Sstevel return (0);
135303831d35Sstevel }
135403831d35Sstevel
135503831d35Sstevel if ((cmd_info_r_p->result >> CPCI_STAT_POWER_ON_SHIFT) & ONE_BIT)
135603831d35Sstevel DEBUGF(1, (CE_NOTE, "sghsc: cpower on"));
135703831d35Sstevel
135803831d35Sstevel if ((cmd_info_r_p->result >> CPCI_STAT_LED_POWER_SHIFT) & ONE_BIT)
135903831d35Sstevel DEBUGF(1, (CE_NOTE, "sghsc: power led on"));
136003831d35Sstevel
136103831d35Sstevel if ((cmd_info_r_p->result >> CPCI_STAT_LED_FAULT_SHIFT) & ONE_BIT)
136203831d35Sstevel DEBUGF(1, (CE_NOTE, "sghsc: fault led on"));
136303831d35Sstevel
136403831d35Sstevel if ((cmd_info_r_p->result >> CPCI_STAT_LED_HP_SHIFT) & ONE_BIT)
136503831d35Sstevel DEBUGF(1, (CE_NOTE, "sghsc: remove(hp) led on"));
136603831d35Sstevel
136703831d35Sstevel if ((cmd_info_r_p->result >> CPCI_STAT_SLOT_EMPTY_SHIFT) & ONE_BIT)
136803831d35Sstevel DEBUGF(1, (CE_NOTE, "sghsc: slot empty"));
136903831d35Sstevel
137003831d35Sstevel tmp = ((cmd_info_r_p->result >> CPCI_STAT_HOT_SWAP_STATUS_SHIFT) &
137103831d35Sstevel THREE_BITS);
137203831d35Sstevel if (tmp)
137303831d35Sstevel DEBUGF(1, (CE_NOTE,
137403831d35Sstevel "sghsc: slot condition(hot swap status) is 0x%x", tmp));
137503831d35Sstevel
137603831d35Sstevel if (cmd_info_r_p->result & CPCI_GET_STAT_SLOT_HZ_CAP)
137703831d35Sstevel DEBUGF(1, (CE_NOTE,
137803831d35Sstevel "sghsc: freq cap %x", cmd_info_r_p->result &
137903831d35Sstevel CPCI_GET_STAT_SLOT_HZ_CAP));
138003831d35Sstevel
138103831d35Sstevel if (cmd_info_r_p->result & CPCI_GET_STAT_SLOT_HZ_SET)
138203831d35Sstevel DEBUGF(1, (CE_NOTE,
138303831d35Sstevel "sghsc: freq setting %x", cmd_info_r_p->result &
138403831d35Sstevel CPCI_GET_STAT_SLOT_HZ_SET));
138503831d35Sstevel
138603831d35Sstevel
138703831d35Sstevel if ((cmd_info_r_p->result >> CPCI_STAT_HEALTHY_SHIFT) & ONE_BIT)
138803831d35Sstevel DEBUGF(1, (CE_NOTE, "sghsc: healthy"));
138903831d35Sstevel
139003831d35Sstevel if ((cmd_info_r_p->result >> CPCI_STAT_RESET_SHIFT) & ONE_BIT)
139103831d35Sstevel DEBUGF(1, (CE_NOTE, "sghsc: in reset"));
139203831d35Sstevel
139303831d35Sstevel if (cmd_info_r_p->result & CPCI_GET_STAT_POWER_GOOD)
139403831d35Sstevel DEBUGF(1, (CE_NOTE, "sghsc: power good"));
139503831d35Sstevel
139603831d35Sstevel if (cmd_info_r_p->result & CPCI_GET_STAT_POWER_FAULT)
139703831d35Sstevel DEBUGF(1, (CE_NOTE, "sghsc: power fault"));
139803831d35Sstevel
139903831d35Sstevel if (cmd_info_r_p->result & CPCI_GET_STAT_PCI_PRESENT)
140003831d35Sstevel DEBUGF(1, (CE_NOTE, "sghsc: pci present"));
140103831d35Sstevel #endif
140203831d35Sstevel
140303831d35Sstevel *resultp = cmd_info_r_p->result;
140403831d35Sstevel return (0);
140503831d35Sstevel }
140603831d35Sstevel
140703831d35Sstevel
140803831d35Sstevel /*
140903831d35Sstevel * sghsc_freemem()
141003831d35Sstevel * deallocates memory resources
141103831d35Sstevel *
141203831d35Sstevel */
141303831d35Sstevel static void
sghsc_freemem(sghsc_t * sghsc)141403831d35Sstevel sghsc_freemem(sghsc_t *sghsc)
141503831d35Sstevel {
141603831d35Sstevel int i;
141703831d35Sstevel
141803831d35Sstevel /*
141903831d35Sstevel * Free up allocated resources
142003831d35Sstevel * sghsc_register_slots => unregister all slots
142103831d35Sstevel */
142203831d35Sstevel for (i = 0; i < sghsc->sghsc_num_slots; i++) {
142303831d35Sstevel if (sghsc->sghsc_slot_table[i].slot_ops)
142403831d35Sstevel hpc_free_slot_ops(sghsc->sghsc_slot_table[i].slot_ops);
142503831d35Sstevel if (sghsc->sghsc_slot_table[i].handle)
142607d06da5SSurya Prakki (void) hpc_slot_unregister(
142707d06da5SSurya Prakki &sghsc->sghsc_slot_table[i].handle);
142803831d35Sstevel }
142903831d35Sstevel
143003831d35Sstevel /* finally free up slot_table */
143103831d35Sstevel kmem_free(sghsc->sghsc_slot_table,
143203831d35Sstevel (size_t)(sghsc->sghsc_num_slots * sizeof (sghsc_slot_t)));
143303831d35Sstevel
143403831d35Sstevel }
143503831d35Sstevel
143603831d35Sstevel /*
143703831d35Sstevel * sghsc_find_sloth()
143803831d35Sstevel * Find slot handle by node id, board number and slot numbert
143903831d35Sstevel * Returns slot handle or 0 if slot not found.
144003831d35Sstevel */
144103831d35Sstevel static hpc_slot_t
sghsc_find_sloth(int node_id,int board,int slot)144203831d35Sstevel sghsc_find_sloth(int node_id, int board, int slot)
144303831d35Sstevel {
144403831d35Sstevel int instance;
144503831d35Sstevel sghsc_t *sghsc;
144603831d35Sstevel
144703831d35Sstevel for (instance = 0; instance < sghsc_maxinst; instance++) {
144803831d35Sstevel sghsc = (sghsc_t *)ddi_get_soft_state(sghsc_state, instance);
144903831d35Sstevel
145003831d35Sstevel if (sghsc == NULL || sghsc->sghsc_node_id != node_id ||
145103831d35Sstevel sghsc->sghsc_board != board)
145203831d35Sstevel continue;
145303831d35Sstevel
145403831d35Sstevel DEBUGF(1, (CE_NOTE, "sghsc_find_sloth on board %d at node %d"
145503831d35Sstevel " slot %d", board, node_id, slot))
145603831d35Sstevel
145703831d35Sstevel if (sghsc->sghsc_num_slots < (slot + 1)) {
145803831d35Sstevel cmn_err(CE_WARN, "sghsc%d: slot data corruption at"
145903831d35Sstevel "node %d / board %d", instance, node_id, board);
146003831d35Sstevel return (NULL);
146103831d35Sstevel }
146203831d35Sstevel
146303831d35Sstevel if (sghsc->sghsc_valid == 0)
146403831d35Sstevel return (NULL);
146503831d35Sstevel
146603831d35Sstevel /*
146703831d35Sstevel * Found matching slot, return handle.
146803831d35Sstevel */
146903831d35Sstevel return (sghsc->sghsc_slot_table[slot].handle);
147003831d35Sstevel }
147103831d35Sstevel
147203831d35Sstevel DEBUGF(1, (CE_WARN, "sghsc_find_sloth: slot %d not found for node %d"
147303831d35Sstevel " / board %d", slot, node_id, board));
147403831d35Sstevel return (NULL);
147503831d35Sstevel }
147603831d35Sstevel
147703831d35Sstevel /*
147803831d35Sstevel * sghsc_event_handler()
147903831d35Sstevel * Event Handler. This is what for other platforms was an interrupt
148003831d35Sstevel * Handler servicing events. It accepts an event and signals it to
148103831d35Sstevel * non-interrupt thread.
148203831d35Sstevel */
148303831d35Sstevel uint_t
sghsc_event_handler(char * arg)148403831d35Sstevel sghsc_event_handler(char *arg)
148503831d35Sstevel {
148603831d35Sstevel sghsc_event_t *rsp_data;
148703831d35Sstevel hpc_slot_t sloth;
148803831d35Sstevel sghsc_t *enum_state;
148903831d35Sstevel
149003831d35Sstevel DEBUGF(1, (CE_NOTE, "sghsc: sghsc_event_handler called"))
149103831d35Sstevel
149203831d35Sstevel rsp_data = (sghsc_event_t *)(((sbbc_msg_t *)arg)->msg_buf);
149303831d35Sstevel
149403831d35Sstevel if (rsp_data == NULL) {
149503831d35Sstevel cmn_err(CE_WARN,
149603831d35Sstevel ("sghsc: sghsc_event_handler argument is null\n"));
1497055d7c80Scarlsonj return (DDI_INTR_CLAIMED);
149803831d35Sstevel }
149903831d35Sstevel
150003831d35Sstevel sloth = sghsc_find_sloth(rsp_data->node_id, rsp_data->board,
150103831d35Sstevel rsp_data->slot);
150203831d35Sstevel /*
150303831d35Sstevel * On a board disconnect sghsc soft state may not exist
150403831d35Sstevel * when the interrupt occurs. We should treat these
150503831d35Sstevel * interrupts as noise and but them.
150603831d35Sstevel */
150703831d35Sstevel if (sloth == NULL) {
150803831d35Sstevel DEBUGF(1, (CE_WARN, "sghsc: slot info not available for"
150903831d35Sstevel " node %d / board %d slot %d. CPCI event rejected",
151003831d35Sstevel rsp_data->node_id, rsp_data->board, rsp_data->slot));
151103831d35Sstevel return (DDI_INTR_CLAIMED);
151203831d35Sstevel }
151303831d35Sstevel
151403831d35Sstevel enum_state = sghsc_find_softstate(rsp_data->node_id, rsp_data->board,
151503831d35Sstevel rsp_data->slot);
151603831d35Sstevel if (enum_state == NULL) {
151703831d35Sstevel cmn_err(CE_WARN, "sghsc: soft state not available for"
151803831d35Sstevel " node %d / board %d slot %d", rsp_data->node_id,
151903831d35Sstevel rsp_data->board, rsp_data->slot);
152003831d35Sstevel return (DDI_INTR_UNCLAIMED);
152103831d35Sstevel }
152203831d35Sstevel
152303831d35Sstevel DEBUGF(1, (CE_NOTE, "sghsc: node %d", rsp_data->node_id));
152403831d35Sstevel DEBUGF(1, (CE_NOTE, "sghsc: board %d", rsp_data->board));
152503831d35Sstevel DEBUGF(1, (CE_NOTE, "sghsc: slot %d", rsp_data->slot));
152603831d35Sstevel DEBUGF(1, (CE_NOTE, "sghsc: event info %d", rsp_data->info));
152703831d35Sstevel
152803831d35Sstevel switch (rsp_data->info) {
152903831d35Sstevel case SGHSC_EVENT_CARD_INSERT:
153003831d35Sstevel DEBUGF(1, (CE_NOTE, "sghsc: card inserted node %d / board %d"
153103831d35Sstevel " slot %d", rsp_data->node_id, rsp_data->board,
153203831d35Sstevel rsp_data->slot));
153303831d35Sstevel enum_state->sghsc_slot_table[rsp_data->slot].board_type =
153403831d35Sstevel HPC_BOARD_CPCI_HS;
153503831d35Sstevel enum_state->sghsc_slot_table[rsp_data->slot].slot_status =
153603831d35Sstevel HPC_SLOT_DISCONNECTED;
153703831d35Sstevel break;
153803831d35Sstevel case SGHSC_EVENT_CARD_REMOVE:
153903831d35Sstevel DEBUGF(1, (CE_NOTE, "sghsc: card removed node %d / board %d"
154003831d35Sstevel " slot %d", rsp_data->node_id, rsp_data->board,
154103831d35Sstevel rsp_data->slot));
154203831d35Sstevel enum_state->sghsc_slot_table[rsp_data->slot].board_type =
154303831d35Sstevel HPC_BOARD_UNKNOWN;
154403831d35Sstevel enum_state->sghsc_slot_table[rsp_data->slot].slot_status =
154503831d35Sstevel HPC_SLOT_EMPTY;
154603831d35Sstevel return (DDI_INTR_CLAIMED);
154703831d35Sstevel case SGHSC_EVENT_POWER_ON:
154803831d35Sstevel DEBUGF(1, (CE_NOTE, "sghsc: power on node %d / board %d"
154903831d35Sstevel " slot %d", rsp_data->node_id, rsp_data->board,
155003831d35Sstevel rsp_data->slot));
155103831d35Sstevel return (DDI_INTR_CLAIMED);
155203831d35Sstevel case SGHSC_EVENT_POWER_OFF:
155303831d35Sstevel DEBUGF(1, (CE_NOTE, "sghsc: power off node %d / board %d"
155403831d35Sstevel " slot %d", rsp_data->node_id, rsp_data->board,
155503831d35Sstevel rsp_data->slot));
155603831d35Sstevel return (DDI_INTR_CLAIMED);
155703831d35Sstevel case SGHSC_EVENT_HEALTHY_LOST:
155803831d35Sstevel DEBUGF(1, (CE_NOTE, "sghsc: healthy lost node %d / board %d"
155903831d35Sstevel " slot %d", rsp_data->node_id, rsp_data->board,
156003831d35Sstevel rsp_data->slot));
156103831d35Sstevel return (DDI_INTR_CLAIMED);
156203831d35Sstevel case SGHSC_EVENT_LEVER_ACTION:
156303831d35Sstevel DEBUGF(1, (CE_NOTE, "sghsc: ENUM generated for node %d /"
156403831d35Sstevel "board %d slot %d", rsp_data->node_id, rsp_data->board,
156503831d35Sstevel rsp_data->slot));
156603831d35Sstevel break;
156703831d35Sstevel default:
156803831d35Sstevel DEBUGF(1, (CE_NOTE, "sghsc: unrecognized event info for"
156903831d35Sstevel " node %d / board %d slot %d", rsp_data->node_id,
157003831d35Sstevel rsp_data->board, rsp_data->slot));
157103831d35Sstevel return (DDI_INTR_CLAIMED);
157203831d35Sstevel }
157303831d35Sstevel
157403831d35Sstevel /*
157503831d35Sstevel * Signal the ENUM event to the non-interrupt thread as the Hot
157603831d35Sstevel * Plug Framework will eventually call sghsc_control() but all
157703831d35Sstevel * the mailbox messages are not allowed from interrupt context.
157803831d35Sstevel */
157903831d35Sstevel
158003831d35Sstevel if (sghsc_rb_put(&sghsc_rb_header, rsp_data) != DDI_SUCCESS) {
158103831d35Sstevel cmn_err(CE_WARN, "sghsc: no space to store #ENUM info");
158203831d35Sstevel return (DDI_INTR_UNCLAIMED);
158303831d35Sstevel }
158403831d35Sstevel
158503831d35Sstevel cv_signal(&sghsc_event_thread_cv);
158603831d35Sstevel
158703831d35Sstevel return (DDI_INTR_CLAIMED);
158803831d35Sstevel }
158903831d35Sstevel
159003831d35Sstevel /*
159103831d35Sstevel * sghsc_event_thread_code()
159203831d35Sstevel * Event Thread. This is non-interrupt thread servicing #ENUM, Insert,
159303831d35Sstevel * Remove, Power on/off, Healthy lost events.
159403831d35Sstevel */
159503831d35Sstevel static void
sghsc_event_thread_code(void)159603831d35Sstevel sghsc_event_thread_code(void)
159703831d35Sstevel {
159803831d35Sstevel int rc;
159903831d35Sstevel int result;
160003831d35Sstevel hpc_slot_t sloth;
160103831d35Sstevel sghsc_t *sghsc;
160203831d35Sstevel sghsc_event_t rsp_data;
160303831d35Sstevel
160403831d35Sstevel mutex_enter(&sghsc_event_thread_mutex);
160503831d35Sstevel
160603831d35Sstevel for (;;) {
160703831d35Sstevel /*
160803831d35Sstevel * Wait for Event handler to signal event or self destruction.
160903831d35Sstevel * Assuming the mutex will be automatically reaccuired.
161003831d35Sstevel */
161103831d35Sstevel cv_wait(&sghsc_event_thread_cv, &sghsc_event_thread_mutex);
161203831d35Sstevel
161303831d35Sstevel if (sghsc_event_thread_exit)
161403831d35Sstevel break;
161503831d35Sstevel
161603831d35Sstevel /*
161703831d35Sstevel * Pick up all the relevant events from the ring buffer.
161803831d35Sstevel */
161903831d35Sstevel while (sghsc_rb_get(&sghsc_rb_header, &rsp_data) ==
162003831d35Sstevel DDI_SUCCESS) {
162103831d35Sstevel
162203831d35Sstevel sghsc = sghsc_find_softstate(rsp_data.node_id,
162303831d35Sstevel rsp_data.board, rsp_data.slot);
162403831d35Sstevel if (sghsc == NULL)
162503831d35Sstevel continue;
162603831d35Sstevel sloth = sghsc_find_sloth(rsp_data.node_id,
162703831d35Sstevel rsp_data.board, rsp_data.slot);
162803831d35Sstevel if (sloth == NULL)
162903831d35Sstevel continue;
163003831d35Sstevel
163103831d35Sstevel if (!(sghsc->sghsc_slot_table[rsp_data.slot].flags &
163203831d35Sstevel SGHSC_SLOT_AUTO_CFG_EN))
163303831d35Sstevel continue;
163403831d35Sstevel /*
163503831d35Sstevel * Insert event leads only to the electrical
163603831d35Sstevel * connection.
163703831d35Sstevel */
163803831d35Sstevel if (rsp_data.info == SGHSC_EVENT_CARD_INSERT) {
163903831d35Sstevel rc = sghsc_connect((caddr_t)sghsc, sloth,
164003831d35Sstevel NULL, 0);
164103831d35Sstevel if (rc != HPC_SUCCESS)
164203831d35Sstevel cmn_err(CE_WARN, "sghsc:"
164303831d35Sstevel " could not connect inserted card,"
164403831d35Sstevel " node %d / board %d slot %d",
164503831d35Sstevel rsp_data.node_id, rsp_data.board,
164603831d35Sstevel rsp_data.slot);
164703831d35Sstevel continue;
164803831d35Sstevel }
164903831d35Sstevel
165003831d35Sstevel /*
165103831d35Sstevel * ENUM event received.
165203831d35Sstevel * Reset ENUM and notify SC to poll for the next one.
165303831d35Sstevel */
165403831d35Sstevel rc = hpc_slot_event_notify(sloth, HPC_EVENT_CLEAR_ENUM,
165503831d35Sstevel HPC_EVENT_SYNCHRONOUS);
165603831d35Sstevel
165703831d35Sstevel if (rc == HPC_EVENT_UNCLAIMED) {
165803831d35Sstevel DEBUGF(1, (CE_WARN,
165903831d35Sstevel "sghsc: unable to clear ENUM"));
166003831d35Sstevel continue;
166103831d35Sstevel }
166203831d35Sstevel
166303831d35Sstevel rc = sghsc_scctl(SGHSC_SET_ENUM_CLEARED,
166403831d35Sstevel rsp_data.node_id, rsp_data.board,
166503831d35Sstevel rsp_data.slot, &result);
166603831d35Sstevel if (rc) {
166703831d35Sstevel DEBUGF(1, (CE_WARN,
166803831d35Sstevel "sghsc: unable to ACK cleared ENUM"));
166903831d35Sstevel continue;
167003831d35Sstevel }
167103831d35Sstevel
167203831d35Sstevel /*
167303831d35Sstevel * process the ENUM.
167403831d35Sstevel */
167503831d35Sstevel rc = hpc_slot_event_notify(sloth,
167603831d35Sstevel HPC_EVENT_PROCESS_ENUM, HPC_EVENT_SYNCHRONOUS);
167703831d35Sstevel
167803831d35Sstevel if (rc == HPC_EVENT_UNCLAIMED) {
167903831d35Sstevel DEBUGF(1, (CE_WARN,
168003831d35Sstevel "sghsc: could not process ENUM"));
168103831d35Sstevel }
168203831d35Sstevel }
168303831d35Sstevel }
168403831d35Sstevel
168503831d35Sstevel DEBUGF(1, (CE_NOTE, "sghsc: thread_exit"));
168603831d35Sstevel cv_signal(&sghsc_event_thread_cv);
168703831d35Sstevel mutex_exit(&sghsc_event_thread_mutex);
168803831d35Sstevel thread_exit();
168903831d35Sstevel }
169003831d35Sstevel
169103831d35Sstevel /*
169203831d35Sstevel * sghsc_find_softstate()
169303831d35Sstevel * Find softstate by node id and board number. Slot number is used for
169403831d35Sstevel * verification.
169503831d35Sstevel * Returns board's softstate or 0 if not found.
169603831d35Sstevel */
169703831d35Sstevel static sghsc_t *
sghsc_find_softstate(int node_id,int board,int slot)169803831d35Sstevel sghsc_find_softstate(int node_id, int board, int slot)
169903831d35Sstevel {
170003831d35Sstevel int instance;
170103831d35Sstevel sghsc_t *sghsc;
170203831d35Sstevel
170303831d35Sstevel for (instance = 0; instance < sghsc_maxinst; instance++) {
170403831d35Sstevel sghsc = (sghsc_t *)ddi_get_soft_state(sghsc_state, instance);
170503831d35Sstevel
170603831d35Sstevel if (sghsc == NULL || sghsc->sghsc_node_id != node_id ||
170703831d35Sstevel sghsc->sghsc_board != board)
170803831d35Sstevel continue;
170903831d35Sstevel
171003831d35Sstevel if (sghsc->sghsc_num_slots < (slot + 1)) {
171103831d35Sstevel cmn_err(CE_WARN, "sghsc%d: "
171203831d35Sstevel "slot data corruption", instance);
171303831d35Sstevel return (NULL);
171403831d35Sstevel }
171503831d35Sstevel
171603831d35Sstevel if (sghsc->sghsc_valid == 0)
171703831d35Sstevel return (NULL);
171803831d35Sstevel
171903831d35Sstevel /*
172003831d35Sstevel * Found matching data, return soft state.
172103831d35Sstevel */
172203831d35Sstevel return (sghsc);
172303831d35Sstevel }
172403831d35Sstevel
172503831d35Sstevel cmn_err(CE_WARN, "sghsc: soft state not found");
172603831d35Sstevel return (NULL);
172703831d35Sstevel }
172803831d35Sstevel
172903831d35Sstevel /*
173003831d35Sstevel * sghsc_rb_setup()
173103831d35Sstevel * Initialize the event ring buffer with a fixed size. It may require
173203831d35Sstevel * a more elaborate scheme with buffer extension
173303831d35Sstevel */
173403831d35Sstevel static void
sghsc_rb_setup(sghsc_rb_head_t * rb_head)173503831d35Sstevel sghsc_rb_setup(sghsc_rb_head_t *rb_head)
173603831d35Sstevel {
173703831d35Sstevel if (rb_head->buf == NULL) {
173803831d35Sstevel rb_head->put_idx = 0;
173903831d35Sstevel rb_head->get_idx = 0;
174003831d35Sstevel rb_head->size = SGHSC_RING_BUFFER_SZ;
174103831d35Sstevel rb_head->state = SGHSC_RB_EMPTY;
174203831d35Sstevel
174303831d35Sstevel /*
174403831d35Sstevel * Allocate space for event ring buffer
174503831d35Sstevel */
174603831d35Sstevel rb_head->buf = (sghsc_event_t *)kmem_zalloc(
174703831d35Sstevel sizeof (sghsc_event_t) * rb_head->size, KM_SLEEP);
174803831d35Sstevel }
174903831d35Sstevel }
175003831d35Sstevel
175103831d35Sstevel /*
175203831d35Sstevel * sghsc_rb_teardown()
175303831d35Sstevel * Free event ring buffer resources.
175403831d35Sstevel */
175503831d35Sstevel static void
sghsc_rb_teardown(sghsc_rb_head_t * rb_head)175603831d35Sstevel sghsc_rb_teardown(sghsc_rb_head_t *rb_head)
175703831d35Sstevel {
175803831d35Sstevel if (rb_head->buf != NULL) {
175903831d35Sstevel /*
176003831d35Sstevel * Deallocate space for event ring buffer
176103831d35Sstevel */
176203831d35Sstevel kmem_free(rb_head->buf,
176303831d35Sstevel (size_t)(sizeof (sghsc_event_t) * rb_head->size));
176403831d35Sstevel
176503831d35Sstevel rb_head->buf = NULL;
176603831d35Sstevel rb_head->put_idx = 0;
176703831d35Sstevel rb_head->get_idx = 0;
176803831d35Sstevel rb_head->size = 0;
176903831d35Sstevel rb_head->state = SGHSC_RB_EMPTY;
177003831d35Sstevel }
177103831d35Sstevel }
177203831d35Sstevel
177303831d35Sstevel /*
177403831d35Sstevel * sghsc_rb_put()
177503831d35Sstevel * Insert an event info into the event ring buffer.
177603831d35Sstevel * Returns DDI_FAILURE if the buffer is full, DDI_SUCCESS otherwise
177703831d35Sstevel */
177803831d35Sstevel static int
sghsc_rb_put(sghsc_rb_head_t * rb_head,sghsc_event_t * event)177903831d35Sstevel sghsc_rb_put(sghsc_rb_head_t *rb_head, sghsc_event_t *event)
178003831d35Sstevel {
178103831d35Sstevel if (rb_head->state == SGHSC_RB_FULL)
178203831d35Sstevel return (DDI_FAILURE);
178303831d35Sstevel
178403831d35Sstevel rb_head->buf[rb_head->put_idx] = *event;
178503831d35Sstevel
1786*2bc98732SRichard Lowe rb_head->put_idx = (rb_head->put_idx + 1) & (rb_head->size - 1);
178703831d35Sstevel
178803831d35Sstevel if (rb_head->put_idx == rb_head->get_idx)
178903831d35Sstevel rb_head->state = SGHSC_RB_FULL;
179003831d35Sstevel else
179103831d35Sstevel rb_head->state = SGHSC_RB_FLOAT;
179203831d35Sstevel
179303831d35Sstevel return (DDI_SUCCESS);
179403831d35Sstevel }
179503831d35Sstevel /*
179603831d35Sstevel * sghsc_rb_get()
179703831d35Sstevel * Remove an event info from the event ring buffer.
179803831d35Sstevel * Returns DDI_FAILURE if the buffer is empty, DDI_SUCCESS otherwise.
179903831d35Sstevel */
180003831d35Sstevel static int
sghsc_rb_get(sghsc_rb_head_t * rb_head,sghsc_event_t * event)180103831d35Sstevel sghsc_rb_get(sghsc_rb_head_t *rb_head, sghsc_event_t *event)
180203831d35Sstevel {
180303831d35Sstevel
180403831d35Sstevel if (rb_head->state == SGHSC_RB_EMPTY)
180503831d35Sstevel return (DDI_FAILURE);
180603831d35Sstevel
180703831d35Sstevel *event = rb_head->buf[rb_head->get_idx];
180803831d35Sstevel
1809*2bc98732SRichard Lowe rb_head->get_idx = (rb_head->get_idx + 1) & (rb_head->size - 1);
181003831d35Sstevel
181103831d35Sstevel if (rb_head->get_idx == rb_head->put_idx)
181203831d35Sstevel rb_head->state = SGHSC_RB_EMPTY;
181303831d35Sstevel else
181403831d35Sstevel rb_head->state = SGHSC_RB_FLOAT;
181503831d35Sstevel
181603831d35Sstevel return (DDI_SUCCESS);
181703831d35Sstevel }
1818