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 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 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 30403831d35Sstevel _info(struct modinfo *modinfop) 30503831d35Sstevel { 30603831d35Sstevel return (mod_info(&modlinkage, modinfop)); 30703831d35Sstevel } 30803831d35Sstevel 30903831d35Sstevel /* 31003831d35Sstevel * sghsc_attach() 31103831d35Sstevel */ 31203831d35Sstevel /* ARGSUSED */ 31303831d35Sstevel static int 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 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 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 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 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 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 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 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 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 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 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 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 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 * 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 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 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 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 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