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 /* 23*07d06da5SSurya Prakki * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 2403831d35Sstevel * Use is subject to license terms. 2503831d35Sstevel */ 2603831d35Sstevel 2703831d35Sstevel /* 2803831d35Sstevel * Netra ct800 and Netra ct400 (MonteCarlo/Tonga) 2903831d35Sstevel * System Controller and Status Boards STREAMS driver. 3003831d35Sstevel * 3103831d35Sstevel * This driver handles all communications with the Netra ct400 and ct800 3203831d35Sstevel * System Controller Boards. 3303831d35Sstevel * I/O to the SCB is through the PCF8584 I2C controller. 3403831d35Sstevel * The SCB I2C interface and driver interface are provided by the 3503831d35Sstevel * Xilinx XCS40XL. 3603831d35Sstevel * 3703831d35Sstevel * N.B.: The design choice of using STREAMS was dictated because 3803831d35Sstevel * the original system monitor card had to multiplex 2 pcf8574's 3903831d35Sstevel * as one device. 4003831d35Sstevel */ 4103831d35Sstevel 4203831d35Sstevel #include <sys/types.h> 4303831d35Sstevel #include <sys/param.h> 4403831d35Sstevel #include <sys/cred.h> 4503831d35Sstevel #include <sys/log.h> 4603831d35Sstevel #include <sys/uio.h> 4703831d35Sstevel #include <sys/stat.h> 4803831d35Sstevel #include <sys/vnode.h> 4903831d35Sstevel #include <sys/file.h> 5003831d35Sstevel #include <sys/open.h> 5103831d35Sstevel #include <sys/kmem.h> 5203831d35Sstevel #include <sys/kstat.h> 5303831d35Sstevel #include <sys/signal.h> 5403831d35Sstevel 5503831d35Sstevel #include <sys/stream.h> 5603831d35Sstevel #include <sys/strsubr.h> 5703831d35Sstevel #include <sys/strsun.h> 5803831d35Sstevel #include <sys/poll.h> 5903831d35Sstevel 6003831d35Sstevel #include <sys/debug.h> 6103831d35Sstevel 6203831d35Sstevel #include <sys/conf.h> 6303831d35Sstevel #include <sys/ddi.h> 6403831d35Sstevel #include <sys/sunddi.h> 6503831d35Sstevel #include <sys/modctl.h> 6603831d35Sstevel 6703831d35Sstevel #include <sys/i2c/misc/i2c_svc.h> 6803831d35Sstevel 6903831d35Sstevel #include <sys/mct_topology.h> 7003831d35Sstevel #include <sys/netract_gen.h> 7103831d35Sstevel #include <sys/scsbioctl.h> 7203831d35Sstevel #include <sys/scsb.h> 7303831d35Sstevel #include <sys/scsb_cbi.h> 7403831d35Sstevel 7503831d35Sstevel #include <sys/hotplug/hpctrl.h> 7603831d35Sstevel #include <sys/hsc.h> 7703831d35Sstevel #include <sys/hscimpl.h> 7803831d35Sstevel 7903831d35Sstevel #define CPCI_HOTSWAP_SUPPORT 8003831d35Sstevel 8103831d35Sstevel #define ALARM_CARD_ON_SLOT 1 8203831d35Sstevel #define SCSB_FRU_OP_GET_REG 1 8303831d35Sstevel #define SCSB_FRU_OP_SET_REGBIT 2 8403831d35Sstevel #define SCSB_FRU_OP_GET_BITVAL 3 8503831d35Sstevel #define SCSB_FRU_OP_GET_REGDATA 4 8603831d35Sstevel 8703831d35Sstevel /* 8803831d35Sstevel * (internal only) 8903831d35Sstevel * scsb build version format is "CCYYMMDD" 9003831d35Sstevel * for integer compares. 9103831d35Sstevel */ 9203831d35Sstevel #define SCSB_BUILD_VERSION "20001206" 9303831d35Sstevel 9403831d35Sstevel #define MUTEX_UNINIT 0 9503831d35Sstevel #define MUTEX_INIT 2 9603831d35Sstevel 9703831d35Sstevel static int scsb_err_threshold = 0; /* max allowed i2c errors */ 9803831d35Sstevel static int scsb_freeze_count = 3; /* #I2C errors to indicate SCB removal */ 9903831d35Sstevel static int scsb_shutdown_count = 5; /* #polls before passing shutdown evt */ 10003831d35Sstevel static int scsb_in_postintr = 0; /* 1 if scsb is processing intr */ 10103831d35Sstevel static kmutex_t *scb_intr_mutex; /* SCSB interrupt mutex */ 10203831d35Sstevel static int nct_mutex_init = MUTEX_UNINIT; 10303831d35Sstevel 10403831d35Sstevel extern int scsb_hsc_board_healthy(); 10503831d35Sstevel 10603831d35Sstevel static char *scsb_name = SCSB_DEVICE_NAME; 10703831d35Sstevel static char *scsb_clone_name = SCSB_DEVICE_NAME "clone"; 10803831d35Sstevel static char *scsb_build_version = SCSB_BUILD_VERSION; 10903831d35Sstevel /* 11003831d35Sstevel * cb_ops section of scsb driver. 11103831d35Sstevel */ 11203831d35Sstevel static int sm_open(queue_t *, dev_t *, int, int, cred_t *); 11303831d35Sstevel static int sm_close(queue_t *, int, int, cred_t *); 11403831d35Sstevel 11503831d35Sstevel static int sm_rput(queue_t *, mblk_t *); /* from i2c below */ 11603831d35Sstevel static int sm_wput(queue_t *, mblk_t *); /* from above */ 11703831d35Sstevel 11803831d35Sstevel uint_t scsb_intr_preprocess(caddr_t arg); 11903831d35Sstevel void scsb_intr(caddr_t arg); 12003831d35Sstevel static void smf_ioctl(queue_t *, mblk_t *); 12103831d35Sstevel static void sm_ioc_rdwr(queue_t *, mblk_t *, int); 12203831d35Sstevel 12303831d35Sstevel static int scsb_info(dev_info_t *, ddi_info_cmd_t, void *, void **); 12403831d35Sstevel static int scsb_attach(dev_info_t *, ddi_attach_cmd_t); 12503831d35Sstevel static int scsb_detach(dev_info_t *, ddi_detach_cmd_t); 12603831d35Sstevel static int initialize_scb(scsb_state_t *); 12703831d35Sstevel 12803831d35Sstevel static dev_info_t *scsb_dip; /* private copy of devinfo pointer */ 12903831d35Sstevel 13003831d35Sstevel static struct module_info info = { 13103831d35Sstevel 0, SCSB_DEVICE_NAME, 0, INFPSZ, 512, 128 13203831d35Sstevel }; 13303831d35Sstevel 13403831d35Sstevel static struct qinit sm_rinit = { 13503831d35Sstevel sm_rput, NULL, sm_open, sm_close, NULL, &info 13603831d35Sstevel }; 13703831d35Sstevel 13803831d35Sstevel static struct qinit sm_winit = { 13903831d35Sstevel sm_wput, NULL, sm_open, sm_close, NULL, &info 14003831d35Sstevel }; 14103831d35Sstevel 14203831d35Sstevel struct streamtab sm_st = { 14303831d35Sstevel &sm_rinit, &sm_winit, NULL, NULL 14403831d35Sstevel }; 14503831d35Sstevel 14603831d35Sstevel static struct cb_ops scsb_cb_ops = { 14703831d35Sstevel 14803831d35Sstevel nulldev, /* open */ 14903831d35Sstevel nulldev, /* close */ 15003831d35Sstevel nodev, /* strategy */ 15103831d35Sstevel nodev, /* print */ 15203831d35Sstevel nodev, /* dump */ 15303831d35Sstevel nodev, /* read */ 15403831d35Sstevel nodev, /* write */ 15503831d35Sstevel nodev, /* ioctl */ 15603831d35Sstevel nodev, /* devmap */ 15703831d35Sstevel nodev, /* mmap */ 15803831d35Sstevel nodev, /* segmap */ 15903831d35Sstevel nochpoll, /* poll */ 16003831d35Sstevel ddi_prop_op, /* cb_prop_op */ 16103831d35Sstevel &sm_st, /* streamtab */ 16203831d35Sstevel D_MP, /* Driver compatibility flag */ 16303831d35Sstevel CB_REV, /* rev */ 16403831d35Sstevel nodev, /* int (*cb_aread)() */ 16503831d35Sstevel nodev /* int (*cb_awrite)() */ 16603831d35Sstevel }; 16703831d35Sstevel 16803831d35Sstevel static struct dev_ops scsb_ops = { 16903831d35Sstevel 17003831d35Sstevel DEVO_REV, /* devo_rev, */ 17103831d35Sstevel 0, /* refcnt */ 17203831d35Sstevel scsb_info, /* info */ 17303831d35Sstevel nulldev, /* identify */ 17403831d35Sstevel nulldev, /* probe */ 17503831d35Sstevel scsb_attach, /* attach */ 17603831d35Sstevel scsb_detach, /* detach */ 17703831d35Sstevel nodev, /* reset */ 17803831d35Sstevel &scsb_cb_ops, /* driver operations */ 17919397407SSherry Moore (struct bus_ops *)0, /* bus operations */ 18019397407SSherry Moore NULL, /* power */ 18119397407SSherry Moore ddi_quiesce_not_supported, /* devo_quiesce */ 18203831d35Sstevel }; 18303831d35Sstevel 18403831d35Sstevel /* 18503831d35Sstevel * Module linkage information for the kernel. 18603831d35Sstevel */ 18703831d35Sstevel 18803831d35Sstevel static struct modldrv modldrv = { 18903831d35Sstevel &mod_driverops, /* Type of module. This one is a pseudo driver */ 19003831d35Sstevel #ifdef DEBUG 19103831d35Sstevel "SCB/SSB driver DBG" SCSB_BUILD_VERSION, 19203831d35Sstevel #else 19319397407SSherry Moore "v1.33 Netra ct System Control/Status Board driver", 19403831d35Sstevel #endif 19503831d35Sstevel &scsb_ops, /* driver ops */ 19603831d35Sstevel }; 19703831d35Sstevel 19803831d35Sstevel static struct modlinkage modlinkage = { 19903831d35Sstevel MODREV_1, 20003831d35Sstevel (void *)&modldrv, 20103831d35Sstevel NULL 20203831d35Sstevel }; 20303831d35Sstevel 20403831d35Sstevel /* 20503831d35Sstevel * local declarations and definitions 20603831d35Sstevel */ 20703831d35Sstevel #if defined(DEBUG) 20803831d35Sstevel uint32_t scsb_debug = 0x00000000; 20903831d35Sstevel #else 21003831d35Sstevel static uint32_t scsb_debug = 0; 21103831d35Sstevel #endif 21203831d35Sstevel 21303831d35Sstevel static hrtime_t scb_pre_s, scb_pre_e, scb_post_s, scb_post_e; 21403831d35Sstevel 21503831d35Sstevel static int scsb_pil = SCSB_INTR_PIL; 21603831d35Sstevel static int hsc_pil = SCSB_INTR_PIL; 21703831d35Sstevel static void *scsb_state; 21803831d35Sstevel static uint32_t scsb_global_state; 21903831d35Sstevel static uint32_t scsb_event_code; /* for event polling */ 22003831d35Sstevel static struct system_info mct_system_info; 22103831d35Sstevel static int scsb_healthy_poll_count = 16; 22203831d35Sstevel 22303831d35Sstevel static fru_id_t fru_id_table[MCT_MAX_FRUS]; 22403831d35Sstevel static uchar_t scb_intr_regs[SCTRL_MAX_GROUP_NUMREGS]; 22503831d35Sstevel 22603831d35Sstevel static uint32_t evc_fifo[EVC_FIFO_SIZE]; 22703831d35Sstevel static uint32_t evc_fifo_count = 0; 22803831d35Sstevel static uint32_t *evc_rptr = evc_fifo; 22903831d35Sstevel static uint32_t *evc_wptr = evc_fifo; 23003831d35Sstevel static void *evc_procs[EVC_PROCS_MAX]; 23103831d35Sstevel static int evc_proc_count = 0; 23203831d35Sstevel static timeout_id_t scsb_intr_tid; 23303831d35Sstevel 23403831d35Sstevel int nct_i2c_transfer(i2c_client_hdl_t i2c_hdl, i2c_transfer_t *i2c_tran); 23503831d35Sstevel 23603831d35Sstevel /* 23703831d35Sstevel * kstat functions 23803831d35Sstevel */ 23903831d35Sstevel static int scsb_alloc_kstats(scsb_state_t *); 24003831d35Sstevel static void scsb_free_kstats(scsb_state_t *); 24103831d35Sstevel static int update_ks_leddata(kstat_t *, int); 24203831d35Sstevel static int update_ks_state(kstat_t *, int); 24303831d35Sstevel static int update_ks_topology(kstat_t *, int); 24403831d35Sstevel static int update_ks_evcreg(kstat_t *, int); 24503831d35Sstevel 24603831d35Sstevel /* 24703831d35Sstevel * local functions 24803831d35Sstevel */ 24903831d35Sstevel static void free_resources(dev_info_t *, scsb_state_t *, int); 25003831d35Sstevel static i2c_transfer_t *scsb_alloc_i2ctx(i2c_client_hdl_t, uint_t); 25103831d35Sstevel static fru_info_t *find_fru_info(fru_id_t fru_id); 25203831d35Sstevel static int scsb_fake_intr(scsb_state_t *, uint32_t); 25303831d35Sstevel static int scsb_get_status(scsb_state_t *, scsb_status_t *); 25403831d35Sstevel static int scsb_leds_switch(scsb_state_t *, scsb_ustate_t); 25503831d35Sstevel static void scsb_freeze(scsb_state_t *scsb); 25603831d35Sstevel static void scsb_freeze_check(scsb_state_t *scsb); 25703831d35Sstevel static void scsb_restore(scsb_state_t *scsb); 25803831d35Sstevel static int scsb_polled_int(scsb_state_t *, int, uint32_t *); 25903831d35Sstevel static int scsb_check_config_status(scsb_state_t *scsb); 26003831d35Sstevel static int scsb_set_scfg_pres_leds(scsb_state_t *, fru_info_t *); 26103831d35Sstevel static void scsb_set_topology(scsb_state_t *); 26203831d35Sstevel static void scsb_free_topology(scsb_state_t *); 26303831d35Sstevel int scsb_read_bhealthy(scsb_state_t *scsb); 26403831d35Sstevel int scsb_read_slot_health(scsb_state_t *, int); 26503831d35Sstevel static void tonga_slotnum_check(scsb_state_t *scsb, scsb_uinfo_t *suip); 26603831d35Sstevel static int tonga_psl_to_ssl(scsb_state_t *scsb, int slotnum); 26703831d35Sstevel static uchar_t tonga_slotnum_led_shift(scsb_state_t *scsb, uchar_t data); 26803831d35Sstevel static int scsb_clear_intptrs(scsb_state_t *scsb); 26903831d35Sstevel static int scsb_clear_intmasks(scsb_state_t *scsb); 27003831d35Sstevel static int scsb_setall_intmasks(scsb_state_t *scsb); 27103831d35Sstevel static int scsb_write_mask(scsb_state_t *, uchar_t, uchar_t, uchar_t, 27203831d35Sstevel uchar_t); 27303831d35Sstevel static int scsb_rdwr_register(scsb_state_t *, int, uchar_t, int, 27403831d35Sstevel uchar_t *, int); 27503831d35Sstevel static int scsb_readall_regs(scsb_state_t *); 27603831d35Sstevel static int scsb_get_led_regnum(scsb_state_t *, scsb_uinfo_t *, uchar_t *, 27703831d35Sstevel int *, scsb_led_t); 27803831d35Sstevel static void scsb_free_i2ctx(i2c_client_hdl_t, i2c_transfer_t *); 27903831d35Sstevel static void check_fru_info(scsb_state_t *, int); 28003831d35Sstevel static void update_fru_info(scsb_state_t *, fru_info_t *); 28103831d35Sstevel static int event_to_index(uint32_t); 28203831d35Sstevel static void add_event_code(scsb_state_t *, uint32_t); 28303831d35Sstevel static uint32_t del_event_code(); 28403831d35Sstevel static uint32_t get_event_code(); 28503831d35Sstevel static int add_event_proc(scsb_state_t *, pid_t); 28603831d35Sstevel static int del_event_proc(scsb_state_t *, pid_t); 28703831d35Sstevel static void rew_event_proc(scsb_state_t *); 28803831d35Sstevel static int event_proc_count(scsb_state_t *); 28903831d35Sstevel static int find_evc_proc(pid_t pid); 29003831d35Sstevel static void signal_evc_procs(scsb_state_t *); 29103831d35Sstevel static int check_event_procs(); 29203831d35Sstevel static int scsb_is_alarm_card_slot(scsb_state_t *, int); 29303831d35Sstevel int scsb_get_slot_state(scsb_state_t *, int, int *); 29403831d35Sstevel static int scsb_fru_op(scsb_state_t *, scsb_utype_t, int, int, int); 29503831d35Sstevel static int scsb_queue_put(queue_t *, int, uint32_t *, char *); 29603831d35Sstevel static int scsb_queue_ops(scsb_state_t *, int, int, void *, char *); 29703831d35Sstevel static int scsb_blind_read(scsb_state_t *, int, uchar_t, int, uchar_t *, int); 29803831d35Sstevel static int scsb_toggle_psmint(scsb_state_t *, int); 29903831d35Sstevel static int scsb_quiesce_psmint(scsb_state_t *); 30003831d35Sstevel static int scsb_invoke_intr_chain(); 30103831d35Sstevel int scsb_intr_register(int (*)(void *), void *, fru_id_t); 30203831d35Sstevel void scsb_intr_unregister(fru_id_t); 30303831d35Sstevel 30403831d35Sstevel #ifdef DEBUG 30503831d35Sstevel static void mct_topology_dump(scsb_state_t *, int); 30603831d35Sstevel static void scsb_failing_event(scsb_state_t *scsb); 30703831d35Sstevel #endif 30803831d35Sstevel 30903831d35Sstevel int 31003831d35Sstevel _init(void) 31103831d35Sstevel { 31203831d35Sstevel int i, status; 31303831d35Sstevel 31403831d35Sstevel if (scsb_debug & 0x0005) 31503831d35Sstevel cmn_err(CE_NOTE, "scsb: _init()"); 316*07d06da5SSurya Prakki (void) ddi_soft_state_init(&scsb_state, sizeof (scsb_state_t), 31703831d35Sstevel SCSB_NO_OF_BOARDS); 318*07d06da5SSurya Prakki (void) hsc_init(); 31903831d35Sstevel if ((status = mod_install(&modlinkage)) != 0) { 32003831d35Sstevel if (scsb_debug & 0x0006) 32103831d35Sstevel cmn_err(CE_NOTE, "scsb: _init(): mod_install failed"); 32203831d35Sstevel ddi_soft_state_fini(&scsb_state); 323*07d06da5SSurya Prakki (void) hsc_fini(); 32403831d35Sstevel return (status); 32503831d35Sstevel } 32603831d35Sstevel /* 32703831d35Sstevel * initialize the FRU ID Table, using real FRU IDs where available 32803831d35Sstevel * such as I2C Addresses for FRUs with I2C support 32903831d35Sstevel */ 33003831d35Sstevel for (i = 0; i < MCT_MAX_FRUS; ++i) 33103831d35Sstevel fru_id_table[i] = i + 1; 33203831d35Sstevel fru_id_table[event_to_index(SCTRL_EVENT_PS1)] = (fru_id_t)MCT_I2C_PS1; 33303831d35Sstevel fru_id_table[event_to_index(SCTRL_EVENT_PS2)] = (fru_id_t)MCT_I2C_PS2; 33403831d35Sstevel fru_id_table[event_to_index(SCTRL_EVENT_FAN1)] = (fru_id_t)MCT_I2C_FAN1; 33503831d35Sstevel fru_id_table[event_to_index(SCTRL_EVENT_FAN2)] = (fru_id_t)MCT_I2C_FAN2; 33603831d35Sstevel fru_id_table[event_to_index(SCTRL_EVENT_FAN3)] = (fru_id_t)MCT_I2C_FAN3; 33703831d35Sstevel fru_id_table[event_to_index(SCTRL_EVENT_SCB)] = (fru_id_t)MCT_I2C_SCB; 33803831d35Sstevel return (status); 33903831d35Sstevel } 34003831d35Sstevel 34103831d35Sstevel int 34203831d35Sstevel _fini(void) 34303831d35Sstevel { 34403831d35Sstevel int status; 34503831d35Sstevel 34603831d35Sstevel if (scsb_debug & 0x0005) 34703831d35Sstevel cmn_err(CE_NOTE, "scsb: _fini()"); 34803831d35Sstevel 34903831d35Sstevel if ((status = mod_remove(&modlinkage)) == 0) { 35003831d35Sstevel ddi_soft_state_fini(&scsb_state); 351*07d06da5SSurya Prakki (void) hsc_fini(); 35203831d35Sstevel } 35303831d35Sstevel if (scsb_debug & 0x0006) 35403831d35Sstevel cmn_err(CE_NOTE, "scsb: _fini, error %x\n", status); 35503831d35Sstevel 35603831d35Sstevel return (status); 35703831d35Sstevel } 35803831d35Sstevel 35903831d35Sstevel int 36003831d35Sstevel _info(struct modinfo *modinfop) 36103831d35Sstevel { 36203831d35Sstevel if (scsb_debug & 0x0005) 36303831d35Sstevel cmn_err(CE_NOTE, "scsb: _info()"); 36403831d35Sstevel 36503831d35Sstevel return (mod_info(&modlinkage, modinfop)); 36603831d35Sstevel } 36703831d35Sstevel 36803831d35Sstevel static int 36903831d35Sstevel scsb_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 37003831d35Sstevel { 37103831d35Sstevel int instance; 37203831d35Sstevel scsb_state_t *scsb; 37303831d35Sstevel register int i; 37403831d35Sstevel int *regs; 37503831d35Sstevel uint_t len; 37603831d35Sstevel uchar_t reg, wdata, rmask; 37703831d35Sstevel 37803831d35Sstevel instance = ddi_get_instance(dip); 37903831d35Sstevel 38003831d35Sstevel if (scsb_debug & 0x0005) 38103831d35Sstevel cmn_err(CE_NOTE, "scsb_attach[%d]", instance); 38203831d35Sstevel 38303831d35Sstevel if (cmd != DDI_ATTACH) { 38403831d35Sstevel if (scsb_debug & 0x0006) 38503831d35Sstevel cmn_err(CE_NOTE, 38603831d35Sstevel "scsb_attach[%d]: cmd 0x%x != DDI_ATTACH", 38703831d35Sstevel instance, cmd); 38803831d35Sstevel return (DDI_FAILURE); 38903831d35Sstevel } 39003831d35Sstevel 39103831d35Sstevel if (ddi_soft_state_zalloc(scsb_state, instance) != DDI_SUCCESS) { 39203831d35Sstevel cmn_err(CE_WARN, "scsb%d: cannot allocate soft state", 39303831d35Sstevel instance); 39403831d35Sstevel return (DDI_FAILURE); 39503831d35Sstevel } 39603831d35Sstevel 39703831d35Sstevel scsb = (scsb_state_t *)ddi_get_soft_state(scsb_state, instance); 39803831d35Sstevel if (scsb == NULL) { 39903831d35Sstevel cmn_err(CE_WARN, "scsb%d: cannot get soft state", instance); 40003831d35Sstevel ddi_soft_state_free(scsb_state, instance); 40103831d35Sstevel return (DDI_FAILURE); 40203831d35Sstevel } 40303831d35Sstevel scsb->scsb_instance = instance; 40403831d35Sstevel scsb->scsb_state = 0; /* just checking strange mutex behavior */ 40503831d35Sstevel 40603831d35Sstevel /* 40703831d35Sstevel * make sure this is the SCB's known address 40803831d35Sstevel */ 40903831d35Sstevel if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 41003831d35Sstevel "reg", ®s, &len) != DDI_PROP_SUCCESS) { 41103831d35Sstevel cmn_err(CE_WARN, 41203831d35Sstevel "scsb%d: Failed to get \"reg\" property", instance); 41303831d35Sstevel ddi_soft_state_free(scsb_state, instance); 41403831d35Sstevel return (DDI_FAILURE); 41503831d35Sstevel } 41603831d35Sstevel scsb->scsb_i2c_addr = regs[1] & SCSB_I2C_ADDR_MASK; 41703831d35Sstevel if (scsb->scsb_i2c_addr != SCSB_I2C_ADDR) { 41803831d35Sstevel cmn_err(CE_WARN, "scsb%d: I2C Addr reg %x %x must be %x", 41903831d35Sstevel instance, regs[0], regs[1], SCSB_I2C_ADDR); 42003831d35Sstevel ddi_soft_state_free(scsb_state, instance); 42103831d35Sstevel ddi_prop_free(regs); 42203831d35Sstevel return (DDI_FAILURE); 42303831d35Sstevel } 42403831d35Sstevel /* done with array lookup, free resource */ 42503831d35Sstevel ddi_prop_free(regs); 42603831d35Sstevel /* 42703831d35Sstevel * initialize synchronization mutex and condition var. 42803831d35Sstevel * for this instance. 42903831d35Sstevel */ 43003831d35Sstevel mutex_init(&scsb->scsb_mutex, NULL, MUTEX_DRIVER, NULL); 43103831d35Sstevel scsb->scsb_state |= SCSB_UMUTEX; 43203831d35Sstevel cv_init(&scsb->scsb_cv, NULL, CV_DRIVER, NULL); 43303831d35Sstevel scsb->scsb_state |= SCSB_CONDVAR; 43403831d35Sstevel 43503831d35Sstevel /* 43603831d35Sstevel * 1. Read interrupt property of the board and register its handler. 43703831d35Sstevel * 2. Get scsb private handle for communication via I2C Services. 43803831d35Sstevel * 3. Allocate and save an i2c_transfer_t for I2C transfers. 43903831d35Sstevel */ 44003831d35Sstevel /* 1 */ 44103831d35Sstevel if (ddi_prop_exists(DDI_DEV_T_ANY, dip, 44203831d35Sstevel DDI_PROP_NOTPROM | DDI_PROP_DONTPASS, 44303831d35Sstevel "interrupt-priorities") != 1) { 44403831d35Sstevel int tmp[2]; 44503831d35Sstevel tmp[0] = scsb_pil; 44603831d35Sstevel tmp[1] = hsc_pil; 44703831d35Sstevel (void) ddi_prop_update_int_array(DDI_DEV_T_NONE, dip, 44803831d35Sstevel "interrupt-priorities", tmp, 2); 44903831d35Sstevel scsb->scsb_state |= SCSB_PROP_CREATE; 45003831d35Sstevel } 45103831d35Sstevel if ((i = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 45203831d35Sstevel DDI_PROP_DONTPASS, "interrupts", -1)) >= 0) 45303831d35Sstevel scsb->scsb_state |= SCSB_P06_INTR_ON; 45403831d35Sstevel else 45503831d35Sstevel scsb->scsb_state |= SCSB_P06_NOINT_KLUGE; 45603831d35Sstevel 45703831d35Sstevel /* 45803831d35Sstevel * Look for the device-err-threshold property which specifies 45903831d35Sstevel * on how many errors will scsb send a warning event about it's 46003831d35Sstevel * health. The scsb_err_threshold is 10 by default. 46103831d35Sstevel */ 46203831d35Sstevel if ((i = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 46303831d35Sstevel DDI_PROP_DONTPASS, "device-err-threshold", -1)) >= 0) { 46403831d35Sstevel scsb_err_threshold = i; 46503831d35Sstevel #ifdef DEBUG 46603831d35Sstevel cmn_err(CE_NOTE, "?scsb_attach: Found device-err-threshold" 46703831d35Sstevel " property, value %d", scsb_err_threshold); 46803831d35Sstevel #endif 46903831d35Sstevel } 47003831d35Sstevel scsb->scsb_i2c_errcnt = 0; 47103831d35Sstevel scsb->scsb_err_flag = B_FALSE; 47203831d35Sstevel scsb->scsb_kstat_flag = B_FALSE; 47303831d35Sstevel 47403831d35Sstevel /* 47503831d35Sstevel * If all went well, create the minor node for user level access. 47603831d35Sstevel */ 47703831d35Sstevel if (ddi_create_minor_node(dip, scsb_name, S_IFCHR, instance, 47803831d35Sstevel "ddi_ctl:pcihpc", NULL) == DDI_FAILURE) { 47903831d35Sstevel cmn_err(CE_WARN, "scsb_attach: Failed to create minor node"); 48003831d35Sstevel free_resources(dip, scsb, instance); 48103831d35Sstevel return (DDI_FAILURE); 48203831d35Sstevel } 48303831d35Sstevel scsb->scsb_state |= SCSB_MINOR_NODE; 48403831d35Sstevel scsb->scsb_dev = dip; 48503831d35Sstevel if (ddi_create_minor_node(dip, scsb_clone_name, S_IFCHR, 48603831d35Sstevel instance|SCSB_CLONE, "ddi_ctl:pcihpc", NULL) 48703831d35Sstevel == DDI_FAILURE) { 48803831d35Sstevel cmn_err(CE_WARN, "scsb_attach: Failed to create clone node"); 48903831d35Sstevel free_resources(dip, scsb, instance); 49003831d35Sstevel return (DDI_FAILURE); 49103831d35Sstevel } 49203831d35Sstevel /* CLONE */ 49303831d35Sstevel bzero(scsb->clone_devs, sizeof (clone_dev_t) * SCSB_CLONES_MAX); 49403831d35Sstevel /* 2 */ 49503831d35Sstevel if (i2c_client_register(dip, &scsb->scsb_phandle) != I2C_SUCCESS) { 49603831d35Sstevel cmn_err(CE_WARN, 49703831d35Sstevel "scsb_attach: Failed I2C Services registration"); 49803831d35Sstevel free_resources(dip, scsb, instance); 49903831d35Sstevel return (DDI_FAILURE); 50003831d35Sstevel } 50103831d35Sstevel scsb->scsb_state |= SCSB_I2C_PHANDLE; 50203831d35Sstevel /* 3 */ 50303831d35Sstevel if ((scsb->scsb_i2ctp = scsb_alloc_i2ctx(scsb->scsb_phandle, 50403831d35Sstevel I2C_SLEEP)) == NULL) { 50503831d35Sstevel cmn_err(CE_WARN, 50603831d35Sstevel "scsb%d: i2c_transfer allocation failed", instance); 50703831d35Sstevel free_resources(dip, scsb, instance); 50803831d35Sstevel return (DDI_FAILURE); 50903831d35Sstevel } 51003831d35Sstevel scsb->scsb_state |= SCSB_I2C_TRANSFER; 51103831d35Sstevel /* 51203831d35Sstevel * Now it's time to INITIALIZE the boards. 51303831d35Sstevel * 51403831d35Sstevel * 1. make sure we can do I2C bus transfers to/from the SCB. 51503831d35Sstevel * Read the SCB PROM version for a check. 51603831d35Sstevel * 2. set SCB_INITIALIZED bit in SysCommand registers (SYS_CMD_BASE) 51703831d35Sstevel * 3. clear all LED Data registers (8) by writing 0's to turn off 51803831d35Sstevel * all LEDs on the SSB. 51903831d35Sstevel * 4. read System Configuration Status registers (SCTRL_CFG) 52003831d35Sstevel * to find present FRUs and set corresponding FRU bits at 52103831d35Sstevel * LED_DATA_BASE. 52203831d35Sstevel * Also enable devices in Topology map for the current MP_ID 52303831d35Sstevel * and set the OK LEDs on the SSB. 52403831d35Sstevel * 5. read Brd_Hlthy registers (2 @ BRD_HLTHY_BASE) 52503831d35Sstevel * 6. Disable PSM Interrupts during initialization, mask all 52603831d35Sstevel * interrupts, and clear Interrupt Pointer registers 52703831d35Sstevel * by writing 0xFF to each register. 52803831d35Sstevel * 7. set SCB EEPROM address bits SPA2-SPA0 at SYS_CMD_BASE + 1 52903831d35Sstevel * 8. Install the interrupt handler if appropriate. 53003831d35Sstevel * 9. clear appropriate bits in Interrupt Mask register for those 53103831d35Sstevel * devices that can be present for this MP_ID Topology. 53203831d35Sstevel * 10. enable PSM Interrupt by writing '1' to PSM_INT_EN bit at 53303831d35Sstevel * SYS_CMD_BASE + 1 53403831d35Sstevel * Also update all shadow registers for test utility 53503831d35Sstevel * if scsb_debug is set. 53603831d35Sstevel * 11. Check if Alarm Card present at boot and set flags 53703831d35Sstevel * 12. Call hsc_attach() for slot registration. 53803831d35Sstevel * 13. Allocate, initialze, and install the kstat structures. 53903831d35Sstevel * 14. Set scsb_state_t flags to indicate SCB is ready 54003831d35Sstevel * and announce the driver is loaded. 54103831d35Sstevel */ 54203831d35Sstevel 54303831d35Sstevel /* 1. through 7. */ 54403831d35Sstevel if (initialize_scb(scsb) != DDI_SUCCESS) { 54503831d35Sstevel if (!(scsb_debug)) { 54603831d35Sstevel free_resources(dip, scsb, instance); 54703831d35Sstevel return (DDI_FAILURE); 54803831d35Sstevel } 54903831d35Sstevel } 55003831d35Sstevel /* 8. */ 55103831d35Sstevel /* 55203831d35Sstevel * P0.6 No Interrupt Support 55303831d35Sstevel * Instead of installing the handler, it will be called from a user 55403831d35Sstevel * program via smf_ioctl(). This flag provides knowledge of the 55503831d35Sstevel * necessary workarounds to several scsb routines. 55603831d35Sstevel */ 55703831d35Sstevel /* 55803831d35Sstevel * Now Install interrupt handler 55903831d35Sstevel */ 56003831d35Sstevel if (scsb->scsb_state & SCSB_P06_INTR_ON) { 56103831d35Sstevel if (ddi_get_iblock_cookie(dip, instance, 56203831d35Sstevel &scsb->scsb_iblock) == DDI_SUCCESS) { 56303831d35Sstevel mutex_init(&scsb->scsb_imutex, NULL, MUTEX_DRIVER, 56403831d35Sstevel (void *)scsb->scsb_iblock); 56503831d35Sstevel scsb->scsb_state |= SCSB_IMUTEX; 56603831d35Sstevel if (ddi_add_intr(dip, instance, &scsb->scsb_iblock, 56703831d35Sstevel NULL, scsb_intr_preprocess, 56803831d35Sstevel (caddr_t)scsb) != DDI_SUCCESS) { 56903831d35Sstevel cmn_err(CE_WARN, 57003831d35Sstevel "scsb_attach: failed interrupt " 57103831d35Sstevel "handler registration"); 57203831d35Sstevel free_resources(dip, scsb, instance); 57303831d35Sstevel return (DDI_FAILURE); 57403831d35Sstevel } 57503831d35Sstevel scb_intr_mutex = &scsb->scsb_imutex; 57603831d35Sstevel nct_mutex_init |= MUTEX_INIT; 57703831d35Sstevel } else { 57803831d35Sstevel cmn_err(CE_WARN, "scsb_attach: failed interrupt " 57903831d35Sstevel "mutex initialization"); 58003831d35Sstevel if (scsb_debug) { 58103831d35Sstevel scsb->scsb_state |= SCSB_P06_NOINT_KLUGE; 58203831d35Sstevel scsb->scsb_state &= ~SCSB_P06_INTR_ON; 58303831d35Sstevel } else { 58403831d35Sstevel free_resources(dip, scsb, instance); 58503831d35Sstevel return (DDI_FAILURE); 58603831d35Sstevel } 58703831d35Sstevel } 58803831d35Sstevel } 58903831d35Sstevel /* 9. */ 59003831d35Sstevel if (i = scsb_clear_intmasks(scsb)) { 59103831d35Sstevel cmn_err(CE_WARN, 59203831d35Sstevel "scsb%d: I2C TRANSFER Failed", instance); 59303831d35Sstevel if (!scsb_debug) { 59403831d35Sstevel free_resources(dip, scsb, instance); 59503831d35Sstevel return (DDI_FAILURE); 59603831d35Sstevel } 59703831d35Sstevel } 59803831d35Sstevel 59903831d35Sstevel /* 10. */ 60003831d35Sstevel /* 60103831d35Sstevel * For P0.6 No Interrupt Support, don't enable PSM Interrupt 60203831d35Sstevel */ 60303831d35Sstevel if (!(scsb->scsb_state & SCSB_P06_NOINT_KLUGE)) { 60403831d35Sstevel rmask = 0x00; 60503831d35Sstevel wdata = 1 << SYS_OFFSET(SCTRL_SYS_PSM_INT_ENABLE); 60603831d35Sstevel i = SYS_REG_INDEX(SCTRL_SYS_PSM_INT_ENABLE, 60703831d35Sstevel SCTRL_SYS_CMD_BASE); 60803831d35Sstevel reg = SCSB_REG_ADDR(i); 60903831d35Sstevel if (i = scsb_write_mask(scsb, reg, rmask, wdata, (uchar_t)0)) { 61003831d35Sstevel cmn_err(CE_WARN, 61103831d35Sstevel "scsb%d: I2C TRANSFER Failed", instance); 61203831d35Sstevel if (!scsb_debug) { 61303831d35Sstevel free_resources(dip, scsb, instance); 61403831d35Sstevel return (DDI_FAILURE); 61503831d35Sstevel } 61603831d35Sstevel } else 61703831d35Sstevel scsb->scsb_state |= SCSB_PSM_INT_ENABLED; 61803831d35Sstevel } 61903831d35Sstevel if (scsb_debug) { 62003831d35Sstevel /* 62103831d35Sstevel * For smctrl test utility, 62203831d35Sstevel * so all data is available in shadow registers 62303831d35Sstevel * 62403831d35Sstevel * DEBUG_MODE enables private testing interfaces 62503831d35Sstevel * DIAGS_MODE permits limited testing interfaces 62603831d35Sstevel */ 62703831d35Sstevel scsb->scsb_state |= SCSB_DEBUG_MODE; 62803831d35Sstevel mutex_enter(&scsb->scsb_mutex); 62903831d35Sstevel if (scsb_readall_regs(scsb)) 63003831d35Sstevel cmn_err(CE_WARN, 63103831d35Sstevel "scsb_attach: scsb_readall FAILED"); 63203831d35Sstevel mutex_exit(&scsb->scsb_mutex); 63303831d35Sstevel } 63403831d35Sstevel /* 11. */ 63503831d35Sstevel /* Check if Alarm Card present at boot and set flags */ 63603831d35Sstevel if (scsb_fru_op(scsb, ALARM, 1, SCTRL_SYSCFG_BASE, 63703831d35Sstevel SCSB_FRU_OP_GET_BITVAL)) 63803831d35Sstevel scsb->scsb_hsc_state |= SCSB_ALARM_CARD_PRES; 63903831d35Sstevel 64003831d35Sstevel /* 12. */ 64103831d35Sstevel if (scsb_debug & 0x0004) 64203831d35Sstevel cmn_err(CE_NOTE, 64303831d35Sstevel "scsb_attach: registering cPCI slots"); 64403831d35Sstevel if (scsb_hsc_attach(dip, scsb, instance) != DDI_SUCCESS) { 64503831d35Sstevel if (scsb_debug & 0x00008000) { 64603831d35Sstevel cmn_err(CE_WARN, 64703831d35Sstevel "scsb: Hotswap controller initialisation" 64803831d35Sstevel " failed\n"); 64903831d35Sstevel } 65003831d35Sstevel } else 65103831d35Sstevel scsb->scsb_hsc_state |= SCSB_HSC_INIT; 65203831d35Sstevel /* 13. */ 65303831d35Sstevel /* 65403831d35Sstevel * allocate and install the kstat data structures 65503831d35Sstevel */ 65603831d35Sstevel if (scsb_alloc_kstats(scsb) != DDI_SUCCESS) { 65703831d35Sstevel if (scsb_debug & 0x0006) 65803831d35Sstevel cmn_err(CE_WARN, "scsb_attach: ERROR adding kstats"); 65903831d35Sstevel } 66003831d35Sstevel /* 14. */ 66103831d35Sstevel scsb->scsb_state |= SCSB_UP; 66203831d35Sstevel scsb_global_state |= SCSB_UP; 66303831d35Sstevel ddi_report_dev(scsb->scsb_dev); 66403831d35Sstevel cmn_err(CE_CONT, "?%s%d: " 66503831d35Sstevel "Prom Version %s, Midplane Id %x\n", 66603831d35Sstevel ddi_driver_name(scsb->scsb_dev), 66703831d35Sstevel scsb->scsb_instance, 66803831d35Sstevel (scsb->scsb_state & SCSB_P06_PROM) ? "0.6" : 66903831d35Sstevel (scsb->scsb_state & SCSB_P10_PROM) ? "1.0" : 67003831d35Sstevel (scsb->scsb_state & SCSB_P15_PROM) ? "1.5" : 67103831d35Sstevel (scsb->scsb_state & SCSB_P20_PROM) ? "2.0" : "Unknown", 67203831d35Sstevel mct_system_info.mid_plane.fru_id); 67303831d35Sstevel return (DDI_SUCCESS); 67403831d35Sstevel } 67503831d35Sstevel 67603831d35Sstevel /* 67703831d35Sstevel * This funciton is called from scsb_attach(), and from scsb_intr() as part 67803831d35Sstevel * of Hot Insertion support, to check the SCB PROM ID register and set 67903831d35Sstevel * scsb_state bits and register table pointers as necessary. 68003831d35Sstevel */ 68103831d35Sstevel static int 68203831d35Sstevel scb_check_version(scsb_state_t *scsb) 68303831d35Sstevel { 68403831d35Sstevel int hotswap = 0; 68503831d35Sstevel uchar_t data; 68603831d35Sstevel if (scsb->scsb_state & SCSB_UP) { 68703831d35Sstevel /* 68803831d35Sstevel * If driver is UP, then this call is from scsb_intr() 68903831d35Sstevel * as part of Hot Insertion support. 69003831d35Sstevel */ 69103831d35Sstevel hotswap = 1; 69203831d35Sstevel } 69303831d35Sstevel /* Read the SCB PROM ID */ 69403831d35Sstevel if (scsb_rdwr_register(scsb, I2C_WR_RD, (uchar_t)SCTRL_PROM_VERSION, 1, 69503831d35Sstevel &data, 1)) { 69603831d35Sstevel if (!(hotswap && scsb->scsb_state & SCSB_FROZEN)) 69703831d35Sstevel cmn_err(CE_WARN, "scsb%d: I2C TRANSFER Failed", 69803831d35Sstevel scsb->scsb_instance); 69903831d35Sstevel if (scsb_debug & 0x0006) { 70003831d35Sstevel cmn_err(CE_WARN, 70103831d35Sstevel "scsb_attach(%d): failed read of PROM ID", 70203831d35Sstevel scsb->scsb_instance); 70303831d35Sstevel } 70403831d35Sstevel return (DDI_FAILURE); 70503831d35Sstevel } 70603831d35Sstevel /* 70703831d35Sstevel * compare with stored version number, and if different, 70803831d35Sstevel * report a warning and keep the driver FROZEN 70903831d35Sstevel */ 71003831d35Sstevel if (hotswap) { 71103831d35Sstevel if (((mct_system_info.fru_info_list[SCB])[0].fru_version & 0xf) 71203831d35Sstevel == (data & 0xf)) { 71303831d35Sstevel return (DDI_SUCCESS); 71403831d35Sstevel } 71503831d35Sstevel if (scsb_debug & 0x00020000) { 71603831d35Sstevel cmn_err(CE_NOTE, 71703831d35Sstevel "scb_check_version: SCB version %d " 71803831d35Sstevel "replacing version %d", data, 71903831d35Sstevel (mct_system_info.fru_info_list[SCB])[0]. 72003831d35Sstevel fru_version & 0xf); 72103831d35Sstevel } 72203831d35Sstevel } 72303831d35Sstevel if ((data & 0xf) == SCTRL_PROM_P06) { 72403831d35Sstevel scsb->scsb_state |= SCSB_P06_PROM; 72503831d35Sstevel } else if ((data & 0xf) == SCTRL_PROM_P10) { 72603831d35Sstevel scsb->scsb_state |= SCSB_P10_PROM; 72703831d35Sstevel } else if ((data & 0xf) == SCTRL_PROM_P15) { 72803831d35Sstevel scsb->scsb_state |= SCSB_P15_PROM; 72903831d35Sstevel } else if ((data & 0xf) == SCTRL_PROM_P20) { 73003831d35Sstevel scsb->scsb_state |= SCSB_P20_PROM; 73103831d35Sstevel } 73203831d35Sstevel if (!(scsb->scsb_state & SCSB_SCB_PRESENT)) 73303831d35Sstevel scsb->scsb_state |= SCSB_SCB_PRESENT; 73403831d35Sstevel if (IS_SCB_P10) { 73503831d35Sstevel scb_reg_index = scb_10_reg_index; 73603831d35Sstevel scb_numregs = scb_10_numregs; 73703831d35Sstevel scb_fru_offset = scb_10_fru_offset; 73803831d35Sstevel scb_sys_offset = scb_10_sys_offset; 73903831d35Sstevel } else { /* if (IS_SCB_P15) */ 74003831d35Sstevel scb_reg_index = scb_15_reg_index; 74103831d35Sstevel scb_numregs = scb_15_numregs; 74203831d35Sstevel scb_fru_offset = scb_15_fru_offset; 74303831d35Sstevel scb_sys_offset = scb_15_sys_offset; 74403831d35Sstevel } 74503831d35Sstevel if (!(IS_SCB_P15) && !(IS_SCB_P10)) { 74603831d35Sstevel cmn_err(CE_WARN, "scsb%d: SCB Version %d not recognized", 74703831d35Sstevel scsb->scsb_instance, data); 74803831d35Sstevel if (hotswap) 74903831d35Sstevel scsb->scsb_state |= SCSB_FROZEN; 75003831d35Sstevel if (!(scsb_debug)) { 75103831d35Sstevel return (DDI_FAILURE); 75203831d35Sstevel } 75303831d35Sstevel /* 75403831d35Sstevel * DEBUG: Assume SCB15 75503831d35Sstevel */ 75603831d35Sstevel scsb->scsb_state |= SCSB_P15_PROM; 75703831d35Sstevel } 75803831d35Sstevel return (DDI_SUCCESS); 75903831d35Sstevel } 76003831d35Sstevel 76103831d35Sstevel /* 76203831d35Sstevel * SCB initialization steps to be called from scsb_attach() 76303831d35Sstevel * or from scsb_intr() calling scsb_restore() on Hot Insertion. 76403831d35Sstevel */ 76503831d35Sstevel static int 76603831d35Sstevel initialize_scb(scsb_state_t *scsb) 76703831d35Sstevel { 76803831d35Sstevel register int i; 76903831d35Sstevel uchar_t reg, wdata, rmask; 77003831d35Sstevel /* 77103831d35Sstevel * If called from scsb_intr(), we've already done this 77203831d35Sstevel */ 77303831d35Sstevel if (!(scsb->scsb_state & SCSB_IN_INTR)) 77403831d35Sstevel if (scb_check_version(scsb) != DDI_SUCCESS) 77503831d35Sstevel return (DDI_FAILURE); 77603831d35Sstevel /* 77703831d35Sstevel * 2. Set the SCB_INIT bit in the System Command register 77803831d35Sstevel */ 77903831d35Sstevel rmask = 0x00; /* P1.0: 0x60; */ 78003831d35Sstevel wdata = 1 << SYS_OFFSET(SCTRL_SYS_SCB_INIT); 78103831d35Sstevel i = SYS_REG_INDEX(SCTRL_SYS_SCB_INIT, SCTRL_SYS_CMD_BASE); 78203831d35Sstevel reg = SCSB_REG_ADDR(i); 78303831d35Sstevel if (i = scsb_write_mask(scsb, reg, rmask, wdata, 0)) { 78403831d35Sstevel cmn_err(CE_WARN, 78503831d35Sstevel "scsb%d: I2C TRANSFER Failed", scsb->scsb_instance); 78603831d35Sstevel if (scsb_debug & 0x0006) { 78703831d35Sstevel cmn_err(CE_NOTE, 78803831d35Sstevel "scsb_attach: failed to set SCB_INIT"); 78903831d35Sstevel } 79003831d35Sstevel return (DDI_FAILURE); 79103831d35Sstevel } 79203831d35Sstevel /* 3. For P1.0 and previous system, turn off all LEDs */ 79303831d35Sstevel if (IS_SCB_P10) { 79403831d35Sstevel if (scsb_debug & 0x0004) { 79503831d35Sstevel cmn_err(CE_NOTE, "scsb_attach(%d): turning LEDs off", 79603831d35Sstevel scsb->scsb_instance); 79703831d35Sstevel } 79803831d35Sstevel if (i = scsb_leds_switch(scsb, OFF)) { 79903831d35Sstevel cmn_err(CE_WARN, "scsb%d: I2C TRANSFER Failed", 80003831d35Sstevel scsb->scsb_instance); 80103831d35Sstevel return (DDI_FAILURE); 80203831d35Sstevel } 80303831d35Sstevel } 80403831d35Sstevel /* 4. Read the SYSCFG registers, update FRU info and SSB LEDs */ 80503831d35Sstevel if (scsb_debug & 0x0004) 80603831d35Sstevel cmn_err(CE_NOTE, "scsb_attach(%d): reading config registers", 80703831d35Sstevel scsb->scsb_instance); 80803831d35Sstevel if ((i = scsb_check_config_status(scsb)) == 0) { 80903831d35Sstevel if (!(scsb->scsb_state & SCSB_TOPOLOGY)) { 81003831d35Sstevel scsb_set_topology(scsb); 81103831d35Sstevel if (scsb_debug & 0x0004) 81203831d35Sstevel cmn_err(CE_NOTE, "scsb_attach(%d): mpid = 0x%x", 81303831d35Sstevel scsb->scsb_instance, 81403831d35Sstevel mct_system_info.mid_plane.fru_id); 81503831d35Sstevel } else { 81603831d35Sstevel fru_info_t *fru_ptr; 81703831d35Sstevel /* 81803831d35Sstevel * walk through FRUs and update FRU info 81903831d35Sstevel */ 82003831d35Sstevel for (i = 0; i < SCSB_UNIT_TYPES; ++i) { 82103831d35Sstevel fru_ptr = mct_system_info.fru_info_list[i]; 82203831d35Sstevel while (fru_ptr != NULL) { 82303831d35Sstevel update_fru_info(scsb, fru_ptr); 82403831d35Sstevel fru_ptr = fru_ptr->next; 82503831d35Sstevel } 82603831d35Sstevel } 82703831d35Sstevel } 82803831d35Sstevel i = scsb_set_scfg_pres_leds(scsb, NULL); 82903831d35Sstevel } 83003831d35Sstevel if (i) { 83103831d35Sstevel cmn_err(CE_WARN, "scsb%d: I2C TRANSFER Failed", 83203831d35Sstevel scsb->scsb_instance); 83303831d35Sstevel return (DDI_FAILURE); 83403831d35Sstevel } 83503831d35Sstevel /* 5. read the Board Healthy registers */ 83603831d35Sstevel if (scsb_debug & 0x0004) 83703831d35Sstevel cmn_err(CE_NOTE, "scsb_attach(%d): reading Brd_Hlthy registers", 83803831d35Sstevel scsb->scsb_instance); 83903831d35Sstevel i = scsb_read_bhealthy(scsb); 84003831d35Sstevel if (i) { 84103831d35Sstevel cmn_err(CE_WARN, "scsb%d: I2C TRANSFER Failed", 84203831d35Sstevel scsb->scsb_instance); 84303831d35Sstevel return (DDI_FAILURE); 84403831d35Sstevel } 84503831d35Sstevel /* 6. Clear Interrupt Source registers */ 84603831d35Sstevel /* 84703831d35Sstevel * Due to some registration problems, we must first disable 84803831d35Sstevel * global interrupts which may be the default reset value 84903831d35Sstevel * itself. However, this is a safe step to do in case of 85003831d35Sstevel * implementation changes. 85103831d35Sstevel * 85203831d35Sstevel * Disable Global SCB Interrupts now 85303831d35Sstevel */ 85403831d35Sstevel rmask = 0x00; /* P1.0: 0x60; */ 85503831d35Sstevel wdata = 1 << SYS_OFFSET(SCTRL_SYS_PSM_INT_ENABLE); 85603831d35Sstevel i = SYS_REG_INDEX(SCTRL_SYS_PSM_INT_ENABLE, SCTRL_SYS_CMD_BASE); 85703831d35Sstevel reg = SCSB_REG_ADDR(i); 85803831d35Sstevel if (i = scsb_write_mask(scsb, reg, rmask, (uchar_t)0, wdata)) { 85903831d35Sstevel cmn_err(CE_WARN, "scsb%d: Cannot turn off PSM_INT", 86003831d35Sstevel scsb->scsb_instance); 86103831d35Sstevel return (DDI_FAILURE); 86203831d35Sstevel } 86303831d35Sstevel /* Mask all interrupt sources */ 86403831d35Sstevel if (i = scsb_setall_intmasks(scsb)) { 86503831d35Sstevel cmn_err(CE_WARN, "scsb%d: I2C TRANSFER Failed", 86603831d35Sstevel scsb->scsb_instance); 86703831d35Sstevel return (DDI_FAILURE); 86803831d35Sstevel } 86903831d35Sstevel /* Clear any latched interrupts */ 87003831d35Sstevel if (i = scsb_clear_intptrs(scsb)) { 87103831d35Sstevel cmn_err(CE_WARN, "scsb%d: I2C TRANSFER Failed", 87203831d35Sstevel scsb->scsb_instance); 87303831d35Sstevel return (DDI_FAILURE); 87403831d35Sstevel } 87503831d35Sstevel /* 7. set SCB EEPROM address: NOT USED */ 87603831d35Sstevel return (DDI_SUCCESS); 87703831d35Sstevel } 87803831d35Sstevel 87903831d35Sstevel /* 88003831d35Sstevel * Based on MC conditions, scsb_detach should eventually be made to always 88103831d35Sstevel * return FAILURE, as the driver should not be allowed to detach after some 88203831d35Sstevel * hs slots have been used. 88303831d35Sstevel */ 88403831d35Sstevel static int 88503831d35Sstevel scsb_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 88603831d35Sstevel { 88703831d35Sstevel int instance; 88803831d35Sstevel scsb_state_t *scsb; 88903831d35Sstevel uchar_t reg, wdata; 89003831d35Sstevel 89103831d35Sstevel /* 89203831d35Sstevel * TBD: make sure there are no outstanding operations on the system 89303831d35Sstevel * monitor card before detaching. 89403831d35Sstevel */ 89503831d35Sstevel instance = ddi_get_instance(dip); 89603831d35Sstevel if (scsb_debug & 0x0005) 89703831d35Sstevel cmn_err(CE_NOTE, "scsb_detach[%d]", instance); 89803831d35Sstevel if (cmd != DDI_DETACH) { 89903831d35Sstevel if (scsb_debug & 0x0006) 90003831d35Sstevel cmn_err(CE_NOTE, 90103831d35Sstevel "scsb_detach(%d): command %x is not DDI_DETACH\n", 90203831d35Sstevel instance, cmd); 90303831d35Sstevel return (DDI_FAILURE); 90403831d35Sstevel } 90503831d35Sstevel scsb = (scsb_state_t *)ddi_get_soft_state(scsb_state, instance); 90603831d35Sstevel scsb->scsb_state &= ~SCSB_UP; 90703831d35Sstevel scsb_global_state &= ~SCSB_UP; 90803831d35Sstevel if (scsb->scsb_hsc_state & SCSB_HSC_INIT) { 909*07d06da5SSurya Prakki (void) scsb_hsc_detach(dip, scsb, instance); 91003831d35Sstevel scsb->scsb_hsc_state &= ~SCSB_HSC_INIT; 91103831d35Sstevel } 91203831d35Sstevel if (scsb->scsb_state & SCSB_PSM_INT_ENABLED) { 91303831d35Sstevel /* 91403831d35Sstevel * Disable Global SCB Interrupts now 91503831d35Sstevel */ 91603831d35Sstevel wdata = 1 << SYS_OFFSET(SCTRL_SYS_PSM_INT_ENABLE); 91703831d35Sstevel reg = SYS_REG_INDEX(SCTRL_SYS_PSM_INT_ENABLE, 91803831d35Sstevel SCTRL_SYS_CMD_BASE); 91903831d35Sstevel if (scsb_write_mask(scsb, reg, (uchar_t)0, (uchar_t)0, wdata)) { 92003831d35Sstevel cmn_err(CE_WARN, 92103831d35Sstevel "scsb%d: Cannot turn off PSM_INT", instance); 92203831d35Sstevel if (!scsb_debug) { 92303831d35Sstevel (void) free_resources(dip, scsb, instance); 92403831d35Sstevel return (DDI_FAILURE); 92503831d35Sstevel } 92603831d35Sstevel } 92703831d35Sstevel /* Mask all interrupts */ 92803831d35Sstevel if (scsb_setall_intmasks(scsb)) { 92903831d35Sstevel cmn_err(CE_WARN, 93003831d35Sstevel "scsb%d: I2C TRANSFER Failed", instance); 93103831d35Sstevel if (!scsb_debug) { 93203831d35Sstevel (void) free_resources(dip, scsb, instance); 93303831d35Sstevel return (DDI_FAILURE); 93403831d35Sstevel } 93503831d35Sstevel } 93603831d35Sstevel /* Clear all latched interrupts */ 93703831d35Sstevel if (scsb_clear_intptrs(scsb)) { 93803831d35Sstevel cmn_err(CE_WARN, 93903831d35Sstevel "scsb%d: I2C TRANSFER Failed", instance); 94003831d35Sstevel if (!scsb_debug) { 94103831d35Sstevel (void) free_resources(dip, scsb, instance); 94203831d35Sstevel return (DDI_FAILURE); 94303831d35Sstevel } 94403831d35Sstevel } 94503831d35Sstevel } 94603831d35Sstevel if (scsb->scsb_opens && scsb->scsb_rq != NULL) 94703831d35Sstevel qprocsoff(scsb->scsb_rq); 94803831d35Sstevel /* CLONE */ 94903831d35Sstevel (void) scsb_queue_ops(scsb, QPROCSOFF, 0, NULL, NULL); 95003831d35Sstevel /* 95103831d35Sstevel * free the allocated resources 95203831d35Sstevel */ 95303831d35Sstevel free_resources(dip, scsb, instance); 95403831d35Sstevel return (DDI_SUCCESS); 95503831d35Sstevel } 95603831d35Sstevel 95703831d35Sstevel static void 95803831d35Sstevel free_resources(dev_info_t *dip, scsb_state_t *scsb, int instance) 95903831d35Sstevel { 96003831d35Sstevel if (scsb_debug & 0x0005) { 96103831d35Sstevel cmn_err(CE_NOTE, "free_resources[%d], scsb_state=0x%x", 96203831d35Sstevel instance, scsb->scsb_state); 96303831d35Sstevel drv_usecwait(500000); 96403831d35Sstevel } 96503831d35Sstevel if (scsb->scsb_state & SCSB_P06_INTR_ON && 96603831d35Sstevel scsb->scsb_state & SCSB_IMUTEX) { 96703831d35Sstevel scsb->scsb_state &= ~SCSB_P06_INTR_ON; 96803831d35Sstevel ddi_remove_intr(dip, 0, scsb->scsb_iblock); 96903831d35Sstevel } 97003831d35Sstevel if (scsb->scsb_state & SCSB_KSTATS) { 97103831d35Sstevel scsb_free_kstats(scsb); 97203831d35Sstevel scsb->scsb_state &= ~SCSB_KSTATS; 97303831d35Sstevel } 97403831d35Sstevel if (scsb->scsb_state & SCSB_TOPOLOGY) { 97503831d35Sstevel scsb_free_topology(scsb); 97603831d35Sstevel scsb->scsb_state &= ~SCSB_TOPOLOGY; 97703831d35Sstevel } 97803831d35Sstevel 97903831d35Sstevel nct_mutex_init = MUTEX_UNINIT; 98003831d35Sstevel if (scsb->scsb_state & SCSB_IMUTEX) { 98103831d35Sstevel scsb->scsb_state &= ~SCSB_IMUTEX; 98203831d35Sstevel mutex_destroy(&scsb->scsb_imutex); 98303831d35Sstevel } 98403831d35Sstevel if (scsb->scsb_state & SCSB_I2C_TRANSFER) { 98503831d35Sstevel scsb->scsb_state &= ~SCSB_I2C_TRANSFER; 98603831d35Sstevel i2c_transfer_free(scsb->scsb_phandle, scsb->scsb_i2ctp); 98703831d35Sstevel } 98803831d35Sstevel if (scsb->scsb_state & SCSB_I2C_PHANDLE) { 98903831d35Sstevel scsb->scsb_state &= ~SCSB_I2C_PHANDLE; 99003831d35Sstevel i2c_client_unregister(scsb->scsb_phandle); 99103831d35Sstevel } 99203831d35Sstevel if (scsb->scsb_state & SCSB_MINOR_NODE) { 99303831d35Sstevel scsb->scsb_state &= ~SCSB_MINOR_NODE; 99403831d35Sstevel ddi_remove_minor_node(dip, NULL); 99503831d35Sstevel } 99603831d35Sstevel if (scsb->scsb_state & SCSB_PROP_CREATE) { 99703831d35Sstevel scsb->scsb_state &= ~SCSB_PROP_CREATE; 99803831d35Sstevel (void) ddi_prop_remove(DDI_DEV_T_NONE, dip, 99903831d35Sstevel "interrupt-priorities"); 100003831d35Sstevel } 100103831d35Sstevel /* ddi_prop_remove_all(dip); */ 100203831d35Sstevel if (scsb->scsb_state & SCSB_CONDVAR) { 100303831d35Sstevel scsb->scsb_state &= ~SCSB_CONDVAR; 100403831d35Sstevel cv_destroy(&scsb->scsb_cv); 100503831d35Sstevel } 100603831d35Sstevel if (scsb->scsb_state & SCSB_UMUTEX) { 100703831d35Sstevel scsb->scsb_state &= ~SCSB_UMUTEX; 100803831d35Sstevel mutex_destroy(&scsb->scsb_mutex); 100903831d35Sstevel } 101003831d35Sstevel ddi_soft_state_free(scsb_state, instance); 101103831d35Sstevel } 101203831d35Sstevel 101303831d35Sstevel /* 101403831d35Sstevel * Just for testing scsb's poll function 101503831d35Sstevel */ 101603831d35Sstevel static int 101703831d35Sstevel scsb_fake_intr(scsb_state_t *scsb, uint32_t evcode) 101803831d35Sstevel { 101903831d35Sstevel if (evcode == 0) 102003831d35Sstevel evcode = scsb_event_code; 102103831d35Sstevel else 102203831d35Sstevel scsb_event_code = evcode; 102303831d35Sstevel if (scsb_debug & 0x4001) { 102403831d35Sstevel cmn_err(CE_NOTE, "scsb_fake_intr: event = 0x%x, scsb_rq=0x%p", 1025*07d06da5SSurya Prakki scsb_event_code, (void *)scsb->scsb_rq); 102603831d35Sstevel } 102703831d35Sstevel /* 102803831d35Sstevel * Allow access to shadow registers even though SCB is removed 102903831d35Sstevel * 103003831d35Sstevel * if (scsb->scsb_state & SCSB_FROZEN) { 103103831d35Sstevel * return (EAGAIN); 103203831d35Sstevel * } 103303831d35Sstevel */ 103403831d35Sstevel if (scsb_debug & 0x00040000) { 103503831d35Sstevel check_fru_info(scsb, evcode); 103603831d35Sstevel add_event_code(scsb, evcode); 103703831d35Sstevel } 103803831d35Sstevel /* just inform user-level via poll about this event */ 103903831d35Sstevel if (scsb_queue_ops(scsb, QPUT_INT32, 1, &evcode, "scsb_fake_intr") 104003831d35Sstevel == QOP_FAILED) 104103831d35Sstevel return (ENOMEM); 104203831d35Sstevel return (0); 104303831d35Sstevel } 104403831d35Sstevel 104503831d35Sstevel /* ARGSUSED */ 104603831d35Sstevel static int 104703831d35Sstevel scsb_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result) 104803831d35Sstevel { 104903831d35Sstevel int retval = DDI_FAILURE; 105003831d35Sstevel 105103831d35Sstevel if (scsb_debug & 0x0001) 105203831d35Sstevel cmn_err(CE_NOTE, "scsb_info()"); 105303831d35Sstevel 105403831d35Sstevel switch (infocmd) { 105503831d35Sstevel case DDI_INFO_DEVT2DEVINFO: 105603831d35Sstevel if (getminor((dev_t)arg) == 0 && scsb_dip != NULL) { 105703831d35Sstevel *result = (void *) scsb_dip; 105803831d35Sstevel retval = DDI_SUCCESS; 105903831d35Sstevel } 106003831d35Sstevel break; 106103831d35Sstevel 106203831d35Sstevel case DDI_INFO_DEVT2INSTANCE: 106303831d35Sstevel if (getminor((dev_t)arg) == 0) { 106403831d35Sstevel *result = (void *)0; 106503831d35Sstevel retval = DDI_SUCCESS; 106603831d35Sstevel } 106703831d35Sstevel break; 106803831d35Sstevel 106903831d35Sstevel default: 107003831d35Sstevel break; 107103831d35Sstevel } 107203831d35Sstevel 107303831d35Sstevel return (retval); 107403831d35Sstevel } 107503831d35Sstevel 107603831d35Sstevel 107703831d35Sstevel /* 107803831d35Sstevel * SCSB STREAMS routines 107903831d35Sstevel */ 108003831d35Sstevel /*ARGSUSED*/ 108103831d35Sstevel static int 108203831d35Sstevel sm_open(queue_t *q, dev_t *devp, int flag, int sflag, cred_t *credp) 108303831d35Sstevel { 108403831d35Sstevel int instance, clone; 108503831d35Sstevel minor_t minor_dev; 108603831d35Sstevel clone_dev_t *clptr; 108703831d35Sstevel scsb_state_t *scsb; 108803831d35Sstevel 108903831d35Sstevel minor_dev = getminor(*devp); 109003831d35Sstevel instance = SCSB_GET_INSTANCE(minor_dev); 109103831d35Sstevel scsb = ddi_get_soft_state(scsb_state, instance); 109203831d35Sstevel if (scsb == NULL) 109303831d35Sstevel return (ENXIO); 109403831d35Sstevel 109503831d35Sstevel if (scsb_debug & 0x0009) { 1096*07d06da5SSurya Prakki cmn_err(CE_NOTE, "sm_open(%d) q=0x%p", instance, (void *)q); 109703831d35Sstevel } 109803831d35Sstevel if (!(scsb->scsb_state & SCSB_UP)) { 109903831d35Sstevel return (ENODEV); 110003831d35Sstevel } 110103831d35Sstevel /* 110203831d35Sstevel * Don't fail the open if SCB removed since we still want to satisfy 110303831d35Sstevel * read requests from the shadow registers, the last know register 110403831d35Sstevel * contents. On new SCB insertion, all will be re-initialized, 110503831d35Sstevel * including envmond and it's policies. 110603831d35Sstevel * 110703831d35Sstevel * if (scsb->scsb_state & SCSB_FROZEN) { 110803831d35Sstevel * return (EAGAIN); 110903831d35Sstevel * } 111003831d35Sstevel */ 111103831d35Sstevel ASSERT(credp != NULL); 111203831d35Sstevel /* 111303831d35Sstevel * XXX check for root access here, return EPERM if not root open 111403831d35Sstevel */ 111503831d35Sstevel if (sflag == MODOPEN) { 111603831d35Sstevel /* scsb module is being pushed */ 111703831d35Sstevel if (scsb_debug & 0x0008) 111803831d35Sstevel cmn_err(CE_NOTE, "sm_open(%d): MODOPEN", instance); 111903831d35Sstevel /* 112003831d35Sstevel * this is no longer supported 112103831d35Sstevel */ 112203831d35Sstevel return (ENXIO); 112303831d35Sstevel } else if (sflag == CLONEOPEN) { 112403831d35Sstevel /* scsb is being opened as a clonable driver */ 112503831d35Sstevel if (scsb_debug & 0x0008) 112603831d35Sstevel cmn_err(CE_NOTE, "sm_open(%d): CLONEOPEN", instance); 112703831d35Sstevel /* 112803831d35Sstevel * The cloned stream is not handled via the clone driver. 112903831d35Sstevel * See the minor device code below. 113003831d35Sstevel */ 113103831d35Sstevel return (ENXIO); 113203831d35Sstevel } else if (minor_dev & SCSB_CLONE) { 113303831d35Sstevel /* 113403831d35Sstevel * First check for the SCSB_CLONE device. 113503831d35Sstevel * Find an available clone_devs[] entry, or return ENXIO. 113603831d35Sstevel * Make new dev_t and store in *devp. 113703831d35Sstevel */ 113803831d35Sstevel if (scsb_debug & 0x0008) 113903831d35Sstevel cmn_err(CE_NOTE, 114003831d35Sstevel "sm_open(%d): SCSB_CLONE OPEN", instance); 114103831d35Sstevel mutex_enter(&scsb->scsb_mutex); 114203831d35Sstevel if ((clone = scsb_queue_ops(scsb, QFIRST_AVAILABLE, 0, NULL, 114303831d35Sstevel "scsb_open")) == QOP_FAILED) { 114403831d35Sstevel mutex_exit(&scsb->scsb_mutex); 114503831d35Sstevel return (ENXIO); 114603831d35Sstevel } 114703831d35Sstevel clptr = &scsb->clone_devs[clone]; 114803831d35Sstevel clptr->cl_flags = SCSB_OPEN; 114903831d35Sstevel clptr->cl_rq = RD(q); 115003831d35Sstevel clptr->cl_minor = SCSB_MAKE_MINOR(instance, clone); 115103831d35Sstevel *devp = makedevice(getmajor(*devp), clptr->cl_minor); 115203831d35Sstevel scsb->scsb_clopens++; 115303831d35Sstevel if (scsb_debug & 0x0008) 115403831d35Sstevel cmn_err(CE_NOTE, 115503831d35Sstevel "sm_open(%d): new clone device minor: 0x%x" 115603831d35Sstevel " stream queue is 0x%p", 1157*07d06da5SSurya Prakki instance, clptr->cl_minor, (void *)q); 115803831d35Sstevel } else { 115903831d35Sstevel /* scsb is being opened as a regular driver */ 116003831d35Sstevel if (scsb_debug & 0x0008) 116103831d35Sstevel cmn_err(CE_NOTE, "sm_open(%d): DEVOPEN", instance); 116203831d35Sstevel mutex_enter(&scsb->scsb_mutex); 116303831d35Sstevel if (scsb->scsb_state & SCSB_EXCL) { 116403831d35Sstevel if (scsb_debug & 0x0008) 116503831d35Sstevel cmn_err(CE_NOTE, 116603831d35Sstevel "sm_open(%d): can't open, state is EXCL", 116703831d35Sstevel instance); 116803831d35Sstevel mutex_exit(&scsb->scsb_mutex); 116903831d35Sstevel return (EBUSY); 117003831d35Sstevel } 117103831d35Sstevel if (flag & FEXCL) { 117203831d35Sstevel if (scsb_debug & 0x0008) 117303831d35Sstevel cmn_err(CE_NOTE, "sm_open(%d): is EXCL", 117403831d35Sstevel instance); 117503831d35Sstevel if (scsb->scsb_state & SCSB_OPEN) { 117603831d35Sstevel if (scsb_debug & 0x0008) 117703831d35Sstevel cmn_err(CE_NOTE, 117803831d35Sstevel "sm_open(%d): cannot open EXCL", 117903831d35Sstevel instance); 118003831d35Sstevel mutex_exit(&scsb->scsb_mutex); 118103831d35Sstevel return (EBUSY); 118203831d35Sstevel } 118303831d35Sstevel scsb->scsb_state |= SCSB_EXCL; 118403831d35Sstevel } 118503831d35Sstevel if (scsb->scsb_opens && scsb->scsb_rq != NULL && 118603831d35Sstevel scsb->scsb_rq != RD(q)) { 118703831d35Sstevel if (scsb_debug & 0x000a) 118803831d35Sstevel cmn_err(CE_WARN, "sm_open[%d]: q (0x%p) != " 118903831d35Sstevel "scsb_rq (0x%p)", 1190*07d06da5SSurya Prakki instance, (void *)RD(q), 1191*07d06da5SSurya Prakki (void *)scsb->scsb_rq); 119203831d35Sstevel } 119303831d35Sstevel scsb->scsb_rq = RD(q); 119403831d35Sstevel scsb->scsb_opens++; 119503831d35Sstevel } 119603831d35Sstevel scsb->scsb_state |= SCSB_OPEN; 119703831d35Sstevel mutex_exit(&scsb->scsb_mutex); 119803831d35Sstevel RD(q)->q_ptr = WR(q)->q_ptr = scsb; 119903831d35Sstevel qprocson(q); 120003831d35Sstevel return (0); 120103831d35Sstevel } 120203831d35Sstevel 120303831d35Sstevel /*ARGSUSED*/ 120403831d35Sstevel static int 120503831d35Sstevel sm_close(queue_t *q, int flag, int otyp, cred_t *credp) 120603831d35Sstevel { 120703831d35Sstevel scsb_state_t *scsb; 120803831d35Sstevel int clone; 120903831d35Sstevel clone_dev_t *clptr = NULL; 121003831d35Sstevel 121103831d35Sstevel scsb = (scsb_state_t *)q->q_ptr; 121203831d35Sstevel if (scsb_debug & 0x0009) 1213*07d06da5SSurya Prakki cmn_err(CE_NOTE, "sm_close[%d](0x%p)", scsb->scsb_instance, 1214*07d06da5SSurya Prakki (void *)q); 121503831d35Sstevel if (scsb->scsb_clopens) { 121603831d35Sstevel mutex_enter(&scsb->scsb_mutex); 121703831d35Sstevel if ((clone = scsb_queue_ops(scsb, QFIND_QUEUE, 0, 121803831d35Sstevel (void *) RD(q), "scsb_close")) != QOP_FAILED) { 121903831d35Sstevel clptr = &scsb->clone_devs[clone]; 122003831d35Sstevel clptr->cl_flags = 0; 122103831d35Sstevel clptr->cl_rq = NULL; 122203831d35Sstevel scsb->scsb_clopens--; 122303831d35Sstevel } 122403831d35Sstevel mutex_exit(&scsb->scsb_mutex); 122503831d35Sstevel if (scsb_debug & 0x0008 && clone < SCSB_CLONES_MAX && 122603831d35Sstevel clone >= SCSB_CLONES_FIRST) 122703831d35Sstevel cmn_err(CE_NOTE, "sm_close(%d): SCSB_CLONE 0x%x", 122803831d35Sstevel scsb->scsb_instance, clptr->cl_minor); 122903831d35Sstevel } 123003831d35Sstevel if (clptr == NULL && scsb->scsb_opens) { 123103831d35Sstevel if (scsb_debug & 0x0008) 123203831d35Sstevel cmn_err(CE_NOTE, "sm_close(%d): DEVOPEN, opens=%d", 123303831d35Sstevel scsb->scsb_instance, scsb->scsb_opens); 123403831d35Sstevel if (RD(q) != scsb->scsb_rq) { 123503831d35Sstevel if (scsb_debug & 0x0008) 123603831d35Sstevel cmn_err(CE_WARN, 123703831d35Sstevel "sm_close(%d): DEVOPEN, q != scsb_rq", 123803831d35Sstevel scsb->scsb_instance); 123903831d35Sstevel } 124003831d35Sstevel mutex_enter(&scsb->scsb_mutex); 124103831d35Sstevel scsb->scsb_opens = 0; 124203831d35Sstevel if (scsb->scsb_state & SCSB_EXCL) { 124303831d35Sstevel scsb->scsb_state &= ~SCSB_EXCL; 124403831d35Sstevel } 124503831d35Sstevel scsb->scsb_rq = (queue_t *)NULL; 124603831d35Sstevel mutex_exit(&scsb->scsb_mutex); 124703831d35Sstevel } 124803831d35Sstevel if (scsb->scsb_opens == 0 && scsb->scsb_clopens == 0) { 124903831d35Sstevel scsb->scsb_state &= ~SCSB_OPEN; 125003831d35Sstevel } 125103831d35Sstevel RD(q)->q_ptr = WR(q)->q_ptr = NULL; 125203831d35Sstevel qprocsoff(q); 125303831d35Sstevel return (0); 125403831d35Sstevel } 125503831d35Sstevel 125603831d35Sstevel /*ARGSUSED*/ 125703831d35Sstevel static int 125803831d35Sstevel sm_rput(queue_t *q, mblk_t *mp) 125903831d35Sstevel { 126003831d35Sstevel if (scsb_debug & 0x0010) 126103831d35Sstevel cmn_err(CE_NOTE, "sm_rput"); 126203831d35Sstevel return (0); 126303831d35Sstevel } 126403831d35Sstevel 126503831d35Sstevel static int 126603831d35Sstevel sm_wput(queue_t *q, mblk_t *mp) 126703831d35Sstevel { 126803831d35Sstevel scsb_state_t *scsb = (scsb_state_t *)WR(q)->q_ptr; 126903831d35Sstevel 127003831d35Sstevel if (scsb_debug & 0x0010) 1271*07d06da5SSurya Prakki cmn_err(CE_NOTE, "sm_wput(%d): mp %p", scsb->scsb_instance, 1272*07d06da5SSurya Prakki (void *)mp); 127303831d35Sstevel 127403831d35Sstevel switch (mp->b_datap->db_type) { 127503831d35Sstevel default: 127603831d35Sstevel freemsg(mp); 127703831d35Sstevel break; 127803831d35Sstevel 127903831d35Sstevel case M_FLUSH: /* canonical flush handling */ 128003831d35Sstevel if (*mp->b_rptr & FLUSHW) { 128103831d35Sstevel flushq(q, FLUSHDATA); 128203831d35Sstevel /* free any messages tied to scsb */ 128303831d35Sstevel } 128403831d35Sstevel 128503831d35Sstevel if (*mp->b_rptr & FLUSHR) { 128603831d35Sstevel *mp->b_rptr &= ~FLUSHW; 128703831d35Sstevel qreply(q, mp); 128803831d35Sstevel } else 128903831d35Sstevel freemsg(mp); 129003831d35Sstevel break; 129103831d35Sstevel 129203831d35Sstevel case M_IOCTL: 129303831d35Sstevel if (scsb_debug & 0x0010) 129403831d35Sstevel cmn_err(CE_NOTE, "sm_wput(%d): M_IOCTL", 129503831d35Sstevel scsb->scsb_instance); 129603831d35Sstevel /* do ioctl */ 129703831d35Sstevel smf_ioctl(q, mp); 129803831d35Sstevel break; 129903831d35Sstevel 130003831d35Sstevel case M_DATA: 130103831d35Sstevel if (scsb_debug & 0x0010) 130203831d35Sstevel cmn_err(CE_NOTE, "sm_wput(%d): M_DATA", 130303831d35Sstevel scsb->scsb_instance); 130403831d35Sstevel if (!(scsb->scsb_state & SCSB_UP)) { 130503831d35Sstevel freemsg(mp); 130603831d35Sstevel return (0); 130703831d35Sstevel } 130803831d35Sstevel freemsg(mp); 130903831d35Sstevel break; 131003831d35Sstevel 131103831d35Sstevel case M_CTL: 131203831d35Sstevel if (scsb_debug & 0x0010) 131303831d35Sstevel cmn_err(CE_NOTE, "sm_wput(%d): M_CTL", 131403831d35Sstevel scsb->scsb_instance); 131503831d35Sstevel freemsg(mp); 131603831d35Sstevel break; 131703831d35Sstevel } 131803831d35Sstevel 131903831d35Sstevel return (0); 132003831d35Sstevel } 132103831d35Sstevel 132203831d35Sstevel 132303831d35Sstevel /* 132403831d35Sstevel * These are the system monitor upper ioctl functions. 132503831d35Sstevel */ 132603831d35Sstevel static void 132703831d35Sstevel smf_ioctl(queue_t *q, mblk_t *mp) 132803831d35Sstevel { 132903831d35Sstevel scsb_state_t *scsb = (scsb_state_t *)q->q_ptr; 133003831d35Sstevel struct iocblk *iocp = (struct iocblk *)mp->b_rptr; 133103831d35Sstevel 133203831d35Sstevel if (scsb_debug & 0x0020) 133303831d35Sstevel cmn_err(CE_NOTE, "smf_ioctl(%d): (%p)->cmd=%x", 1334*07d06da5SSurya Prakki scsb->scsb_instance, (void *)mp, iocp->ioc_cmd); 133503831d35Sstevel 133603831d35Sstevel if (!(scsb->scsb_state & SCSB_UP)) { 133703831d35Sstevel miocnak(q, mp, 0, ENXIO); 133803831d35Sstevel return; 133903831d35Sstevel } 134003831d35Sstevel /* 134103831d35Sstevel * Don't fail ALL commands if the SCB removed, since we still want to 134203831d35Sstevel * satisfy some requests from the shadow registers, the last known 134303831d35Sstevel * register contents. 134403831d35Sstevel * 134503831d35Sstevel * if (scsb->scsb_state & SCSB_FROZEN) { 134603831d35Sstevel * iocp->ioc_error = EAGAIN; 134703831d35Sstevel * mp->b_datap->db_type = M_IOCNAK; 134803831d35Sstevel * qreply(q, mp); 134903831d35Sstevel * return; 135003831d35Sstevel * } 135103831d35Sstevel */ 135203831d35Sstevel 135303831d35Sstevel iocp->ioc_error = 0; 135403831d35Sstevel switch (iocp->ioc_cmd) { 135503831d35Sstevel default: 135603831d35Sstevel /* if we don't understand the ioctl */ 135703831d35Sstevel if (scsb_debug & 0x0022) 135803831d35Sstevel cmn_err(CE_NOTE, "smf_ioctl(%d):unkown ioctl %x", 135903831d35Sstevel scsb->scsb_instance, iocp->ioc_cmd); 136003831d35Sstevel iocp->ioc_error = EINVAL; 136103831d35Sstevel break; 136203831d35Sstevel 136303831d35Sstevel case ENVC_IOC_GETMODE: 136403831d35Sstevel { 136503831d35Sstevel uint8_t *curr_mode; 136603831d35Sstevel 136703831d35Sstevel iocp->ioc_error = miocpullup(mp, sizeof (uint8_t)); 136803831d35Sstevel if (iocp->ioc_error != 0) 136903831d35Sstevel break; 137003831d35Sstevel 137103831d35Sstevel curr_mode = (uint8_t *)mp->b_cont->b_rptr; 137203831d35Sstevel if (scsb->scsb_state & SCSB_DEBUG_MODE) 137303831d35Sstevel *curr_mode = (uint8_t)ENVC_DEBUG_MODE; 137403831d35Sstevel else if (scsb->scsb_state & SCSB_DIAGS_MODE) 137503831d35Sstevel *curr_mode = (uint8_t)ENVCTRL_DIAG_MODE; 137603831d35Sstevel else 137703831d35Sstevel *curr_mode = (uint8_t)ENVCTRL_NORMAL_MODE; 137803831d35Sstevel 137903831d35Sstevel if (scsb_debug & 0x20) { 138003831d35Sstevel cmn_err(CE_NOTE, "IOC_GETMODE: returning mode 0x%x", 138103831d35Sstevel *curr_mode); 138203831d35Sstevel } 138303831d35Sstevel break; 138403831d35Sstevel } 138503831d35Sstevel 138603831d35Sstevel case ENVC_IOC_SETMODE: 138703831d35Sstevel { 138803831d35Sstevel uint8_t *curr_mode; 138903831d35Sstevel 139003831d35Sstevel iocp->ioc_error = miocpullup(mp, sizeof (uint8_t)); 139103831d35Sstevel if (iocp->ioc_error != 0) 139203831d35Sstevel break; 139303831d35Sstevel 139403831d35Sstevel curr_mode = (uint8_t *)mp->b_cont->b_rptr; 139503831d35Sstevel switch (*curr_mode) { 139603831d35Sstevel case ENVCTRL_NORMAL_MODE: 139703831d35Sstevel scsb->scsb_state &= 139803831d35Sstevel ~(SCSB_DEBUG_MODE | SCSB_DIAGS_MODE); 139903831d35Sstevel break; 140003831d35Sstevel case ENVCTRL_DIAG_MODE: 140103831d35Sstevel scsb->scsb_state |= SCSB_DIAGS_MODE; 140203831d35Sstevel scsb->scsb_state &= ~SCSB_DEBUG_MODE; 140303831d35Sstevel break; 140403831d35Sstevel case ENVC_DEBUG_MODE: 140503831d35Sstevel if (scsb->scsb_state & 140603831d35Sstevel (SCSB_DIAGS_MODE | SCSB_DEBUG_MODE)) { 140703831d35Sstevel scsb->scsb_state &= ~SCSB_DIAGS_MODE; 140803831d35Sstevel scsb->scsb_state |= SCSB_DEBUG_MODE; 140903831d35Sstevel } else { 141003831d35Sstevel iocp->ioc_error = EACCES; 141103831d35Sstevel } 141203831d35Sstevel break; 141303831d35Sstevel default: 141403831d35Sstevel if (scsb_debug & 0x22) { 141503831d35Sstevel cmn_err(CE_WARN, 141603831d35Sstevel "IOC_SETMODE: Invalid mode 0x%x", 141703831d35Sstevel *curr_mode); 141803831d35Sstevel } 141903831d35Sstevel iocp->ioc_error = EINVAL; 142003831d35Sstevel break; 142103831d35Sstevel } 142203831d35Sstevel break; 142303831d35Sstevel } 142403831d35Sstevel 142503831d35Sstevel case ENVC_IOC_ACQUIRE_SLOT_LED_CTRL: 142603831d35Sstevel if (scsb->scsb_state & SCSB_APP_SLOTLED_CTRL) 142703831d35Sstevel iocp->ioc_error = EAGAIN; 142803831d35Sstevel else { 142903831d35Sstevel scsb->scsb_state |= SCSB_APP_SLOTLED_CTRL; 143003831d35Sstevel iocp->ioc_error = 0; 143103831d35Sstevel } 143203831d35Sstevel break; 143303831d35Sstevel 143403831d35Sstevel case ENVC_IOC_RELEASE_SLOT_LED_CTRL: 143503831d35Sstevel scsb->scsb_state &= ~SCSB_APP_SLOTLED_CTRL; 143603831d35Sstevel iocp->ioc_error = 0; 143703831d35Sstevel break; 143803831d35Sstevel 143903831d35Sstevel /* 144003831d35Sstevel * Not an exposed interface, only used by development utilities. 144103831d35Sstevel */ 144203831d35Sstevel case SCSBIOC_GET_VERSIONS: 144303831d35Sstevel { 144403831d35Sstevel uint8_t *ppromid, promid; 144503831d35Sstevel scsb_ids_t *sids; 144603831d35Sstevel 144703831d35Sstevel if (iocp->ioc_count == sizeof (uint8_t)) { 144803831d35Sstevel iocp->ioc_error = miocpullup(mp, sizeof (uint8_t)); 144903831d35Sstevel if (iocp->ioc_error != 0) 145003831d35Sstevel break; 145103831d35Sstevel 145203831d35Sstevel ppromid = (uint8_t *)mp->b_cont->b_rptr; 145303831d35Sstevel *ppromid = (uint8_t)(mct_system_info. 145403831d35Sstevel fru_info_list[SCB])->fru_version; 145503831d35Sstevel promid = *ppromid; 145603831d35Sstevel } else { 145703831d35Sstevel iocp->ioc_error = miocpullup(mp, sizeof (scsb_ids_t)); 145803831d35Sstevel if (iocp->ioc_error != 0) 145903831d35Sstevel break; 146003831d35Sstevel 146103831d35Sstevel sids = (scsb_ids_t *)mp->b_cont->b_rptr; 146203831d35Sstevel bcopy(modldrv.drv_linkinfo, sids->modldrv_string, 146303831d35Sstevel SCSB_MODSTR_LEN); 146403831d35Sstevel bcopy(scsb_build_version, sids->scsb_version, 146503831d35Sstevel SCSB_VERSTR_LEN); 146603831d35Sstevel sids->promid = (uint8_t)(mct_system_info. 146703831d35Sstevel fru_info_list[SCB])->fru_version; 146803831d35Sstevel 146903831d35Sstevel promid = sids->promid; 147003831d35Sstevel if (scsb_debug & 0x20) { 147103831d35Sstevel cmn_err(CE_NOTE, 147203831d35Sstevel "IOC_GET_VERSIONS: sizeof(scsb_ids_t) " 147303831d35Sstevel "= %lu", sizeof (scsb_ids_t)); 147403831d35Sstevel } 147503831d35Sstevel } 147603831d35Sstevel if (scsb_debug & 0x20) { 147703831d35Sstevel cmn_err(CE_NOTE, 147803831d35Sstevel "IOC_GET_VERSIONS: SCB PROMID = 0x%x", promid); 147903831d35Sstevel } 148003831d35Sstevel break; 148103831d35Sstevel } 148203831d35Sstevel 148303831d35Sstevel #ifdef DEBUG 148403831d35Sstevel case ENVC_IOC_REGISTER_PID: 148503831d35Sstevel iocp->ioc_error = miocpullup(mp, sizeof (pid_t)); 148603831d35Sstevel if (iocp->ioc_error == 0) { 148703831d35Sstevel if (add_event_proc(scsb, *(pid_t *)mp->b_cont->b_rptr)) 148803831d35Sstevel iocp->ioc_error = ENOMEM; 148903831d35Sstevel } 149003831d35Sstevel break; 149103831d35Sstevel 149203831d35Sstevel case ENVC_IOC_UNREGISTER_PID: 149303831d35Sstevel iocp->ioc_error = miocpullup(mp, sizeof (pid_t)); 149403831d35Sstevel if (iocp->ioc_error == 0) { 149503831d35Sstevel if (del_event_proc(scsb, *(pid_t *)mp->b_cont->b_rptr)) 149603831d35Sstevel iocp->ioc_error = EINVAL; 149703831d35Sstevel } 149803831d35Sstevel break; 149903831d35Sstevel 150003831d35Sstevel case SCSBIOC_VALUE_MODE: 150103831d35Sstevel { 150203831d35Sstevel uint32_t *mode_vals; 150303831d35Sstevel int three_vals = 0; 150403831d35Sstevel 150503831d35Sstevel if (!(scsb->scsb_state & SCSB_DEBUG_MODE)) { 150603831d35Sstevel iocp->ioc_error = EINVAL; 150703831d35Sstevel break; 150803831d35Sstevel } 150903831d35Sstevel 151003831d35Sstevel if (iocp->ioc_count == sizeof (uint32_t) * 3) 151103831d35Sstevel three_vals = 1; 151203831d35Sstevel else if (iocp->ioc_count != sizeof (uint32_t) * 2) { 151303831d35Sstevel iocp->ioc_error = EINVAL; 151403831d35Sstevel break; 151503831d35Sstevel } 151603831d35Sstevel 151703831d35Sstevel iocp->ioc_error = miocpullup(mp, iocp->ioc_count); 151803831d35Sstevel if (iocp->ioc_error != 0) 151903831d35Sstevel break; 152003831d35Sstevel 152103831d35Sstevel /* 152203831d35Sstevel * check mode_vals[0] for get/set option. setting 152303831d35Sstevel * scsb_state is not valid for now. 0 == GET, 1 == SET 152403831d35Sstevel */ 152503831d35Sstevel mode_vals = (uint32_t *)mp->b_cont->b_rptr; 152603831d35Sstevel if (mode_vals[0]) { 152703831d35Sstevel scsb_debug = mode_vals[1]; 152803831d35Sstevel } else { 152903831d35Sstevel mode_vals[0] = scsb->scsb_state; 153003831d35Sstevel if (three_vals) { 153103831d35Sstevel mode_vals[1] = scsb->scsb_hsc_state; 153203831d35Sstevel mode_vals[2] = scsb_debug; 153303831d35Sstevel } else 153403831d35Sstevel mode_vals[1] = scsb_debug; 153503831d35Sstevel } 153603831d35Sstevel if ((scsb_debug & 0x20) && three_vals) { 153703831d35Sstevel cmn_err(CE_NOTE, "IOC_VALUE_MODE: mode_vals: " 153803831d35Sstevel "0x%x/0x%x/0x%x; ioc_count = 0x%lx", 153903831d35Sstevel mode_vals[0], mode_vals[1], mode_vals[2], 154003831d35Sstevel iocp->ioc_count); 154103831d35Sstevel } 154203831d35Sstevel break; 154303831d35Sstevel } 154403831d35Sstevel 154503831d35Sstevel #ifdef DEBUG 154603831d35Sstevel case SCSBIOC_GET_SLOT_INFO: 154703831d35Sstevel { 154803831d35Sstevel hsc_slot_t *slot_info = NULL; 154903831d35Sstevel uint32_t *slot_vals; 155003831d35Sstevel int pslotnum; 155103831d35Sstevel 155203831d35Sstevel if (!(scsb->scsb_state & SCSB_DEBUG_MODE)) { 155303831d35Sstevel iocp->ioc_error = EINVAL; 155403831d35Sstevel break; 155503831d35Sstevel } 155603831d35Sstevel 155703831d35Sstevel iocp->ioc_error = miocpullup(mp, sizeof (uint32_t) * 2); 155803831d35Sstevel if (iocp->ioc_error != 0) 155903831d35Sstevel break; 156003831d35Sstevel 156103831d35Sstevel slot_vals = (uint32_t *)mp->b_cont->b_rptr; 156203831d35Sstevel pslotnum = (int)*slot_vals; 1563*07d06da5SSurya Prakki hsc_ac_op((int)scsb->scsb_instance, pslotnum, 156403831d35Sstevel SCSB_HSC_AC_GET_SLOT_INFO, &slot_info); 156503831d35Sstevel if (slot_info == NULL) { 156603831d35Sstevel iocp->ioc_error = ENODEV; 156703831d35Sstevel break; 156803831d35Sstevel } 156903831d35Sstevel *slot_vals = (uint32_t)slot_info->hs_flags; 157003831d35Sstevel *(++slot_vals) = (uint32_t)slot_info->hs_slot_state; 157103831d35Sstevel if (scsb_debug & 0x20) { 157203831d35Sstevel cmn_err(CE_NOTE, "IOC_GET_SLOT_STATE: slot_vals: " 157303831d35Sstevel "0x%x/0x%x; ioc_count = 0x%lx", 157403831d35Sstevel slot_vals[0], slot_vals[1], iocp->ioc_count); 157503831d35Sstevel } 157603831d35Sstevel break; 157703831d35Sstevel } 157803831d35Sstevel #endif /* DEBUG */ 157903831d35Sstevel 158003831d35Sstevel case SCSBIOC_GET_FAN_STATUS: 158103831d35Sstevel case SCSBIOC_GET_INTR_ARRAY: 158203831d35Sstevel /* for now we don't understand these ioctls */ 158303831d35Sstevel if (scsb_debug & 0x0022) 158403831d35Sstevel cmn_err(CE_NOTE, "smf_ioctl(%d):unknown ioctl %x", 158503831d35Sstevel scsb->scsb_instance, iocp->ioc_cmd); 158603831d35Sstevel iocp->ioc_error = EINVAL; 158703831d35Sstevel break; 158803831d35Sstevel #endif /* DEBUG */ 158903831d35Sstevel 159003831d35Sstevel case SCSBIOC_LED_OK_GET: 159103831d35Sstevel case SCSBIOC_LED_NOK_GET: 159203831d35Sstevel case SCSBIOC_LED_OK_SET: 159303831d35Sstevel case SCSBIOC_LED_NOK_SET: 159403831d35Sstevel case SCSBIOC_BHEALTHY_GET: 159503831d35Sstevel case SCSBIOC_SLOT_OCCUPANCY: 159603831d35Sstevel case SCSBIOC_RESET_UNIT: 159703831d35Sstevel if (!(scsb->scsb_state & (SCSB_DIAGS_MODE | SCSB_DEBUG_MODE))) { 159803831d35Sstevel iocp->ioc_error = EACCES; 159903831d35Sstevel break; 160003831d35Sstevel } 160103831d35Sstevel /*FALLTHROUGH*/ 160203831d35Sstevel 160303831d35Sstevel case ENVC_IOC_GETDSKLED: 160403831d35Sstevel case ENVC_IOC_SETDSKLED: 160503831d35Sstevel case ENVC_IOC_SETFSP: 160603831d35Sstevel { 160703831d35Sstevel scsb_uinfo_t *suip; 160803831d35Sstevel 160903831d35Sstevel iocp->ioc_error = miocpullup(mp, sizeof (scsb_uinfo_t)); 161003831d35Sstevel if (iocp->ioc_error != 0) 161103831d35Sstevel break; 161203831d35Sstevel 161303831d35Sstevel suip = (scsb_uinfo_t *)mp->b_cont->b_rptr; 161403831d35Sstevel switch (iocp->ioc_cmd) { 161503831d35Sstevel case SCSBIOC_LED_OK_GET: 161603831d35Sstevel iocp->ioc_error = scsb_led_get(scsb, suip, OK); 161703831d35Sstevel break; 161803831d35Sstevel case SCSBIOC_LED_NOK_GET: 161903831d35Sstevel iocp->ioc_error = scsb_led_get(scsb, suip, NOK); 162003831d35Sstevel break; 162103831d35Sstevel case SCSBIOC_LED_OK_SET: 162203831d35Sstevel iocp->ioc_error = scsb_led_set(scsb, suip, OK); 162303831d35Sstevel break; 162403831d35Sstevel case SCSBIOC_LED_NOK_SET: 162503831d35Sstevel iocp->ioc_error = scsb_led_set(scsb, suip, NOK); 162603831d35Sstevel break; 162703831d35Sstevel case SCSBIOC_BHEALTHY_GET: 162803831d35Sstevel iocp->ioc_error = scsb_bhealthy_slot(scsb, suip); 162903831d35Sstevel break; 163003831d35Sstevel case SCSBIOC_SLOT_OCCUPANCY: 163103831d35Sstevel iocp->ioc_error = scsb_slot_occupancy(scsb, suip); 163203831d35Sstevel break; 163303831d35Sstevel case SCSBIOC_RESET_UNIT: 163403831d35Sstevel iocp->ioc_error = scsb_reset_unit(scsb, suip); 163503831d35Sstevel break; 163603831d35Sstevel case ENVC_IOC_GETDSKLED: 163703831d35Sstevel if (suip->unit_type != DISK) { 163803831d35Sstevel iocp->ioc_error = EINVAL; 163903831d35Sstevel break; 164003831d35Sstevel } 164103831d35Sstevel iocp->ioc_error = scsb_led_get(scsb, suip, NOUSE); 164203831d35Sstevel break; 164303831d35Sstevel case ENVC_IOC_SETDSKLED: 164403831d35Sstevel if (suip->unit_type != DISK) { 164503831d35Sstevel iocp->ioc_error = EINVAL; 164603831d35Sstevel break; 164703831d35Sstevel } 164803831d35Sstevel iocp->ioc_error = scsb_led_set(scsb, suip, NOUSE); 164903831d35Sstevel break; 165003831d35Sstevel case ENVC_IOC_SETFSP: 165103831d35Sstevel if (scsb->scsb_state & SCSB_FROZEN) { 165203831d35Sstevel iocp->ioc_error = EAGAIN; 165303831d35Sstevel break; 165403831d35Sstevel } 165503831d35Sstevel iocp->ioc_error = scsb_led_set(scsb, suip, NOUSE); 165603831d35Sstevel break; 165703831d35Sstevel } 165803831d35Sstevel break; 165903831d35Sstevel } 166003831d35Sstevel 166103831d35Sstevel case SCSBIOC_FAKE_INTR: { 166203831d35Sstevel uint32_t ui; 166303831d35Sstevel 166403831d35Sstevel if (!(scsb->scsb_state & SCSB_DEBUG_MODE)) { 166503831d35Sstevel iocp->ioc_error = EINVAL; 166603831d35Sstevel break; 166703831d35Sstevel } 166803831d35Sstevel if (mp->b_cont == NULL) 166903831d35Sstevel ui = 0; 167003831d35Sstevel else { 167103831d35Sstevel iocp->ioc_error = miocpullup(mp, sizeof (uint32_t)); 167203831d35Sstevel if (iocp->ioc_error != 0) 167303831d35Sstevel break; 167403831d35Sstevel ui = *(uint32_t *)mp->b_cont->b_rptr; 167503831d35Sstevel } 167603831d35Sstevel iocp->ioc_error = scsb_fake_intr(scsb, ui); 167703831d35Sstevel break; 167803831d35Sstevel } 167903831d35Sstevel 168003831d35Sstevel case SCSBIOC_GET_STATUS : 168103831d35Sstevel if (!(scsb->scsb_state & SCSB_DEBUG_MODE)) { 168203831d35Sstevel iocp->ioc_error = EINVAL; 168303831d35Sstevel break; 168403831d35Sstevel } 168503831d35Sstevel iocp->ioc_error = miocpullup(mp, sizeof (scsb_status_t)); 168603831d35Sstevel if (iocp->ioc_error == 0) 168703831d35Sstevel iocp->ioc_error = scsb_get_status(scsb, 168803831d35Sstevel (scsb_status_t *)mp->b_cont->b_rptr); 168903831d35Sstevel break; 169003831d35Sstevel 169103831d35Sstevel case SCSBIOC_ALL_LEDS_ON : 169203831d35Sstevel if (!(scsb->scsb_state & (SCSB_DIAGS_MODE | SCSB_DEBUG_MODE))) 169303831d35Sstevel iocp->ioc_error = EACCES; 169403831d35Sstevel else 169503831d35Sstevel iocp->ioc_error = scsb_leds_switch(scsb, ON); 169603831d35Sstevel break; 169703831d35Sstevel 169803831d35Sstevel case SCSBIOC_ALL_LEDS_OFF : 169903831d35Sstevel if (!(scsb->scsb_state & (SCSB_DIAGS_MODE | SCSB_DEBUG_MODE))) 170003831d35Sstevel iocp->ioc_error = EACCES; 170103831d35Sstevel else 170203831d35Sstevel iocp->ioc_error = scsb_leds_switch(scsb, OFF); 170303831d35Sstevel break; 170403831d35Sstevel 170503831d35Sstevel case SCSBIOC_REG_READ: 170603831d35Sstevel case SCSBIOC_REG_WRITE: 170703831d35Sstevel if (!(scsb->scsb_state & (SCSB_DIAGS_MODE | SCSB_DEBUG_MODE))) { 170803831d35Sstevel iocp->ioc_error = EACCES; 170903831d35Sstevel } else { 171003831d35Sstevel scsb_ioc_rdwr_t *iocrdwrp; 171103831d35Sstevel 171203831d35Sstevel if (scsb->scsb_state & SCSB_FROZEN && 171303831d35Sstevel !(scsb->scsb_state & SCSB_DEBUG_MODE)) { 171403831d35Sstevel iocp->ioc_error = EAGAIN; 171503831d35Sstevel break; 171603831d35Sstevel } 171703831d35Sstevel 171803831d35Sstevel iocp->ioc_error = miocpullup(mp, sizeof (*iocrdwrp)); 171903831d35Sstevel if (iocp->ioc_error == 0) { 172003831d35Sstevel iocrdwrp = 172103831d35Sstevel (scsb_ioc_rdwr_t *)mp->b_cont->b_rptr; 172203831d35Sstevel 172303831d35Sstevel if (iocp->ioc_cmd == SCSBIOC_REG_READ) { 172403831d35Sstevel if (iocrdwrp->ioc_rlen > 0) { 172503831d35Sstevel sm_ioc_rdwr(q, mp, I2C_WR_RD); 172603831d35Sstevel return; 172703831d35Sstevel } 172803831d35Sstevel } else { 172903831d35Sstevel if (iocrdwrp->ioc_wlen > 0) { 173003831d35Sstevel sm_ioc_rdwr(q, mp, I2C_WR); 173103831d35Sstevel return; 173203831d35Sstevel } 173303831d35Sstevel } 173403831d35Sstevel iocp->ioc_error = EINVAL; 173503831d35Sstevel break; 173603831d35Sstevel } 173703831d35Sstevel } 173803831d35Sstevel break; 173903831d35Sstevel 174003831d35Sstevel case SCSBIOC_SHUTDOWN_POLL: 174103831d35Sstevel case SCSBIOC_INTEVENT_POLL: 174203831d35Sstevel if (!(scsb->scsb_state & SCSB_DEBUG_MODE)) { 174303831d35Sstevel iocp->ioc_error = EINVAL; 174403831d35Sstevel break; 174503831d35Sstevel } 174603831d35Sstevel iocp->ioc_error = miocpullup(mp, sizeof (uint32_t)); 174703831d35Sstevel if (iocp->ioc_error == 0) 174803831d35Sstevel iocp->ioc_error = scsb_polled_int(scsb, iocp->ioc_cmd, 174903831d35Sstevel (uint32_t *)mp->b_cont->b_rptr); 175003831d35Sstevel break; 175103831d35Sstevel 175203831d35Sstevel case SCSBIOC_RESTORE : 175303831d35Sstevel if (!(scsb->scsb_state & (SCSB_DIAGS_MODE | SCSB_DEBUG_MODE))) 175403831d35Sstevel iocp->ioc_error = EACCES; 175503831d35Sstevel else { 175603831d35Sstevel scsb_restore(scsb); 1757*07d06da5SSurya Prakki (void) scsb_toggle_psmint(scsb, 1); 175803831d35Sstevel iocp->ioc_error = 0; 175903831d35Sstevel } 176003831d35Sstevel break; 176103831d35Sstevel 176203831d35Sstevel case SCSBIOC_FREEZE : 176303831d35Sstevel if (!(scsb->scsb_state & (SCSB_DIAGS_MODE | SCSB_DEBUG_MODE))) 176403831d35Sstevel iocp->ioc_error = EACCES; 176503831d35Sstevel else { 176603831d35Sstevel scsb_freeze_check(scsb); 176703831d35Sstevel scsb_freeze(scsb); 176803831d35Sstevel iocp->ioc_error = 0; 176903831d35Sstevel } 177003831d35Sstevel break; 177103831d35Sstevel 177203831d35Sstevel /* 177303831d35Sstevel * envmond:alarmcard.so response to SCTRL_EVENT_ALARM_INSERTION 177403831d35Sstevel */ 177503831d35Sstevel case ENVC_IOC_ACCONF_RESTORED: 177603831d35Sstevel (void) scsb_hsc_ac_op(scsb, scsb->ac_slotnum, 177703831d35Sstevel SCSB_HSC_AC_SET_BUSY); 177803831d35Sstevel break; 177903831d35Sstevel 178003831d35Sstevel /* 178103831d35Sstevel * envmond:alarmcard.so response to SCTRL_EVENT_ALARM_REMOVAL 178203831d35Sstevel */ 178303831d35Sstevel case ENVC_IOC_ACCONF_STORED: 178403831d35Sstevel if (scsb->scsb_state & SCSB_FROZEN) { 178503831d35Sstevel iocp->ioc_error = EAGAIN; 178603831d35Sstevel break; 178703831d35Sstevel } 178803831d35Sstevel (void) scsb_hsc_ac_op(scsb, scsb->ac_slotnum, 178903831d35Sstevel SCSB_HSC_AC_UNCONFIGURE); 179003831d35Sstevel break; 179103831d35Sstevel 179203831d35Sstevel #ifdef DEBUG 179303831d35Sstevel case SCSBIOC_TOPOLOGY_DUMP: 179403831d35Sstevel if (!(scsb->scsb_state & SCSB_DEBUG_MODE)) 179503831d35Sstevel iocp->ioc_error = EINVAL; 179603831d35Sstevel else { 179703831d35Sstevel mct_topology_dump(scsb, 1); 179803831d35Sstevel iocp->ioc_error = 0; 179903831d35Sstevel } 180003831d35Sstevel break; 180103831d35Sstevel #endif 180203831d35Sstevel } 180303831d35Sstevel if (iocp->ioc_error) 180403831d35Sstevel mp->b_datap->db_type = M_IOCNAK; 180503831d35Sstevel else 180603831d35Sstevel mp->b_datap->db_type = M_IOCACK; 180703831d35Sstevel qreply(q, mp); 180803831d35Sstevel } 180903831d35Sstevel 181003831d35Sstevel static fru_info_t * 181103831d35Sstevel find_fru_info(fru_id_t fru_id) 181203831d35Sstevel { 181303831d35Sstevel int i; 181403831d35Sstevel fru_info_t *fru_ptr; 181503831d35Sstevel 181603831d35Sstevel if (scsb_debug & 0x00100001) 181703831d35Sstevel cmn_err(CE_NOTE, "find_fru_info(0x%x)", fru_id); 181803831d35Sstevel if (fru_id == (fru_id_t)0) 181903831d35Sstevel return ((fru_info_t *)NULL); 182003831d35Sstevel for (i = 0; i < SCSB_UNIT_TYPES; ++i) { 182103831d35Sstevel fru_ptr = mct_system_info.fru_info_list[i]; 182203831d35Sstevel while (fru_ptr != NULL) { 182303831d35Sstevel if (fru_ptr->fru_id == fru_id) 182403831d35Sstevel return (fru_ptr); 182503831d35Sstevel fru_ptr = fru_ptr->next; 182603831d35Sstevel } 182703831d35Sstevel } 182803831d35Sstevel return ((fru_info_t *)NULL); 182903831d35Sstevel } 183003831d35Sstevel 183103831d35Sstevel 183203831d35Sstevel struct scsb_cb_entry { 183303831d35Sstevel void *cb_softstate_ptr; 183403831d35Sstevel fru_id_t cb_fru_id; 183503831d35Sstevel scsb_fru_event_t cb_event; 183603831d35Sstevel void (*cb_func) 183703831d35Sstevel (void *, scsb_fru_event_t, scsb_fru_status_t); 183803831d35Sstevel fru_info_t *cb_fru_ptr; 183903831d35Sstevel struct scsb_cb_entry *cb_next; 184003831d35Sstevel }; 184103831d35Sstevel 184203831d35Sstevel #ifdef DEBUG 184303831d35Sstevel int scsb_cb_count = 0; 184403831d35Sstevel #else 184503831d35Sstevel static 184603831d35Sstevel #endif 184703831d35Sstevel struct scsb_cb_entry *scsb_cb_table; 184803831d35Sstevel 184903831d35Sstevel /* 185003831d35Sstevel * global function for interested FRU drivers to register a callback function, 185103831d35Sstevel * to be called when FRU presence status changes. 185203831d35Sstevel */ 185303831d35Sstevel scsb_fru_status_t 185403831d35Sstevel scsb_fru_register(void (*cb_func)(void *, scsb_fru_event_t, scsb_fru_status_t), 185503831d35Sstevel void *soft_ptr, fru_id_t fru_id) 185603831d35Sstevel { 185703831d35Sstevel struct scsb_cb_entry *cbe_ptr; 185803831d35Sstevel 185903831d35Sstevel if (scsb_debug & 0x00800001) { 186003831d35Sstevel cmn_err(CE_NOTE, 186103831d35Sstevel "scsb_fru_register: FRU_ID 0x%x", (int)fru_id); 186203831d35Sstevel } 186303831d35Sstevel if (!(scsb_global_state & SCSB_UP)) { 186403831d35Sstevel return (FRU_NOT_AVAILABLE); 186503831d35Sstevel } 186603831d35Sstevel if (cb_func == NULL || fru_id == (fru_id_t)0) 186703831d35Sstevel return (FRU_NOT_AVAILABLE); 186803831d35Sstevel if (scsb_cb_table == NULL) 186903831d35Sstevel scsb_cb_table = (struct scsb_cb_entry *) 187003831d35Sstevel kmem_zalloc(sizeof (struct scsb_cb_entry), KM_SLEEP); 187103831d35Sstevel cbe_ptr = scsb_cb_table; 187203831d35Sstevel while (cbe_ptr->cb_softstate_ptr != NULL) { 187303831d35Sstevel if (cbe_ptr->cb_next == (struct scsb_cb_entry *)NULL) { 187403831d35Sstevel cbe_ptr->cb_next = (struct scsb_cb_entry *) 187503831d35Sstevel kmem_zalloc(sizeof (struct scsb_cb_entry), 187603831d35Sstevel KM_SLEEP); 187703831d35Sstevel cbe_ptr = cbe_ptr->cb_next; 187803831d35Sstevel break; 187903831d35Sstevel } 188003831d35Sstevel cbe_ptr = cbe_ptr->cb_next; 188103831d35Sstevel } 188203831d35Sstevel cbe_ptr->cb_softstate_ptr = soft_ptr; 188303831d35Sstevel cbe_ptr->cb_fru_id = fru_id; 188403831d35Sstevel cbe_ptr->cb_func = cb_func; 188503831d35Sstevel cbe_ptr->cb_next = (struct scsb_cb_entry *)NULL; 188603831d35Sstevel cbe_ptr->cb_fru_ptr = find_fru_info(fru_id); 188703831d35Sstevel #ifdef DEBUG 188803831d35Sstevel scsb_cb_count++; 188903831d35Sstevel #endif 189003831d35Sstevel if (scsb_debug & 0x00800000) { 189103831d35Sstevel cmn_err(CE_NOTE, 189203831d35Sstevel "scsb_fru_register: FRU_ID 0x%x, status=%d", 189303831d35Sstevel (int)fru_id, 189403831d35Sstevel (cbe_ptr->cb_fru_ptr == (fru_info_t *)NULL) ? 189503831d35Sstevel 0xff : cbe_ptr->cb_fru_ptr->fru_status); 189603831d35Sstevel } 189703831d35Sstevel if (cbe_ptr->cb_fru_ptr == (fru_info_t *)NULL) 189803831d35Sstevel return (FRU_NOT_AVAILABLE); 189903831d35Sstevel if (cbe_ptr->cb_fru_ptr->fru_status & FRU_PRESENT) 190003831d35Sstevel return (FRU_PRESENT); 190103831d35Sstevel return (FRU_NOT_PRESENT); 190203831d35Sstevel } 190303831d35Sstevel 190403831d35Sstevel void 190503831d35Sstevel scsb_fru_unregister(void *soft_ptr, fru_id_t fru_id) 190603831d35Sstevel { 190703831d35Sstevel struct scsb_cb_entry *prev_ptr, *cbe_ptr; 190803831d35Sstevel 190903831d35Sstevel if (scsb_debug & 0x00800001) { 191003831d35Sstevel cmn_err(CE_NOTE, "scsb_fru_unregister(0x%p, 0x%x)", 191103831d35Sstevel soft_ptr, (int)fru_id); 191203831d35Sstevel } 191303831d35Sstevel if ((cbe_ptr = scsb_cb_table) == NULL || fru_id == (fru_id_t)0) 191403831d35Sstevel return; 191503831d35Sstevel prev_ptr = cbe_ptr; 191603831d35Sstevel do { 191703831d35Sstevel if (cbe_ptr->cb_softstate_ptr == soft_ptr && 191803831d35Sstevel cbe_ptr->cb_fru_id == fru_id) { 191903831d35Sstevel if (cbe_ptr == scsb_cb_table) 192003831d35Sstevel scsb_cb_table = cbe_ptr->cb_next; 192103831d35Sstevel else 192203831d35Sstevel prev_ptr->cb_next = cbe_ptr->cb_next; 192303831d35Sstevel kmem_free(cbe_ptr, sizeof (struct scsb_cb_entry)); 192403831d35Sstevel #ifdef DEBUG 192503831d35Sstevel scsb_cb_count--; 192603831d35Sstevel #endif 192703831d35Sstevel return; 192803831d35Sstevel } 192903831d35Sstevel prev_ptr = cbe_ptr; 193003831d35Sstevel } while ((cbe_ptr = cbe_ptr->cb_next) != NULL); 193103831d35Sstevel } 193203831d35Sstevel 193303831d35Sstevel /* 193403831d35Sstevel * global function for interested FRU drivers to call to check 193503831d35Sstevel * FRU presence status. 193603831d35Sstevel */ 193703831d35Sstevel scsb_fru_status_t 193803831d35Sstevel scsb_fru_status(uchar_t fru_id) 193903831d35Sstevel { 194003831d35Sstevel fru_info_t *fru_ptr; 194103831d35Sstevel 194203831d35Sstevel fru_ptr = find_fru_info(fru_id); 194303831d35Sstevel if (scsb_debug & 0x00800001) { 194403831d35Sstevel cmn_err(CE_NOTE, "scsb_fru_status(0x%x): status=0x%x", 194503831d35Sstevel fru_id, (fru_ptr == (fru_info_t *)NULL) ? 0xff : 194603831d35Sstevel (int)fru_ptr->fru_status); 194703831d35Sstevel } 194803831d35Sstevel if (fru_ptr == (fru_info_t *)NULL) 194903831d35Sstevel return (FRU_NOT_AVAILABLE); 195003831d35Sstevel return (fru_ptr->fru_status); 195103831d35Sstevel } 195203831d35Sstevel 195303831d35Sstevel /* 195403831d35Sstevel * Global function for the other interruptible FRU device sharing the 195503831d35Sstevel * same interrupt line to register the interrupt handler with scsb. 195603831d35Sstevel * This enables all the handlers to be called whenever the interrupt 195703831d35Sstevel * line is asserted by anyone shaing the interrupt line. 195803831d35Sstevel */ 195903831d35Sstevel 196003831d35Sstevel /* 196103831d35Sstevel * The interrupt handler table is currently a linked list. probably a 196203831d35Sstevel * hash table will be more efficient. Usage of these facilities can 196303831d35Sstevel * happen even before scsb is attached, so do not depend on scsb 196403831d35Sstevel * structure being present. 196503831d35Sstevel */ 196603831d35Sstevel struct fru_intr_entry { 196703831d35Sstevel void *softstate_ptr; 196803831d35Sstevel int (*fru_intr_handler)(void *); 196903831d35Sstevel fru_id_t fru_id; 197003831d35Sstevel struct fru_intr_entry *fru_intr_next; 197103831d35Sstevel } *fru_intr_table = NULL; 197203831d35Sstevel 197303831d35Sstevel int 197403831d35Sstevel scsb_intr_register(int (*intr_handler)(void *), void * soft_ptr, 197503831d35Sstevel fru_id_t fru_id) 197603831d35Sstevel { 197703831d35Sstevel struct fru_intr_entry *intr_table_entry; 197803831d35Sstevel intr_table_entry = (struct fru_intr_entry *) 197903831d35Sstevel kmem_zalloc(sizeof (struct fru_intr_entry), KM_SLEEP); 198003831d35Sstevel 198103831d35Sstevel if (intr_table_entry == NULL) { 198203831d35Sstevel return (DDI_FAILURE); 198303831d35Sstevel } 198403831d35Sstevel 198503831d35Sstevel if (intr_handler == NULL || soft_ptr == NULL || fru_id == 0) { 198603831d35Sstevel kmem_free(intr_table_entry, sizeof (struct fru_intr_entry)); 198703831d35Sstevel return (DDI_FAILURE); 198803831d35Sstevel } 198903831d35Sstevel 199003831d35Sstevel intr_table_entry->softstate_ptr = soft_ptr; 199103831d35Sstevel intr_table_entry->fru_intr_handler = intr_handler; 199203831d35Sstevel intr_table_entry->fru_id = fru_id; 199303831d35Sstevel intr_table_entry->fru_intr_next = fru_intr_table; 199403831d35Sstevel fru_intr_table = intr_table_entry; 199503831d35Sstevel 199603831d35Sstevel return (DDI_SUCCESS); 199703831d35Sstevel } 199803831d35Sstevel 199903831d35Sstevel /* 200003831d35Sstevel * Removed interrupt_handler of fru from interrupt call chain 200103831d35Sstevel */ 200203831d35Sstevel void 200303831d35Sstevel scsb_intr_unregister(fru_id_t fru_id) 200403831d35Sstevel { 200503831d35Sstevel struct fru_intr_entry *intr_entry = fru_intr_table, 200603831d35Sstevel *prev_entry = intr_entry; 200703831d35Sstevel 200803831d35Sstevel if (fru_id == 0) { 200903831d35Sstevel return; 201003831d35Sstevel } 201103831d35Sstevel 201203831d35Sstevel do { 201303831d35Sstevel if (intr_entry->fru_id == fru_id) { 201403831d35Sstevel /* found a match, remove entry */ 201503831d35Sstevel if (intr_entry == fru_intr_table) 201603831d35Sstevel fru_intr_table = intr_entry->fru_intr_next; 201703831d35Sstevel else 201803831d35Sstevel prev_entry->fru_intr_next = 201903831d35Sstevel intr_entry->fru_intr_next; 202003831d35Sstevel 202103831d35Sstevel kmem_free(intr_entry, 202203831d35Sstevel sizeof (struct fru_intr_entry)); 202303831d35Sstevel return; 202403831d35Sstevel } 202503831d35Sstevel prev_entry = intr_entry; 202603831d35Sstevel 202703831d35Sstevel } while ((intr_entry = intr_entry->fru_intr_next) != NULL); 202803831d35Sstevel } 202903831d35Sstevel 203003831d35Sstevel /* 203103831d35Sstevel * Invoke all the registered interrupt handlers, whenever scsb_intr 203203831d35Sstevel * is called. This function will go through the list of entries 203303831d35Sstevel * in the fru interrupt table and invoke each function. Returns 203403831d35Sstevel * whether interrupt is claimed or unclaimed. 203503831d35Sstevel */ 203603831d35Sstevel static int 203703831d35Sstevel scsb_invoke_intr_chain() 203803831d35Sstevel { 203903831d35Sstevel int retval = DDI_INTR_UNCLAIMED; 204003831d35Sstevel struct fru_intr_entry *intr_entry = fru_intr_table; 204103831d35Sstevel 204203831d35Sstevel while (intr_entry != NULL) { 204303831d35Sstevel retval = (*intr_entry-> 204403831d35Sstevel fru_intr_handler)(intr_entry->softstate_ptr); 204503831d35Sstevel if (retval == DDI_INTR_CLAIMED) { 204603831d35Sstevel return (retval); 204703831d35Sstevel } 204803831d35Sstevel 204903831d35Sstevel intr_entry = intr_entry->fru_intr_next; 205003831d35Sstevel } 205103831d35Sstevel 205203831d35Sstevel return (retval); 205303831d35Sstevel } 205403831d35Sstevel 205503831d35Sstevel 205603831d35Sstevel /* 205703831d35Sstevel * The scsb_ioc_rdwr_t is similar enough to an i2c_transfer_t that we can 205803831d35Sstevel * translate the structures and use the i2c_transfer() service. 205903831d35Sstevel */ 206003831d35Sstevel static void 206103831d35Sstevel sm_ioc_rdwr(queue_t *q, mblk_t *mp, int op) 206203831d35Sstevel { 206303831d35Sstevel scsb_state_t *scsb = (scsb_state_t *)q->q_ptr; 206403831d35Sstevel struct iocblk *iocp = (struct iocblk *)mp->b_rptr; 206503831d35Sstevel scsb_ioc_rdwr_t *iocrdwrp; 206603831d35Sstevel int len, error; 206703831d35Sstevel uchar_t *uc, reg; 206803831d35Sstevel 206903831d35Sstevel if (scsb_debug & 0x0040) 207003831d35Sstevel cmn_err(CE_CONT, "sm_ioc_rdwr[%d]:", scsb->scsb_instance); 207103831d35Sstevel iocrdwrp = (scsb_ioc_rdwr_t *)mp->b_cont->b_rptr; 207203831d35Sstevel if (op == I2C_WR) { 207303831d35Sstevel len = iocrdwrp->ioc_wlen; 207403831d35Sstevel uc = iocrdwrp->ioc_wbuf; 207503831d35Sstevel } else { 207603831d35Sstevel len = iocrdwrp->ioc_rlen; 207703831d35Sstevel uc = iocrdwrp->ioc_rbuf; 207803831d35Sstevel } 207903831d35Sstevel /* 208003831d35Sstevel * Check SCB register index boundries and requested len of read/write 208103831d35Sstevel */ 208203831d35Sstevel reg = iocrdwrp->ioc_regindex; 208303831d35Sstevel if (reg < SCSB_REG_ADDR_START || (reg + len) > 208403831d35Sstevel (SCSB_REG_ADDR_START + SCTRL_TOTAL_NUMREGS)) 208503831d35Sstevel error = EINVAL; 208603831d35Sstevel else 208703831d35Sstevel error = scsb_rdwr_register(scsb, op, reg, len, uc, 1); 208803831d35Sstevel if (error) { 208903831d35Sstevel if (scsb_debug & 0x0042) 209003831d35Sstevel cmn_err(CE_WARN, 209103831d35Sstevel "sm_ioc_rdwr: rdwr_register failure: %d", error); 209203831d35Sstevel mp->b_datap->db_type = M_IOCNAK; 209303831d35Sstevel } else 209403831d35Sstevel mp->b_datap->db_type = M_IOCACK; 209503831d35Sstevel iocp->ioc_error = error; 209603831d35Sstevel qreply(q, mp); 209703831d35Sstevel } 209803831d35Sstevel 209903831d35Sstevel /* 210003831d35Sstevel * names for (scsb_utype_t) FRU types 210103831d35Sstevel */ 210203831d35Sstevel static char *led_name[SCSB_LED_TYPES] = { "NOK", "OK" }; 210303831d35Sstevel static char *unit_type_name[SCSB_UNIT_TYPES] = { 210403831d35Sstevel "SLOT", "PDU", "POWER SUPPLY", "DISK", "FAN", "ALARM", 210503831d35Sstevel "SCB", "SSB", "CFTM", "CRTM", "PRTM" 210603831d35Sstevel }; 210703831d35Sstevel 210803831d35Sstevel /* 210903831d35Sstevel * Discover the register and bit-offset for LEDs and Reset registers, 211003831d35Sstevel * according to unit_type, unit_number, and led_type. 211103831d35Sstevel */ 211203831d35Sstevel static int 211303831d35Sstevel scsb_get_led_regnum(scsb_state_t *scsb, 211403831d35Sstevel scsb_uinfo_t *suip, 211503831d35Sstevel uchar_t *regptr, 211603831d35Sstevel int *unitptr, 211703831d35Sstevel scsb_led_t led_type) 211803831d35Sstevel { 211903831d35Sstevel int code, base, error; 212003831d35Sstevel 212103831d35Sstevel /* OK here means presence (OK) LEDs */ 212203831d35Sstevel if (led_type == OK) 212303831d35Sstevel base = (SCTRL_LED_OK_BASE); 212403831d35Sstevel else 212503831d35Sstevel base = (SCTRL_LED_NOK_BASE); 212603831d35Sstevel error = 0; 212703831d35Sstevel if (scsb_debug & 0x0100) { 212803831d35Sstevel cmn_err(CE_NOTE, "get_led_regnum: suip <%x, %x, %x, %x>\n", 212903831d35Sstevel suip->unit_type, suip->unit_number, 213003831d35Sstevel led_type, suip->unit_state); 213103831d35Sstevel } 213203831d35Sstevel /* 213303831d35Sstevel * It was requested that the scsb driver allow accesses to SCB device 213403831d35Sstevel * registers for FRUs that cannot be present. 213503831d35Sstevel * So except for SLOTs, if the unit_number check fails, we now 213603831d35Sstevel * just log a message, but ONLY if scsb_debug error messages are 213703831d35Sstevel * enabled. 213803831d35Sstevel */ 213903831d35Sstevel switch (suip->unit_type) { 214003831d35Sstevel case SLOT: 214103831d35Sstevel if (suip->unit_number < 1 || suip->unit_number > 214203831d35Sstevel ((scsb->scsb_state & SCSB_IS_TONGA) ? 214303831d35Sstevel TG_MAX_SLOTS : MC_MAX_SLOTS)) { 214403831d35Sstevel error = EINVAL; 214503831d35Sstevel break; 214603831d35Sstevel } 214703831d35Sstevel code = FRU_UNIT_TO_EVCODE(SLOT, suip->unit_number); 214803831d35Sstevel break; 214903831d35Sstevel 215003831d35Sstevel case PDU: 215103831d35Sstevel if (suip->unit_number < 1 || suip->unit_number > 215203831d35Sstevel ((scsb->scsb_state & SCSB_IS_TONGA) ? 215303831d35Sstevel TG_MAX_PDU : MC_MAX_PDU)) { 215403831d35Sstevel if (scsb_debug & 0x0002) { 215503831d35Sstevel cmn_err(CE_WARN, 215603831d35Sstevel "get_led_regnum: unit number %d " 215703831d35Sstevel "is out of range", suip->unit_number); 215803831d35Sstevel } 215903831d35Sstevel error = EINVAL; 216003831d35Sstevel break; 216103831d35Sstevel } 216203831d35Sstevel code = FRU_UNIT_TO_EVCODE(PDU, suip->unit_number); 216303831d35Sstevel break; 216403831d35Sstevel 216503831d35Sstevel case PS: 216603831d35Sstevel if ((suip->unit_number < 1 || suip->unit_number > 216703831d35Sstevel ((scsb->scsb_state & SCSB_IS_TONGA) ? 216803831d35Sstevel TG_MAX_PS : MC_MAX_PS))) { 216903831d35Sstevel if (scsb_debug & 0x0002) { 217003831d35Sstevel cmn_err(CE_WARN, 217103831d35Sstevel "get_led_regnum: unit number %d " 217203831d35Sstevel "is out of range", suip->unit_number); 217303831d35Sstevel } 217403831d35Sstevel error = EINVAL; 217503831d35Sstevel break; 217603831d35Sstevel } 217703831d35Sstevel code = FRU_UNIT_TO_EVCODE(PS, suip->unit_number); 217803831d35Sstevel break; 217903831d35Sstevel 218003831d35Sstevel case DISK: 218103831d35Sstevel if ((suip->unit_number < 1 || suip->unit_number > 218203831d35Sstevel ((scsb->scsb_state & SCSB_IS_TONGA) ? 218303831d35Sstevel TG_MAX_DISK : MC_MAX_DISK))) { 218403831d35Sstevel if (scsb_debug & 0x0002) { 218503831d35Sstevel cmn_err(CE_WARN, 218603831d35Sstevel "get_led_regnum: unit number %d " 218703831d35Sstevel "is out of range", suip->unit_number); 218803831d35Sstevel } 218903831d35Sstevel if (!(scsb_debug & 0x20000000)) { 219003831d35Sstevel error = EINVAL; 219103831d35Sstevel break; 219203831d35Sstevel } 219303831d35Sstevel } 219403831d35Sstevel code = FRU_UNIT_TO_EVCODE(DISK, suip->unit_number); 219503831d35Sstevel break; 219603831d35Sstevel 219703831d35Sstevel case FAN: 219803831d35Sstevel if (suip->unit_number < 1 || suip->unit_number > 219903831d35Sstevel ((scsb->scsb_state & SCSB_IS_TONGA) ? 220003831d35Sstevel TG_MAX_FAN : MC_MAX_FAN)) { 220103831d35Sstevel if (scsb_debug & 0x0002) { 220203831d35Sstevel cmn_err(CE_WARN, 220303831d35Sstevel "get_led_regnum: unit number %d " 220403831d35Sstevel "is out of range", suip->unit_number); 220503831d35Sstevel } 220603831d35Sstevel error = EINVAL; 220703831d35Sstevel break; 220803831d35Sstevel } 220903831d35Sstevel code = FRU_UNIT_TO_EVCODE(FAN, suip->unit_number); 221003831d35Sstevel break; 221103831d35Sstevel 221203831d35Sstevel case CFTM: 221303831d35Sstevel if (suip->unit_number < 1 || suip->unit_number > 221403831d35Sstevel ((scsb->scsb_state & SCSB_IS_TONGA) ? 221503831d35Sstevel TG_MAX_CFTM : MC_MAX_CFTM)) { 221603831d35Sstevel if (scsb_debug & 0x0002) { 221703831d35Sstevel cmn_err(CE_WARN, 221803831d35Sstevel "get_led_regnum: unit number %d " 221903831d35Sstevel "is out of range", suip->unit_number); 222003831d35Sstevel } 222103831d35Sstevel error = EINVAL; 222203831d35Sstevel break; 222303831d35Sstevel } 222403831d35Sstevel code = FRU_UNIT_TO_EVCODE(CFTM, suip->unit_number); 222503831d35Sstevel break; 222603831d35Sstevel 222703831d35Sstevel case SCB: 222803831d35Sstevel if (suip->unit_number < 1 || suip->unit_number > 222903831d35Sstevel ((scsb->scsb_state & SCSB_IS_TONGA) ? 223003831d35Sstevel TG_MAX_SCB : MC_MAX_SCB)) { 223103831d35Sstevel if (scsb_debug & 0x0002) { 223203831d35Sstevel cmn_err(CE_WARN, 223303831d35Sstevel "get_led_regnum: unit number %d " 223403831d35Sstevel "is out of range", suip->unit_number); 223503831d35Sstevel } 223603831d35Sstevel error = EINVAL; 223703831d35Sstevel break; 223803831d35Sstevel } 223903831d35Sstevel code = FRU_UNIT_TO_EVCODE(SCB, suip->unit_number); 224003831d35Sstevel break; 224103831d35Sstevel 224203831d35Sstevel case ALARM: 224303831d35Sstevel error = EINVAL; 224403831d35Sstevel break; 224503831d35Sstevel 224603831d35Sstevel default: 224703831d35Sstevel if (scsb_debug & 0x0102) { 224803831d35Sstevel cmn_err(CE_WARN, 224903831d35Sstevel "scsb_get_led_regnum(): unknown unit type %d", 225003831d35Sstevel suip->unit_type); 225103831d35Sstevel } 225203831d35Sstevel error = EINVAL; 225303831d35Sstevel break; 225403831d35Sstevel } 225503831d35Sstevel if (!error) { 225603831d35Sstevel *unitptr = FRU_OFFSET(code, base); 225703831d35Sstevel *regptr = FRU_REG_ADDR(code, base); 225803831d35Sstevel if (scsb_debug & 0x0100) { 225903831d35Sstevel cmn_err(CE_NOTE, "get_led_regnum: unitptr=%x, " 226003831d35Sstevel "regptr=%x, code = %x\n", 226103831d35Sstevel *unitptr, *regptr, code); 226203831d35Sstevel } 226303831d35Sstevel } 226403831d35Sstevel return (error); 226503831d35Sstevel } 226603831d35Sstevel 226703831d35Sstevel /* 226803831d35Sstevel * P1.0 and P1.5 226903831d35Sstevel * Map 1.0 Tonga Slot Numbers: SCB to user interface and back. 227003831d35Sstevel * User interface means positional slot numbers, as on P1.0 SSB, 227103831d35Sstevel * which are used by hpcsvc/hsc and kstat/ioctl interfaces. 227203831d35Sstevel */ 227303831d35Sstevel 227403831d35Sstevel /* HSC slotnum (Positional SLotnum) to SCB CFG bit-offset */ 227503831d35Sstevel static int psl2sco[TG_MAX_SLOTS + 1] = { -1 }; 227603831d35Sstevel 227703831d35Sstevel /* 227803831d35Sstevel * MAP Positional (HSC) slot number to SCB CFG register bit-offset 227903831d35Sstevel */ 228003831d35Sstevel static int 228103831d35Sstevel tonga_pslotnum_to_cfgbit(scsb_state_t *scsb, int sln) 228203831d35Sstevel { 228303831d35Sstevel int base = SCTRL_SYSCFG_BASE; 228403831d35Sstevel if (!(scsb->scsb_state & SCSB_IS_TONGA)) { 228503831d35Sstevel return (sln); 228603831d35Sstevel } 228703831d35Sstevel if (sln < 1 || sln > TG_MAX_SLOTS) { 228803831d35Sstevel return (sln); 228903831d35Sstevel } 229003831d35Sstevel /* 229103831d35Sstevel * Should move this to _init(), but for now, 229203831d35Sstevel * check for initialized table 229303831d35Sstevel */ 229403831d35Sstevel if (psl2sco[0]) { 229503831d35Sstevel psl2sco[0] = 0; 229603831d35Sstevel psl2sco[1] = FRU_OFFSET(SCTRL_EVENT_SLOT5, base); 229703831d35Sstevel psl2sco[2] = FRU_OFFSET(SCTRL_EVENT_SLOT2, base); 229803831d35Sstevel psl2sco[3] = FRU_OFFSET(SCTRL_EVENT_SLOT1, base); 229903831d35Sstevel psl2sco[4] = FRU_OFFSET(SCTRL_EVENT_SLOT3, base); 230003831d35Sstevel psl2sco[5] = FRU_OFFSET(SCTRL_EVENT_SLOT4, base); 230103831d35Sstevel } 230203831d35Sstevel #ifdef DEBUG 230303831d35Sstevel if (scsb_debug & 0x10000000) { 230403831d35Sstevel cmn_err(CE_NOTE, "tonga_pslotnum_to_cfgbit: old/new: %d/%d", 230503831d35Sstevel sln, psl2sco[sln]); 230603831d35Sstevel } 230703831d35Sstevel #endif 230803831d35Sstevel return (psl2sco[sln]); 230903831d35Sstevel } 231003831d35Sstevel 231103831d35Sstevel /* positional slotnum to SCB slotnum */ 231203831d35Sstevel static int psl2ssl[6] = { 231303831d35Sstevel 0, 5, 2, 1, 3, 4 231403831d35Sstevel }; 231503831d35Sstevel 231603831d35Sstevel /* SCB slotnum to positional slotnum */ 231703831d35Sstevel static int ssl2psl[6] = { 231803831d35Sstevel 0, 3, 2, 4, 5, 1 231903831d35Sstevel }; 232003831d35Sstevel 232103831d35Sstevel /* 232203831d35Sstevel * P1.0 and P1.5 232303831d35Sstevel * HSC Slot numbers (physical positions or positional slotnum) 232403831d35Sstevel * to 232503831d35Sstevel * SCB slot numbers (reset,present,healthy) 232603831d35Sstevel * 232703831d35Sstevel * These requests come mainly from application interface and 232803831d35Sstevel * HSC using the scsb_uinfo_t structure. 232903831d35Sstevel */ 233003831d35Sstevel static void 233103831d35Sstevel tonga_slotnum_check(scsb_state_t *scsb, scsb_uinfo_t *suip) 233203831d35Sstevel { 233303831d35Sstevel if (!(scsb->scsb_state & SCSB_IS_TONGA && scsb->scsb_state & 233403831d35Sstevel (SCSB_P10_PROM | SCSB_P15_PROM | SCSB_P20_PROM))) { 233503831d35Sstevel return; 233603831d35Sstevel } 233703831d35Sstevel if (suip->unit_number < 1 || suip->unit_number > TG_MAX_SLOTS) { 233803831d35Sstevel return; 233903831d35Sstevel } 234003831d35Sstevel #ifdef DEBUG 234103831d35Sstevel if (scsb_debug & 0x10000000) { 234203831d35Sstevel cmn_err(CE_NOTE, "tonga_slotnum_check: old/new: %d/%d", 234303831d35Sstevel suip->unit_number, psl2ssl[suip->unit_number]); 234403831d35Sstevel } 234503831d35Sstevel #endif 234603831d35Sstevel suip->unit_number = psl2ssl[suip->unit_number]; 234703831d35Sstevel } 234803831d35Sstevel 234903831d35Sstevel /* 235003831d35Sstevel * P1.0 and P1.5 235103831d35Sstevel */ 235203831d35Sstevel static int 235303831d35Sstevel tonga_psl_to_ssl(scsb_state_t *scsb, int slotnum) 235403831d35Sstevel { 235503831d35Sstevel if (!(scsb->scsb_state & SCSB_IS_TONGA && scsb->scsb_state & 235603831d35Sstevel (SCSB_P10_PROM | SCSB_P15_PROM | SCSB_P20_PROM))) { 235703831d35Sstevel return (slotnum); 235803831d35Sstevel } 235903831d35Sstevel if (slotnum < 1 || slotnum > TG_MAX_SLOTS) { 236003831d35Sstevel return (slotnum); 236103831d35Sstevel } 236203831d35Sstevel #ifdef DEBUG 236303831d35Sstevel if (scsb_debug & 0x10000000) { 236403831d35Sstevel cmn_err(CE_NOTE, "tonga_psl_to_ssl: old/new: %d/%d", 236503831d35Sstevel slotnum, psl2ssl[slotnum]); 236603831d35Sstevel } 236703831d35Sstevel #endif 236803831d35Sstevel return (psl2ssl[slotnum]); 236903831d35Sstevel } 237003831d35Sstevel 237103831d35Sstevel /* 237203831d35Sstevel * P1.0 and P1.5 237303831d35Sstevel */ 237403831d35Sstevel static int 237503831d35Sstevel tonga_ssl_to_psl(scsb_state_t *scsb, int slotnum) 237603831d35Sstevel { 237703831d35Sstevel if (!(scsb->scsb_state & SCSB_IS_TONGA && scsb->scsb_state & 237803831d35Sstevel (SCSB_P10_PROM | SCSB_P15_PROM | SCSB_P20_PROM))) { 237903831d35Sstevel return (slotnum); 238003831d35Sstevel } 238103831d35Sstevel if (slotnum < 1 || slotnum > TG_MAX_SLOTS) { 238203831d35Sstevel return (slotnum); 238303831d35Sstevel } 238403831d35Sstevel #ifdef DEBUG 238503831d35Sstevel if (scsb_debug & 0x10000000) { 238603831d35Sstevel cmn_err(CE_NOTE, "tonga_ssl_to_psl: old/new: %d/%d", 238703831d35Sstevel slotnum, ssl2psl[slotnum]); 238803831d35Sstevel } 238903831d35Sstevel #endif 239003831d35Sstevel return (ssl2psl[slotnum]); 239103831d35Sstevel } 239203831d35Sstevel /* 239303831d35Sstevel * tonga_slotnum_led_shift: this function remaps slot bits ONLY for Slots 1-5 239403831d35Sstevel * and ONLY for the register sets in bit-offset groups 1,2: 239503831d35Sstevel * LEDs, Confg/Status, Reset, BrdHlthy 239603831d35Sstevel * 239703831d35Sstevel * IN bits: SCB slot numbers (led,reset,present,healthy) 239803831d35Sstevel * to 239903831d35Sstevel * OUT bits: HSC Slot numbers (positional slot numbers as marked on the SSB) 240003831d35Sstevel */ 240103831d35Sstevel static uchar_t 240203831d35Sstevel tonga_slotnum_led_shift(scsb_state_t *scsb, uchar_t data) 240303831d35Sstevel { 240403831d35Sstevel int i; 240503831d35Sstevel uchar_t mask, new_data = 0; 240603831d35Sstevel #ifdef DEBUG 240703831d35Sstevel uchar_t old_data = data; 240803831d35Sstevel #endif 240903831d35Sstevel if (!(scsb->scsb_state & SCSB_IS_TONGA)) { 241003831d35Sstevel return (data); 241103831d35Sstevel } 241203831d35Sstevel /* 241303831d35Sstevel * P1.0 and P1.5 slot 1-5 offsets are the same 241403831d35Sstevel */ 241503831d35Sstevel for (i = 1; i <= TG_MAX_SLOTS; ++i) { 241603831d35Sstevel mask = 1 << (i - 1); 241703831d35Sstevel switch (i) { 241803831d35Sstevel case 1: /* map to slot 3 */ 241903831d35Sstevel new_data |= (data & mask) << 2; 242003831d35Sstevel data &= ~(mask); 242103831d35Sstevel break; 242203831d35Sstevel case 2: /* map to slot 2 */ 242303831d35Sstevel new_data |= (data & mask); 242403831d35Sstevel data &= ~(mask); 242503831d35Sstevel break; 242603831d35Sstevel case 3: /* map to slot 4 */ 242703831d35Sstevel case 4: /* map to slot 5 */ 242803831d35Sstevel new_data |= (data & mask) << 1; 242903831d35Sstevel data &= ~(mask); 243003831d35Sstevel break; 243103831d35Sstevel case 5: /* map to slot 1 */ 243203831d35Sstevel new_data |= (data & mask) >> 4; 243303831d35Sstevel data &= ~(mask); 243403831d35Sstevel break; 243503831d35Sstevel } 243603831d35Sstevel } 243703831d35Sstevel new_data |= data; /* set any remaining bits */ 243803831d35Sstevel #ifdef DEBUG 243903831d35Sstevel if (scsb_debug & 0x10000000) { 244003831d35Sstevel cmn_err(CE_NOTE, "tonga_slotnum_led_shift: old/new: 0x%x/0x%x", 244103831d35Sstevel old_data, new_data); 244203831d35Sstevel } 244303831d35Sstevel #endif 244403831d35Sstevel return (new_data); 244503831d35Sstevel } 244603831d35Sstevel 244703831d35Sstevel /* 244803831d35Sstevel * P1.0 and P1.5 244903831d35Sstevel */ 245003831d35Sstevel int 245103831d35Sstevel scsb_led_get(scsb_state_t *scsb, scsb_uinfo_t *suip, scsb_led_t led_type) 245203831d35Sstevel { 245303831d35Sstevel int error; 245403831d35Sstevel int unit_number; 245503831d35Sstevel uchar_t reg; 245603831d35Sstevel int index; 245703831d35Sstevel 245803831d35Sstevel /* 245903831d35Sstevel * Allow access to shadow registers even though SCB is removed 246003831d35Sstevel * 246103831d35Sstevel * if (scsb->scsb_state & SCSB_FROZEN) { 246203831d35Sstevel * return (EAGAIN); 246303831d35Sstevel * } 246403831d35Sstevel */ 246503831d35Sstevel if (suip == NULL) { 246603831d35Sstevel return (EFAULT); 246703831d35Sstevel } 246803831d35Sstevel if (led_type == NOUSE) { 246903831d35Sstevel led_type = suip->led_type; 247003831d35Sstevel } 247103831d35Sstevel if (led_type != OK && led_type != NOK) { 247203831d35Sstevel cmn_err(CE_NOTE, "scsb_led_get(%d): unknown led type %x", 247303831d35Sstevel scsb->scsb_instance, led_type); 247403831d35Sstevel return (EINVAL); 247503831d35Sstevel } 247603831d35Sstevel error = 0; 247703831d35Sstevel if (scsb_debug & 0x0100) { 247803831d35Sstevel cmn_err(CE_NOTE, "scsb_led_get: %s %s %d", 247903831d35Sstevel led_name[led_type], unit_type_name[suip->unit_type], 248003831d35Sstevel suip->unit_number); 248103831d35Sstevel } 248203831d35Sstevel /* 248303831d35Sstevel * Map to Tonga Slot Number, if NOT P1.0 SCB 248403831d35Sstevel * P1.0 SSB workaround 248503831d35Sstevel */ 248603831d35Sstevel if (suip->unit_type == SLOT && !(scsb->scsb_state & SCSB_P10_PROM)) { 248703831d35Sstevel tonga_slotnum_check(scsb, suip); 248803831d35Sstevel } 248903831d35Sstevel /* discover the register and index we need to operate on */ 249003831d35Sstevel if ((error = scsb_get_led_regnum(scsb, suip, ®, &unit_number, 249103831d35Sstevel led_type)) == 0) { 249203831d35Sstevel index = SCSB_REG_INDEX(reg); 249303831d35Sstevel mutex_enter(&scsb->scsb_mutex); 249403831d35Sstevel if (scsb->scsb_data_reg[index] & (1 << unit_number)) { 249503831d35Sstevel suip->unit_state = ON; 249603831d35Sstevel if (led_type == OK) { 249703831d35Sstevel int code = FRU_UNIT_TO_EVCODE(suip->unit_type, 249803831d35Sstevel suip->unit_number); 249903831d35Sstevel reg = FRU_REG_ADDR(code, SCTRL_BLINK_OK_BASE); 250003831d35Sstevel index = SCSB_REG_INDEX(reg); 250103831d35Sstevel if (scsb->scsb_data_reg[index] & 250203831d35Sstevel (1 << unit_number)) 250303831d35Sstevel suip->unit_state = BLINK; 250403831d35Sstevel } 250503831d35Sstevel } else { 250603831d35Sstevel suip->unit_state = OFF; 250703831d35Sstevel } 250803831d35Sstevel mutex_exit(&scsb->scsb_mutex); 250903831d35Sstevel } 251003831d35Sstevel return (error); 251103831d35Sstevel } 251203831d35Sstevel 251303831d35Sstevel int 251403831d35Sstevel scsb_led_set(scsb_state_t *scsb, scsb_uinfo_t *suip, scsb_led_t led_type) 251503831d35Sstevel { 251603831d35Sstevel int error; 251703831d35Sstevel int unit_number; 251803831d35Sstevel uchar_t reg; 251903831d35Sstevel int code, index; 252003831d35Sstevel 252103831d35Sstevel /* we should really allow led state changes while frozen... */ 252203831d35Sstevel if (scsb->scsb_state & SCSB_FROZEN) 252303831d35Sstevel return (EAGAIN); 252403831d35Sstevel 252503831d35Sstevel if (suip == NULL) { 252603831d35Sstevel return (EFAULT); 252703831d35Sstevel } 252803831d35Sstevel 252903831d35Sstevel /* 253003831d35Sstevel * Sanity check, make sure we got plausible values for set command. 253103831d35Sstevel * Also check for application only control of slot leds using NOUSE 253203831d35Sstevel * interface 253303831d35Sstevel */ 253403831d35Sstevel if (led_type == NOUSE) { 253503831d35Sstevel led_type = suip->led_type; 253603831d35Sstevel } else if (suip->unit_type == SLOT && 253703831d35Sstevel scsb->scsb_state & SCSB_APP_SLOTLED_CTRL && 253803831d35Sstevel !(scsb->scsb_state & 253903831d35Sstevel (SCSB_DIAGS_MODE | SCSB_DEBUG_MODE))) { 254003831d35Sstevel /* 254103831d35Sstevel * kernel modules using this interface need to think they are 254203831d35Sstevel * succeeding, so we won't return an error for this 254303831d35Sstevel * application configuration 254403831d35Sstevel */ 254503831d35Sstevel return (0); 254603831d35Sstevel } 254703831d35Sstevel if (led_type != OK && led_type != NOK) { 254803831d35Sstevel return (EINVAL); 254903831d35Sstevel } 255003831d35Sstevel if (suip->unit_state != OFF && suip->unit_state != ON && 255103831d35Sstevel suip->unit_state != BLINK) { 255203831d35Sstevel return (EINVAL); 255303831d35Sstevel } 255403831d35Sstevel if (suip->unit_state == BLINK) { 255503831d35Sstevel if (led_type != OK) 255603831d35Sstevel return (EINVAL); 255703831d35Sstevel if (suip->unit_type != SLOT && scsb->scsb_state & 255803831d35Sstevel (SCSB_P06_PROM | SCSB_P10_PROM)) 255903831d35Sstevel return (EINVAL); 256003831d35Sstevel } 256103831d35Sstevel if (scsb_debug & 0x0100) { 256203831d35Sstevel cmn_err(CE_NOTE, 256303831d35Sstevel "scsb_led_set: led %s, type %s, unit %d, state %s", 256403831d35Sstevel led_name[led_type], 256503831d35Sstevel unit_type_name[suip->unit_type], suip->unit_number, 256603831d35Sstevel suip->unit_state == ON ? "ON": 256703831d35Sstevel suip->unit_state == OFF ? "OFF": "BLINK"); 256803831d35Sstevel } 256903831d35Sstevel /* 257003831d35Sstevel * Map to Tonga Slot Number, if NOT P1.0 SCB 257103831d35Sstevel * P1.0 SSB workaround 257203831d35Sstevel */ 257303831d35Sstevel if (suip->unit_type == SLOT && !(scsb->scsb_state & SCSB_P10_PROM)) { 257403831d35Sstevel tonga_slotnum_check(scsb, suip); 257503831d35Sstevel } 257603831d35Sstevel /* 257703831d35Sstevel * discover the register and index we need to access 257803831d35Sstevel */ 257903831d35Sstevel if ((error = scsb_get_led_regnum(scsb, suip, ®, &unit_number, 258003831d35Sstevel led_type)) == 0) { 258103831d35Sstevel index = SCSB_REG_INDEX(reg); 258203831d35Sstevel mutex_enter(&scsb->scsb_mutex); 258303831d35Sstevel if (suip->unit_state == ON || suip->unit_state == BLINK) 258403831d35Sstevel scsb->scsb_data_reg[index] |= (1 << unit_number); 258503831d35Sstevel else 258603831d35Sstevel scsb->scsb_data_reg[index] &= ~(1 << unit_number); 258703831d35Sstevel 258803831d35Sstevel if (scsb_debug & 0x0100) { 258903831d35Sstevel cmn_err(CE_NOTE, "Writing %x to Reg %x", 259003831d35Sstevel scsb->scsb_data_reg[index], reg); 259103831d35Sstevel } 259203831d35Sstevel error = scsb_rdwr_register(scsb, I2C_WR, reg, 1, 259303831d35Sstevel &scsb->scsb_data_reg[index], 1); 259403831d35Sstevel if (error) { 259503831d35Sstevel cmn_err(CE_WARN, "%s#%d: Could not Update %s LEDs.", 259603831d35Sstevel ddi_driver_name(scsb->scsb_dev), 259703831d35Sstevel ddi_get_instance(scsb->scsb_dev), 259803831d35Sstevel led_name[led_type]); 259903831d35Sstevel goto ledset_done; 260003831d35Sstevel } 260103831d35Sstevel if (led_type != OK || 260203831d35Sstevel (IS_SCB_P10 && suip->unit_type != SLOT) || 260303831d35Sstevel suip->unit_type == ALARM || 260403831d35Sstevel suip->unit_type == SSB || 260503831d35Sstevel suip->unit_type == CRTM || 260603831d35Sstevel suip->unit_type == PRTM) { 260703831d35Sstevel goto ledset_done; 260803831d35Sstevel } 260903831d35Sstevel code = FRU_UNIT_TO_EVCODE(suip->unit_type, suip->unit_number); 261003831d35Sstevel reg = FRU_REG_ADDR(code, SCTRL_BLINK_OK_BASE); 261103831d35Sstevel index = SCSB_REG_INDEX(reg); 261203831d35Sstevel if (suip->unit_state == BLINK) 261303831d35Sstevel scsb->scsb_data_reg[index] |= (1 << unit_number); 261403831d35Sstevel else 261503831d35Sstevel scsb->scsb_data_reg[index] &= ~(1 << unit_number); 261603831d35Sstevel if (scsb_debug & 0x0100) { 261703831d35Sstevel cmn_err(CE_NOTE, "Writing %x to Reg %x", 261803831d35Sstevel scsb->scsb_data_reg[index], reg); 261903831d35Sstevel } 262003831d35Sstevel error = scsb_rdwr_register(scsb, I2C_WR, reg, 1, 262103831d35Sstevel &scsb->scsb_data_reg[index], 1); 262203831d35Sstevel if (error) { 262303831d35Sstevel cmn_err(CE_WARN, "%s#%d: Could not Blink %s LEDs.", 262403831d35Sstevel ddi_driver_name(scsb->scsb_dev), 262503831d35Sstevel ddi_get_instance(scsb->scsb_dev), 262603831d35Sstevel led_name[led_type]); 262703831d35Sstevel } 262803831d35Sstevel ledset_done: 262903831d35Sstevel mutex_exit(&scsb->scsb_mutex); 263003831d35Sstevel } 263103831d35Sstevel return (error); 263203831d35Sstevel } 263303831d35Sstevel 263403831d35Sstevel struct ps_auto_on { 263503831d35Sstevel scsb_state_t *scsb; 263603831d35Sstevel scsb_utype_t utype; 263703831d35Sstevel scsb_unum_t unit; 263803831d35Sstevel }; 263903831d35Sstevel 264003831d35Sstevel static struct ps_auto_on pao; 264103831d35Sstevel 264203831d35Sstevel static void 264303831d35Sstevel scsb_ps_auto_on(void *arg) 264403831d35Sstevel { 264503831d35Sstevel struct ps_auto_on *ppao = (struct ps_auto_on *)arg; 264603831d35Sstevel uchar_t rmask = 0; 264703831d35Sstevel uchar_t ondata, sysreg; 264803831d35Sstevel int tmp, bit_index; 264903831d35Sstevel /* 265003831d35Sstevel * Turn on the PSU. 265103831d35Sstevel * Notice: not checking Power Supply unit number 265203831d35Sstevel */ 265303831d35Sstevel bit_index = SCTRL_SYS_PS_ON_BASE + (ppao->unit - 1); 265403831d35Sstevel ondata = 1 << SYS_OFFSET(bit_index); 265503831d35Sstevel tmp = SYS_REG_INDEX(bit_index, SCTRL_SYS_CMD_BASE); 265603831d35Sstevel sysreg = SCSB_REG_ADDR(tmp); 265703831d35Sstevel if (scsb_write_mask(ppao->scsb, sysreg, rmask, ondata, (uchar_t)0)) { 265803831d35Sstevel cmn_err(CE_WARN, "scsb%d: " "I2C TRANSFER Failed", 265903831d35Sstevel ppao->scsb->scsb_instance); 266003831d35Sstevel } 266103831d35Sstevel ppao->scsb->scsb_btid = 0; 266203831d35Sstevel } 266303831d35Sstevel 266403831d35Sstevel /* 266503831d35Sstevel * called with mutex held from 266603831d35Sstevel * scsb_attach() with int_fru_ptr == NULL 266703831d35Sstevel * scsb_intr() with int_fru_ptr == info for FRU that caused interrupt 266803831d35Sstevel */ 266903831d35Sstevel static int 267003831d35Sstevel scsb_set_scfg_pres_leds(scsb_state_t *scsb, fru_info_t *int_fru_ptr) 267103831d35Sstevel { 267203831d35Sstevel int i, error = 0; 267303831d35Sstevel int cfg_idx, led_idx, blink_idx, lid, bid; 267403831d35Sstevel int cfg_bit, led_bit; 267503831d35Sstevel uchar_t *puc, reg, led_reg, led_data[SCSB_LEDDATA_REGISTERS]; 267603831d35Sstevel uchar_t blink_bit, blink_reg, blink[SCSB_LEDDATA_REGISTERS]; 267703831d35Sstevel uchar_t update_reg = 0; 267803831d35Sstevel scsb_utype_t fru_type; 267903831d35Sstevel fru_info_t *fru_ptr; 268003831d35Sstevel 268103831d35Sstevel if (scsb->scsb_state & SCSB_FROZEN && 268203831d35Sstevel !(scsb->scsb_state & SCSB_IN_INTR)) { 268303831d35Sstevel return (EAGAIN); 268403831d35Sstevel } 268503831d35Sstevel for (i = 0; i < SCTRL_LED_OK_NUMREGS; ++i) { 268603831d35Sstevel led_data[i] = 0; 268703831d35Sstevel blink[i] = 0; 268803831d35Sstevel } 268903831d35Sstevel led_reg = SCSB_REG_ADDR(SCTRL_LED_OK_BASE); 269003831d35Sstevel reg = SCSB_REG_ADDR(SCTRL_BLINK_OK_BASE); 269103831d35Sstevel lid = SCSB_REG_INDEX(led_reg); /* the LED Index Delta */ 269203831d35Sstevel bid = SCSB_REG_INDEX(reg); /* the Blink Index Delta */ 269303831d35Sstevel blink_reg = 0; 269403831d35Sstevel if (int_fru_ptr != NULL) { 269503831d35Sstevel update_reg = int_fru_ptr->i2c_info->ledata_reg; 269603831d35Sstevel } 269703831d35Sstevel for (fru_type = 0; fru_type < SCSB_UNIT_TYPES; ++fru_type) { 269803831d35Sstevel int is_present; 269903831d35Sstevel fru_ptr = mct_system_info.fru_info_list[fru_type]; 270003831d35Sstevel for (; fru_ptr != NULL; fru_ptr = fru_ptr->next) { 270103831d35Sstevel is_present = 0; 270203831d35Sstevel if (fru_type == SLOT && (scsb->scsb_state & 270303831d35Sstevel SCSB_APP_SLOTLED_CTRL)) 270403831d35Sstevel break; 270503831d35Sstevel if (fru_ptr->i2c_info == NULL) 270603831d35Sstevel continue; 270703831d35Sstevel if ((led_reg = fru_ptr->i2c_info->ledata_reg) == 0) { 270803831d35Sstevel /* 270903831d35Sstevel * No LED exceptions: SSB,CRTM,PRTM 271003831d35Sstevel */ 271103831d35Sstevel continue; 271203831d35Sstevel } 271303831d35Sstevel if (update_reg && update_reg != led_reg) 271403831d35Sstevel continue; 271503831d35Sstevel led_idx = SCSB_REG_INDEX(led_reg) - lid; 271603831d35Sstevel led_bit = fru_ptr->i2c_info->ledata_bit; 271703831d35Sstevel if ((reg = fru_ptr->i2c_info->syscfg_reg) == 0) { 271803831d35Sstevel if (fru_type != SCB) 271903831d35Sstevel continue; 272003831d35Sstevel /* 272103831d35Sstevel * exception: SCB 272203831d35Sstevel */ 272303831d35Sstevel if (scsb->scsb_state & SCSB_SCB_PRESENT) { 272403831d35Sstevel led_data[led_idx] |= 1 << led_bit; 272503831d35Sstevel is_present = 1; 272603831d35Sstevel } else { 272703831d35Sstevel led_data[led_idx] &= ~(1 << led_bit); 272803831d35Sstevel } 272903831d35Sstevel if (IS_SCB_P10) 273003831d35Sstevel continue; 273103831d35Sstevel } else { 273203831d35Sstevel cfg_idx = SCSB_REG_INDEX(reg); 273303831d35Sstevel cfg_bit = fru_ptr->i2c_info->syscfg_bit; 273403831d35Sstevel if (scsb->scsb_data_reg[cfg_idx] & 273503831d35Sstevel (1 << cfg_bit)) { 273603831d35Sstevel is_present = 1; 273703831d35Sstevel } 273803831d35Sstevel } 273903831d35Sstevel if (is_present) { 274003831d35Sstevel /* 274103831d35Sstevel * If the FRU is a Power Supply, AND 274203831d35Sstevel * the call is from scsb_attach() OR 274303831d35Sstevel * from scsb_intr() and FRUs match, 274403831d35Sstevel * turn it on. 274503831d35Sstevel */ 274603831d35Sstevel if (fru_type == PS && (int_fru_ptr == NULL || 274703831d35Sstevel (int_fru_ptr == fru_ptr))) { 274803831d35Sstevel pao.scsb = scsb; 274903831d35Sstevel pao.utype = fru_type; 275003831d35Sstevel pao.unit = fru_ptr->fru_unit; 275103831d35Sstevel #ifdef PS_ON_DELAY 275203831d35Sstevel /* 275303831d35Sstevel * HW recommended not implementing 275403831d35Sstevel * this delay for now. 275503831d35Sstevel * The code is tested on PSUs: 275603831d35Sstevel * -06 275703831d35Sstevel * -07 rev 2 275803831d35Sstevel * -08 plus 275903831d35Sstevel */ 276003831d35Sstevel if (int_fru_ptr) { 276103831d35Sstevel /* 276203831d35Sstevel * Hot insertion, so give it 276303831d35Sstevel * the 3 seconds it needs to 276403831d35Sstevel * become stable 276503831d35Sstevel */ 276603831d35Sstevel if (!scsb->scsb_btid) 276703831d35Sstevel scsb->scsb_btid = 276819397407SSherry Moore timeout( 276919397407SSherry Moore scsb_ps_auto_on, 277003831d35Sstevel &pao, (4 * 277119397407SSherry Moore drv_usectohz( 277219397407SSherry Moore 1000000))); 277303831d35Sstevel } else 277403831d35Sstevel #endif /* PS_ON_DELAY */ 277503831d35Sstevel scsb_ps_auto_on((void *)&pao); 277603831d35Sstevel } 277703831d35Sstevel /* 277803831d35Sstevel * Special SLOT handling. 277903831d35Sstevel * Make sure the OK LED is on for the CPU Slot 278003831d35Sstevel * and for the FTC (CFTM) Slot for MonteCarlo. 278103831d35Sstevel * Both will report as FRU_PRESENT. 278203831d35Sstevel */ 278303831d35Sstevel if (fru_type != SLOT || (fru_type == SLOT && 278403831d35Sstevel (fru_ptr->fru_type == 278503831d35Sstevel (scsb_utype_t)OC_CPU || 278603831d35Sstevel fru_ptr->fru_type == 278703831d35Sstevel (scsb_utype_t)OC_CTC))) { 278803831d35Sstevel /* 278903831d35Sstevel * Set OK (green) LED register bit 279003831d35Sstevel */ 279103831d35Sstevel led_data[led_idx] |= 1 << led_bit; 279203831d35Sstevel } 279303831d35Sstevel if (IS_SCB_P10) 279403831d35Sstevel continue; 279503831d35Sstevel /* 279603831d35Sstevel * Turn off BLINK register bit. 279703831d35Sstevel * If single register update, then save the 279803831d35Sstevel * corresponding blink register in blink_reg. 279903831d35Sstevel */ 280003831d35Sstevel reg = fru_ptr->i2c_info->blink_reg; 280103831d35Sstevel if (!reg) 280203831d35Sstevel continue; 280303831d35Sstevel blink_bit = fru_ptr->i2c_info->blink_bit; 280403831d35Sstevel blink_idx = SCSB_REG_INDEX(reg) - bid; 280503831d35Sstevel blink[blink_idx] |= 1 << blink_bit; 280603831d35Sstevel if (update_reg && update_reg == led_reg) 280703831d35Sstevel blink_reg = reg; 280803831d35Sstevel } 280903831d35Sstevel } 281003831d35Sstevel } 281103831d35Sstevel if (update_reg) { 281203831d35Sstevel reg = update_reg; 281303831d35Sstevel i = SCSB_REG_INDEX(reg); 281403831d35Sstevel puc = &led_data[i - lid]; 281503831d35Sstevel i = 1; 281603831d35Sstevel } else { 281703831d35Sstevel reg = SCSB_REG_ADDR(SCTRL_LED_OK_BASE); 281803831d35Sstevel puc = led_data; 281903831d35Sstevel i = SCTRL_LED_OK_NUMREGS; 282003831d35Sstevel } 282103831d35Sstevel if (scsb_debug & 0x0100) { 282203831d35Sstevel cmn_err(CE_NOTE, "scsb_set_scfg_pres(): writing %d bytes " 282303831d35Sstevel "to 0x%x", i, reg); 282403831d35Sstevel } 282503831d35Sstevel if ((error = scsb_rdwr_register(scsb, I2C_WR, reg, i, puc, 1)) != 0) { 282603831d35Sstevel if (scsb_debug & 0x0102) 282703831d35Sstevel cmn_err(CE_NOTE, "scsb_set_scfg_pres(): " 282803831d35Sstevel "I2C write to 0x%x failed", reg); 282903831d35Sstevel error = EIO; 283003831d35Sstevel } else { 283103831d35Sstevel /* 283203831d35Sstevel * Now see which BLINK bits need to be turned off for the 283303831d35Sstevel * corresponding OK LED bits. 283403831d35Sstevel */ 283503831d35Sstevel reg = SCSB_REG_ADDR(SCTRL_BLINK_OK_BASE); 283603831d35Sstevel for (i = 0; i < SCTRL_BLINK_NUMREGS; ++i, ++reg) { 283703831d35Sstevel if (blink_reg && blink_reg != reg) 283803831d35Sstevel continue; 283903831d35Sstevel if (!blink[i]) { 284003831d35Sstevel continue; 284103831d35Sstevel } 284203831d35Sstevel if (scsb_debug & 0x0100) { 284303831d35Sstevel cmn_err(CE_NOTE, "scsb_set_scfg_pres(): turn " 284403831d35Sstevel "OFF Blink bits 0x%x in 0x%x", 284503831d35Sstevel blink[i], reg); 284603831d35Sstevel } 284703831d35Sstevel if (scsb_write_mask(scsb, reg, 0, 0, blink[i])) { 284803831d35Sstevel if (scsb_debug & 0x0102) 284903831d35Sstevel cmn_err(CE_NOTE, 285003831d35Sstevel "scsb_set_scfg_pres(): " 285103831d35Sstevel "Write to 0x%x failed", reg); 285203831d35Sstevel error = EIO; 285303831d35Sstevel break; 285403831d35Sstevel } 285503831d35Sstevel } 285603831d35Sstevel } 285703831d35Sstevel return (error); 285803831d35Sstevel } 285903831d35Sstevel 286003831d35Sstevel static int 286103831d35Sstevel scsb_check_config_status(scsb_state_t *scsb) 286203831d35Sstevel { 286303831d35Sstevel int error; 286403831d35Sstevel uchar_t reg; 286503831d35Sstevel int index, p06; 286603831d35Sstevel 286703831d35Sstevel if (scsb_debug & 0x0201) { 286803831d35Sstevel cmn_err(CE_NOTE, "scsb_check_config_status:"); 286903831d35Sstevel } 287003831d35Sstevel /* 287103831d35Sstevel * Base of register set 287203831d35Sstevel */ 287303831d35Sstevel reg = SCSB_REG_ADDR(SCTRL_SYSCFG_BASE); 287403831d35Sstevel index = SCSB_REG_INDEX(reg); 287503831d35Sstevel /* 287603831d35Sstevel * SCB P0.6 workaround: read registers twice, use 2nd value set 287703831d35Sstevel */ 287803831d35Sstevel mutex_enter(&scsb->scsb_mutex); 287903831d35Sstevel p06 = 2; 288003831d35Sstevel do { 288103831d35Sstevel if (error = scsb_rdwr_register(scsb, I2C_WR_RD, reg, 288203831d35Sstevel SCTRL_CFG_NUMREGS, &scsb->scsb_data_reg[index], 1)) { 288303831d35Sstevel break; 288403831d35Sstevel } 288503831d35Sstevel if (p06 == 1) { 288603831d35Sstevel if (scsb_debug & 0x0200) 288703831d35Sstevel cmn_err(CE_NOTE, 288803831d35Sstevel "scsb_check_config_status: P0.6 workaround"); 288903831d35Sstevel } 289003831d35Sstevel /* 289103831d35Sstevel * If not P0.6 PROM, just break here 289203831d35Sstevel */ 289303831d35Sstevel if (!(scsb->scsb_state & SCSB_P06_PROM)) 289403831d35Sstevel break; 289503831d35Sstevel } while (--p06); 289603831d35Sstevel mutex_exit(&scsb->scsb_mutex); 289703831d35Sstevel 289803831d35Sstevel if (error == 0) { 289903831d35Sstevel if (!(scsb->scsb_state & SCSB_SCB_PRESENT)) 290003831d35Sstevel scsb->scsb_state |= SCSB_SCB_PRESENT; 290103831d35Sstevel if (scsb_fru_op(scsb, SSB, 1, SCTRL_SYSCFG_BASE, 290203831d35Sstevel SCSB_FRU_OP_GET_BITVAL)) 290303831d35Sstevel scsb->scsb_state |= SCSB_SSB_PRESENT; 290403831d35Sstevel else 290503831d35Sstevel scsb->scsb_state &= ~SCSB_SSB_PRESENT; 290603831d35Sstevel } 290703831d35Sstevel return (error); 290803831d35Sstevel } 290903831d35Sstevel 291003831d35Sstevel static void 291103831d35Sstevel scsb_set_topology(scsb_state_t *scsb) 291203831d35Sstevel { 291303831d35Sstevel int i, t, index, unit, is_tonga = 0; 291403831d35Sstevel int alarm_slot_num, cpu_slot_num, ctc_slot_num; 291503831d35Sstevel fru_info_t *fru_ptr, *last_ptr, *acslot_ptr, *ctcslot_ptr; 291603831d35Sstevel uchar_t syscfg, led_reg, blink_reg, t_uchar; 291703831d35Sstevel uchar_t bit_num, led_bit, blink_bit; 291803831d35Sstevel int pad = 0; 291903831d35Sstevel 292003831d35Sstevel /* 292103831d35Sstevel * Get the presence status from the SysConfigStatus shadow registers 292203831d35Sstevel * in scsb->scsb_data_reg[] 292303831d35Sstevel */ 292403831d35Sstevel /* Mid Plane */ 292503831d35Sstevel i = SYS_REG_INDEX(SCTRL_CFG_MPID0, SCTRL_SYSCFG_BASE); 292603831d35Sstevel t_uchar = SCSB_REG_ADDR(i); 292703831d35Sstevel index = SCSB_REG_INDEX(t_uchar); 292803831d35Sstevel mct_system_info.mid_plane.fru_type = MIDPLANE; 292903831d35Sstevel mct_system_info.mid_plane.fru_version = (fru_version_t)0; 293003831d35Sstevel t = SYS_OFFSET(SCTRL_CFG_MPID0); 293103831d35Sstevel mct_system_info.mid_plane.fru_id = (int)((scsb->scsb_data_reg[index] & 293203831d35Sstevel (SCTRL_MPID_MASK << t)) >> t); 293303831d35Sstevel switch (mct_system_info.mid_plane.fru_id) { 293403831d35Sstevel case SCTRL_MPID_HALF: /* Monte Carlo */ 293503831d35Sstevel if (scsb_debug & 0x00100005) 293603831d35Sstevel cmn_err(CE_NOTE, "scsb_set_topology: Monte Carlo"); 293703831d35Sstevel cpu_slot_num = SC_MC_CPU_SLOT; 293803831d35Sstevel ctc_slot_num = SC_MC_CTC_SLOT; 293903831d35Sstevel alarm_slot_num = scsb->ac_slotnum = SC_MC_AC_SLOT; 294003831d35Sstevel mct_system_info.max_units[SLOT] = MC_MAX_SLOTS; 294103831d35Sstevel mct_system_info.max_units[ALARM] = MC_MAX_AC; 294203831d35Sstevel mct_system_info.max_units[DISK] = MC_MAX_DISK; 294303831d35Sstevel mct_system_info.max_units[FAN] = MC_MAX_FAN; 294403831d35Sstevel mct_system_info.max_units[PS] = MC_MAX_PS; 294503831d35Sstevel mct_system_info.max_units[PDU] = MC_MAX_PDU; 294603831d35Sstevel mct_system_info.max_units[SCB] = MC_MAX_SCB; 294703831d35Sstevel mct_system_info.max_units[SSB] = MC_MAX_SCB; 294803831d35Sstevel mct_system_info.max_units[CFTM] = MC_MAX_CFTM; 294903831d35Sstevel mct_system_info.max_units[CRTM] = MC_MAX_CRTM; 295003831d35Sstevel mct_system_info.max_units[PRTM] = MC_MAX_PRTM; 295103831d35Sstevel break; 295203831d35Sstevel case SCTRL_MPID_QUARTER_NODSK: /* Tonga w/o disk */ 295303831d35Sstevel case SCTRL_MPID_QUARTER: /* Tonga w/ disk */ 295403831d35Sstevel scsb->scsb_state |= SCSB_IS_TONGA; 295503831d35Sstevel is_tonga = 1; 295603831d35Sstevel ctc_slot_num = -1; 295703831d35Sstevel ctcslot_ptr = NULL; 295803831d35Sstevel if (scsb_debug & 0x00100005) 295903831d35Sstevel cmn_err(CE_NOTE, "scsb_set_topology: Tonga%s", 296003831d35Sstevel mct_system_info.mid_plane.fru_id == 296103831d35Sstevel SCTRL_MPID_QUARTER_NODSK ? 296203831d35Sstevel ", no disk" : " with disk"); 296303831d35Sstevel cpu_slot_num = SC_TG_CPU_SLOT; 296403831d35Sstevel alarm_slot_num = scsb->ac_slotnum = SC_TG_AC_SLOT; 296503831d35Sstevel mct_system_info.max_units[SLOT] = TG_MAX_SLOTS; 296603831d35Sstevel mct_system_info.max_units[ALARM] = TG_MAX_AC; 296703831d35Sstevel mct_system_info.max_units[DISK] = TG_MAX_DISK; 296803831d35Sstevel mct_system_info.max_units[FAN] = TG_MAX_FAN; 296903831d35Sstevel mct_system_info.max_units[PS] = TG_MAX_PS; 297003831d35Sstevel mct_system_info.max_units[PDU] = TG_MAX_PDU; 297103831d35Sstevel mct_system_info.max_units[SCB] = TG_MAX_SCB; 297203831d35Sstevel mct_system_info.max_units[SSB] = TG_MAX_SCB; 297303831d35Sstevel mct_system_info.max_units[CFTM] = TG_MAX_CFTM; 297403831d35Sstevel mct_system_info.max_units[CRTM] = TG_MAX_CRTM; 297503831d35Sstevel mct_system_info.max_units[PRTM] = TG_MAX_PRTM; 297603831d35Sstevel break; 297703831d35Sstevel default: 297803831d35Sstevel cmn_err(CE_WARN, "%s#%d: Unknown MidPlane Id %x", 297903831d35Sstevel ddi_driver_name(scsb->scsb_dev), 298003831d35Sstevel ddi_get_instance(scsb->scsb_dev), 298103831d35Sstevel mct_system_info.mid_plane.fru_id); 298203831d35Sstevel if (scsb_debug & 0x00100005) 298303831d35Sstevel cmn_err(CE_NOTE, "scsb_set_topology: 0x%x: unknown!", 298403831d35Sstevel mct_system_info.mid_plane.fru_id); 298503831d35Sstevel return; 298603831d35Sstevel } 298703831d35Sstevel /* 298803831d35Sstevel * cPCI Slots 298903831d35Sstevel * 299003831d35Sstevel * NOTE: The Tonga slot fru_unit needs to get mapped to the logical 299103831d35Sstevel * slot number in slot_table[]. The field is not in the slot_table 299203831d35Sstevel * at least until we know the format of the OBP slot table for the FCS 299303831d35Sstevel * release. 299403831d35Sstevel */ 299503831d35Sstevel mct_system_info.fru_info_list[SLOT] = (fru_info_t *) 299603831d35Sstevel kmem_zalloc(sizeof (fru_info_t) * 299719397407SSherry Moore (mct_system_info.max_units[SLOT] + pad), KM_SLEEP); 299803831d35Sstevel fru_ptr = mct_system_info.fru_info_list[SLOT]; 299903831d35Sstevel for (unit = 1; unit <= mct_system_info.max_units[SLOT]; ++unit) { 300003831d35Sstevel int iunit; 300103831d35Sstevel if (unit == cpu_slot_num) { 300203831d35Sstevel fru_ptr->fru_type = (scsb_utype_t)OC_CPU; 300303831d35Sstevel } else if (unit == ctc_slot_num) { 300403831d35Sstevel /* fru_ptr saved for Transition Card Presence check */ 300503831d35Sstevel ctcslot_ptr = fru_ptr; 300603831d35Sstevel fru_ptr->fru_type = (scsb_utype_t)OC_UNKN; 300703831d35Sstevel } else if (unit == alarm_slot_num) { 300803831d35Sstevel /* fru_ptr saved for Alarm Card Presence check below */ 300903831d35Sstevel acslot_ptr = fru_ptr; 301003831d35Sstevel fru_ptr->fru_type = (scsb_utype_t)OC_UNKN; 301103831d35Sstevel } else { 301203831d35Sstevel fru_ptr->fru_type = (scsb_utype_t)OC_UNKN; 301303831d35Sstevel } 301403831d35Sstevel /* 301503831d35Sstevel * Get the slot event code (t), then use it to get the 301603831d35Sstevel * slot bit-offsets for LED, BLINK, and SYSCFG registers. 301703831d35Sstevel * On a P1.5 Tonga, the internal slot number must be used to 301803831d35Sstevel * find the event code. 301903831d35Sstevel * The P1.0 Tonga does not get mapped due to a SSB difference. 302003831d35Sstevel */ 302103831d35Sstevel if (IS_SCB_P15) { 302203831d35Sstevel iunit = tonga_psl_to_ssl(scsb, unit); 302303831d35Sstevel t = FRU_UNIT_TO_EVCODE(SLOT, iunit); 302403831d35Sstevel } else { 302503831d35Sstevel t = FRU_UNIT_TO_EVCODE(SLOT, unit); 302603831d35Sstevel } 302703831d35Sstevel led_bit = FRU_OFFSET(t, SCTRL_LED_OK_BASE); 302803831d35Sstevel blink_bit = FRU_OFFSET(t, SCTRL_BLINK_OK_BASE); 302903831d35Sstevel blink_reg = FRU_REG_ADDR(t, SCTRL_BLINK_OK_BASE); 303003831d35Sstevel if (is_tonga && unit <= TG_MAX_SLOTS) { 303103831d35Sstevel bit_num = tonga_pslotnum_to_cfgbit(scsb, unit); 303203831d35Sstevel } else { 303303831d35Sstevel bit_num = FRU_OFFSET(t, SCTRL_SYSCFG_BASE); 303403831d35Sstevel } 303503831d35Sstevel /* 303603831d35Sstevel * get the registers addresses and shadow register index for 303703831d35Sstevel * the SYSCFG register 303803831d35Sstevel */ 303903831d35Sstevel syscfg = FRU_REG_ADDR(t, SCTRL_SYSCFG_BASE); 304003831d35Sstevel index = SCSB_REG_INDEX(syscfg); 304103831d35Sstevel led_reg = FRU_REG_ADDR(t, SCTRL_LED_OK_BASE); 304203831d35Sstevel /* 304303831d35Sstevel * check and set presence status 304403831d35Sstevel */ 304503831d35Sstevel if (scsb->scsb_state & SCSB_P06_PROM) { 304603831d35Sstevel fru_ptr->fru_status = FRU_NOT_PRESENT; 304703831d35Sstevel } else if (scsb->scsb_data_reg[index] & (1 << bit_num)) { 304803831d35Sstevel fru_ptr->fru_status = FRU_PRESENT; 304903831d35Sstevel } else { 305003831d35Sstevel fru_ptr->fru_status = FRU_NOT_PRESENT; 305103831d35Sstevel } 305203831d35Sstevel fru_ptr->fru_unit = (scsb_unum_t)unit; 305303831d35Sstevel fru_ptr->fru_id = fru_id_table[event_to_index( 305403831d35Sstevel FRU_UNIT_TO_EVCODE(SLOT, unit))]; 305503831d35Sstevel fru_ptr->fru_version = (fru_version_t)0; 305603831d35Sstevel fru_ptr->type_list = (fru_options_t *)NULL; 305703831d35Sstevel fru_ptr->i2c_info = (fru_i2c_info_t *) 305803831d35Sstevel kmem_zalloc(sizeof (fru_i2c_info_t), KM_SLEEP); 305903831d35Sstevel fru_ptr->i2c_info->syscfg_reg = syscfg; 306003831d35Sstevel fru_ptr->i2c_info->syscfg_bit = bit_num; 306103831d35Sstevel fru_ptr->i2c_info->ledata_reg = led_reg; 306203831d35Sstevel fru_ptr->i2c_info->ledata_bit = led_bit; 306303831d35Sstevel fru_ptr->i2c_info->blink_reg = blink_reg; 306403831d35Sstevel fru_ptr->i2c_info->blink_bit = blink_bit; 306503831d35Sstevel last_ptr = fru_ptr; 306603831d35Sstevel fru_ptr++; 306703831d35Sstevel last_ptr->next = fru_ptr; 306803831d35Sstevel } 306903831d35Sstevel last_ptr->next = (fru_info_t *)NULL; 307003831d35Sstevel /* 307103831d35Sstevel * PDU 307203831d35Sstevel */ 307303831d35Sstevel mct_system_info.fru_info_list[PDU] = (fru_info_t *) 307403831d35Sstevel kmem_zalloc(sizeof (fru_info_t) * 307519397407SSherry Moore (mct_system_info.max_units[PDU] + pad), KM_SLEEP); 307603831d35Sstevel fru_ptr = mct_system_info.fru_info_list[PDU]; 307703831d35Sstevel for (unit = 1; unit <= mct_system_info.max_units[PDU]; ++unit) { 307803831d35Sstevel fru_ptr->fru_type = PDU; 307903831d35Sstevel /* SCB15 */ 308003831d35Sstevel /* 308103831d35Sstevel * get the FRU event code (t), then use it to get the 308203831d35Sstevel * FRU bit-offsets for LED and SYSCFG registers 308303831d35Sstevel */ 308403831d35Sstevel t = FRU_UNIT_TO_EVCODE(PDU, unit); 308503831d35Sstevel led_bit = FRU_OFFSET(t, SCTRL_LED_OK_BASE); 308603831d35Sstevel bit_num = FRU_OFFSET(t, SCTRL_SYSCFG_BASE); 308703831d35Sstevel if (IS_SCB_P15) { 308803831d35Sstevel blink_bit = FRU_OFFSET(t, SCTRL_BLINK_OK_BASE); 308903831d35Sstevel i = FRU_REG_INDEX(t, SCTRL_BLINK_OK_BASE); 309003831d35Sstevel blink_reg = SCSB_REG_ADDR(i); 309103831d35Sstevel } else { 309203831d35Sstevel blink_bit = 0; 309303831d35Sstevel blink_reg = 0; 309403831d35Sstevel } 309503831d35Sstevel /* 309603831d35Sstevel * get the registers addresses and shadow register index for 309703831d35Sstevel * the SYSCFG register 309803831d35Sstevel */ 309903831d35Sstevel i = FRU_REG_INDEX(t, SCTRL_SYSCFG_BASE); 310003831d35Sstevel syscfg = SCSB_REG_ADDR(i); 310103831d35Sstevel index = SCSB_REG_INDEX(syscfg); 310203831d35Sstevel i = FRU_REG_INDEX(t, SCTRL_LED_OK_BASE); 310303831d35Sstevel led_reg = SCSB_REG_ADDR(i); 310403831d35Sstevel /* 310503831d35Sstevel * check and set presence status 310603831d35Sstevel */ 310703831d35Sstevel if (scsb->scsb_data_reg[index] & (1 << bit_num)) { 310803831d35Sstevel fru_ptr->fru_status = FRU_PRESENT; 310903831d35Sstevel fru_ptr->fru_version = (fru_version_t)0; 311003831d35Sstevel } else { 311103831d35Sstevel fru_ptr->fru_status = FRU_NOT_PRESENT; 311203831d35Sstevel fru_ptr->fru_version = (fru_version_t)0; 311303831d35Sstevel } 311403831d35Sstevel fru_ptr->fru_unit = (scsb_unum_t)unit; 311503831d35Sstevel fru_ptr->fru_id = fru_id_table[event_to_index(t)]; 311603831d35Sstevel fru_ptr->type_list = (fru_options_t *)NULL; 311703831d35Sstevel fru_ptr->i2c_info = (fru_i2c_info_t *) 311803831d35Sstevel kmem_zalloc(sizeof (fru_i2c_info_t), KM_SLEEP); 311903831d35Sstevel fru_ptr->i2c_info->syscfg_reg = syscfg; 312003831d35Sstevel fru_ptr->i2c_info->syscfg_bit = bit_num; 312103831d35Sstevel fru_ptr->i2c_info->ledata_reg = led_reg; 312203831d35Sstevel fru_ptr->i2c_info->ledata_bit = led_bit; 312303831d35Sstevel fru_ptr->i2c_info->blink_reg = blink_reg; 312403831d35Sstevel fru_ptr->i2c_info->blink_bit = blink_bit; 312503831d35Sstevel last_ptr = fru_ptr; 312603831d35Sstevel fru_ptr++; 312703831d35Sstevel last_ptr->next = fru_ptr; 312803831d35Sstevel } 312903831d35Sstevel last_ptr->next = (fru_info_t *)NULL; 313003831d35Sstevel /* 313103831d35Sstevel * Power Supplies 313203831d35Sstevel */ 313303831d35Sstevel mct_system_info.fru_info_list[PS] = (fru_info_t *) 313403831d35Sstevel kmem_zalloc(sizeof (fru_info_t) * 313519397407SSherry Moore (mct_system_info.max_units[PS] + pad), KM_SLEEP); 313603831d35Sstevel fru_ptr = mct_system_info.fru_info_list[PS]; 313703831d35Sstevel for (unit = 1; unit <= mct_system_info.max_units[PS]; ++unit) { 313803831d35Sstevel /* 313903831d35Sstevel * get the FRU event code (t), then use it to get the 314003831d35Sstevel * FRU bit-offsets for LED and SYSCFG registers 314103831d35Sstevel */ 314203831d35Sstevel t = FRU_UNIT_TO_EVCODE(PS, unit); 314303831d35Sstevel led_bit = FRU_OFFSET(t, SCTRL_LED_OK_BASE); 314403831d35Sstevel bit_num = FRU_OFFSET(t, SCTRL_SYSCFG_BASE); 314503831d35Sstevel if (IS_SCB_P15) { 314603831d35Sstevel blink_bit = FRU_OFFSET(t, SCTRL_BLINK_OK_BASE); 314703831d35Sstevel i = FRU_REG_INDEX(t, SCTRL_BLINK_OK_BASE); 314803831d35Sstevel blink_reg = SCSB_REG_ADDR(i); 314903831d35Sstevel } else { 315003831d35Sstevel blink_bit = 0; 315103831d35Sstevel blink_reg = 0; 315203831d35Sstevel } 315303831d35Sstevel /* 315403831d35Sstevel * get the registers addresses and shadow register index for 315503831d35Sstevel * the SYSCFG register 315603831d35Sstevel */ 315703831d35Sstevel i = FRU_REG_INDEX(t, SCTRL_SYSCFG_BASE); 315803831d35Sstevel syscfg = SCSB_REG_ADDR(i); 315903831d35Sstevel index = SCSB_REG_INDEX(syscfg); 316003831d35Sstevel i = FRU_REG_INDEX(t, SCTRL_LED_OK_BASE); 316103831d35Sstevel led_reg = SCSB_REG_ADDR(i); 316203831d35Sstevel /* 316303831d35Sstevel * check and set presence status 316403831d35Sstevel */ 316503831d35Sstevel if (scsb->scsb_data_reg[index] & (1 << bit_num)) { 316603831d35Sstevel fru_ptr->fru_status = FRU_PRESENT; 316703831d35Sstevel } else { 316803831d35Sstevel fru_ptr->fru_status = FRU_NOT_PRESENT; 316903831d35Sstevel } 317003831d35Sstevel fru_ptr->fru_type = PS; 317103831d35Sstevel fru_ptr->fru_unit = (scsb_unum_t)unit; 317203831d35Sstevel fru_ptr->fru_id = fru_id_table[event_to_index(t)]; 317303831d35Sstevel fru_ptr->fru_version = (fru_version_t)0; 317403831d35Sstevel fru_ptr->type_list = (fru_options_t *)NULL; 317503831d35Sstevel fru_ptr->i2c_info = (fru_i2c_info_t *) 317603831d35Sstevel kmem_zalloc(sizeof (fru_i2c_info_t), KM_SLEEP); 317703831d35Sstevel fru_ptr->i2c_info->syscfg_reg = syscfg; 317803831d35Sstevel fru_ptr->i2c_info->syscfg_bit = bit_num; 317903831d35Sstevel fru_ptr->i2c_info->ledata_reg = led_reg; 318003831d35Sstevel fru_ptr->i2c_info->ledata_bit = led_bit; 318103831d35Sstevel fru_ptr->i2c_info->blink_reg = blink_reg; 318203831d35Sstevel fru_ptr->i2c_info->blink_bit = blink_bit; 318303831d35Sstevel last_ptr = fru_ptr; 318403831d35Sstevel fru_ptr++; 318503831d35Sstevel last_ptr->next = fru_ptr; 318603831d35Sstevel } 318703831d35Sstevel last_ptr->next = (fru_info_t *)NULL; 318803831d35Sstevel /* 318903831d35Sstevel * SCSI Disks and removable media 319003831d35Sstevel */ 319103831d35Sstevel mct_system_info.fru_info_list[DISK] = (fru_info_t *) 319203831d35Sstevel kmem_zalloc(sizeof (fru_info_t) * 319319397407SSherry Moore (mct_system_info.max_units[DISK] + pad), KM_SLEEP); 319403831d35Sstevel fru_ptr = mct_system_info.fru_info_list[DISK]; 319503831d35Sstevel for (unit = 1; unit <= mct_system_info.max_units[DISK]; ++unit) { 319603831d35Sstevel /* SCB15 */ 319703831d35Sstevel /* 319803831d35Sstevel * get the FRU event code (t), then use it to get the 319903831d35Sstevel * FRU bit-offsets for LED and SYSCFG registers 320003831d35Sstevel */ 320103831d35Sstevel t = FRU_UNIT_TO_EVCODE(DISK, unit); 320203831d35Sstevel led_bit = FRU_OFFSET(t, SCTRL_LED_OK_BASE); 320303831d35Sstevel bit_num = FRU_OFFSET(t, SCTRL_SYSCFG_BASE); 320403831d35Sstevel if (IS_SCB_P15) { 320503831d35Sstevel blink_bit = FRU_OFFSET(t, SCTRL_BLINK_OK_BASE); 320603831d35Sstevel i = FRU_REG_INDEX(t, SCTRL_BLINK_OK_BASE); 320703831d35Sstevel blink_reg = SCSB_REG_ADDR(i); 320803831d35Sstevel } else { 320903831d35Sstevel blink_bit = 0; 321003831d35Sstevel blink_reg = 0; 321103831d35Sstevel } 321203831d35Sstevel /* 321303831d35Sstevel * get the registers addresses and shadow register index for 321403831d35Sstevel * the SYSCFG register 321503831d35Sstevel */ 321603831d35Sstevel i = FRU_REG_INDEX(t, SCTRL_SYSCFG_BASE); 321703831d35Sstevel syscfg = SCSB_REG_ADDR(i); 321803831d35Sstevel index = SCSB_REG_INDEX(syscfg); 321903831d35Sstevel i = FRU_REG_INDEX(t, SCTRL_LED_OK_BASE); 322003831d35Sstevel led_reg = SCSB_REG_ADDR(i); 322103831d35Sstevel /* 322203831d35Sstevel * check and set presence status 322303831d35Sstevel */ 322403831d35Sstevel if (scsb->scsb_data_reg[index] & (1 << bit_num)) { 322503831d35Sstevel fru_ptr->fru_status = FRU_PRESENT; 322603831d35Sstevel fru_ptr->fru_version = (fru_version_t)0; 322703831d35Sstevel } else 322803831d35Sstevel fru_ptr->fru_status = FRU_NOT_PRESENT; 322903831d35Sstevel fru_ptr->fru_type = DISK; 323003831d35Sstevel fru_ptr->fru_unit = (scsb_unum_t)unit; 323103831d35Sstevel fru_ptr->fru_id = fru_id_table[event_to_index(t)]; 323203831d35Sstevel fru_ptr->type_list = (fru_options_t *)NULL; 323303831d35Sstevel fru_ptr->i2c_info = (fru_i2c_info_t *) 323403831d35Sstevel kmem_zalloc(sizeof (fru_i2c_info_t), KM_SLEEP); 323503831d35Sstevel fru_ptr->i2c_info->syscfg_reg = syscfg; 323603831d35Sstevel fru_ptr->i2c_info->syscfg_bit = bit_num; 323703831d35Sstevel fru_ptr->i2c_info->ledata_reg = led_reg; 323803831d35Sstevel fru_ptr->i2c_info->ledata_bit = led_bit; 323903831d35Sstevel fru_ptr->i2c_info->blink_reg = blink_reg; 324003831d35Sstevel fru_ptr->i2c_info->blink_bit = blink_bit; 324103831d35Sstevel last_ptr = fru_ptr; 324203831d35Sstevel fru_ptr++; 324303831d35Sstevel last_ptr->next = fru_ptr; 324403831d35Sstevel } 324503831d35Sstevel last_ptr->next = (fru_info_t *)NULL; 324603831d35Sstevel /* 324703831d35Sstevel * Fan Trays 324803831d35Sstevel */ 324903831d35Sstevel mct_system_info.fru_info_list[FAN] = (fru_info_t *) 325003831d35Sstevel kmem_zalloc(sizeof (fru_info_t) * 325119397407SSherry Moore (mct_system_info.max_units[FAN] + pad), KM_SLEEP); 325203831d35Sstevel fru_ptr = mct_system_info.fru_info_list[FAN]; 325303831d35Sstevel for (unit = 1; unit <= mct_system_info.max_units[FAN]; ++unit) { 325403831d35Sstevel int bit_num; 325503831d35Sstevel /* SCB15 */ 325603831d35Sstevel /* 325703831d35Sstevel * get the FRU event code (t), then use it to get the 325803831d35Sstevel * FRU bit-offsets for LED and SYSCFG registers 325903831d35Sstevel */ 326003831d35Sstevel t = FRU_UNIT_TO_EVCODE(FAN, unit); 326103831d35Sstevel led_bit = FRU_OFFSET(t, SCTRL_LED_OK_BASE); 326203831d35Sstevel bit_num = FRU_OFFSET(t, SCTRL_SYSCFG_BASE); 326303831d35Sstevel if (IS_SCB_P15) { 326403831d35Sstevel blink_bit = FRU_OFFSET(t, SCTRL_BLINK_OK_BASE); 326503831d35Sstevel i = FRU_REG_INDEX(t, SCTRL_BLINK_OK_BASE); 326603831d35Sstevel blink_reg = SCSB_REG_ADDR(i); 326703831d35Sstevel } else { 326803831d35Sstevel blink_bit = 0; 326903831d35Sstevel blink_reg = 0; 327003831d35Sstevel } 327103831d35Sstevel /* 327203831d35Sstevel * get the registers addresses and shadow register index for 327303831d35Sstevel * the SYSCFG register 327403831d35Sstevel */ 327503831d35Sstevel i = FRU_REG_INDEX(t, SCTRL_SYSCFG_BASE); 327603831d35Sstevel syscfg = SCSB_REG_ADDR(i); 327703831d35Sstevel index = SCSB_REG_INDEX(syscfg); 327803831d35Sstevel i = FRU_REG_INDEX(t, SCTRL_LED_OK_BASE); 327903831d35Sstevel led_reg = SCSB_REG_ADDR(i); 328003831d35Sstevel /* 328103831d35Sstevel * check and set presence status 328203831d35Sstevel */ 328303831d35Sstevel if (scsb->scsb_data_reg[index] & (1 << bit_num)) { 328403831d35Sstevel fru_ptr->fru_status = FRU_PRESENT; 328503831d35Sstevel } else { 328603831d35Sstevel fru_ptr->fru_status = FRU_NOT_PRESENT; 328703831d35Sstevel } 328803831d35Sstevel fru_ptr->fru_type = FAN; 328903831d35Sstevel fru_ptr->fru_unit = (scsb_unum_t)unit; 329003831d35Sstevel fru_ptr->fru_id = fru_id_table[event_to_index(t)]; 329103831d35Sstevel fru_ptr->fru_version = (fru_version_t)0; 329203831d35Sstevel fru_ptr->type_list = (fru_options_t *)NULL; 329303831d35Sstevel fru_ptr->i2c_info = (fru_i2c_info_t *) 329403831d35Sstevel kmem_zalloc(sizeof (fru_i2c_info_t), KM_SLEEP); 329503831d35Sstevel fru_ptr->i2c_info->syscfg_reg = syscfg; 329603831d35Sstevel fru_ptr->i2c_info->syscfg_bit = bit_num; 329703831d35Sstevel fru_ptr->i2c_info->ledata_reg = led_reg; 329803831d35Sstevel fru_ptr->i2c_info->ledata_bit = led_bit; 329903831d35Sstevel fru_ptr->i2c_info->blink_reg = blink_reg; 330003831d35Sstevel fru_ptr->i2c_info->blink_bit = blink_bit; 330103831d35Sstevel last_ptr = fru_ptr; 330203831d35Sstevel fru_ptr++; 330303831d35Sstevel last_ptr->next = fru_ptr; 330403831d35Sstevel } 330503831d35Sstevel last_ptr->next = (fru_info_t *)NULL; 330603831d35Sstevel /* 330703831d35Sstevel * Alarm Cards 330803831d35Sstevel */ 330903831d35Sstevel mct_system_info.fru_info_list[ALARM] = (fru_info_t *) 331003831d35Sstevel kmem_zalloc(sizeof (fru_info_t) * 331119397407SSherry Moore (mct_system_info.max_units[ALARM] + pad), KM_SLEEP); 331203831d35Sstevel fru_ptr = mct_system_info.fru_info_list[ALARM]; 331303831d35Sstevel for (unit = 1; unit <= mct_system_info.max_units[ALARM]; ++unit) { 331403831d35Sstevel int bit_num; 331503831d35Sstevel 331603831d35Sstevel /* 331703831d35Sstevel * get the FRU event code (t), then use it to get the 331803831d35Sstevel * FRU bit-offsets for SYSCFG register 331903831d35Sstevel */ 332003831d35Sstevel t = FRU_UNIT_TO_EVCODE(ALARM, unit); 332103831d35Sstevel bit_num = FRU_OFFSET(t, SCTRL_SYSCFG_BASE); 332203831d35Sstevel /* 332303831d35Sstevel * get the registers addresses and shadow register index for 332403831d35Sstevel * the SYSCFG register 332503831d35Sstevel */ 332603831d35Sstevel i = FRU_REG_INDEX(t, SCTRL_SYSCFG_BASE); 332703831d35Sstevel syscfg = SCSB_REG_ADDR(i); 332803831d35Sstevel index = SCSB_REG_INDEX(syscfg); 332903831d35Sstevel /* 333003831d35Sstevel * check and set presence status 333103831d35Sstevel */ 333203831d35Sstevel if (scsb->scsb_data_reg[index] & (1 << bit_num)) { 333303831d35Sstevel fru_ptr->fru_status = FRU_PRESENT; 333403831d35Sstevel if (acslot_ptr != NULL && acslot_ptr->fru_status == 333503831d35Sstevel FRU_PRESENT) { 333603831d35Sstevel acslot_ptr->fru_type = (scsb_utype_t)OC_AC; 333703831d35Sstevel /* 333803831d35Sstevel * acslot_ptr->fru_id = 333903831d35Sstevel * fru_id_table[event_to_index(t)]; 334003831d35Sstevel */ 334103831d35Sstevel } 334203831d35Sstevel } else { 334303831d35Sstevel fru_ptr->fru_status = FRU_NOT_PRESENT; 334403831d35Sstevel } 334503831d35Sstevel 334603831d35Sstevel fru_ptr->fru_type = ALARM; 334703831d35Sstevel fru_ptr->fru_unit = (scsb_unum_t)unit; 334803831d35Sstevel fru_ptr->fru_id = fru_id_table[event_to_index(t)]; 334903831d35Sstevel fru_ptr->fru_version = (fru_version_t)0; 335003831d35Sstevel fru_ptr->type_list = (fru_options_t *)NULL; 335103831d35Sstevel fru_ptr->i2c_info = (fru_i2c_info_t *) 335203831d35Sstevel kmem_zalloc(sizeof (fru_i2c_info_t), KM_SLEEP); 335303831d35Sstevel fru_ptr->i2c_info->syscfg_reg = syscfg; 335403831d35Sstevel fru_ptr->i2c_info->syscfg_bit = bit_num; 335503831d35Sstevel fru_ptr->i2c_info->ledata_reg = 0; 335603831d35Sstevel fru_ptr->i2c_info->ledata_bit = 0; 335703831d35Sstevel fru_ptr->i2c_info->blink_reg = 0; 335803831d35Sstevel fru_ptr->i2c_info->blink_bit = 0; 335903831d35Sstevel last_ptr = fru_ptr; 336003831d35Sstevel fru_ptr++; 336103831d35Sstevel last_ptr->next = fru_ptr; 336203831d35Sstevel } 336303831d35Sstevel last_ptr->next = (fru_info_t *)NULL; 336403831d35Sstevel /* 336503831d35Sstevel * SCB 336603831d35Sstevel */ 336703831d35Sstevel mct_system_info.fru_info_list[SCB] = (fru_info_t *) 336803831d35Sstevel kmem_zalloc(sizeof (fru_info_t) * 336919397407SSherry Moore (mct_system_info.max_units[SCB] + pad), KM_SLEEP); 337003831d35Sstevel fru_ptr = mct_system_info.fru_info_list[SCB]; 337103831d35Sstevel unit = 1; 337203831d35Sstevel /* SCB15 */ 337303831d35Sstevel /* 337403831d35Sstevel * get the FRU event code (t), then use it to get the 337503831d35Sstevel * FRU bit-offset for LED register 337603831d35Sstevel */ 337703831d35Sstevel t = FRU_UNIT_TO_EVCODE(SCB, unit); 337803831d35Sstevel led_bit = FRU_OFFSET(t, SCTRL_LED_OK_BASE); 337903831d35Sstevel i = FRU_REG_INDEX(t, SCTRL_LED_OK_BASE); 338003831d35Sstevel led_reg = SCSB_REG_ADDR(i); 338103831d35Sstevel if (IS_SCB_P15) { 338203831d35Sstevel blink_bit = FRU_OFFSET(t, SCTRL_BLINK_OK_BASE); 338303831d35Sstevel i = FRU_REG_INDEX(t, SCTRL_BLINK_OK_BASE); 338403831d35Sstevel blink_reg = SCSB_REG_ADDR(i); 338503831d35Sstevel } else { 338603831d35Sstevel blink_bit = 0; 338703831d35Sstevel blink_reg = 0; 338803831d35Sstevel } 338903831d35Sstevel i = SYS_REG_INDEX(SCTRL_SCBID0, SCTRL_SCBID_BASE); 339003831d35Sstevel index = SCSB_REG_ADDR(i); 339103831d35Sstevel /* 339203831d35Sstevel * check and set presence status 339303831d35Sstevel */ 339403831d35Sstevel if (scsb->scsb_state & SCSB_SCB_PRESENT) { 339503831d35Sstevel fru_ptr->fru_status = FRU_PRESENT; 339603831d35Sstevel } else { 339703831d35Sstevel fru_ptr->fru_status = FRU_NOT_PRESENT; 339803831d35Sstevel } 339903831d35Sstevel fru_ptr->fru_type = SCB; 340003831d35Sstevel fru_ptr->fru_unit = (scsb_unum_t)unit; 340103831d35Sstevel fru_ptr->fru_id = fru_id_table[event_to_index(t)]; 340203831d35Sstevel /* get PROM_VERSION from shadow registers */ 340303831d35Sstevel if (scsb_rdwr_register(scsb, I2C_WR_RD, index, 1, &t_uchar, 1)) 340403831d35Sstevel fru_ptr->fru_version = (fru_version_t)0; 340503831d35Sstevel else 340603831d35Sstevel fru_ptr->fru_version = (fru_version_t)t_uchar; 340703831d35Sstevel fru_ptr->type_list = (fru_options_t *)NULL; 340803831d35Sstevel fru_ptr->i2c_info = (fru_i2c_info_t *) 340903831d35Sstevel kmem_zalloc(sizeof (fru_i2c_info_t), KM_SLEEP); 341003831d35Sstevel fru_ptr->i2c_info->syscfg_reg = 0; 341103831d35Sstevel fru_ptr->i2c_info->syscfg_bit = 0; 341203831d35Sstevel fru_ptr->i2c_info->ledata_reg = led_reg; 341303831d35Sstevel fru_ptr->i2c_info->ledata_bit = led_bit; 341403831d35Sstevel fru_ptr->i2c_info->blink_reg = blink_reg; 341503831d35Sstevel fru_ptr->i2c_info->blink_bit = blink_bit; 341603831d35Sstevel fru_ptr->next = (fru_info_t *)NULL; 341703831d35Sstevel /* 341803831d35Sstevel * SSB 341903831d35Sstevel */ 342003831d35Sstevel mct_system_info.fru_info_list[SSB] = (fru_info_t *) 342103831d35Sstevel kmem_zalloc(sizeof (fru_info_t) * 342219397407SSherry Moore (mct_system_info.max_units[SSB] + pad), KM_SLEEP); 342303831d35Sstevel fru_ptr = mct_system_info.fru_info_list[SSB]; 342403831d35Sstevel unit = 1; 342503831d35Sstevel /* SCB15 */ 342603831d35Sstevel /* 342703831d35Sstevel * get the FRU event code (t), then use it to get the 342803831d35Sstevel * FRU bit-offset for SYSCFG register 342903831d35Sstevel */ 343003831d35Sstevel t = FRU_UNIT_TO_EVCODE(SSB, unit); 343103831d35Sstevel bit_num = FRU_OFFSET(t, SCTRL_SYSCFG_BASE); 343203831d35Sstevel /* 343303831d35Sstevel * get the registers addresses and shadow register index for 343403831d35Sstevel * the SYSCFG register 343503831d35Sstevel */ 343603831d35Sstevel i = FRU_REG_INDEX(t, SCTRL_SYSCFG_BASE); 343703831d35Sstevel syscfg = SCSB_REG_ADDR(i); 343803831d35Sstevel index = SCSB_REG_INDEX(syscfg); 343903831d35Sstevel /* 344003831d35Sstevel * check and set presence status 344103831d35Sstevel */ 344203831d35Sstevel if (scsb->scsb_data_reg[index] & (1 << bit_num)) { 344303831d35Sstevel fru_ptr->fru_status = FRU_PRESENT; 344403831d35Sstevel } else { 344503831d35Sstevel fru_ptr->fru_status = FRU_NOT_PRESENT; 344603831d35Sstevel } 344703831d35Sstevel fru_ptr->fru_type = SSB; 344803831d35Sstevel fru_ptr->fru_unit = (scsb_unum_t)unit; 344903831d35Sstevel fru_ptr->fru_id = fru_id_table[event_to_index(t)]; 345003831d35Sstevel fru_ptr->fru_version = (fru_version_t)0; 345103831d35Sstevel fru_ptr->type_list = (fru_options_t *)NULL; 345203831d35Sstevel fru_ptr->i2c_info = (fru_i2c_info_t *) 345303831d35Sstevel kmem_zalloc(sizeof (fru_i2c_info_t), KM_SLEEP); 345403831d35Sstevel fru_ptr->i2c_info->syscfg_reg = syscfg; 345503831d35Sstevel fru_ptr->i2c_info->syscfg_bit = bit_num; 345603831d35Sstevel fru_ptr->i2c_info->ledata_reg = 0; 345703831d35Sstevel fru_ptr->i2c_info->ledata_bit = 0; 345803831d35Sstevel fru_ptr->i2c_info->blink_reg = 0; 345903831d35Sstevel fru_ptr->i2c_info->blink_bit = 0; 346003831d35Sstevel fru_ptr->next = (fru_info_t *)NULL; 346103831d35Sstevel /* 346203831d35Sstevel * CFTM 346303831d35Sstevel */ 346403831d35Sstevel mct_system_info.fru_info_list[CFTM] = (fru_info_t *) 346503831d35Sstevel kmem_zalloc(sizeof (fru_info_t) * 346619397407SSherry Moore (mct_system_info.max_units[CFTM] + pad), KM_SLEEP); 346703831d35Sstevel fru_ptr = mct_system_info.fru_info_list[CFTM]; 346803831d35Sstevel unit = 1; 346903831d35Sstevel /* SCB15 */ 347003831d35Sstevel /* 347103831d35Sstevel * get the FRU event code (t), then use it to get the 347203831d35Sstevel * FRU bit-offsets for LED and SYSCFG registers 347303831d35Sstevel */ 347403831d35Sstevel t = FRU_UNIT_TO_EVCODE(CFTM, unit); 347503831d35Sstevel led_bit = FRU_OFFSET(t, SCTRL_LED_OK_BASE); 347603831d35Sstevel bit_num = FRU_OFFSET(t, SCTRL_SYSCFG_BASE); 347703831d35Sstevel if (IS_SCB_P15) { 347803831d35Sstevel blink_bit = FRU_OFFSET(t, SCTRL_BLINK_OK_BASE); 347903831d35Sstevel i = FRU_REG_INDEX(t, SCTRL_BLINK_OK_BASE); 348003831d35Sstevel blink_reg = SCSB_REG_ADDR(i); 348103831d35Sstevel } else { 348203831d35Sstevel blink_bit = 0; 348303831d35Sstevel blink_reg = 0; 348403831d35Sstevel } 348503831d35Sstevel /* 348603831d35Sstevel * get the registers addresses and shadow register index for 348703831d35Sstevel * the SYSCFG register 348803831d35Sstevel */ 348903831d35Sstevel i = FRU_REG_INDEX(t, SCTRL_SYSCFG_BASE); 349003831d35Sstevel syscfg = SCSB_REG_ADDR(i); 349103831d35Sstevel index = SCSB_REG_INDEX(syscfg); 349203831d35Sstevel i = FRU_REG_INDEX(t, SCTRL_LED_OK_BASE); 349303831d35Sstevel led_reg = SCSB_REG_ADDR(i); 349403831d35Sstevel /* 349503831d35Sstevel * check and set presence status 349603831d35Sstevel */ 349703831d35Sstevel if (scsb->scsb_data_reg[index] & (1 << bit_num)) { 349803831d35Sstevel fru_ptr->fru_status = FRU_PRESENT; 349903831d35Sstevel if (ctcslot_ptr != NULL && ctcslot_ptr->fru_status == 350003831d35Sstevel FRU_PRESENT) { 350103831d35Sstevel ctcslot_ptr->fru_type = (scsb_utype_t)OC_CTC; 350203831d35Sstevel scsb->scsb_hsc_state |= SCSB_HSC_CTC_PRES; 350303831d35Sstevel } 350403831d35Sstevel } else { 350503831d35Sstevel fru_ptr->fru_status = FRU_NOT_PRESENT; 350603831d35Sstevel } 350703831d35Sstevel fru_ptr->fru_type = CFTM; 350803831d35Sstevel fru_ptr->fru_unit = (scsb_unum_t)1; 350903831d35Sstevel fru_ptr->fru_id = fru_id_table[event_to_index(t)]; 351003831d35Sstevel fru_ptr->fru_version = (fru_version_t)0; 351103831d35Sstevel fru_ptr->type_list = (fru_options_t *)NULL; 351203831d35Sstevel fru_ptr->i2c_info = (fru_i2c_info_t *) 351303831d35Sstevel kmem_zalloc(sizeof (fru_i2c_info_t), KM_SLEEP); 351403831d35Sstevel fru_ptr->i2c_info->syscfg_reg = syscfg; 351503831d35Sstevel fru_ptr->i2c_info->syscfg_bit = bit_num; 351603831d35Sstevel fru_ptr->i2c_info->ledata_reg = led_reg; 351703831d35Sstevel fru_ptr->i2c_info->ledata_bit = led_bit; 351803831d35Sstevel fru_ptr->i2c_info->blink_reg = blink_reg; 351903831d35Sstevel fru_ptr->i2c_info->blink_bit = blink_bit; 352003831d35Sstevel fru_ptr->next = (fru_info_t *)NULL; 352103831d35Sstevel /* 352203831d35Sstevel * CRTM 352303831d35Sstevel */ 352403831d35Sstevel mct_system_info.fru_info_list[CRTM] = (fru_info_t *) 352503831d35Sstevel kmem_zalloc(sizeof (fru_info_t) * 352603831d35Sstevel (mct_system_info.max_units[CRTM] + pad), 352703831d35Sstevel KM_SLEEP); 352803831d35Sstevel fru_ptr = mct_system_info.fru_info_list[CRTM]; 352903831d35Sstevel unit = 1; 353003831d35Sstevel /* SCB15 */ 353103831d35Sstevel /* 353203831d35Sstevel * get the FRU event code (t), then use it to get the 353303831d35Sstevel * FRU bit-offsets for LED and SYSCFG registers 353403831d35Sstevel */ 353503831d35Sstevel t = FRU_UNIT_TO_EVCODE(CRTM, unit); 353603831d35Sstevel bit_num = FRU_OFFSET(t, SCTRL_SYSCFG_BASE); 353703831d35Sstevel /* 353803831d35Sstevel * get the registers addresses and shadow register index for 353903831d35Sstevel * the SYSCFG register 354003831d35Sstevel */ 354103831d35Sstevel i = FRU_REG_INDEX(t, SCTRL_SYSCFG_BASE); 354203831d35Sstevel syscfg = SCSB_REG_ADDR(i); 354303831d35Sstevel index = SCSB_REG_INDEX(syscfg); 354403831d35Sstevel /* 354503831d35Sstevel * check and set presence status 354603831d35Sstevel */ 354703831d35Sstevel if (scsb->scsb_data_reg[index] & (1 << bit_num)) { 354803831d35Sstevel fru_ptr->fru_status = FRU_PRESENT; 354903831d35Sstevel } else { 355003831d35Sstevel fru_ptr->fru_status = FRU_NOT_PRESENT; 355103831d35Sstevel } 355203831d35Sstevel fru_ptr->fru_type = CRTM; 355303831d35Sstevel fru_ptr->fru_unit = (scsb_unum_t)unit; 355403831d35Sstevel fru_ptr->fru_id = fru_id_table[event_to_index(t)]; 355503831d35Sstevel fru_ptr->fru_version = (fru_version_t)0; 355603831d35Sstevel fru_ptr->type_list = (fru_options_t *)NULL; 355703831d35Sstevel fru_ptr->i2c_info = (fru_i2c_info_t *) 355803831d35Sstevel kmem_zalloc(sizeof (fru_i2c_info_t), KM_SLEEP); 355903831d35Sstevel fru_ptr->i2c_info->syscfg_reg = syscfg; 356003831d35Sstevel fru_ptr->i2c_info->syscfg_bit = bit_num; 356103831d35Sstevel fru_ptr->i2c_info->ledata_reg = 0; 356203831d35Sstevel fru_ptr->i2c_info->ledata_bit = 0; 356303831d35Sstevel fru_ptr->i2c_info->blink_reg = 0; 356403831d35Sstevel fru_ptr->i2c_info->blink_bit = 0; 356503831d35Sstevel fru_ptr->next = (fru_info_t *)NULL; 356603831d35Sstevel /* 356703831d35Sstevel * PRTM 356803831d35Sstevel */ 356903831d35Sstevel mct_system_info.fru_info_list[PRTM] = (fru_info_t *) 357003831d35Sstevel kmem_zalloc(sizeof (fru_info_t) * 357119397407SSherry Moore (mct_system_info.max_units[PRTM] + pad), KM_SLEEP); 357203831d35Sstevel fru_ptr = mct_system_info.fru_info_list[PRTM]; 357303831d35Sstevel unit = 1; 357403831d35Sstevel /* 357503831d35Sstevel * SCB15 357603831d35Sstevel * get the FRU event code (t), then use it to get the 357703831d35Sstevel * FRU bit-offsets for LED and SYSCFG registers 357803831d35Sstevel */ 357903831d35Sstevel t = FRU_UNIT_TO_EVCODE(PRTM, unit); 358003831d35Sstevel bit_num = FRU_OFFSET(t, SCTRL_SYSCFG_BASE); 358103831d35Sstevel /* 358203831d35Sstevel * get the registers addresses and shadow register index for 358303831d35Sstevel * the SYSCFG register 358403831d35Sstevel */ 358503831d35Sstevel i = FRU_REG_INDEX(t, SCTRL_SYSCFG_BASE); 358603831d35Sstevel syscfg = SCSB_REG_ADDR(i); 358703831d35Sstevel index = SCSB_REG_INDEX(syscfg); 358803831d35Sstevel /* 358903831d35Sstevel * check and set presence status 359003831d35Sstevel */ 359103831d35Sstevel if (scsb->scsb_data_reg[index] & (1 << bit_num)) { 359203831d35Sstevel fru_ptr->fru_status = FRU_PRESENT; 359303831d35Sstevel } else { 359403831d35Sstevel fru_ptr->fru_status = FRU_NOT_PRESENT; 359503831d35Sstevel } 359603831d35Sstevel fru_ptr->fru_type = PRTM; 359703831d35Sstevel fru_ptr->fru_unit = (scsb_unum_t)unit; 359803831d35Sstevel fru_ptr->fru_id = fru_id_table[event_to_index(t)]; 359903831d35Sstevel fru_ptr->fru_version = (fru_version_t)0; 360003831d35Sstevel fru_ptr->type_list = (fru_options_t *)NULL; 360103831d35Sstevel fru_ptr->i2c_info = (fru_i2c_info_t *) 360203831d35Sstevel kmem_zalloc(sizeof (fru_i2c_info_t), KM_SLEEP); 360303831d35Sstevel fru_ptr->i2c_info->syscfg_reg = syscfg; 360403831d35Sstevel fru_ptr->i2c_info->syscfg_bit = bit_num; 360503831d35Sstevel fru_ptr->i2c_info->ledata_reg = 0; 360603831d35Sstevel fru_ptr->i2c_info->ledata_bit = 0; 360703831d35Sstevel fru_ptr->i2c_info->blink_reg = 0; 360803831d35Sstevel fru_ptr->i2c_info->blink_bit = 0; 360903831d35Sstevel fru_ptr->next = (fru_info_t *)NULL; 361003831d35Sstevel 361103831d35Sstevel scsb->scsb_state |= SCSB_TOPOLOGY; 361203831d35Sstevel #ifdef DEBUG 361303831d35Sstevel mct_topology_dump(scsb, 0); 361403831d35Sstevel #endif 361503831d35Sstevel } 361603831d35Sstevel 361703831d35Sstevel /*ARGSUSED*/ 361803831d35Sstevel static void 361903831d35Sstevel scsb_free_topology(scsb_state_t *scsb) 362003831d35Sstevel { 362103831d35Sstevel int i; 362203831d35Sstevel fru_info_t *fru_ptr; 362303831d35Sstevel 362403831d35Sstevel if (scsb_debug & 0x00100005) 362503831d35Sstevel cmn_err(CE_NOTE, "scsb_free_topology:"); 362603831d35Sstevel for (i = 0; i < SCSB_UNIT_TYPES; ++i) { 362703831d35Sstevel fru_ptr = mct_system_info.fru_info_list[i]; 362803831d35Sstevel while (fru_ptr != NULL) { 362903831d35Sstevel if (fru_ptr->i2c_info != (fru_i2c_info_t *)NULL) 363003831d35Sstevel kmem_free(fru_ptr->i2c_info, 363103831d35Sstevel sizeof (fru_i2c_info_t)); 363203831d35Sstevel fru_ptr = fru_ptr->next; 363303831d35Sstevel } 363403831d35Sstevel if ((fru_ptr = mct_system_info.fru_info_list[i]) != 363503831d35Sstevel (fru_info_t *)NULL) { 363603831d35Sstevel kmem_free(fru_ptr, sizeof (fru_info_t) * 363703831d35Sstevel mct_system_info.max_units[i]); 363803831d35Sstevel mct_system_info.fru_info_list[i] = (fru_info_t *)NULL; 363903831d35Sstevel } 364003831d35Sstevel } 364103831d35Sstevel } 364203831d35Sstevel 364303831d35Sstevel #ifdef DEBUG 364403831d35Sstevel static void 364503831d35Sstevel mct_topology_dump(scsb_state_t *scsb, int force) 364603831d35Sstevel { 364703831d35Sstevel int i; 364803831d35Sstevel fru_info_t *fru_ptr; 364903831d35Sstevel 365003831d35Sstevel if (!force && !(scsb_debug & 0x00200000)) 365103831d35Sstevel return; 365203831d35Sstevel if (force && !(scsb->scsb_state & (SCSB_DIAGS_MODE | SCSB_DEBUG_MODE))) 365303831d35Sstevel return; 365403831d35Sstevel if (!(scsb->scsb_state & SCSB_TOPOLOGY)) { 365503831d35Sstevel cmn_err(CE_NOTE, "mct_topology_dump: Topology not set!"); 365603831d35Sstevel return; 365703831d35Sstevel } 365803831d35Sstevel for (i = 0; i < SCSB_UNIT_TYPES; ++i) { 365903831d35Sstevel fru_ptr = mct_system_info.fru_info_list[i]; 366003831d35Sstevel switch ((scsb_utype_t)i) { 366103831d35Sstevel case SLOT: 366203831d35Sstevel cmn_err(CE_NOTE, "MCT: Number of Slots: %d", 366303831d35Sstevel mct_system_info.max_units[SLOT]); 366403831d35Sstevel break; 366503831d35Sstevel case ALARM: 366603831d35Sstevel cmn_err(CE_NOTE, "MCT: MAX Number of Alarm Cards: %d", 366703831d35Sstevel mct_system_info.max_units[ALARM]); 366803831d35Sstevel break; 366903831d35Sstevel case DISK: 367003831d35Sstevel cmn_err(CE_NOTE, "MCT: MAX Number of SCSI Devices: %d", 367103831d35Sstevel mct_system_info.max_units[DISK]); 367203831d35Sstevel break; 367303831d35Sstevel case FAN: 367403831d35Sstevel cmn_err(CE_NOTE, "MCT: MAX Number of Fan Trays: %d", 367503831d35Sstevel mct_system_info.max_units[FAN]); 367603831d35Sstevel break; 367703831d35Sstevel case PDU: 367803831d35Sstevel cmn_err(CE_NOTE, "MCT: MAX Number of PDUs: %d", 367903831d35Sstevel mct_system_info.max_units[PDU]); 368003831d35Sstevel break; 368103831d35Sstevel case PS: 368203831d35Sstevel cmn_err(CE_NOTE, 368303831d35Sstevel "MCT: MAX Number of Power Supplies: %d", 368403831d35Sstevel mct_system_info.max_units[PS]); 368503831d35Sstevel break; 368603831d35Sstevel case SCB: 368703831d35Sstevel cmn_err(CE_NOTE, "MCT: MAX Number of SCBs: %d", 368803831d35Sstevel mct_system_info.max_units[SCB]); 368903831d35Sstevel break; 369003831d35Sstevel case SSB: 369103831d35Sstevel cmn_err(CE_NOTE, "MCT: MAX Number of SSBs: %d", 369203831d35Sstevel mct_system_info.max_units[SSB]); 369303831d35Sstevel break; 369403831d35Sstevel } 369503831d35Sstevel while (fru_ptr != NULL) { 369603831d35Sstevel if (fru_ptr->fru_status & FRU_PRESENT) { 369703831d35Sstevel cmn_err(CE_NOTE, 369803831d35Sstevel "MCT: type=%d, unit=%d, id=0x%x, " 369903831d35Sstevel "version=0x%x", 370003831d35Sstevel fru_ptr->fru_type, 370103831d35Sstevel fru_ptr->fru_unit, 370203831d35Sstevel fru_ptr->fru_id, 370303831d35Sstevel fru_ptr->fru_version); 370403831d35Sstevel } 370503831d35Sstevel fru_ptr = fru_ptr->next; 370603831d35Sstevel } 370703831d35Sstevel } 370803831d35Sstevel } 370903831d35Sstevel 371003831d35Sstevel /* 371103831d35Sstevel * Sends an event when the system controller board I2C errors 371203831d35Sstevel * exceed the threshold. 371303831d35Sstevel */ 371403831d35Sstevel static void 371503831d35Sstevel scsb_failing_event(scsb_state_t *scsb) 371603831d35Sstevel { 371703831d35Sstevel uint32_t scsb_event_code = SCTRL_EVENT_SCB; 371803831d35Sstevel 371903831d35Sstevel add_event_code(scsb, scsb_event_code); 372003831d35Sstevel (void) scsb_queue_ops(scsb, QPUT_INT32, 1, &scsb_event_code, 372103831d35Sstevel "scsb_intr"); 372203831d35Sstevel } 372303831d35Sstevel #endif 372403831d35Sstevel 372503831d35Sstevel int 372603831d35Sstevel scsb_read_bhealthy(scsb_state_t *scsb) 372703831d35Sstevel { 372803831d35Sstevel int error; 372903831d35Sstevel uchar_t reg; 373003831d35Sstevel int index; 373103831d35Sstevel 373203831d35Sstevel if (scsb_debug & 0x8001) { 373303831d35Sstevel cmn_err(CE_NOTE, "scsb_read_bhealthy()"); 373403831d35Sstevel } 373503831d35Sstevel reg = SCSB_REG_ADDR(SCTRL_BHLTHY_BASE); 373603831d35Sstevel index = SCSB_REG_INDEX(reg); 373703831d35Sstevel error = scsb_rdwr_register(scsb, I2C_WR_RD, reg, 373803831d35Sstevel SCTRL_BHLTHY_NUMREGS, &scsb->scsb_data_reg[index], 1); 373903831d35Sstevel return (error); 374003831d35Sstevel } 374103831d35Sstevel 374203831d35Sstevel /* 374303831d35Sstevel * Returns the health status of a slot 374403831d35Sstevel */ 374503831d35Sstevel int 374603831d35Sstevel scsb_read_slot_health(scsb_state_t *scsb, int pslotnum) 374703831d35Sstevel { 374803831d35Sstevel int slotnum = tonga_psl_to_ssl(scsb, pslotnum); 374903831d35Sstevel return (scsb_fru_op(scsb, SLOT, slotnum, 375003831d35Sstevel SCTRL_BHLTHY_BASE, SCSB_FRU_OP_GET_BITVAL)); 375103831d35Sstevel } 375203831d35Sstevel 375303831d35Sstevel /* 375403831d35Sstevel * DIAGNOSTIC and DEBUG only. 375503831d35Sstevel * Called from ioctl command (SCSBIOC_BHEALTHY_GET) 375603831d35Sstevel */ 375703831d35Sstevel int 375803831d35Sstevel scsb_bhealthy_slot(scsb_state_t *scsb, scsb_uinfo_t *suip) 375903831d35Sstevel { 376003831d35Sstevel int error = 0; 376103831d35Sstevel int base, code, unit_number; 376203831d35Sstevel uchar_t reg; 376303831d35Sstevel int index; 376403831d35Sstevel 376503831d35Sstevel if (scsb->scsb_state & SCSB_FROZEN) 376603831d35Sstevel return (EAGAIN); 376703831d35Sstevel 376803831d35Sstevel /* operation valid for slots only */ 376903831d35Sstevel if (suip == NULL || suip->unit_type != SLOT) { 377003831d35Sstevel return (EINVAL); 377103831d35Sstevel } 377203831d35Sstevel 377303831d35Sstevel if (scsb_debug & 0x8001) 377403831d35Sstevel cmn_err(CE_NOTE, "scsb_bhealthy_slot: slot %d", 377503831d35Sstevel suip->unit_number); 377603831d35Sstevel if (suip->unit_number > mct_system_info.max_units[SLOT]) { 377703831d35Sstevel return (EINVAL); 377803831d35Sstevel } 377903831d35Sstevel /* 378003831d35Sstevel * Map 1.0 Tonga Slot Number, if necessary 378103831d35Sstevel */ 378203831d35Sstevel tonga_slotnum_check(scsb, suip); 378303831d35Sstevel base = SCTRL_BHLTHY_BASE; 378403831d35Sstevel code = FRU_UNIT_TO_EVCODE(suip->unit_type, suip->unit_number); 378503831d35Sstevel unit_number = FRU_OFFSET(code, base); 378603831d35Sstevel index = FRU_REG_INDEX(code, base); 378703831d35Sstevel reg = SCSB_REG_ADDR(index); 378803831d35Sstevel index = SCSB_REG_INDEX(reg); /* shadow index */ 378903831d35Sstevel 379003831d35Sstevel if (scsb->scsb_state & SCSB_P10_PROM) { 379103831d35Sstevel error = scsb_read_bhealthy(scsb); 379203831d35Sstevel } 379303831d35Sstevel /* else shadow regs are updated by interrupt handler */ 379403831d35Sstevel if (error == 0) { 379503831d35Sstevel if (scsb->scsb_data_reg[index] & (1 << unit_number)) 379603831d35Sstevel suip->unit_state = ON; 379703831d35Sstevel else 379803831d35Sstevel suip->unit_state = OFF; 379903831d35Sstevel } 380003831d35Sstevel return (error); 380103831d35Sstevel } 380203831d35Sstevel 380303831d35Sstevel /* 380403831d35Sstevel * Called from HSC and ioctl command (SCSBIOC_RESET_UNIT) 380503831d35Sstevel * to reset one specified slot 380603831d35Sstevel */ 380703831d35Sstevel int 380803831d35Sstevel scsb_reset_unit(scsb_state_t *scsb, scsb_uinfo_t *suip) 380903831d35Sstevel { 381003831d35Sstevel int error; 381103831d35Sstevel int unit_number; 381203831d35Sstevel uchar_t reg; 381303831d35Sstevel int index, slotnum, reset_state; 381403831d35Sstevel 381503831d35Sstevel if (scsb->scsb_state & SCSB_FROZEN) 381603831d35Sstevel return (EAGAIN); 381703831d35Sstevel if (scsb_debug & 0x8001) { 381803831d35Sstevel cmn_err(CE_NOTE, "scsb_reset_slot(%d): slot %d, state %d\n", 381903831d35Sstevel scsb->scsb_instance, suip->unit_number, 382003831d35Sstevel suip->unit_state); 382103831d35Sstevel } 382203831d35Sstevel if (suip->unit_type != ALARM && !(scsb->scsb_state & 382303831d35Sstevel (SCSB_DIAGS_MODE | SCSB_DEBUG_MODE))) { 382403831d35Sstevel return (EINVAL); 382503831d35Sstevel } 382603831d35Sstevel if (suip->unit_state != ON && suip->unit_state != OFF) { 382703831d35Sstevel return (EINVAL); 382803831d35Sstevel } 382903831d35Sstevel error = 0; 383003831d35Sstevel switch (suip->unit_type) { 383103831d35Sstevel case ALARM: 383203831d35Sstevel { 383303831d35Sstevel int i, code; 383403831d35Sstevel if (suip->unit_number != 1) 383503831d35Sstevel return (EINVAL); 383603831d35Sstevel code = FRU_UNIT_TO_EVCODE(suip->unit_type, suip->unit_number); 383703831d35Sstevel unit_number = FRU_OFFSET(code, SCTRL_RESET_BASE); 383803831d35Sstevel i = ALARM_RESET_REG_INDEX(code, SCTRL_RESET_BASE); 383903831d35Sstevel reg = SCSB_REG_ADDR(i); 384003831d35Sstevel break; 384103831d35Sstevel } 384203831d35Sstevel case SLOT: 384303831d35Sstevel slotnum = suip->unit_number; 384403831d35Sstevel reset_state = (suip->unit_state == ON) ? SCSB_RESET_SLOT : 384503831d35Sstevel SCSB_UNRESET_SLOT; 384603831d35Sstevel if (scsb->scsb_state & SCSB_IS_TONGA) { 384703831d35Sstevel if (slotnum > TG_MAX_SLOTS || 384803831d35Sstevel slotnum == SC_TG_CPU_SLOT) { 384903831d35Sstevel return (EINVAL); 385003831d35Sstevel } 385103831d35Sstevel } else { 385203831d35Sstevel if (slotnum > MC_MAX_SLOTS || 385303831d35Sstevel slotnum == SC_MC_CPU_SLOT || 385403831d35Sstevel (scsb->scsb_hsc_state & SCSB_HSC_CTC_PRES && 385503831d35Sstevel slotnum == SC_MC_CTC_SLOT)) { 385603831d35Sstevel return (EINVAL); 385703831d35Sstevel } 385803831d35Sstevel } 385903831d35Sstevel return (scsb_reset_slot(scsb, slotnum, reset_state)); 386003831d35Sstevel default: 386103831d35Sstevel return (EINVAL); 386203831d35Sstevel } 386303831d35Sstevel index = SCSB_REG_INDEX(reg); 386403831d35Sstevel mutex_enter(&scsb->scsb_mutex); 386503831d35Sstevel if (suip->unit_state == ON) 386603831d35Sstevel scsb->scsb_data_reg[index] |= (1 << unit_number); 386703831d35Sstevel else /* OFF */ 386803831d35Sstevel scsb->scsb_data_reg[index] &= ~(1 << unit_number); 386903831d35Sstevel if ((error = scsb_rdwr_register(scsb, I2C_WR, reg, 1, 387003831d35Sstevel &scsb->scsb_data_reg[index], 0)) != 0) { 387103831d35Sstevel if (scsb_debug & 0x8002) 387203831d35Sstevel cmn_err(CE_WARN, 387303831d35Sstevel "scsb_leds: write failure to 0x%x", reg); 387403831d35Sstevel return (error); 387503831d35Sstevel } 387603831d35Sstevel mutex_exit(&scsb->scsb_mutex); 387703831d35Sstevel return (error); 387803831d35Sstevel } 387903831d35Sstevel 388003831d35Sstevel /* 388103831d35Sstevel * Diagnostic and DEBUG 388203831d35Sstevel * This is a helper function for the helper ioctl to pretend that 388303831d35Sstevel * scsb h/w is doing its job!!! 388403831d35Sstevel */ 388503831d35Sstevel int 388603831d35Sstevel scsb_slot_occupancy(scsb_state_t *scsb, scsb_uinfo_t *suip) 388703831d35Sstevel { 388803831d35Sstevel int error; 388903831d35Sstevel int saved_unit_number; 389003831d35Sstevel 389103831d35Sstevel if (!(scsb->scsb_state & (SCSB_DEBUG_MODE | SCSB_DIAGS_MODE))) 389203831d35Sstevel return (EACCES); 389303831d35Sstevel if (scsb->scsb_state & SCSB_FROZEN) { 389403831d35Sstevel return (EAGAIN); 389503831d35Sstevel } 389603831d35Sstevel error = 0; 389703831d35Sstevel switch (suip->unit_type) { 389803831d35Sstevel case ALARM: 389903831d35Sstevel if (suip->unit_number != 390003831d35Sstevel (mct_system_info.fru_info_list[ALARM])->fru_unit) { 390103831d35Sstevel return (EINVAL); 390203831d35Sstevel } 390303831d35Sstevel break; 390403831d35Sstevel 390503831d35Sstevel case SLOT: 390603831d35Sstevel /* 390703831d35Sstevel * All slots are acceptable, except slots 11 & 12. 390803831d35Sstevel */ 390903831d35Sstevel if (suip->unit_number < 1 || suip->unit_number > 391003831d35Sstevel mct_system_info.max_units[ALARM]) { 391103831d35Sstevel error = EINVAL; 391203831d35Sstevel break; 391303831d35Sstevel } 391403831d35Sstevel /* Map 1.0 Tonga Slot Numbers if necessary */ 391503831d35Sstevel saved_unit_number = suip->unit_number; 391603831d35Sstevel tonga_slotnum_check(scsb, suip); 391703831d35Sstevel break; 391803831d35Sstevel 391903831d35Sstevel default: 392003831d35Sstevel error = EINVAL; 392103831d35Sstevel break; 392203831d35Sstevel } 392303831d35Sstevel 392403831d35Sstevel if (error) 392503831d35Sstevel return (error); 392603831d35Sstevel if (suip->unit_state == ON) { 392703831d35Sstevel if (hsc_slot_occupancy(saved_unit_number, B_TRUE, 0, B_TRUE) 392803831d35Sstevel != 0) 392903831d35Sstevel error = EFAULT; 393003831d35Sstevel } else { 393103831d35Sstevel if (hsc_slot_occupancy(saved_unit_number, B_FALSE, 0, B_FALSE) 393203831d35Sstevel != 0) 393303831d35Sstevel error = EFAULT; 393403831d35Sstevel } 393503831d35Sstevel 393603831d35Sstevel return (error); 393703831d35Sstevel } 393803831d35Sstevel 393903831d35Sstevel static int 394003831d35Sstevel scsb_clear_intptrs(scsb_state_t *scsb) 394103831d35Sstevel { 394203831d35Sstevel int i, error; 394303831d35Sstevel uchar_t wbuf[SCTRL_MAX_GROUP_NUMREGS]; 394403831d35Sstevel error = 0; 394503831d35Sstevel for (i = 1; i <= SCTRL_INTR_NUMREGS; ++i) { 394603831d35Sstevel wbuf[i] = 0xff; 394703831d35Sstevel } 394803831d35Sstevel if (error = scsb_rdwr_register(scsb, I2C_WR, 394903831d35Sstevel SCSB_REG_ADDR(SCTRL_INTSRC_BASE), 395003831d35Sstevel SCTRL_INTR_NUMREGS, wbuf, 1)) { 395103831d35Sstevel if (scsb_debug & 0x0402) 395203831d35Sstevel cmn_err(CE_NOTE, "scsb_clear_intptrs(): " 395303831d35Sstevel "write to 0x%x failed", 395403831d35Sstevel SCSB_REG_ADDR(SCTRL_INTSRC_BASE)); 395503831d35Sstevel } 395603831d35Sstevel return (error); 395703831d35Sstevel } 395803831d35Sstevel 395903831d35Sstevel static int 396003831d35Sstevel scsb_setall_intmasks(scsb_state_t *scsb) 396103831d35Sstevel { 396203831d35Sstevel int error; 396303831d35Sstevel uchar_t reg, wdata, rmask; 396403831d35Sstevel int i; 396503831d35Sstevel 396603831d35Sstevel /* 396703831d35Sstevel * write loop for Interrupt Mask registers 396803831d35Sstevel */ 396903831d35Sstevel if (scsb_debug & 0x0401) 397003831d35Sstevel cmn_err(CE_NOTE, "setall_intmasks()"); 397103831d35Sstevel error = 0; 397203831d35Sstevel rmask = 0; 397303831d35Sstevel wdata = 0xff; 397403831d35Sstevel reg = SCSB_REG_ADDR(SCTRL_INTMASK_BASE); 397503831d35Sstevel for (i = 0; i < SCTRL_MASK_NUMREGS; ++i, ++reg) { 397603831d35Sstevel if (error = scsb_write_mask(scsb, reg, rmask, wdata, 0)) { 397703831d35Sstevel if (scsb_debug & 0x0402) 397803831d35Sstevel cmn_err(CE_NOTE, "scsb_setall_intmasks: " 397903831d35Sstevel "write to 0x%x failed: %d", reg, error); 398003831d35Sstevel error = EIO; 398103831d35Sstevel break; 398203831d35Sstevel } 398303831d35Sstevel } 398403831d35Sstevel return (error); 398503831d35Sstevel } 398603831d35Sstevel 398703831d35Sstevel 398803831d35Sstevel /* 398903831d35Sstevel * Clear Interrupt masks based on the FRUs that could be installed 399003831d35Sstevel * for this particular topology, determined by the MidPlane ID 399103831d35Sstevel * from SCTRL_SYSCFG registers 399203831d35Sstevel * case SCTRL_MPID_HALF: 399303831d35Sstevel * 1 CPU, 1 AlarmCard, 1 SCB/SSB, 2 PS, 3 FAN, 3 SCSI, 8 Slots 399403831d35Sstevel * case SCTRL_MPID_QUARTER: 399503831d35Sstevel * 1 CPU, 1 AlarmCard, 1 SCB/SSB, 1 PS, 2 FAN, 1 SCSI, 4 Slots 399603831d35Sstevel * case SCTRL_MPID_QUARTER_NODSK: 399703831d35Sstevel * 1 CPU, 1 AlarmCard, 1 SCB/SSB, 1 PS, 2 FAN, 0 SCSI, 4 Slots 399803831d35Sstevel */ 399903831d35Sstevel static int 400003831d35Sstevel scsb_clear_intmasks(scsb_state_t *scsb) 400103831d35Sstevel { 400203831d35Sstevel int error; 400303831d35Sstevel uchar_t msk_reg, reg, wdata, rmask; 400403831d35Sstevel uchar_t mask_data[SCTRL_MAX_GROUP_NUMREGS]; 400503831d35Sstevel int tmp, idx, code, unit, offset, mbid; 400603831d35Sstevel scsb_utype_t fru_type; 400703831d35Sstevel fru_info_t *fru_ptr; 400803831d35Sstevel 400903831d35Sstevel if (scsb->scsb_state & SCSB_FROZEN && 401003831d35Sstevel !(scsb->scsb_state & SCSB_IN_INTR)) { 401103831d35Sstevel return (EAGAIN); 401203831d35Sstevel } 401303831d35Sstevel error = 0; 401403831d35Sstevel for (tmp = 0; tmp < SCTRL_MASK_NUMREGS; ++tmp) 401503831d35Sstevel mask_data[tmp] = 0; 401603831d35Sstevel msk_reg = SCSB_REG_ADDR(SCTRL_INTMASK_BASE); 401703831d35Sstevel mbid = SCSB_REG_INDEX(msk_reg); /* the Mask Base Index Delta */ 401803831d35Sstevel if (scsb_debug & 0x0400) { 401903831d35Sstevel cmn_err(CE_NOTE, "clear_intmasks: msk_reg=0x%x; mbid=%d", 402003831d35Sstevel msk_reg, mbid); 402103831d35Sstevel } 402203831d35Sstevel for (fru_type = 0; fru_type < SCSB_UNIT_TYPES; ++fru_type) { 402303831d35Sstevel if (fru_type == SCB) 402403831d35Sstevel continue; /* handle below, 2 reg offsets */ 402503831d35Sstevel fru_ptr = mct_system_info.fru_info_list[fru_type]; 402603831d35Sstevel for (; fru_ptr != NULL; fru_ptr = fru_ptr->next) { 402703831d35Sstevel unit = fru_ptr->fru_unit; 402803831d35Sstevel code = FRU_UNIT_TO_EVCODE(fru_type, unit); 402903831d35Sstevel offset = FRU_OFFSET(code, SCTRL_INTMSK_BASE); 403003831d35Sstevel reg = FRU_REG_ADDR(code, SCTRL_INTMSK_BASE); 403103831d35Sstevel idx = SCSB_REG_INDEX(reg); 403203831d35Sstevel tmp = idx - mbid; 403303831d35Sstevel mask_data[tmp] |= (1 << offset); 403403831d35Sstevel if (scsb_debug & 0x0400) 403503831d35Sstevel cmn_err(CE_NOTE, 403603831d35Sstevel "clear_intmasks:%d:%d: PRES mask[%d]:0x%x", 403703831d35Sstevel fru_type, unit, tmp, mask_data[tmp]); 403803831d35Sstevel if ((fru_type == SLOT) && (IS_SCB_P15)) { 403903831d35Sstevel /* 404003831d35Sstevel * Unmask the corresponding Slot HLTHY mask 404103831d35Sstevel * Use Slot bit and register offsets, 404203831d35Sstevel * but with SCTRL_INTMASK_HLTHY_BASE 404303831d35Sstevel */ 404403831d35Sstevel reg = FRU_REG_ADDR(code, 404503831d35Sstevel SCTRL_INTMASK_HLTHY_BASE); 404603831d35Sstevel idx = SCSB_REG_INDEX(reg); 404703831d35Sstevel tmp = idx - mbid; 404803831d35Sstevel mask_data[tmp] |= (1 << offset); 404903831d35Sstevel if (scsb_debug & 0x0400) { 405003831d35Sstevel cmn_err(CE_NOTE, 405103831d35Sstevel "clear_intmasks:Slot:%d: HLTHY mask[%d]:0x%x" 405203831d35Sstevel "; reg=0x%x, idx=%d, mbid=%d", 405303831d35Sstevel unit, tmp, mask_data[tmp], 405403831d35Sstevel reg, idx, mbid); 405503831d35Sstevel } 405603831d35Sstevel } 405703831d35Sstevel } 405803831d35Sstevel } 405903831d35Sstevel /* 406003831d35Sstevel * Now unmask these non-fru interrupt events 406103831d35Sstevel * SCTRL_EVENT_PWRDWN (almost normal) 406203831d35Sstevel * SCTRL_EVENT_REPLACE (not used) 406303831d35Sstevel * SCTRL_EVENT_ALARM_INT (not working in P0.6/P1.0) 406403831d35Sstevel * SCTRL_EVENT_SCB (SCB 1.5 ONLY; plus SCB_INT_OFFSET) 406503831d35Sstevel */ 406603831d35Sstevel code = SCTRL_EVENT_PWRDWN; 406703831d35Sstevel offset = FRU_OFFSET(code, SCTRL_INTMSK_BASE); 406803831d35Sstevel reg = FRU_REG_ADDR(code, SCTRL_INTMSK_BASE); 406903831d35Sstevel idx = SCSB_REG_INDEX(reg); 407003831d35Sstevel tmp = idx - mbid; 407103831d35Sstevel mask_data[tmp] |= (1 << offset); 407203831d35Sstevel if (IS_SCB_P15) { 407303831d35Sstevel code = SCTRL_EVENT_SCB; 407403831d35Sstevel offset = FRU_OFFSET(code, SCTRL_INTMSK_BASE); 407503831d35Sstevel reg = FRU_REG_ADDR(code, SCTRL_INTMSK_BASE) + SCB_INT_OFFSET; 407603831d35Sstevel idx = SCSB_REG_INDEX(reg); 407703831d35Sstevel tmp = idx - mbid; 407803831d35Sstevel mask_data[tmp] |= (1 << offset); 407903831d35Sstevel code = SCTRL_EVENT_ALARM_INT; 408003831d35Sstevel offset = FRU_OFFSET(code, SCTRL_INTMSK_BASE); 408103831d35Sstevel reg = FRU_REG_ADDR(code, SCTRL_INTMSK_BASE); 408203831d35Sstevel idx = SCSB_REG_INDEX(reg); 408303831d35Sstevel tmp = idx - mbid; 408403831d35Sstevel mask_data[tmp] |= (1 << offset); 408503831d35Sstevel } 408603831d35Sstevel for (tmp = 0; tmp < SCTRL_MASK_NUMREGS; ++tmp) { 408703831d35Sstevel rmask = 0; 408803831d35Sstevel wdata = mask_data[tmp]; 408903831d35Sstevel if (scsb_debug & 0x0400) 409003831d35Sstevel cmn_err(CE_NOTE, "clear_intmasks:0x%x: ~(0x%x),0x%x", 409103831d35Sstevel msk_reg, (~wdata) & 0xff, wdata); 409203831d35Sstevel mutex_enter(&scsb->scsb_mutex); 409303831d35Sstevel if (error = scsb_write_mask(scsb, msk_reg, rmask, 409403831d35Sstevel (~wdata) & 0xff, wdata)) { 409503831d35Sstevel mutex_exit(&scsb->scsb_mutex); 409603831d35Sstevel if (scsb_debug & 0x0402) 409703831d35Sstevel cmn_err(CE_NOTE, "scsb_clear_intmasks: " 409803831d35Sstevel "write to 0x%x failed: %d", 409903831d35Sstevel msk_reg, error); 410003831d35Sstevel error = EIO; 410103831d35Sstevel break; 410203831d35Sstevel } 410303831d35Sstevel mutex_exit(&scsb->scsb_mutex); 410403831d35Sstevel ++msk_reg; 410503831d35Sstevel } 410603831d35Sstevel return (error); 410703831d35Sstevel } 410803831d35Sstevel 410903831d35Sstevel static int 411003831d35Sstevel scsb_get_status(scsb_state_t *scsb, scsb_status_t *smp) 411103831d35Sstevel { 411203831d35Sstevel register int i; 411303831d35Sstevel 411403831d35Sstevel if (smp == NULL) { 411503831d35Sstevel return (EFAULT); 411603831d35Sstevel } 411703831d35Sstevel if (scsb_debug & 0x40000000 && 411803831d35Sstevel (scsb->scsb_state & SCSB_DEBUG_MODE || 411903831d35Sstevel scsb->scsb_state & SCSB_DIAGS_MODE)) { 412003831d35Sstevel if (scsb->scsb_state & SCSB_FROZEN) { 412103831d35Sstevel return (EAGAIN); 412203831d35Sstevel } 412303831d35Sstevel mutex_enter(&scsb->scsb_mutex); 412403831d35Sstevel if (scsb_debug & 0x80000000) { 412503831d35Sstevel if ((i = scsb_readall_regs(scsb)) != 0 && 412603831d35Sstevel scsb->scsb_state & SCSB_DEBUG_MODE) 412703831d35Sstevel cmn_err(CE_WARN, "scsb_get_status: " 412803831d35Sstevel "scsb_readall_regs() FAILED"); 412903831d35Sstevel } else { 413003831d35Sstevel if ((i = scsb_check_config_status(scsb)) == 0) { 413103831d35Sstevel i = scsb_set_scfg_pres_leds(scsb, NULL); 413203831d35Sstevel } 413303831d35Sstevel } 413403831d35Sstevel mutex_exit(&scsb->scsb_mutex); 413503831d35Sstevel if (i) { 413603831d35Sstevel cmn_err(CE_WARN, 413703831d35Sstevel "scsb_get_status: FAILED Presence LEDs update"); 413803831d35Sstevel return (EIO); 413903831d35Sstevel } 414003831d35Sstevel } 414103831d35Sstevel for (i = 0; i < SCSB_DATA_REGISTERS; ++i) 414203831d35Sstevel smp->scsb_reg[i] = scsb->scsb_data_reg[i]; 414303831d35Sstevel return (0); 414403831d35Sstevel } 414503831d35Sstevel 414603831d35Sstevel /* 414703831d35Sstevel * scsb_freeze_check: 414803831d35Sstevel * Turn all the leds off on the system monitor card, without changing 414903831d35Sstevel * the state of what we have for scsb. This routine is called only when 415003831d35Sstevel * replacing system monitor card, so the state of the card leds could be 415103831d35Sstevel * restored, using scsb_restore(). 415203831d35Sstevel * Also, set state to SCSB_FROZEN which denies access to scsb while in 415303831d35Sstevel * freeze mode. 415403831d35Sstevel */ 415503831d35Sstevel static char *BAD_BOARD_MSG = 415603831d35Sstevel "SCSB: Should NOT remove SCB(%d) while cPCI Slot %d is " 415703831d35Sstevel "in RESET with a possible bad board."; 415803831d35Sstevel static int slots_in_reset[SCTRL_MAX_GROUP_NUMREGS]; 415903831d35Sstevel 416003831d35Sstevel static void 416103831d35Sstevel scsb_freeze_check(scsb_state_t *scsb) 416203831d35Sstevel { 416303831d35Sstevel register int i; 416403831d35Sstevel int offset; 416503831d35Sstevel int unit, slotnum; 416603831d35Sstevel int index; 416703831d35Sstevel fru_info_t *fru_ptr; 416803831d35Sstevel uint32_t code; 416903831d35Sstevel uchar_t reg; 417003831d35Sstevel 417103831d35Sstevel if (scsb_debug & 0x20001) 417203831d35Sstevel cmn_err(CE_NOTE, "scsb_freeze_check(%d):", scsb->scsb_instance); 417303831d35Sstevel 417403831d35Sstevel if (scsb->scsb_state & SCSB_FROZEN) { 417503831d35Sstevel return; 417603831d35Sstevel } 417703831d35Sstevel mutex_enter(&scsb->scsb_mutex); 417803831d35Sstevel for (i = 0; i < SCTRL_MAX_GROUP_NUMREGS; ++i) 417903831d35Sstevel slots_in_reset[i] = 0; 418003831d35Sstevel /* 418103831d35Sstevel * We allow the SCB to be removed only if none of 418203831d35Sstevel * the cPCI resets are asserted for occupied slots. 418303831d35Sstevel * There shouldn't be a bad board plugged in the system 418403831d35Sstevel * while swapping the SCB. 418503831d35Sstevel */ 418603831d35Sstevel fru_ptr = mct_system_info.fru_info_list[SLOT]; 418703831d35Sstevel for (unit = 1; unit <= mct_system_info.max_units[SLOT]; ++unit) { 418803831d35Sstevel if (IS_SCB_P15) { 418903831d35Sstevel slotnum = tonga_psl_to_ssl(scsb, unit); 419003831d35Sstevel } else { 419103831d35Sstevel slotnum = unit; 419203831d35Sstevel } 419303831d35Sstevel code = FRU_UNIT_TO_EVCODE(SLOT, slotnum); 419403831d35Sstevel offset = FRU_OFFSET(code, SCTRL_RESET_BASE); 419503831d35Sstevel reg = FRU_REG_ADDR(code, SCTRL_RESET_BASE); 419603831d35Sstevel index = SCSB_REG_INDEX(reg); 419703831d35Sstevel if (scsb->scsb_data_reg[index] & (1 << offset)) { 419803831d35Sstevel if (fru_ptr[unit - 1].fru_status == FRU_PRESENT) { 419903831d35Sstevel slots_in_reset[unit - 1] = unit; 420003831d35Sstevel cmn_err(CE_NOTE, BAD_BOARD_MSG, 420103831d35Sstevel scsb->scsb_instance, unit); 420203831d35Sstevel } 420303831d35Sstevel } 420403831d35Sstevel } 420503831d35Sstevel mutex_exit(&scsb->scsb_mutex); 420603831d35Sstevel } 420703831d35Sstevel 420803831d35Sstevel static void 420903831d35Sstevel scsb_freeze(scsb_state_t *scsb) 421003831d35Sstevel { 421103831d35Sstevel uint32_t code; 421203831d35Sstevel if (scsb_debug & 0x00020002) { 421303831d35Sstevel cmn_err(CE_WARN, "scsb_freeze: SCB%d possibly removed", 421403831d35Sstevel scsb->scsb_instance); 421503831d35Sstevel } 421603831d35Sstevel if (scsb->scsb_state & SCSB_FROZEN) 421703831d35Sstevel return; 421803831d35Sstevel scsb->scsb_state |= SCSB_FROZEN; 421903831d35Sstevel scsb->scsb_state &= ~SCSB_SCB_PRESENT; 4220*07d06da5SSurya Prakki (void) scsb_hsc_freeze(scsb->scsb_dev); 422103831d35Sstevel /* 422203831d35Sstevel * Send the EVENT_SCB since there is evidence that the 422303831d35Sstevel * System Controller Board has been removed. 422403831d35Sstevel */ 422503831d35Sstevel code = SCTRL_EVENT_SCB; 422603831d35Sstevel if (!(scsb->scsb_state & SCSB_IN_INTR)) 422703831d35Sstevel scsb_event_code = code; 422803831d35Sstevel check_fru_info(scsb, code); 422903831d35Sstevel add_event_code(scsb, code); 423003831d35Sstevel (void) scsb_queue_ops(scsb, QPUT_INT32, 1, &code, "scsb_freeze"); 423103831d35Sstevel } 423203831d35Sstevel 423303831d35Sstevel /* 423403831d35Sstevel * scsb_restore will only be called from the interrupt handler context on 423503831d35Sstevel * INIT_SCB interrupt for newly inserted SCB. 423603831d35Sstevel * Called with mutex held. 423703831d35Sstevel */ 423803831d35Sstevel static void 423903831d35Sstevel scsb_restore(scsb_state_t *scsb) 424003831d35Sstevel { 424103831d35Sstevel if (scsb_debug & 0x20001) 424203831d35Sstevel cmn_err(CE_NOTE, "scsb_restore(%d):", scsb->scsb_instance); 424303831d35Sstevel 424403831d35Sstevel if (initialize_scb(scsb) != DDI_SUCCESS) { 424503831d35Sstevel if (scsb_debug & 0x00020002) { 424603831d35Sstevel cmn_err(CE_WARN, "scsb_restore: INIT Failed"); 424703831d35Sstevel return; 424803831d35Sstevel } 424903831d35Sstevel } 425003831d35Sstevel /* 9. Clear all Interrupts */ 425103831d35Sstevel if (scsb_clear_intmasks(scsb)) { 425203831d35Sstevel cmn_err(CE_WARN, 425303831d35Sstevel "scsb%d: I2C TRANSFER Failed", scsb->scsb_instance); 425403831d35Sstevel if (scsb_debug & 0x00020002) { 425503831d35Sstevel cmn_err(CE_WARN, "scsb_restore: clear_intmasks Failed"); 425603831d35Sstevel } 425703831d35Sstevel return; 425803831d35Sstevel } 425903831d35Sstevel 426003831d35Sstevel /* 10. */ 426103831d35Sstevel /* Check if Alarm Card present at boot and set flags */ 426203831d35Sstevel if (scsb_fru_op(scsb, ALARM, 1, SCTRL_SYSCFG_BASE, 426303831d35Sstevel SCSB_FRU_OP_GET_BITVAL)) 426403831d35Sstevel scsb->scsb_hsc_state |= SCSB_ALARM_CARD_PRES; 426503831d35Sstevel else 426603831d35Sstevel scsb->scsb_hsc_state &= ~SCSB_ALARM_CARD_PRES; 426703831d35Sstevel 426803831d35Sstevel scsb->scsb_state &= ~SCSB_FROZEN; 426903831d35Sstevel (void) scsb_hsc_restore(scsb->scsb_dev); 427003831d35Sstevel } 427103831d35Sstevel 427203831d35Sstevel /* 427303831d35Sstevel * Given an Event Code, 427403831d35Sstevel * Return: 427503831d35Sstevel * FRU type in LSByte 427603831d35Sstevel * unit number in MSByte 427703831d35Sstevel */ 427803831d35Sstevel uint16_t 427903831d35Sstevel event_to_type(uint32_t evcode) 428003831d35Sstevel { 428103831d35Sstevel int i, li, unit; 428203831d35Sstevel uint32_t ec; 428303831d35Sstevel uint16_t ret; 428403831d35Sstevel for (i = li = 0; i < SCSB_UNIT_TYPES; ++i) { 428503831d35Sstevel if (evcode == type_to_code1[i]) { 428603831d35Sstevel ret = (uint16_t)(0x0100 | i); 428703831d35Sstevel return (ret); 428803831d35Sstevel } 428903831d35Sstevel if (evcode < type_to_code1[i]) { 429003831d35Sstevel unit = 1; 429103831d35Sstevel ec = type_to_code1[li]; 429203831d35Sstevel while (ec < evcode) 429303831d35Sstevel ec = ec << 1, ++unit; 429403831d35Sstevel ret = (unit << 8) | li; 429503831d35Sstevel return (ret); 429603831d35Sstevel } 429703831d35Sstevel li = i; 429803831d35Sstevel } 429903831d35Sstevel return ((uint16_t)0xffff); 430003831d35Sstevel } 430103831d35Sstevel 430203831d35Sstevel /* 430303831d35Sstevel * scsb interrupt handler for (MC) PSM_INT vector 430403831d35Sstevel * P0.6: HW shipped to beta customers 430503831d35Sstevel * 1. did not have Slot Occupant Presense support 430603831d35Sstevel * 2. I2C interrupt-map properties not yet tested, using polling daemon 430703831d35Sstevel * 3. Polling detects each event reliably twice. 430803831d35Sstevel * clr_bits# are used to keep track of events to be ignored 2nd time 430903831d35Sstevel * 431003831d35Sstevel * retval flags allow all events to be checked, and still returning the 431103831d35Sstevel * correct DDI value. 431203831d35Sstevel * 431303831d35Sstevel */ 431403831d35Sstevel #define SCSB_INTR_CLAIMED 1 431503831d35Sstevel #define SCSB_INTR_UNCLAIMED 2 431603831d35Sstevel #define SCSB_INTR_EVENT 4 431703831d35Sstevel 431803831d35Sstevel /* 431903831d35Sstevel * Does preprocessing of the interrupt. The only thing this 432003831d35Sstevel * needs to do is to ask scsb to release the interrupt line. 432103831d35Sstevel * and then schedule delayed actual processing using timeout() 432203831d35Sstevel */ 432303831d35Sstevel uint_t 432403831d35Sstevel scsb_intr_preprocess(caddr_t arg) 432503831d35Sstevel { 432603831d35Sstevel scsb_state_t *scsb = (scsb_state_t *)arg; 432703831d35Sstevel 432803831d35Sstevel scb_pre_s = gethrtime(); 432903831d35Sstevel 433003831d35Sstevel /* 433103831d35Sstevel * If SCSB_IN_INTR is already set in scsb_state, 433203831d35Sstevel * it means we are being interrupted by someone else. This can 433303831d35Sstevel * happen only if the interrupt does not belong to scsb, and some 433403831d35Sstevel * other device, e.g. a FAN or PS is interrupting. So, we 433503831d35Sstevel * cancel the previous timeout(). 433603831d35Sstevel */ 433703831d35Sstevel 433803831d35Sstevel if (scsb->scsb_state & SCSB_IN_INTR) { 4339*07d06da5SSurya Prakki (void) untimeout(scsb_intr_tid); 4340*07d06da5SSurya Prakki (void) scsb_invoke_intr_chain(); 4341*07d06da5SSurya Prakki (void) scsb_toggle_psmint(scsb, 1); 434203831d35Sstevel scsb->scsb_state &= ~SCSB_IN_INTR; 434303831d35Sstevel goto intr_end; 434403831d35Sstevel } 434503831d35Sstevel scsb->scsb_state |= SCSB_IN_INTR; 434603831d35Sstevel 434703831d35Sstevel /* 434803831d35Sstevel * Stop scsb from interrupting first. 434903831d35Sstevel */ 435003831d35Sstevel if (scsb_quiesce_psmint(scsb) != DDI_SUCCESS) { 435103831d35Sstevel goto intr_end; 435203831d35Sstevel } 435303831d35Sstevel 435403831d35Sstevel /* 435503831d35Sstevel * Schedule a timeout to actually process the 435603831d35Sstevel * interrupt. 435703831d35Sstevel */ 435803831d35Sstevel scsb_intr_tid = timeout((void (*)(void *))scsb_intr, arg, 435903831d35Sstevel drv_usectohz(1000)); 436003831d35Sstevel 436103831d35Sstevel intr_end: 436203831d35Sstevel 436303831d35Sstevel scb_pre_e = gethrtime(); 436403831d35Sstevel return (DDI_INTR_CLAIMED); 436503831d35Sstevel } 436603831d35Sstevel 436703831d35Sstevel static void scsb_healthy_intr(scsb_state_t *scsb, int pslotnum); 436803831d35Sstevel void 436903831d35Sstevel scsb_intr(caddr_t arg) 437003831d35Sstevel { 437103831d35Sstevel scsb_state_t *scsb = (scsb_state_t *)arg; 437203831d35Sstevel int i, idx, offset, unit, numregs, error; 437303831d35Sstevel int intr_idx, index, offset_base, retval, slotnum, val; 437403831d35Sstevel uint32_t code; 437503831d35Sstevel uchar_t intr_reg, tmp_reg, intr_addr, clr_bits = 0; 437603831d35Sstevel uchar_t ac_slot = B_FALSE; 437703831d35Sstevel uchar_t *int_masks; 437803831d35Sstevel uchar_t cstatus_regs[SCTRL_MAX_GROUP_NUMREGS]; 437903831d35Sstevel scsb_utype_t fru_type; 438003831d35Sstevel fru_info_t *fru_ptr; 438103831d35Sstevel int ac_present; 438203831d35Sstevel 438303831d35Sstevel /* 438403831d35Sstevel * Avoid mayhem, make sure we have only one timeout thread running. 438503831d35Sstevel */ 438603831d35Sstevel mutex_enter(&scsb->scsb_mutex); 438703831d35Sstevel while (scsb_in_postintr) 438803831d35Sstevel cv_wait(&scsb->scsb_cv, &scsb->scsb_mutex); 438903831d35Sstevel scsb_in_postintr = 1; 439003831d35Sstevel mutex_exit(&scsb->scsb_mutex); 439103831d35Sstevel 439203831d35Sstevel scb_post_s = gethrtime(); 439303831d35Sstevel if (scsb_debug & 0x00002000) 439403831d35Sstevel cmn_err(CE_NOTE, "scsb_intr(%d)", scsb->scsb_instance); 439503831d35Sstevel retval = 0; 439603831d35Sstevel tmp_reg = 0; 439703831d35Sstevel /* 439803831d35Sstevel * XXX: Problem, when we want to support swapping between SCB 439903831d35Sstevel * versions, then we need to check the SCB PROM ID (CF) register here 440003831d35Sstevel * before assuming the same SCB version was re-inserted. 440103831d35Sstevel * We will have to duplicate some of the scb_initialization() 440203831d35Sstevel * code to set the scsb_state PROM ID bits and to set up the 440303831d35Sstevel * register table pointers. 440403831d35Sstevel * 440503831d35Sstevel * Only if NOT SSB_PRESENT, check the SCB PROM ID 440603831d35Sstevel */ 440703831d35Sstevel if (!(scsb->scsb_state & SCSB_SSB_PRESENT)) { 440803831d35Sstevel if (scb_check_version(scsb) != DDI_SUCCESS) { 440903831d35Sstevel #ifdef DEBUG 441003831d35Sstevel if (scsb->scsb_state & SCSB_SSB_PRESENT && 441103831d35Sstevel scsb->scsb_i2c_errcnt > scsb_err_threshold) 441203831d35Sstevel scsb_failing_event(scsb); 441303831d35Sstevel #endif 441403831d35Sstevel goto intr_error; 441503831d35Sstevel } 441603831d35Sstevel } 441703831d35Sstevel if (IS_SCB_P15) { 441803831d35Sstevel int_masks = scb_15_int_masks; 441903831d35Sstevel } else { 442003831d35Sstevel int_masks = scb_10_int_masks; 442103831d35Sstevel } 442203831d35Sstevel /* 442303831d35Sstevel * Now check the INTSRC registers for set bits. 442403831d35Sstevel * Do a quick check by OR'ing INTSRC registers together as we copy 442503831d35Sstevel * them from the transfer buffer. For P1.0 or earlier we had already 442603831d35Sstevel * read the interrupt source registers and wrote them back to stop 442703831d35Sstevel * interrupt. So we need to do this step only for P1.5 or later. 442803831d35Sstevel * We already read INTSRC6 to take care of SCB insertion case, so 442903831d35Sstevel * do not read INTSRC6 again. 443003831d35Sstevel */ 443103831d35Sstevel 443203831d35Sstevel if (IS_SCB_P15) { 443303831d35Sstevel intr_addr = SCSB_REG_ADDR(SCTRL_INTSRC_BASE); 443403831d35Sstevel /* read the interrupt register from scsb */ 443503831d35Sstevel if (scsb_rdwr_register(scsb, I2C_WR_RD, intr_addr, 443603831d35Sstevel SCTRL_INTR_NUMREGS - 1, scb_intr_regs, 1)) { 443703831d35Sstevel cmn_err(CE_WARN, "scsb_intr: " 443803831d35Sstevel " Failed read of interrupt registers."); 443903831d35Sstevel #ifdef DEBUG 444003831d35Sstevel if (scsb->scsb_state & SCSB_SSB_PRESENT && 444103831d35Sstevel scsb->scsb_i2c_errcnt > scsb_err_threshold) 444203831d35Sstevel scsb_failing_event(scsb); 444303831d35Sstevel #endif 444403831d35Sstevel goto intr_error; 444503831d35Sstevel } 444603831d35Sstevel } 444703831d35Sstevel 444803831d35Sstevel /* 444903831d35Sstevel * We have seen that an interrupt source bit can be set 445003831d35Sstevel * even though the corresponding interrupt mask bit 445103831d35Sstevel * has been set to mask the interrupt. So we must 445203831d35Sstevel * clear all bits set in the interrupt source register. 445303831d35Sstevel */ 445403831d35Sstevel for (i = 0; i < SCTRL_INTR_NUMREGS; ++i) { 445503831d35Sstevel retval |= scb_intr_regs[i]; /* Quick INTSRC check */ 445603831d35Sstevel #ifdef DEBUG 445703831d35Sstevel if (scsb_debug & 0x08000000) { 445803831d35Sstevel if (tmp_reg || scb_intr_regs[i]) { 445903831d35Sstevel cmn_err(CE_NOTE, "scsb_intr: INTSRC%d=0x%x", 446003831d35Sstevel i + 1, scb_intr_regs[i]); 446103831d35Sstevel ++tmp_reg; 446203831d35Sstevel } 446303831d35Sstevel } 446403831d35Sstevel #endif 446503831d35Sstevel } 446603831d35Sstevel /* 446703831d35Sstevel * Any bits from quick check? If this is not our interrupt, 446803831d35Sstevel * something is wrong. FAN/PS interrupts are supposed to be 446903831d35Sstevel * blocked, but we can not be sure. So, go ahead and call the 447003831d35Sstevel * emergency interrupt handlers for FAN/PS devices and mask 447103831d35Sstevel * their interrupts, if they aren't already masked. 447203831d35Sstevel */ 447303831d35Sstevel if (retval == 0) { 447403831d35Sstevel goto intr_error; 447503831d35Sstevel } 447603831d35Sstevel 447703831d35Sstevel retval = 0; 447803831d35Sstevel 447903831d35Sstevel /* 448003831d35Sstevel * If SCB 1.5 or 2.0, check for the INIT_SCB Interrupt 448103831d35Sstevel * to support Hot SCB Insertion. 448203831d35Sstevel * The check was moved here during debugging of the SCB hot insertion. 448303831d35Sstevel * Theoretically, this code could be moved back to the check for 448403831d35Sstevel * SCTRL_EVENT_SCB in the processing loop below. 448503831d35Sstevel */ 448603831d35Sstevel if (IS_SCB_P15) { 448703831d35Sstevel int iid; 448803831d35Sstevel iid = SCSB_REG_INDEX(intr_addr); 448903831d35Sstevel offset = FRU_OFFSET(SCTRL_EVENT_SCB, SCTRL_INTPTR_BASE); 449003831d35Sstevel tmp_reg = SCSB_REG_ADDR(SCTRL_INTSRC_SCB_P15); 449103831d35Sstevel intr_idx = SCSB_REG_INDEX(tmp_reg) - iid; 449203831d35Sstevel clr_bits = 1 << offset; 449303831d35Sstevel if (scb_intr_regs[intr_idx] & clr_bits) { 449403831d35Sstevel /* 449503831d35Sstevel * Must be newly inserted SCB 449603831d35Sstevel * Time to re-initialize. 449703831d35Sstevel */ 449803831d35Sstevel if (scsb_debug & 0x00023000) { 449903831d35Sstevel cmn_err(CE_NOTE, 450003831d35Sstevel "scsb_intr(%d): INIT_SCB INT", 450103831d35Sstevel scsb->scsb_instance); 450203831d35Sstevel } 450303831d35Sstevel scsb_restore(scsb); 450403831d35Sstevel retval |= (SCSB_INTR_CLAIMED | SCSB_INTR_EVENT); 450503831d35Sstevel /* 450603831d35Sstevel * The INTSRC bit will be cleared by the 450703831d35Sstevel * scsb_restore() function. 450803831d35Sstevel * Also, leave the bit set in scb_intr_regs[] so we can 450903831d35Sstevel * report the event code as we check for other 451003831d35Sstevel * interrupt source bits. 451103831d35Sstevel * 451203831d35Sstevel * scsb_write_mask(scsb, tmp_reg, 0, clr_bits, 0); 451303831d35Sstevel * scb_intr_regs[intr_idx] &= ~clr_bits; 451403831d35Sstevel */ 451503831d35Sstevel } 451603831d35Sstevel /* 451703831d35Sstevel * In case this is a power down interrupt, check the validity 451803831d35Sstevel * of the request to make sure it's not an I2C noise 451903831d35Sstevel */ 452003831d35Sstevel offset = FRU_OFFSET(SCTRL_EVENT_PWRDWN, 452103831d35Sstevel SCTRL_INTPTR_BASE); 452203831d35Sstevel clr_bits = 1 << offset; 452303831d35Sstevel intr_reg = scb_intr_regs[intr_idx]; 452403831d35Sstevel if (intr_reg & clr_bits) { 452503831d35Sstevel /* 452603831d35Sstevel * A shutdown request has been detected. Poll 452703831d35Sstevel * the corresponding register ? more times to 452803831d35Sstevel * make sure it's a genuine shutdown request. 452903831d35Sstevel */ 453003831d35Sstevel for (i = 0; i < scsb_shutdown_count; i++) { 453103831d35Sstevel drv_usecwait(1000); 453203831d35Sstevel if (scsb_rdwr_register(scsb, I2C_WR_RD, tmp_reg, 453303831d35Sstevel 1, &intr_reg, 1)) { 453403831d35Sstevel cmn_err(CE_WARN, "Failed to read " 453503831d35Sstevel " interrupt register"); 453603831d35Sstevel goto intr_error; 453703831d35Sstevel } 453803831d35Sstevel if (scsb_debug & 0x08000000) { 453903831d35Sstevel cmn_err(CE_NOTE, "scsb_intr: " 454003831d35Sstevel " INTSRC6[%d]=0x%x", i, 454103831d35Sstevel intr_reg); 454203831d35Sstevel } 454303831d35Sstevel if (!(intr_reg & clr_bits)) { 454403831d35Sstevel scb_intr_regs[intr_idx] &= ~clr_bits; 454503831d35Sstevel break; 454603831d35Sstevel } 454703831d35Sstevel } 454803831d35Sstevel } 454903831d35Sstevel } 455003831d35Sstevel /* 455103831d35Sstevel * if retval == 0, then we didn't call scsb_restore, 455203831d35Sstevel * so we update the shadow copy of SYSCFG registers 455303831d35Sstevel * We *MUST* read the syscfg registers before any attempt 455403831d35Sstevel * to clear the interrupt source registers is made. 455503831d35Sstevel */ 455603831d35Sstevel if (retval == 0 && scsb_check_config_status(scsb)) { 455703831d35Sstevel cmn_err(CE_WARN, 455803831d35Sstevel "scsb_intr: Failed read of config/status registers"); 455903831d35Sstevel if (scsb->scsb_state & SCSB_P06_NOINT_KLUGE) { 456003831d35Sstevel if (!scsb_debug) { 456103831d35Sstevel goto intr_error; 456203831d35Sstevel } 456303831d35Sstevel } 456403831d35Sstevel #ifdef DEBUG 456503831d35Sstevel if (scsb->scsb_state & SCSB_SSB_PRESENT && 456603831d35Sstevel scsb->scsb_i2c_errcnt > scsb_err_threshold) { 456703831d35Sstevel scsb_failing_event(scsb); 456803831d35Sstevel } 456903831d35Sstevel #endif 457003831d35Sstevel /* 457103831d35Sstevel * Allow to go on so we clear the INTSRC bits 457203831d35Sstevel */ 457303831d35Sstevel } 457403831d35Sstevel 457503831d35Sstevel /* 457603831d35Sstevel * Read the board healthy registers here, if any of the healthy 457703831d35Sstevel * interrupts are set. 457803831d35Sstevel */ 457903831d35Sstevel if (IS_SCB_P15) { 458003831d35Sstevel intr_idx = intr_reg = 0; 458103831d35Sstevel intr_addr = SCSB_REG_ADDR(SCTRL_INTSRC_BASE); 458203831d35Sstevel index = SCSB_REG_INDEX(intr_addr); 458303831d35Sstevel for (i = 0; i < SCTRL_BHLTHY_NUMREGS; ++i, ++intr_idx) { 458403831d35Sstevel scsb->scsb_data_reg[index++] = 458503831d35Sstevel scb_intr_regs[intr_idx] & int_masks[intr_idx]; 458603831d35Sstevel intr_reg |= scb_intr_regs[i]; 458703831d35Sstevel } 458803831d35Sstevel 458903831d35Sstevel if (intr_reg && scsb_read_bhealthy(scsb) != 0) { 459003831d35Sstevel cmn_err(CE_WARN, "%s#%d: Error Reading Healthy# " 459103831d35Sstevel " Registers", ddi_driver_name(scsb->scsb_dev), 459203831d35Sstevel ddi_get_instance(scsb->scsb_dev)); 459303831d35Sstevel #ifdef DEBUG 459403831d35Sstevel if (scsb->scsb_state & SCSB_SSB_PRESENT && 459503831d35Sstevel scsb->scsb_i2c_errcnt > scsb_err_threshold) { 459603831d35Sstevel scsb_failing_event(scsb); 459703831d35Sstevel } 459803831d35Sstevel #endif 459903831d35Sstevel goto intr_error; 460003831d35Sstevel } 460103831d35Sstevel } 460203831d35Sstevel 460303831d35Sstevel /* 460403831d35Sstevel * We clear the interrupt source registers now itself so that 460503831d35Sstevel * future interrupts can be latched quickly, instead of after 460603831d35Sstevel * finishing processing of all interrupt conditions. The global 460703831d35Sstevel * interrupt mask however remain disabled. 460803831d35Sstevel */ 460903831d35Sstevel if (IS_SCB_P15) { 461003831d35Sstevel if (scsb_rdwr_register(scsb, I2C_WR, intr_addr, 461103831d35Sstevel SCTRL_INTR_NUMREGS, scb_intr_regs, 1)) { 461203831d35Sstevel cmn_err(CE_WARN, "scsb_intr: Failed write to interrupt" 461303831d35Sstevel " registers."); 461403831d35Sstevel #ifdef DEBUG 461503831d35Sstevel if (scsb->scsb_state & SCSB_SSB_PRESENT && 461603831d35Sstevel scsb->scsb_i2c_errcnt > scsb_err_threshold) { 461703831d35Sstevel scsb_failing_event(scsb); 461803831d35Sstevel } 461903831d35Sstevel #endif 462003831d35Sstevel goto intr_error; 462103831d35Sstevel } 462203831d35Sstevel } 462303831d35Sstevel 462403831d35Sstevel /* 462503831d35Sstevel * At this point, all interrupt source registers are read. 462603831d35Sstevel * We only handle interrups which are not masked 462703831d35Sstevel */ 462803831d35Sstevel for (i = 0; i < SCTRL_INTR_NUMREGS; ++i) { 462903831d35Sstevel scb_intr_regs[i] &= int_masks[i]; 463003831d35Sstevel } 463103831d35Sstevel 463203831d35Sstevel /* 463303831d35Sstevel * We are here means that there was some bit set in the interrupt 463403831d35Sstevel * source register. So we must claim the interrupt no matter 463503831d35Sstevel * whatever error we may encounter in the course of processing. 463603831d35Sstevel */ 463703831d35Sstevel retval |= SCSB_INTR_CLAIMED; 463803831d35Sstevel 463903831d35Sstevel /* store config status data */ 464003831d35Sstevel tmp_reg = SCSB_REG_ADDR(SCTRL_SYSCFG_BASE); 464103831d35Sstevel index = SCSB_REG_INDEX(tmp_reg); 464203831d35Sstevel for (i = 0; i < SCTRL_CFG_NUMREGS; ++i) 464303831d35Sstevel cstatus_regs[i] = scsb->scsb_data_reg[index + i]; 464403831d35Sstevel /* 464503831d35Sstevel * Clear the event code, 464603831d35Sstevel * then check to see what kind(s) of events we were interrupted for. 464703831d35Sstevel * Check all SCTRL_INTSRC registers 464803831d35Sstevel */ 464903831d35Sstevel scsb_event_code = 0; 465003831d35Sstevel clr_bits = 0; 465103831d35Sstevel intr_idx = 0; 465203831d35Sstevel numregs = SCTRL_INTR_NUMREGS; 465303831d35Sstevel index = SCSB_REG_INDEX(intr_addr); 465403831d35Sstevel /* 465503831d35Sstevel * If SCB 1.5, adjust some variables to skip the SCTRL_BHLTHY_REGS 465603831d35Sstevel * which will be handled last in this function. 465703831d35Sstevel */ 465803831d35Sstevel if (IS_SCB_P15) { 465903831d35Sstevel i = SCTRL_BHLTHY_NUMREGS; 466003831d35Sstevel intr_idx += i; 466103831d35Sstevel intr_addr += i; 466203831d35Sstevel index += i; 466303831d35Sstevel } 466403831d35Sstevel /* 466503831d35Sstevel * For the rest of the INTSRC registers, we walk through the 466603831d35Sstevel * scb_fru_offset[] table, matching register offsets with our offset 466703831d35Sstevel * counter. Then we check for the scb_fru_offset[] bit in intr_reg. 466803831d35Sstevel * The scb_fru_offset[] index is now the SCTRL_EVENT code. 466903831d35Sstevel * The code is then compared to type_to_code1[] entries to find the 467003831d35Sstevel * fru_type. The fru_type will help us recognize when to do 467103831d35Sstevel * SLOT Hot Swap processing. 467203831d35Sstevel * 467303831d35Sstevel * offset_base: the appropriate scb_fru_offset[] base index 467403831d35Sstevel * for the INTPTR_BASE register group 467503831d35Sstevel * offset: bit offset found in INTSRC register 467603831d35Sstevel * intr_idx: index to temporary INTSRC register copies 467703831d35Sstevel * intr: modified copy of current INTR register 467803831d35Sstevel * intr_addr: SCB register address of current INTR register 467903831d35Sstevel * index: index to current INTR shadow register 468003831d35Sstevel * idx: bit-number of current INTR event bit 468103831d35Sstevel * uc: uchar_t from scb_fru_offset[] table, 468203831d35Sstevel * containing register and FRU offsets. 468303831d35Sstevel * j: used to walk fru_offset[] table, which is also 468403831d35Sstevel * the bit-number of the current event code 468503831d35Sstevel * code: manufactured event code for current INT event 468603831d35Sstevel */ 468703831d35Sstevel offset_base = FRU_OFFSET_BASE(SCTRL_INTPTR_BASE); 468803831d35Sstevel for (offset = 0; intr_idx < numregs; 468903831d35Sstevel ++offset, ++intr_idx, ++intr_addr, ++index) { 469003831d35Sstevel scsb->scsb_data_reg[index] = scb_intr_regs[intr_idx]; 469103831d35Sstevel intr_reg = scb_intr_regs[intr_idx]; 469203831d35Sstevel while (intr_reg) { /* for each INTSRC bit that's set */ 469303831d35Sstevel int j; 469403831d35Sstevel uint16_t ui; 469503831d35Sstevel uchar_t uc; 469603831d35Sstevel idx = event_to_index((uint32_t)intr_reg); /* offset */ 469703831d35Sstevel code = (1 << idx); /* back to bit mask */ 469803831d35Sstevel clr_bits |= code; 469903831d35Sstevel intr_reg = intr_reg & ~code; /* clear this one */ 470003831d35Sstevel for (j = 0; j < MCT_MAX_FRUS; ++j) { 470103831d35Sstevel /* 470203831d35Sstevel * Get register offset from table and check 470303831d35Sstevel * for a match with our loop offset counter. 470403831d35Sstevel * Then check for intr_reg bit-offset match 470503831d35Sstevel * with bit-offset from table entry. 470603831d35Sstevel */ 470703831d35Sstevel uc = scb_fru_offset[offset_base + j]; 470803831d35Sstevel if (offset != ((uc >> 4) & 0xf)) { 470903831d35Sstevel if (IS_SCB_P10) 471003831d35Sstevel continue; 471103831d35Sstevel if (j != FRU_INDEX(SCTRL_EVENT_SCB)) 471203831d35Sstevel continue; 471303831d35Sstevel if (offset != ((uc >> 4) & 0xf) 471403831d35Sstevel + SCB_INT_OFFSET) 471503831d35Sstevel continue; 471603831d35Sstevel } 471703831d35Sstevel if (idx == (uc & 0xf)) 471803831d35Sstevel break; 471903831d35Sstevel } 472003831d35Sstevel if (uc == 0xff) { 472103831d35Sstevel /* 472203831d35Sstevel * bit idx not recognized, check another. 472303831d35Sstevel */ 472403831d35Sstevel continue; 472503831d35Sstevel } 472603831d35Sstevel /* 472703831d35Sstevel * We found the fru_offset[] entry, now use the index 472803831d35Sstevel * to get the event code. 472903831d35Sstevel */ 473003831d35Sstevel code = (uint32_t)(1 << j); 473103831d35Sstevel if (scsb_debug & 0x00002000) { 473203831d35Sstevel cmn_err(CE_NOTE, "scsb_intr: code=0x%x", code); 473303831d35Sstevel } 473403831d35Sstevel /* 473503831d35Sstevel * Now check for the NON-FRU type events. 473603831d35Sstevel */ 473703831d35Sstevel if (code == SCTRL_EVENT_PWRDWN) { 473803831d35Sstevel if (scsb_debug & 0x1002) { 473903831d35Sstevel cmn_err(CE_NOTE, 474003831d35Sstevel "scsb_intr(%d): power down req." 474103831d35Sstevel " INT.", scsb->scsb_instance); 474203831d35Sstevel } 474303831d35Sstevel scsb_event_code |= code; 474403831d35Sstevel if (scsb->scsb_state & SCSB_OPEN && 474503831d35Sstevel scsb->scsb_rq != (queue_t *)NULL) { 474603831d35Sstevel /* 474703831d35Sstevel * inform applications using poll(2) 474803831d35Sstevel * about this event, and provide the 474903831d35Sstevel * event code to EnvMon scsb policy 475003831d35Sstevel */ 475103831d35Sstevel if (!(scsb_debug & 0x00040000)) 475203831d35Sstevel (void) scsb_queue_put(scsb->scsb_rq, 1, 475303831d35Sstevel &scsb_event_code, "scsb_intr"); 475403831d35Sstevel goto intr_error; 475503831d35Sstevel } 475603831d35Sstevel continue; 475703831d35Sstevel } else if (code == SCTRL_EVENT_REPLACE) { 475803831d35Sstevel if (scsb_debug & 0x1002) { 475903831d35Sstevel cmn_err(CE_NOTE, 476003831d35Sstevel "scsb_intr(%d): replacement " 476103831d35Sstevel "req. INT.", 476203831d35Sstevel scsb->scsb_instance); 476303831d35Sstevel } 476403831d35Sstevel scsb_freeze_check(scsb); 476503831d35Sstevel scsb_freeze(scsb); 476603831d35Sstevel scsb_event_code |= code; 476703831d35Sstevel retval |= (SCSB_INTR_CLAIMED | SCSB_INTR_EVENT); 476803831d35Sstevel continue; 476903831d35Sstevel } else if (code == SCTRL_EVENT_SCB) { 477003831d35Sstevel int tmp; 477103831d35Sstevel /* 477203831d35Sstevel * Must be newly inserted SCB 477303831d35Sstevel * Time to re-initialize. 477403831d35Sstevel */ 477503831d35Sstevel if (scsb_debug & 0x1002) { 477603831d35Sstevel cmn_err(CE_NOTE, 477703831d35Sstevel "scsb_intr(%d): INIT SCB INTR", 477803831d35Sstevel scsb->scsb_instance); 477903831d35Sstevel } 478003831d35Sstevel /* 478103831d35Sstevel * SCB initialization already handled, but we 478203831d35Sstevel * set the event code bit here in order to 478303831d35Sstevel * report the event to interested utilities. 478403831d35Sstevel * 478503831d35Sstevel * scsb_restore(scsb); 478603831d35Sstevel * The INTSRC bit is already cleared, 478703831d35Sstevel * so we won't do it again. 478803831d35Sstevel */ 478903831d35Sstevel tmp = FRU_OFFSET(SCTRL_EVENT_SCB, 479003831d35Sstevel SCTRL_INTPTR_BASE); 479103831d35Sstevel clr_bits &= ~(1 << tmp); 479203831d35Sstevel scsb_event_code |= code; 479303831d35Sstevel retval |= (SCSB_INTR_CLAIMED | SCSB_INTR_EVENT); 479403831d35Sstevel continue; 479503831d35Sstevel } else if (code == SCTRL_EVENT_ALARM_INT) { 479603831d35Sstevel /* 479703831d35Sstevel * P0.6/P1.0: SCTRL_INTR_ALARM_INT is always 479803831d35Sstevel * set and cannot be cleared, so ignore it. 479903831d35Sstevel */ 480003831d35Sstevel if (!IS_SCB_P15) { 480103831d35Sstevel continue; 480203831d35Sstevel } 480303831d35Sstevel if (scsb_debug & 0x1002) { 480403831d35Sstevel cmn_err(CE_NOTE, 480503831d35Sstevel "scsb_intr(%d): Alarm INT.", 480603831d35Sstevel scsb->scsb_instance); 480703831d35Sstevel } 480803831d35Sstevel scsb_event_code |= code; 480903831d35Sstevel retval |= (SCSB_INTR_CLAIMED | SCSB_INTR_EVENT); 481003831d35Sstevel /* 481103831d35Sstevel * XXX: 481203831d35Sstevel * Must service the Alarm INT by clearing INT 481303831d35Sstevel * condition on Alarm Card, 481403831d35Sstevel * then clear the SCTRL_INTR_ALARM_INT bit here. 481503831d35Sstevel * Waiting for specs and test environment. 481603831d35Sstevel */ 481703831d35Sstevel continue; 481803831d35Sstevel } else if ((ui = event_to_type(code)) == 0xffff) { 481903831d35Sstevel /* 482003831d35Sstevel * FRU type not found 482103831d35Sstevel */ 482203831d35Sstevel break; 482303831d35Sstevel } 482403831d35Sstevel /* 482503831d35Sstevel * Check for special processing 482603831d35Sstevel * now that we found the FRU type. 482703831d35Sstevel */ 482803831d35Sstevel fru_type = (scsb_utype_t)(ui & 0xff); 482903831d35Sstevel unit = (ui >> 8) & 0xff; 483003831d35Sstevel if (scsb_debug & 0x00002000) { 483103831d35Sstevel cmn_err(CE_NOTE, "scsb_intr: " 483203831d35Sstevel "FRU type/unit/code %d/%d/0x%x", 483303831d35Sstevel fru_type, unit, code); 483403831d35Sstevel } 483503831d35Sstevel switch (fru_type) { 483603831d35Sstevel case PDU: 483703831d35Sstevel break; 483803831d35Sstevel case PS: 483903831d35Sstevel break; 484003831d35Sstevel case DISK: 484103831d35Sstevel break; 484203831d35Sstevel case FAN: 484303831d35Sstevel break; 484403831d35Sstevel case SSB: 484503831d35Sstevel /* 484603831d35Sstevel * in check_fru_info() below, we see if the 484703831d35Sstevel * SSB has been removed, then check for 484803831d35Sstevel * occupied slots in reset to see if we should 484903831d35Sstevel * WARN agains SCB removal 485003831d35Sstevel */ 485103831d35Sstevel break; 485203831d35Sstevel case CFTM: 485303831d35Sstevel break; 485403831d35Sstevel case CRTM: 485503831d35Sstevel break; 485603831d35Sstevel case PRTM: 485703831d35Sstevel break; 485803831d35Sstevel case SLOT: 485903831d35Sstevel slotnum = tonga_ssl_to_psl(scsb, unit); 486003831d35Sstevel if (scsb_debug & 0x00002000) { 486103831d35Sstevel cmn_err(CE_NOTE, "scsb_intr: " 486203831d35Sstevel "unit/slot %d/%d", 486303831d35Sstevel unit, slotnum); 486403831d35Sstevel } 486503831d35Sstevel 486603831d35Sstevel /* 486703831d35Sstevel * If the slot number is not valid, continue. 486803831d35Sstevel */ 486903831d35Sstevel if (scsb->scsb_state & SCSB_IS_TONGA) { 487003831d35Sstevel if (slotnum > TG_MAX_SLOTS || 487103831d35Sstevel slotnum == SC_TG_CPU_SLOT) { 487203831d35Sstevel continue; 487303831d35Sstevel } 487403831d35Sstevel /* 487503831d35Sstevel * For a tonga, we need to return 487603831d35Sstevel * the code corresponding to the 487703831d35Sstevel * actual physical slot 487803831d35Sstevel */ 487903831d35Sstevel code = FRU_UNIT_TO_EVCODE(SLOT, 488003831d35Sstevel slotnum); 488103831d35Sstevel } else { 488203831d35Sstevel if (slotnum > MC_MAX_SLOTS || 488303831d35Sstevel slotnum == SC_MC_CPU_SLOT || 488403831d35Sstevel (scsb->scsb_hsc_state & 488503831d35Sstevel SCSB_HSC_CTC_PRES && 488603831d35Sstevel slotnum == SC_MC_CTC_SLOT)) { 488703831d35Sstevel continue; 488803831d35Sstevel } 488903831d35Sstevel } 489003831d35Sstevel /* FALLTHROUGH */ 489103831d35Sstevel case ALARM: 489203831d35Sstevel /* 489303831d35Sstevel * INDENT CHEATING, 2 indentations 489403831d35Sstevel */ 489503831d35Sstevel ac_present = 0; 489603831d35Sstevel /* 489703831d35Sstevel * If it is an Alarm Card Interrupt, we just do some sanity 489803831d35Sstevel * checks and then wait for the slot interrupt to take 489903831d35Sstevel * connect or disconnect action. 490003831d35Sstevel * XXX - Is there a gaurantee that ALARM int will occur first ? 490103831d35Sstevel */ 490203831d35Sstevel if (fru_type == ALARM) { 490303831d35Sstevel DEBUG2("AC Intr %d(%d)\n", scsb->ac_slotnum, idx+1); 490403831d35Sstevel val = scsb_fru_op(scsb, SLOT, 490503831d35Sstevel tonga_ssl_to_psl(scsb, scsb->ac_slotnum), 490603831d35Sstevel SCTRL_SYSCFG_BASE, SCSB_FRU_OP_GET_BITVAL); 490703831d35Sstevel ac_present = scsb_fru_op(scsb, ALARM, 1, 490803831d35Sstevel SCTRL_SYSCFG_BASE, 490903831d35Sstevel SCSB_FRU_OP_GET_BITVAL); 491003831d35Sstevel /* 491103831d35Sstevel * It is observed that slot presence and Alarm 491203831d35Sstevel * presence bits do not go ON at the same time. 491303831d35Sstevel * Hence we wait till both events happen. 491403831d35Sstevel */ 491503831d35Sstevel #ifdef DEBUG 491603831d35Sstevel if ((((val) && (!ac_present)) || 491703831d35Sstevel ((!val) && (ac_present))) && 491803831d35Sstevel (scsb->scsb_hsc_state & 491903831d35Sstevel SCSB_AC_SLOT_INTR_DONE)) 492003831d35Sstevel 492103831d35Sstevel cmn_err(CE_WARN, "?Alarm and Slot presence " 492203831d35Sstevel "state bits do not match! (%x,%x)", 492303831d35Sstevel val, ac_present); 492403831d35Sstevel #endif 492503831d35Sstevel if (scsb->scsb_hsc_state & SCSB_AC_SLOT_INTR_DONE) 492603831d35Sstevel scsb->scsb_hsc_state &= ~SCSB_AC_SLOT_INTR_DONE; 492703831d35Sstevel else 492803831d35Sstevel scsb->scsb_hsc_state |= SCSB_AC_SLOT_INTR_DONE; 492903831d35Sstevel break; /* we break and wait for slot interrupt. */ 493003831d35Sstevel } 493103831d35Sstevel 493203831d35Sstevel /* 493303831d35Sstevel * cPCI slot interrupt event 493403831d35Sstevel */ 493503831d35Sstevel if (scsb->scsb_state & SCSB_IS_TONGA) { 493603831d35Sstevel if (slotnum > TG_MAX_SLOTS || 493703831d35Sstevel slotnum == SC_TG_CPU_SLOT) { 493803831d35Sstevel continue; 493903831d35Sstevel } 494003831d35Sstevel } else { 494103831d35Sstevel if (slotnum > MC_MAX_SLOTS || 494203831d35Sstevel slotnum == SC_MC_CPU_SLOT || 494303831d35Sstevel (scsb->scsb_hsc_state & SCSB_HSC_CTC_PRES && 494403831d35Sstevel slotnum == SC_MC_CTC_SLOT)) { 494503831d35Sstevel continue; 494603831d35Sstevel } 494703831d35Sstevel } 494803831d35Sstevel if (scsb_is_alarm_card_slot(scsb, slotnum) == B_TRUE) { 494903831d35Sstevel DEBUG2("AC slot Intr %d(%d)\n", slotnum, idx+1); 495003831d35Sstevel ac_slot = B_TRUE; 495103831d35Sstevel } 495203831d35Sstevel val = scsb_fru_op(scsb, SLOT, unit, SCTRL_SYSCFG_BASE, 495303831d35Sstevel SCSB_FRU_OP_GET_BITVAL); 495403831d35Sstevel if (ac_slot == B_TRUE) { 495503831d35Sstevel ac_present = scsb_fru_op(scsb, ALARM, 1, 495603831d35Sstevel SCTRL_SYSCFG_BASE, 495703831d35Sstevel SCSB_FRU_OP_GET_BITVAL); 495803831d35Sstevel #ifdef DEBUG 495903831d35Sstevel if ((((val) && (!ac_present)) || 496003831d35Sstevel ((!val) && (ac_present))) && 496103831d35Sstevel (scsb->scsb_hsc_state & 496203831d35Sstevel SCSB_AC_SLOT_INTR_DONE)) { 496303831d35Sstevel 496403831d35Sstevel cmn_err(CE_WARN, "?Alarm and Slot presence " 496503831d35Sstevel "state bits do not match! (%x,%x)", 496603831d35Sstevel val, ac_present); 496703831d35Sstevel } 496803831d35Sstevel #endif 496903831d35Sstevel if (scsb->scsb_hsc_state & SCSB_AC_SLOT_INTR_DONE) 497003831d35Sstevel scsb->scsb_hsc_state &= ~SCSB_AC_SLOT_INTR_DONE; 497103831d35Sstevel else 497203831d35Sstevel scsb->scsb_hsc_state |= SCSB_AC_SLOT_INTR_DONE; 497303831d35Sstevel } 497403831d35Sstevel if (val) { 497503831d35Sstevel if (ac_present) { 497603831d35Sstevel DEBUG1("AC insertion on slot %d!\n", slotnum); 497703831d35Sstevel if (scsb_debug & 0x00010000) { 497803831d35Sstevel cmn_err(CE_NOTE, "scsb_intr: " 497903831d35Sstevel "AC_PRES slot %d", slotnum); 498003831d35Sstevel } 498103831d35Sstevel scsb->scsb_hsc_state |= SCSB_ALARM_CARD_PRES; 498203831d35Sstevel } 498303831d35Sstevel #ifndef lint 498403831d35Sstevel else 498503831d35Sstevel DEBUG1("IO Insertion on slot %d!\n", slotnum); 498603831d35Sstevel #endif 498703831d35Sstevel /* 498803831d35Sstevel * Special case : check MPID type. 498903831d35Sstevel * If MC midplane type, 499003831d35Sstevel * check to make sure the Alarm Card present 499103831d35Sstevel * bit is ON. If not, this is a regular IO card. 499203831d35Sstevel */ 499303831d35Sstevel (void) scsb_connect_slot(scsb, slotnum, B_FALSE); 499403831d35Sstevel } else { 499503831d35Sstevel if ((ac_slot == B_TRUE) && 499603831d35Sstevel (scsb->scsb_hsc_state & SCSB_ALARM_CARD_PRES)) { 499703831d35Sstevel 499803831d35Sstevel DEBUG1("AC Removal on slot %d!\n", slotnum); 499903831d35Sstevel #ifdef DEBUG 500003831d35Sstevel if (scsb_debug & 0x00010000) { 500103831d35Sstevel cmn_err(CE_NOTE, "scsb_intr: " 500203831d35Sstevel "!AC_PRES slot %d", 500303831d35Sstevel slotnum); 500403831d35Sstevel } 500503831d35Sstevel #endif /* DEBUG */ 500603831d35Sstevel scsb->scsb_hsc_state &= ~SCSB_ALARM_CARD_PRES; 500703831d35Sstevel } 500803831d35Sstevel #ifndef lint 500903831d35Sstevel else 501003831d35Sstevel DEBUG1("IO Removal on slot %d!\n", slotnum); 501103831d35Sstevel #endif 501203831d35Sstevel (void) scsb_disconnect_slot(scsb, B_FALSE, slotnum); 501303831d35Sstevel } 501403831d35Sstevel /* 501503831d35Sstevel * END INDENT CHEATING, 2 indentations 501603831d35Sstevel */ 501703831d35Sstevel 501803831d35Sstevel break; 501903831d35Sstevel default: 502003831d35Sstevel /* 502103831d35Sstevel * ERROR: Did not find cause of INTSRC bit 502203831d35Sstevel */ 502303831d35Sstevel if (scsb_debug & 0x00000002) { 502403831d35Sstevel cmn_err(CE_WARN, 502503831d35Sstevel "scsb_intr: FRU type %d" 502603831d35Sstevel " not recognized", fru_type); 502703831d35Sstevel } 502803831d35Sstevel continue; 502903831d35Sstevel } 503003831d35Sstevel scsb_event_code |= code; 503103831d35Sstevel retval |= (SCSB_INTR_CLAIMED | SCSB_INTR_EVENT); 503203831d35Sstevel if (fru_type == SLOT) 503303831d35Sstevel continue; 503403831d35Sstevel error = 0; 503503831d35Sstevel fru_ptr = mct_system_info.fru_info_list[fru_type]; 503603831d35Sstevel for (; fru_ptr != NULL; fru_ptr = fru_ptr->next) { 503703831d35Sstevel if (unit != fru_ptr->fru_unit) 503803831d35Sstevel continue; 503903831d35Sstevel if (fru_ptr->i2c_info == NULL || 504003831d35Sstevel (tmp_reg = fru_ptr->i2c_info-> 504103831d35Sstevel ledata_reg) == 0) 504203831d35Sstevel continue; 504303831d35Sstevel error = scsb_set_scfg_pres_leds(scsb, fru_ptr); 504403831d35Sstevel if (error) { 504503831d35Sstevel cmn_err(CE_WARN, "scsb_intr(): " 504603831d35Sstevel "I2C write error to 0x%x", 504703831d35Sstevel tmp_reg); 504803831d35Sstevel if (!(scsb->scsb_state & 504903831d35Sstevel SCSB_DEBUG_MODE)) { 505003831d35Sstevel goto intr_error; 505103831d35Sstevel } 505203831d35Sstevel } 505303831d35Sstevel break; 505403831d35Sstevel } 505503831d35Sstevel } 505603831d35Sstevel if (clr_bits) { 505703831d35Sstevel clr_bits = 0; 505803831d35Sstevel } 505903831d35Sstevel } 506003831d35Sstevel /* 506103831d35Sstevel * Check for SCB 1.5 interrupt for SLOT HEALTHY changes 506203831d35Sstevel */ 506303831d35Sstevel clr_bits = 0; 506403831d35Sstevel intr_idx = 0; 506503831d35Sstevel numregs = SCTRL_INTR_NUMREGS; 506603831d35Sstevel intr_addr = SCSB_REG_ADDR(SCTRL_INTSRC_BASE); 506703831d35Sstevel index = SCSB_REG_INDEX(intr_addr); 506803831d35Sstevel if (IS_SCB_P15) { 506903831d35Sstevel for (i = 0; i < SCTRL_BHLTHY_NUMREGS; 507003831d35Sstevel ++i, ++intr_idx, ++intr_addr) { 507103831d35Sstevel scsb->scsb_data_reg[index++] = scb_intr_regs[intr_idx]; 507203831d35Sstevel intr_reg = scb_intr_regs[i]; 507303831d35Sstevel while (intr_reg) { 507403831d35Sstevel idx = event_to_index((uint32_t)intr_reg); 507503831d35Sstevel code = (1 << idx); 507603831d35Sstevel clr_bits |= code; 507703831d35Sstevel intr_reg = intr_reg & ~code; 507803831d35Sstevel /* idx + 1 because bit 0 is for Slot 1 */ 507903831d35Sstevel slotnum = tonga_ssl_to_psl(scsb, idx + 1); 508003831d35Sstevel if (scsb->scsb_state & SCSB_IS_TONGA) { 508103831d35Sstevel if (slotnum > TG_MAX_SLOTS || 508203831d35Sstevel slotnum == SC_TG_CPU_SLOT) { 508303831d35Sstevel continue; 508403831d35Sstevel } 508503831d35Sstevel } else { 508603831d35Sstevel if (slotnum > MC_MAX_SLOTS || 508703831d35Sstevel slotnum == SC_MC_CPU_SLOT || 508803831d35Sstevel (scsb->scsb_hsc_state & 508903831d35Sstevel SCSB_HSC_CTC_PRES && 509003831d35Sstevel slotnum == SC_MC_CTC_SLOT)) { 509103831d35Sstevel continue; 509203831d35Sstevel } 509303831d35Sstevel } 509403831d35Sstevel scsb_healthy_intr(scsb, slotnum); 509503831d35Sstevel } 509603831d35Sstevel if (clr_bits) { 509703831d35Sstevel clr_bits = 0; 509803831d35Sstevel } 509903831d35Sstevel } 510003831d35Sstevel } 510103831d35Sstevel code = scsb_event_code; 510203831d35Sstevel if (retval & SCSB_INTR_EVENT && 510303831d35Sstevel !(scsb->scsb_state & SCSB_P06_NOINT_KLUGE)) { 510403831d35Sstevel check_fru_info(scsb, code); 510503831d35Sstevel add_event_code(scsb, code); 510603831d35Sstevel (void) scsb_queue_ops(scsb, QPUT_INT32, 1, &scsb_event_code, 510703831d35Sstevel "scsb_intr"); 510803831d35Sstevel } 510903831d35Sstevel intr_error: 511003831d35Sstevel scb_post_e = gethrtime(); 511103831d35Sstevel 511203831d35Sstevel if (scsb_debug & 0x8000000) 511303831d35Sstevel cmn_err(CE_NOTE, "Summary of times in nsec: pre_time %llu, \ 511403831d35Sstevel post_time %llu", scb_pre_e - scb_pre_s, 511503831d35Sstevel scb_post_e - scb_post_s); 511603831d35Sstevel 511703831d35Sstevel 511803831d35Sstevel mutex_enter(&scsb->scsb_mutex); 511903831d35Sstevel scsb_in_postintr = 0; 512003831d35Sstevel cv_broadcast(&scsb->scsb_cv); 512103831d35Sstevel mutex_exit(&scsb->scsb_mutex); 512203831d35Sstevel 512303831d35Sstevel /* 512403831d35Sstevel * Re-enable interrupt now. 512503831d35Sstevel */ 5126*07d06da5SSurya Prakki (void) scsb_toggle_psmint(scsb, 1); 512703831d35Sstevel scsb->scsb_state &= ~SCSB_IN_INTR; 512803831d35Sstevel } 512903831d35Sstevel 513003831d35Sstevel static int 513103831d35Sstevel scsb_polled_int(scsb_state_t *scsb, int cmd, uint32_t *set) 513203831d35Sstevel { 513303831d35Sstevel if (scsb_debug & 0x4000) 513403831d35Sstevel cmn_err(CE_NOTE, "scsb_polled_int(scsb,0x%x)", cmd); 513503831d35Sstevel *set = 0; 513603831d35Sstevel if (cmd == SCSBIOC_SHUTDOWN_POLL) { 513703831d35Sstevel return (EINVAL); 513803831d35Sstevel } 513903831d35Sstevel if (cmd != SCSBIOC_INTEVENT_POLL) { 514003831d35Sstevel return (EINVAL); 514103831d35Sstevel } 514203831d35Sstevel if (scsb->scsb_state & SCSB_P06_NOINT_KLUGE) { 514303831d35Sstevel /* 514403831d35Sstevel * scsb_intr() may modify scsb_event_code 514503831d35Sstevel */ 514603831d35Sstevel scsb_event_code = SCTRL_EVENT_NONE; 514703831d35Sstevel (void) scsb_intr((caddr_t)scsb); 514803831d35Sstevel *set = scsb_event_code; 514903831d35Sstevel scsb_event_code = 0; 515003831d35Sstevel } else { 515103831d35Sstevel /* 515203831d35Sstevel * SCSB_P06_INTR_ON, we know there was an event 515303831d35Sstevel * and we're retrieving the event code from the event FIFO. 515403831d35Sstevel */ 515503831d35Sstevel *set = get_event_code(); 515603831d35Sstevel } 515703831d35Sstevel if (scsb_debug & 0x01004000) { 515803831d35Sstevel cmn_err(CE_NOTE, "scsb_polled_int: event_code = 0x%x", *set); 515903831d35Sstevel } 516003831d35Sstevel return (0); 516103831d35Sstevel } 516203831d35Sstevel 516303831d35Sstevel static int 516403831d35Sstevel scsb_leds_switch(scsb_state_t *scsb, scsb_ustate_t op) 516503831d35Sstevel { 516603831d35Sstevel register int i; 516703831d35Sstevel int index; 516803831d35Sstevel uchar_t reg, idata, rwbuf[SCTRL_MAX_GROUP_NUMREGS]; 516903831d35Sstevel 517003831d35Sstevel if (scsb->scsb_state & SCSB_FROZEN && 517103831d35Sstevel !(scsb->scsb_state & SCSB_IN_INTR)) { 517203831d35Sstevel return (EAGAIN); 517303831d35Sstevel } 517403831d35Sstevel if (scsb_debug & 0x0101) { 517503831d35Sstevel cmn_err(CE_NOTE, "scsb_leds_switch(%s):", 517603831d35Sstevel op == ON ? "ON" : "OFF"); 517703831d35Sstevel } 517803831d35Sstevel /* Step 1: turn ON/OFF all NOK LEDs. */ 517903831d35Sstevel if (scsb_debug & 0x0100) { 518003831d35Sstevel cmn_err(CE_NOTE, "scsb%d: turning all NOK LEDs %s", 518103831d35Sstevel scsb->scsb_instance, 518203831d35Sstevel op == ON ? "ON" : "OFF"); 518303831d35Sstevel } 518403831d35Sstevel if (op == ON) 518503831d35Sstevel idata = 0xff; 518603831d35Sstevel else /* off */ 518703831d35Sstevel idata = 0x00; 518803831d35Sstevel reg = SCSB_REG_ADDR(SCTRL_LED_NOK_BASE); 518903831d35Sstevel index = SCSB_REG_INDEX(reg); 519003831d35Sstevel for (i = 0; i < SCTRL_LED_NOK_NUMREGS; ++i) { 519103831d35Sstevel rwbuf[i] = idata; 519203831d35Sstevel scsb->scsb_data_reg[index + i] = idata; 519303831d35Sstevel } 519403831d35Sstevel mutex_enter(&scsb->scsb_mutex); 519503831d35Sstevel i = scsb_rdwr_register(scsb, I2C_WR, reg, SCTRL_LED_NOK_NUMREGS, 519603831d35Sstevel rwbuf, 1); 519703831d35Sstevel mutex_exit(&scsb->scsb_mutex); 519803831d35Sstevel if (i) { 519903831d35Sstevel if (scsb_debug & 0x0102) 520003831d35Sstevel cmn_err(CE_WARN, "scsb_leds_switch(): " 520103831d35Sstevel "Failed to turn %s NOK LEDs", 520203831d35Sstevel op == ON ? "ON" : "OFF"); 520303831d35Sstevel } 520403831d35Sstevel /* Step 2: turn ON/OFF all OK LEDs. */ 520503831d35Sstevel if (scsb_debug & 0x0100) { 520603831d35Sstevel cmn_err(CE_NOTE, "scsb%d: turning all OK LEDs %s", 520703831d35Sstevel scsb->scsb_instance, 520803831d35Sstevel op == ON ? "ON" : "OFF"); 520903831d35Sstevel } 521003831d35Sstevel reg = SCSB_REG_ADDR(SCTRL_LED_OK_BASE); 521103831d35Sstevel index = SCSB_REG_INDEX(reg); 521203831d35Sstevel for (i = 0; i < SCTRL_LED_OK_NUMREGS; ++i) { 521303831d35Sstevel rwbuf[i] = idata; 521403831d35Sstevel scsb->scsb_data_reg[index + i] = idata; 521503831d35Sstevel } 521603831d35Sstevel mutex_enter(&scsb->scsb_mutex); 521703831d35Sstevel i = scsb_rdwr_register(scsb, I2C_WR, reg, SCTRL_LED_OK_NUMREGS, 521803831d35Sstevel rwbuf, 1); 521903831d35Sstevel mutex_exit(&scsb->scsb_mutex); 522003831d35Sstevel if (i) { 522103831d35Sstevel if (scsb_debug & 0x0102) 522203831d35Sstevel cmn_err(CE_WARN, "scsb_leds_switch(): " 522303831d35Sstevel "Failed to turn %s NOK LEDs", 522403831d35Sstevel op == ON ? "ON" : "OFF"); 522503831d35Sstevel } 522603831d35Sstevel /* Step 3: turn OFF all BLINK LEDs. */ 522703831d35Sstevel if (op == OFF) { 522803831d35Sstevel reg = SCSB_REG_ADDR(SCTRL_BLINK_OK_BASE); 522903831d35Sstevel index = SCSB_REG_INDEX(reg); 523003831d35Sstevel for (i = 0; i < SCTRL_BLINK_NUMREGS; ++i) { 523103831d35Sstevel rwbuf[i] = idata; 523203831d35Sstevel scsb->scsb_data_reg[index + i] = idata; 523303831d35Sstevel } 523403831d35Sstevel mutex_enter(&scsb->scsb_mutex); 523503831d35Sstevel i = scsb_rdwr_register(scsb, I2C_WR, reg, SCTRL_BLINK_NUMREGS, 523603831d35Sstevel rwbuf, 1); 523703831d35Sstevel mutex_exit(&scsb->scsb_mutex); 523803831d35Sstevel if (i) { 523903831d35Sstevel if (scsb_debug & 0x0102) 524003831d35Sstevel cmn_err(CE_WARN, "scsb_leds_switch(): " 524103831d35Sstevel "Failed to turn %s BLINK BITs", 524203831d35Sstevel op == ON ? "ON" : "OFF"); 524303831d35Sstevel } 524403831d35Sstevel } 524503831d35Sstevel return (0); 524603831d35Sstevel } 524703831d35Sstevel 524803831d35Sstevel static int 524903831d35Sstevel scsb_readall_regs(scsb_state_t *scsb) 525003831d35Sstevel { 525103831d35Sstevel int error; 525203831d35Sstevel int index; 525303831d35Sstevel uchar_t reg; 525403831d35Sstevel 525503831d35Sstevel if (!(scsb_debug & 0x40000000)) 525603831d35Sstevel return (0); 525703831d35Sstevel if (scsb_debug & 0x0005) { 525803831d35Sstevel cmn_err(CE_NOTE, "scsb_readall_regs:"); 525903831d35Sstevel } 526003831d35Sstevel if (scsb->scsb_state & SCSB_FROZEN) { 526103831d35Sstevel return (EAGAIN); 526203831d35Sstevel } 526303831d35Sstevel reg = SCSB_REG_ADDR_START; /* 1st register in set */ 526403831d35Sstevel index = SCSB_REG_INDEX(reg); 526503831d35Sstevel error = scsb_rdwr_register(scsb, I2C_WR_RD, reg, SCSB_DATA_REGISTERS, 526603831d35Sstevel &scsb->scsb_data_reg[index], 1); 526703831d35Sstevel return (error); 526803831d35Sstevel } 526903831d35Sstevel 527003831d35Sstevel 527103831d35Sstevel /* 527203831d35Sstevel * read 1-byte register, mask with read bits (rmask), 527303831d35Sstevel * turn ON bits in on_mask, turn OFF bits in off_mask 527403831d35Sstevel * write the byte back to register 527503831d35Sstevel * NOTE: MUST be called with mutex held 527603831d35Sstevel */ 527703831d35Sstevel static int 527803831d35Sstevel scsb_write_mask(scsb_state_t *scsb, 527903831d35Sstevel uchar_t reg, 528003831d35Sstevel uchar_t rmask, 528103831d35Sstevel uchar_t on_mask, 528203831d35Sstevel uchar_t off_mask) 528303831d35Sstevel { 528403831d35Sstevel i2c_transfer_t *i2cxferp; 528503831d35Sstevel int index, error = 0; 528603831d35Sstevel uchar_t reg_data; 528703831d35Sstevel 528803831d35Sstevel if (scsb_debug & 0x0800) { 528903831d35Sstevel cmn_err(CE_NOTE, "scsb_write_mask(,%x,,%x,%x):", 529003831d35Sstevel reg, on_mask, off_mask); 529103831d35Sstevel } 529203831d35Sstevel if (scsb->scsb_state & SCSB_FROZEN && 529303831d35Sstevel !(scsb->scsb_state & SCSB_IN_INTR)) { 529403831d35Sstevel return (EAGAIN); 529503831d35Sstevel } 529603831d35Sstevel /* select the register address and read the register */ 529703831d35Sstevel i2cxferp = (i2c_transfer_t *)scsb->scsb_i2ctp; 529803831d35Sstevel i2cxferp->i2c_flags = I2C_WR_RD; 529903831d35Sstevel i2cxferp->i2c_wlen = 1; 530003831d35Sstevel i2cxferp->i2c_rlen = 1; 530103831d35Sstevel i2cxferp->i2c_wbuf[0] = reg; 530203831d35Sstevel i2cxferp->i2c_rbuf[0] = 0; 530303831d35Sstevel scsb->scsb_kstat_flag = B_TRUE; /* we did a i2c transaction */ 530403831d35Sstevel if (error = nct_i2c_transfer(scsb->scsb_phandle, i2cxferp)) { 530503831d35Sstevel error = EIO; 530603831d35Sstevel goto wm_error; 530703831d35Sstevel } 530803831d35Sstevel scsb->scsb_i2c_errcnt = 0; 530903831d35Sstevel if (scsb_debug & 0x0800) 531003831d35Sstevel cmn_err(CE_NOTE, "scsb_write_mask() read 0x%x", 531103831d35Sstevel i2cxferp->i2c_rbuf[0]); 531203831d35Sstevel reg_data = i2cxferp->i2c_rbuf[0]; 531303831d35Sstevel if (rmask) 531403831d35Sstevel reg_data &= rmask; 531503831d35Sstevel if (off_mask) 531603831d35Sstevel reg_data &= ~off_mask; 531703831d35Sstevel if (on_mask) 531803831d35Sstevel reg_data |= on_mask; 531903831d35Sstevel i2cxferp->i2c_flags = I2C_WR; 532003831d35Sstevel i2cxferp->i2c_wlen = 2; 532103831d35Sstevel i2cxferp->i2c_wbuf[0] = reg; 532203831d35Sstevel i2cxferp->i2c_wbuf[1] = reg_data; 532303831d35Sstevel if (error = nct_i2c_transfer(scsb->scsb_phandle, i2cxferp)) { 532403831d35Sstevel error = EIO; 532503831d35Sstevel goto wm_error; 532603831d35Sstevel } 532703831d35Sstevel /* keep shadow registers updated */ 532803831d35Sstevel index = SCSB_REG_INDEX(reg); 532903831d35Sstevel scsb->scsb_data_reg[index] = reg_data; 533003831d35Sstevel if (scsb_debug & 0x0800) 533103831d35Sstevel cmn_err(CE_NOTE, "scsb_write_mask() wrote 0x%x", reg_data); 533203831d35Sstevel scsb->scsb_i2c_errcnt = 0; 533303831d35Sstevel return (error); 533403831d35Sstevel wm_error: 533503831d35Sstevel scsb->scsb_i2c_errcnt++; 533603831d35Sstevel if (scsb->scsb_i2c_errcnt > scsb_err_threshold) 533703831d35Sstevel scsb->scsb_err_flag = B_TRUE; /* latch error */ 533803831d35Sstevel if (scsb->scsb_state & SCSB_SSB_PRESENT) { 533903831d35Sstevel if (scsb_debug & 0x0802) 534003831d35Sstevel cmn_err(CE_WARN, 534103831d35Sstevel "scsb_write_mask(): reg %x %s error, data=%x", 534203831d35Sstevel reg, 534303831d35Sstevel i2cxferp->i2c_flags & I2C_WR ? "write" : "read", 534403831d35Sstevel i2cxferp->i2c_flags & I2C_WR ? 534503831d35Sstevel i2cxferp->i2c_wbuf[1] : i2cxferp->i2c_rbuf[0]); 534603831d35Sstevel } else { 534703831d35Sstevel if (scsb->scsb_i2c_errcnt >= scsb_freeze_count) 534803831d35Sstevel scsb_freeze(scsb); 534903831d35Sstevel return (EAGAIN); 535003831d35Sstevel } 535103831d35Sstevel return (error); 535203831d35Sstevel } 535303831d35Sstevel 535403831d35Sstevel /* 535503831d35Sstevel * read/write len consecutive single byte registers to/from rbuf 535603831d35Sstevel * NOTE: should be called with mutex held 535703831d35Sstevel */ 535803831d35Sstevel static int 535903831d35Sstevel scsb_rdwr_register(scsb_state_t *scsb, int op, uchar_t reg, int len, 536003831d35Sstevel uchar_t *rwbuf, int i2c_alloc) 536103831d35Sstevel { 536203831d35Sstevel i2c_transfer_t *i2cxferp; 536303831d35Sstevel int i, rlen, wlen, index, error = 0; 536403831d35Sstevel 536503831d35Sstevel if (scsb_debug & 0x0800) { 536603831d35Sstevel cmn_err(CE_NOTE, "scsb_rdwr_register(scsb,%s,%x,%x,buf):", 536703831d35Sstevel (op == I2C_WR) ? "write" : "read", reg, len); 536803831d35Sstevel } 536903831d35Sstevel if (scsb->scsb_state & SCSB_FROZEN && 537003831d35Sstevel !(scsb->scsb_state & SCSB_IN_INTR)) { 537103831d35Sstevel return (EAGAIN); 537203831d35Sstevel } 537303831d35Sstevel if (i2c_alloc) { 537403831d35Sstevel i2cxferp = scsb_alloc_i2ctx(scsb->scsb_phandle, I2C_NOSLEEP); 537503831d35Sstevel if (i2cxferp == NULL) { 537603831d35Sstevel if (scsb_debug & 0x0042) 537703831d35Sstevel cmn_err(CE_WARN, "scsb_rdwr_register: " 537803831d35Sstevel "i2ctx allocation failure"); 537903831d35Sstevel return (ENOMEM); 538003831d35Sstevel } 538103831d35Sstevel } else { 538203831d35Sstevel i2cxferp = scsb->scsb_i2ctp; 538303831d35Sstevel } 538403831d35Sstevel index = SCSB_REG_INDEX(reg); 538503831d35Sstevel switch (op) { 538603831d35Sstevel case I2C_WR: 538703831d35Sstevel wlen = len + 1; /* add the address */ 538803831d35Sstevel rlen = 0; 538903831d35Sstevel i2cxferp->i2c_wbuf[0] = reg; 539003831d35Sstevel for (i = 0; i < len; ++i) { 539103831d35Sstevel scsb->scsb_data_reg[index + i] = 539203831d35Sstevel i2cxferp->i2c_wbuf[1 + i] = rwbuf[i]; 539303831d35Sstevel if (scsb_debug & 0x0080) 539403831d35Sstevel cmn_err(CE_NOTE, 539503831d35Sstevel "scsb_rdwr_register: writing rwbuf[%d]=0x%x", 539603831d35Sstevel i, rwbuf[i]); 539703831d35Sstevel } 539803831d35Sstevel break; 539903831d35Sstevel case I2C_WR_RD: 540003831d35Sstevel wlen = 1; /* for the address */ 540103831d35Sstevel rlen = len; 540203831d35Sstevel i2cxferp->i2c_wbuf[0] = reg; 540303831d35Sstevel break; 540403831d35Sstevel default: 540503831d35Sstevel if (i2c_alloc) 540603831d35Sstevel scsb_free_i2ctx(scsb->scsb_phandle, i2cxferp); 540703831d35Sstevel return (EINVAL); 540803831d35Sstevel } 540903831d35Sstevel /* select the register address */ 541003831d35Sstevel i2cxferp->i2c_flags = op; 541103831d35Sstevel i2cxferp->i2c_rlen = rlen; 541203831d35Sstevel i2cxferp->i2c_wlen = wlen; 541303831d35Sstevel i2cxferp->i2c_wbuf[0] = reg; 541403831d35Sstevel scsb->scsb_kstat_flag = B_TRUE; /* we did a i2c transaction */ 541503831d35Sstevel if (error = nct_i2c_transfer(scsb->scsb_phandle, i2cxferp)) { 541603831d35Sstevel error = EIO; 541703831d35Sstevel } else if (rlen) { 541803831d35Sstevel /* copy to rwbuf[] and keep shadow registers updated */ 541903831d35Sstevel for (i = 0; i < len; ++i) { 542003831d35Sstevel scsb->scsb_data_reg[index + i] = rwbuf[i] = 542103831d35Sstevel i2cxferp->i2c_rbuf[i]; 542203831d35Sstevel if (scsb_debug & 0x0080) 542303831d35Sstevel cmn_err(CE_NOTE, 542403831d35Sstevel "scsb_rdwr_register: read rwbuf[%d]=0x%x", 542503831d35Sstevel i, rwbuf[i]); 542603831d35Sstevel } 542703831d35Sstevel } 542803831d35Sstevel if (i2c_alloc) 542903831d35Sstevel scsb_free_i2ctx(scsb->scsb_phandle, i2cxferp); 543003831d35Sstevel if (error) { 543103831d35Sstevel scsb->scsb_i2c_errcnt++; 543203831d35Sstevel if (scsb->scsb_i2c_errcnt > scsb_err_threshold) 543303831d35Sstevel scsb->scsb_err_flag = B_TRUE; /* latch error */ 543403831d35Sstevel if (!(scsb->scsb_state & SCSB_SSB_PRESENT)) { 543503831d35Sstevel if (scsb->scsb_i2c_errcnt >= scsb_freeze_count) 543603831d35Sstevel scsb_freeze(scsb); 543703831d35Sstevel return (EAGAIN); 543803831d35Sstevel } else { 543903831d35Sstevel cmn_err(CE_WARN, 544003831d35Sstevel "scsb_rdwr_register(): I2C read error from %x", 544103831d35Sstevel reg); 544203831d35Sstevel } 544303831d35Sstevel } else { 544403831d35Sstevel scsb->scsb_i2c_errcnt = 0; 544503831d35Sstevel } 544603831d35Sstevel 544703831d35Sstevel return (error); 544803831d35Sstevel } 544903831d35Sstevel 545003831d35Sstevel /* 545103831d35Sstevel * Called from scsb_intr() 545203831d35Sstevel * First find the fru_info for this fru_id, and set fru_status for callback. 545303831d35Sstevel * Then check for a registered call_back entry for this fru_id, 545403831d35Sstevel * and if found, call it. 545503831d35Sstevel * Recursize call until no EVENTS left in evcode. 545603831d35Sstevel */ 545703831d35Sstevel static void 545803831d35Sstevel check_fru_info(scsb_state_t *scsb, int evcode) 545903831d35Sstevel { 546003831d35Sstevel struct scsb_cb_entry *cbe_ptr; 546103831d35Sstevel fru_info_t *fru_ptr; 546203831d35Sstevel fru_id_t fru_id; 546303831d35Sstevel scsb_fru_status_t fru_status; 546403831d35Sstevel int i, new_evcode; 546503831d35Sstevel 546603831d35Sstevel if (scsb_debug & 0x00100001) 546703831d35Sstevel cmn_err(CE_NOTE, "check_fru_info(scsb,0x%x)", evcode); 546803831d35Sstevel if (evcode == 0) 546903831d35Sstevel return; 547003831d35Sstevel i = event_to_index((uint32_t)evcode); 547103831d35Sstevel new_evcode = evcode & ~(1 << i); 547203831d35Sstevel if (i > MCT_MAX_FRUS) { 547303831d35Sstevel if (scsb_debug & 0x00100000) 547403831d35Sstevel cmn_err(CE_NOTE, 547503831d35Sstevel "check_fru_info: index %d out of range", i); 547603831d35Sstevel check_fru_info(scsb, new_evcode); 547703831d35Sstevel return; 547803831d35Sstevel } 547903831d35Sstevel fru_id = fru_id_table[i]; 548003831d35Sstevel fru_ptr = find_fru_info(fru_id); 548103831d35Sstevel if (fru_ptr == (fru_info_t *)NULL) { 548203831d35Sstevel check_fru_info(scsb, new_evcode); 548303831d35Sstevel return; 548403831d35Sstevel } 548503831d35Sstevel update_fru_info(scsb, fru_ptr); 548603831d35Sstevel if (fru_ptr->fru_status & FRU_PRESENT) { 548703831d35Sstevel fru_status = FRU_PRESENT; 548803831d35Sstevel } else { 548903831d35Sstevel fru_status = FRU_NOT_PRESENT; 549003831d35Sstevel if (fru_ptr->fru_type == SSB) { 549103831d35Sstevel /* 549203831d35Sstevel * WARN against SCB removal if any 549303831d35Sstevel * occupied slots are in reset 549403831d35Sstevel */ 549503831d35Sstevel scsb_freeze_check(scsb); 549603831d35Sstevel } 549703831d35Sstevel } 549803831d35Sstevel /* 549903831d35Sstevel * check for an entry in the CallBack table 550003831d35Sstevel */ 550103831d35Sstevel for (cbe_ptr = scsb_cb_table; cbe_ptr != NULL; 550203831d35Sstevel cbe_ptr = cbe_ptr->cb_next) { 550303831d35Sstevel if (cbe_ptr->cb_fru_id == fru_id && 550403831d35Sstevel cbe_ptr->cb_fru_ptr == fru_ptr) { 550503831d35Sstevel if (scsb_debug & 0x00800000) 550603831d35Sstevel cmn_err(CE_NOTE, 550703831d35Sstevel "check_fru_info: callback for FRU_ID " 550803831d35Sstevel "0x%x; device is %spresent", 550903831d35Sstevel (int)fru_id, 551003831d35Sstevel fru_status == FRU_PRESENT ? 551103831d35Sstevel "" : "not "); 551203831d35Sstevel (*cbe_ptr->cb_func)( 551303831d35Sstevel cbe_ptr->cb_softstate_ptr, 551403831d35Sstevel cbe_ptr->cb_event, 551503831d35Sstevel fru_status); 551603831d35Sstevel break; 551703831d35Sstevel } 551803831d35Sstevel } 551903831d35Sstevel check_fru_info(scsb, new_evcode); 552003831d35Sstevel } 552103831d35Sstevel 552203831d35Sstevel /* 552303831d35Sstevel * ----------------------------- 552403831d35Sstevel * scsb kstat support functions. 552503831d35Sstevel * ----------------------------- 552603831d35Sstevel */ 552703831d35Sstevel /* 552803831d35Sstevel * Create and initialize the kstat data structures 552903831d35Sstevel */ 553003831d35Sstevel static int 553103831d35Sstevel scsb_alloc_kstats(scsb_state_t *scsb) 553203831d35Sstevel { 553303831d35Sstevel kstat_named_t *kn; 553403831d35Sstevel /* 553503831d35Sstevel * scsb_ks_leddata_t for "scsb_leddata" 553603831d35Sstevel */ 553703831d35Sstevel if (scsb_debug & 0x00080001) 553803831d35Sstevel cmn_err(CE_NOTE, 553903831d35Sstevel "scsb_alloc_kstats: create scsb_leddata: %lu bytes", 554003831d35Sstevel sizeof (scsb_ks_leddata_t)); 554103831d35Sstevel if ((scsb->ks_leddata = kstat_create(scsb_name, scsb->scsb_instance, 554203831d35Sstevel SCSB_KS_LEDDATA, "misc", KSTAT_TYPE_RAW, 554303831d35Sstevel sizeof (scsb_ks_leddata_t), KSTAT_FLAG_PERSISTENT)) 554403831d35Sstevel == NULL) { 554503831d35Sstevel scsb->scsb_state |= SCSB_KSTATS; 554603831d35Sstevel scsb_free_kstats(scsb); 554703831d35Sstevel return (DDI_FAILURE); 554803831d35Sstevel } 554903831d35Sstevel scsb->ks_leddata->ks_update = update_ks_leddata; 555003831d35Sstevel scsb->ks_leddata->ks_private = (void *)scsb; 555103831d35Sstevel if (update_ks_leddata(scsb->ks_leddata, KSTAT_READ) != DDI_SUCCESS) { 555203831d35Sstevel scsb->scsb_state |= SCSB_KSTATS; 555303831d35Sstevel scsb_free_kstats(scsb); 555403831d35Sstevel return (DDI_FAILURE); 555503831d35Sstevel } 555603831d35Sstevel kstat_install(scsb->ks_leddata); 555703831d35Sstevel /* 555803831d35Sstevel * scsb_ks_state_t for "scsb_state" 555903831d35Sstevel */ 556003831d35Sstevel if (scsb_debug & 0x00080000) 556103831d35Sstevel cmn_err(CE_NOTE, 556203831d35Sstevel "scsb_alloc_kstats: create scsb_state: %lu bytes", 556303831d35Sstevel sizeof (scsb_ks_state_t)); 556403831d35Sstevel if ((scsb->ks_state = kstat_create(scsb_name, scsb->scsb_instance, 556503831d35Sstevel SCSB_KS_STATE, "misc", KSTAT_TYPE_RAW, 556603831d35Sstevel sizeof (scsb_ks_state_t), KSTAT_FLAG_PERSISTENT)) 556703831d35Sstevel == NULL) { 556803831d35Sstevel scsb->scsb_state |= SCSB_KSTATS; 556903831d35Sstevel scsb_free_kstats(scsb); 557003831d35Sstevel return (DDI_FAILURE); 557103831d35Sstevel } 557203831d35Sstevel scsb->ks_state->ks_update = update_ks_state; 557303831d35Sstevel scsb->ks_state->ks_private = (void *)scsb; 557403831d35Sstevel if (update_ks_state(scsb->ks_state, KSTAT_READ) != DDI_SUCCESS) { 557503831d35Sstevel scsb->scsb_state |= SCSB_KSTATS; 557603831d35Sstevel scsb_free_kstats(scsb); 557703831d35Sstevel return (DDI_FAILURE); 557803831d35Sstevel } 557903831d35Sstevel kstat_install(scsb->ks_state); 558003831d35Sstevel /* 558103831d35Sstevel * mct_topology_t for "env_topology" 558203831d35Sstevel */ 558303831d35Sstevel if (scsb_debug & 0x00080000) 558403831d35Sstevel cmn_err(CE_NOTE, 558503831d35Sstevel "scsb_alloc_kstats: create env_toploogy: %lu bytes", 558603831d35Sstevel sizeof (mct_topology_t)); 558703831d35Sstevel if ((scsb->ks_topology = kstat_create(scsb_name, scsb->scsb_instance, 558803831d35Sstevel SCSB_KS_TOPOLOGY, "misc", KSTAT_TYPE_RAW, 558903831d35Sstevel sizeof (mct_topology_t), KSTAT_FLAG_PERSISTENT)) 559003831d35Sstevel == NULL) { 559103831d35Sstevel scsb->scsb_state |= SCSB_KSTATS; 559203831d35Sstevel scsb_free_kstats(scsb); 559303831d35Sstevel return (DDI_FAILURE); 559403831d35Sstevel } 559503831d35Sstevel scsb->ks_topology->ks_update = update_ks_topology; 559603831d35Sstevel scsb->ks_topology->ks_private = (void *)scsb; 559703831d35Sstevel if (update_ks_topology(scsb->ks_topology, KSTAT_READ) != DDI_SUCCESS) { 559803831d35Sstevel scsb->scsb_state |= SCSB_KSTATS; 559903831d35Sstevel scsb_free_kstats(scsb); 560003831d35Sstevel return (DDI_FAILURE); 560103831d35Sstevel } 560203831d35Sstevel kstat_install(scsb->ks_topology); 560303831d35Sstevel /* 560403831d35Sstevel * kstat_named_t * 2 for "scsb_evc_register" 560503831d35Sstevel */ 560603831d35Sstevel if (scsb_debug & 0x00080001) 560703831d35Sstevel cmn_err(CE_NOTE, 560803831d35Sstevel "scsb_alloc_kstats: create scsb_evc_register: %lu bytes", 560903831d35Sstevel sizeof (kstat_named_t) * 2); 561003831d35Sstevel if ((scsb->ks_evcreg = kstat_create(scsb_name, scsb->scsb_instance, 561103831d35Sstevel SCSB_KS_EVC_REGISTER, "misc", KSTAT_TYPE_NAMED, 2, 561203831d35Sstevel KSTAT_FLAG_PERSISTENT|KSTAT_FLAG_WRITABLE)) == NULL) { 561303831d35Sstevel scsb->scsb_state |= SCSB_KSTATS; 561403831d35Sstevel scsb_free_kstats(scsb); 561503831d35Sstevel return (DDI_FAILURE); 561603831d35Sstevel } 561703831d35Sstevel scsb->ks_evcreg->ks_update = update_ks_evcreg; 561803831d35Sstevel scsb->ks_evcreg->ks_private = (void *)scsb; 561903831d35Sstevel kn = KSTAT_NAMED_PTR(scsb->ks_evcreg); 562003831d35Sstevel kstat_named_init(&kn[0], "pid_register", KSTAT_DATA_INT64); 562103831d35Sstevel kstat_named_init(&kn[1], "pid_unregister", KSTAT_DATA_INT64); 562203831d35Sstevel kstat_install(scsb->ks_evcreg); 562303831d35Sstevel /* 562403831d35Sstevel * Done, set the flag for scsb_detach() and other checks 562503831d35Sstevel */ 562603831d35Sstevel scsb->scsb_state |= SCSB_KSTATS; 562703831d35Sstevel return (DDI_SUCCESS); 562803831d35Sstevel } 562903831d35Sstevel 563003831d35Sstevel static int 563103831d35Sstevel update_ks_leddata(kstat_t *ksp, int rw) 563203831d35Sstevel { 563303831d35Sstevel scsb_state_t *scsb; 563403831d35Sstevel scsb_ks_leddata_t *pks_leddata; 563503831d35Sstevel int i, numregs, index, error = DDI_SUCCESS; 563603831d35Sstevel uchar_t reg; 563703831d35Sstevel 563803831d35Sstevel scsb = (scsb_state_t *)ksp->ks_private; 563903831d35Sstevel if (scsb_debug & 0x00080001) 564003831d35Sstevel cmn_err(CE_NOTE, "update_ks_leddata: KS_UPDATE%sset", 564103831d35Sstevel scsb->scsb_state & SCSB_KS_UPDATE ? " " : " not "); 564203831d35Sstevel /* 564303831d35Sstevel * Since this is satisfied from the shadow registers, let it succeed 564403831d35Sstevel * even if the SCB is not present. It would be nice to return the 564503831d35Sstevel * shadow values with a warning. 564603831d35Sstevel * 564703831d35Sstevel * if (scsb->scsb_state & SCSB_FROZEN) { 564803831d35Sstevel * return (DDI_FAILURE); 564903831d35Sstevel * } 565003831d35Sstevel */ 565103831d35Sstevel if (rw == KSTAT_WRITE) { 565203831d35Sstevel return (EACCES); 565303831d35Sstevel } 565403831d35Sstevel mutex_enter(&scsb->scsb_mutex); 565503831d35Sstevel while (scsb->scsb_state & SCSB_KS_UPDATE) { 565603831d35Sstevel if (cv_wait_sig(&scsb->scsb_cv, &scsb->scsb_mutex) <= 0) { 565703831d35Sstevel mutex_exit(&scsb->scsb_mutex); 565803831d35Sstevel return (EINTR); 565903831d35Sstevel } 566003831d35Sstevel } 566103831d35Sstevel scsb->scsb_state |= SCSB_KS_UPDATE; 566203831d35Sstevel mutex_exit(&scsb->scsb_mutex); 566303831d35Sstevel if (scsb_debug & 0x00080001) 566403831d35Sstevel cmn_err(CE_NOTE, "update_ks_leddata: updating data"); 566503831d35Sstevel pks_leddata = (scsb_ks_leddata_t *)ksp->ks_data; 566603831d35Sstevel /* 566703831d35Sstevel * Call tonga_slotnum_led_shift() for each register that 566803831d35Sstevel * contains Slot 1-5 information, the first register at each base: 566903831d35Sstevel * NOK_BASE, OK_BASE, BLINK_OK_BASE 567003831d35Sstevel * XXX: breaking register table access rules by not using macros. 567103831d35Sstevel */ 567203831d35Sstevel /* NOK */ 567303831d35Sstevel reg = SCSB_REG_ADDR(SCTRL_LED_NOK_BASE); 567403831d35Sstevel index = SCSB_REG_INDEX(reg); 567503831d35Sstevel numregs = SCTRL_LED_NOK_NUMREGS; 567603831d35Sstevel i = 0; 567703831d35Sstevel if (IS_SCB_P15) 567803831d35Sstevel reg = tonga_slotnum_led_shift(scsb, scsb->scsb_data_reg[index]); 567903831d35Sstevel else 568003831d35Sstevel reg = scsb->scsb_data_reg[index]; 568103831d35Sstevel pks_leddata->scb_led_regs[i] = reg; 568203831d35Sstevel for (++i, ++index; i < numregs; ++i, ++index) 568303831d35Sstevel pks_leddata->scb_led_regs[i] = scsb->scsb_data_reg[index]; 568403831d35Sstevel /* OK */ 568503831d35Sstevel reg = SCSB_REG_ADDR(SCTRL_LED_OK_BASE); 568603831d35Sstevel index = SCSB_REG_INDEX(reg); 568703831d35Sstevel numregs += SCTRL_LED_OK_NUMREGS; 568803831d35Sstevel if (IS_SCB_P15) 568903831d35Sstevel reg = tonga_slotnum_led_shift(scsb, scsb->scsb_data_reg[index]); 569003831d35Sstevel else 569103831d35Sstevel reg = scsb->scsb_data_reg[index]; 569203831d35Sstevel pks_leddata->scb_led_regs[i] = reg; 569303831d35Sstevel for (++i, ++index; i < numregs; ++i, ++index) 569403831d35Sstevel pks_leddata->scb_led_regs[i] = scsb->scsb_data_reg[index]; 569503831d35Sstevel /* BLINK */ 569603831d35Sstevel reg = SCSB_REG_ADDR(SCTRL_BLINK_OK_BASE); 569703831d35Sstevel index = SCSB_REG_INDEX(reg); 569803831d35Sstevel numregs += SCTRL_BLINK_NUMREGS; 569903831d35Sstevel if (IS_SCB_P15) 570003831d35Sstevel reg = tonga_slotnum_led_shift(scsb, scsb->scsb_data_reg[index]); 570103831d35Sstevel else 570203831d35Sstevel reg = scsb->scsb_data_reg[index]; 570303831d35Sstevel pks_leddata->scb_led_regs[i] = reg; 570403831d35Sstevel for (++i, ++index; i < numregs; ++i, ++index) 570503831d35Sstevel pks_leddata->scb_led_regs[i] = scsb->scsb_data_reg[index]; 570603831d35Sstevel mutex_enter(&scsb->scsb_mutex); 570703831d35Sstevel scsb->scsb_state &= ~SCSB_KS_UPDATE; 570803831d35Sstevel cv_signal(&scsb->scsb_cv); 570903831d35Sstevel mutex_exit(&scsb->scsb_mutex); 571003831d35Sstevel if (scsb_debug & 0x00080001) 571103831d35Sstevel cmn_err(CE_NOTE, "update_ks_leddata: returning"); 571203831d35Sstevel return (error); 571303831d35Sstevel } 571403831d35Sstevel 571503831d35Sstevel static int 571603831d35Sstevel update_ks_evcreg(kstat_t *ksp, int rw) 571703831d35Sstevel { 571803831d35Sstevel scsb_state_t *scsb; 571903831d35Sstevel int error = 0; 572003831d35Sstevel kstat_named_t *kn = KSTAT_NAMED_PTR(ksp); 572103831d35Sstevel pid_t pid; 572203831d35Sstevel 572303831d35Sstevel scsb = (scsb_state_t *)ksp->ks_private; 572403831d35Sstevel if (scsb_debug & 0x00080001) 572503831d35Sstevel cmn_err(CE_NOTE, "update_ks_evcreg: %s(%d), KS_UPDATE%sset", 572603831d35Sstevel rw == KSTAT_READ ? "read" : "write", rw, 572703831d35Sstevel scsb->scsb_state & SCSB_KS_UPDATE ? " " : " not "); 572803831d35Sstevel /* 572903831d35Sstevel * Let this registration succeed 573003831d35Sstevel * 573103831d35Sstevel * if (scsb->scsb_state & SCSB_FROZEN) { 573203831d35Sstevel * return (DDI_FAILURE); 573303831d35Sstevel * } 573403831d35Sstevel */ 573503831d35Sstevel mutex_enter(&scsb->scsb_mutex); 573603831d35Sstevel while (scsb->scsb_state & SCSB_KS_UPDATE) { 573703831d35Sstevel if (cv_wait_sig(&scsb->scsb_cv, &scsb->scsb_mutex) <= 0) { 573803831d35Sstevel mutex_exit(&scsb->scsb_mutex); 573903831d35Sstevel return (EINTR); 574003831d35Sstevel } 574103831d35Sstevel } 574203831d35Sstevel scsb->scsb_state |= SCSB_KS_UPDATE; 574303831d35Sstevel mutex_exit(&scsb->scsb_mutex); 574403831d35Sstevel if (rw == KSTAT_READ) { 574503831d35Sstevel kn[0].value.i64 = (int64_t)0; 574603831d35Sstevel kn[1].value.i64 = (int64_t)0; 574703831d35Sstevel } else if (rw == KSTAT_WRITE) { 574803831d35Sstevel /* 574903831d35Sstevel * kn[0] is "pid_register", kn[1] is "pid_unregister" 575003831d35Sstevel */ 575103831d35Sstevel if (kn[0].value.i64 != 0 && kn[1].value.i64 == 0) { 575203831d35Sstevel pid = (pid_t)kn[0].value.i64; 575303831d35Sstevel if (add_event_proc(scsb, pid)) { 575403831d35Sstevel if (scsb_debug & 0x02000002) { 575503831d35Sstevel cmn_err(CE_WARN, 575603831d35Sstevel "update_ks_evcreg: " 575703831d35Sstevel "process add failed for %d", 575803831d35Sstevel pid); 575903831d35Sstevel } 576003831d35Sstevel error = EOVERFLOW; 576103831d35Sstevel } 576203831d35Sstevel } else if (kn[0].value.i64 == 0 && kn[1].value.i64 != 0) { 576303831d35Sstevel pid = (pid_t)kn[1].value.i64; 576403831d35Sstevel if (del_event_proc(scsb, pid)) { 576503831d35Sstevel if (scsb_debug & 0x02000000) { 576603831d35Sstevel cmn_err(CE_NOTE, 576703831d35Sstevel "update_ks_evcreg: " 576803831d35Sstevel "process delete failed for %d", 576903831d35Sstevel pid); 577003831d35Sstevel } 577103831d35Sstevel error = EOVERFLOW; 577203831d35Sstevel } 577303831d35Sstevel } else if (kn[0].value.i64 == 0 && kn[1].value.i64 == 0) { 577403831d35Sstevel /* 577503831d35Sstevel * rewind the pointers and counts, zero the table. 577603831d35Sstevel */ 577703831d35Sstevel rew_event_proc(scsb); 577803831d35Sstevel } else { 577903831d35Sstevel error = EINVAL; 578003831d35Sstevel } 578103831d35Sstevel } else { 578203831d35Sstevel error = EINVAL; 578303831d35Sstevel } 578403831d35Sstevel mutex_enter(&scsb->scsb_mutex); 578503831d35Sstevel scsb->scsb_state &= ~SCSB_KS_UPDATE; 578603831d35Sstevel cv_signal(&scsb->scsb_cv); 578703831d35Sstevel mutex_exit(&scsb->scsb_mutex); 578803831d35Sstevel return (error); 578903831d35Sstevel } 579003831d35Sstevel 579103831d35Sstevel static int 579203831d35Sstevel update_ks_state(kstat_t *ksp, int rw) 579303831d35Sstevel { 579403831d35Sstevel scsb_state_t *scsb; 579503831d35Sstevel scsb_ks_state_t *pks_state; 579603831d35Sstevel int error = DDI_SUCCESS; 579703831d35Sstevel uint32_t current_evc; 579803831d35Sstevel 579903831d35Sstevel scsb = (scsb_state_t *)ksp->ks_private; 580003831d35Sstevel if (scsb_debug & 0x00080001) 580103831d35Sstevel cmn_err(CE_NOTE, "update_ks_state: KS_UPDATE%sset", 580203831d35Sstevel scsb->scsb_state & SCSB_KS_UPDATE ? " " : " not "); 580303831d35Sstevel /* 580403831d35Sstevel * Let this succeed based on last known data 580503831d35Sstevel * 580603831d35Sstevel * if (scsb->scsb_state & SCSB_FROZEN) { 580703831d35Sstevel * return (DDI_FAILURE); 580803831d35Sstevel * } 580903831d35Sstevel */ 581003831d35Sstevel if (rw == KSTAT_WRITE) { 581103831d35Sstevel return (EACCES); 581203831d35Sstevel } 581303831d35Sstevel mutex_enter(&scsb->scsb_mutex); 581403831d35Sstevel while (scsb->scsb_state & SCSB_KS_UPDATE) { 581503831d35Sstevel if (cv_wait_sig(&scsb->scsb_cv, &scsb->scsb_mutex) <= 0) { 581603831d35Sstevel mutex_exit(&scsb->scsb_mutex); 581703831d35Sstevel return (EINTR); 581803831d35Sstevel } 581903831d35Sstevel } 582003831d35Sstevel scsb->scsb_state |= SCSB_KS_UPDATE; 582103831d35Sstevel /* 582203831d35Sstevel * If SSB not present and scsb not SCSB_FROZEN, check for SCB presence 582303831d35Sstevel * by initiating an I2C read from the SCB. If an error occurs, 582403831d35Sstevel * scsb_freeze() will be called to update SCB info and scsb state. 582503831d35Sstevel */ 582603831d35Sstevel if (!(scsb->scsb_state & SCSB_SSB_PRESENT) && 582703831d35Sstevel !(scsb->scsb_state & SCSB_FROZEN)) { 582803831d35Sstevel uchar_t data; 582903831d35Sstevel /* Read the SCB PROM ID */ 583003831d35Sstevel if (data = scsb_rdwr_register(scsb, I2C_WR_RD, 583103831d35Sstevel (uchar_t)SCTRL_PROM_VERSION, 1, &data, 1)) 583203831d35Sstevel if (scsb_debug & 0x00080002) 583303831d35Sstevel cmn_err(CE_NOTE, "update_ks_state: SCB/I2C " 583403831d35Sstevel "failure %d", data); 583503831d35Sstevel } 583603831d35Sstevel mutex_exit(&scsb->scsb_mutex); 583703831d35Sstevel pks_state = (scsb_ks_state_t *)ksp->ks_data; 583803831d35Sstevel pks_state->scb_present = (scsb->scsb_state & SCSB_SCB_PRESENT) ? 1 : 0; 583903831d35Sstevel pks_state->ssb_present = (scsb->scsb_state & SCSB_SSB_PRESENT) ? 1 : 0; 584003831d35Sstevel pks_state->scsb_frozen = (scsb->scsb_state & SCSB_FROZEN) ? 1 : 0; 584103831d35Sstevel if (scsb->scsb_state & SCSB_DEBUG_MODE) 584203831d35Sstevel pks_state->scsb_mode = (uint8_t)ENVC_DEBUG_MODE; 584303831d35Sstevel else if (scsb->scsb_state & SCSB_DIAGS_MODE) 584403831d35Sstevel pks_state->scsb_mode = (uint8_t)ENVCTRL_DIAG_MODE; 584503831d35Sstevel else 584603831d35Sstevel pks_state->scsb_mode = (uint8_t)ENVCTRL_NORMAL_MODE; 584703831d35Sstevel /* 584803831d35Sstevel * If scsb_attach() has not completed the kstat installs, 584903831d35Sstevel * then there are no event processes to check for. 585003831d35Sstevel */ 585103831d35Sstevel if (scsb->scsb_state & SCSB_KSTATS) { 585203831d35Sstevel switch (check_event_procs(¤t_evc)) { 585303831d35Sstevel case EVC_NO_EVENT_CODE: 585403831d35Sstevel pks_state->event_code = 0; 585503831d35Sstevel break; 585603831d35Sstevel case EVC_NEW_EVENT_CODE: 585703831d35Sstevel /* FALLTHROUGH */ 585803831d35Sstevel case EVC_NO_CURR_PROC: 585903831d35Sstevel pks_state->event_code = current_evc; 586003831d35Sstevel break; 586103831d35Sstevel case EVC_OR_EVENT_CODE: 586203831d35Sstevel pks_state->event_code |= current_evc; 586303831d35Sstevel break; 586403831d35Sstevel case EVC_FAILURE: 586503831d35Sstevel pks_state->event_code = 0; 586603831d35Sstevel error = DDI_FAILURE; 586703831d35Sstevel break; 586803831d35Sstevel } 586903831d35Sstevel } else { 587003831d35Sstevel pks_state->event_code = 0; 587103831d35Sstevel } 587203831d35Sstevel mutex_enter(&scsb->scsb_mutex); 587303831d35Sstevel scsb->scsb_state &= ~SCSB_KS_UPDATE; 587403831d35Sstevel cv_signal(&scsb->scsb_cv); 587503831d35Sstevel mutex_exit(&scsb->scsb_mutex); 587603831d35Sstevel return (error); 587703831d35Sstevel } 587803831d35Sstevel 587903831d35Sstevel static int 588003831d35Sstevel update_ks_topology(kstat_t *ksp, int rw) 588103831d35Sstevel { 588203831d35Sstevel scsb_state_t *scsb; 588303831d35Sstevel mct_topology_t *pks_topo; 588403831d35Sstevel fru_info_t *fru_ptr; 588503831d35Sstevel int i, val, error = DDI_SUCCESS, slotnum; 588603831d35Sstevel 588703831d35Sstevel scsb = (scsb_state_t *)ksp->ks_private; 588803831d35Sstevel if (scsb_debug & 0x00080001) 588903831d35Sstevel cmn_err(CE_NOTE, "update_ks_topology: KS_UPDATE%sset", 589003831d35Sstevel scsb->scsb_state & SCSB_KS_UPDATE ? " " : " not "); 589103831d35Sstevel /* 589203831d35Sstevel * Let this succeed based on last known data 589303831d35Sstevel * 589403831d35Sstevel * if (scsb->scsb_state & SCSB_FROZEN) { 589503831d35Sstevel * return (DDI_FAILURE); 589603831d35Sstevel * } 589703831d35Sstevel */ 589803831d35Sstevel if (rw == KSTAT_WRITE) { 589903831d35Sstevel return (EACCES); 590003831d35Sstevel } 590103831d35Sstevel mutex_enter(&scsb->scsb_mutex); 590203831d35Sstevel while (scsb->scsb_state & SCSB_KS_UPDATE) { 590303831d35Sstevel if (cv_wait_sig(&scsb->scsb_cv, &scsb->scsb_mutex) <= 0) { 590403831d35Sstevel mutex_exit(&scsb->scsb_mutex); 590503831d35Sstevel return (EINTR); 590603831d35Sstevel } 590703831d35Sstevel } 590803831d35Sstevel scsb->scsb_state |= SCSB_KS_UPDATE; 590903831d35Sstevel /* 591003831d35Sstevel * If SSB not present and scsb not SCSB_FROZEN, check for SCB presence 591103831d35Sstevel * by initiating an I2C read from the SCB. If an error occurs, 591203831d35Sstevel * scsb_freeze() will be called to update SCB info and scsb state. 591303831d35Sstevel */ 591403831d35Sstevel if (!(scsb->scsb_state & SCSB_SSB_PRESENT) && 591503831d35Sstevel !(scsb->scsb_state & SCSB_FROZEN)) { 591603831d35Sstevel uchar_t data; 591703831d35Sstevel /* Read the SCB PROM ID */ 591803831d35Sstevel if (data = scsb_rdwr_register(scsb, I2C_WR_RD, 591903831d35Sstevel (uchar_t)SCTRL_PROM_VERSION, 1, &data, 1)) 592003831d35Sstevel if (scsb_debug & 0x00080002) 592103831d35Sstevel cmn_err(CE_NOTE, "update_ks_topology: SCB/I2C " 592203831d35Sstevel "failure %d", data); 592303831d35Sstevel } 592403831d35Sstevel mutex_exit(&scsb->scsb_mutex); 592503831d35Sstevel pks_topo = (mct_topology_t *)ksp->ks_data; 592603831d35Sstevel for (i = SLOT; i < SCSB_UNIT_TYPES; ++i) { 592703831d35Sstevel pks_topo->max_units[i] = mct_system_info.max_units[i]; 592803831d35Sstevel } 592903831d35Sstevel 593003831d35Sstevel pks_topo->mid_plane.fru_status = FRU_PRESENT; 593103831d35Sstevel pks_topo->mid_plane.fru_unit = (scsb_unum_t)1; 593203831d35Sstevel pks_topo->mid_plane.fru_type = mct_system_info.mid_plane.fru_type; 593303831d35Sstevel pks_topo->mid_plane.fru_id = mct_system_info.mid_plane.fru_id; 593403831d35Sstevel pks_topo->mid_plane.fru_version = mct_system_info.mid_plane.fru_version; 593503831d35Sstevel pks_topo->mid_plane.fru_health = MCT_HEALTH_OK; 593603831d35Sstevel fru_ptr = mct_system_info.fru_info_list[SLOT]; 593703831d35Sstevel for (i = 0; i < pks_topo->max_units[SLOT]; ++i, ++fru_ptr) { 593803831d35Sstevel pks_topo->mct_slots[i].fru_status = fru_ptr->fru_status; 593903831d35Sstevel pks_topo->mct_slots[i].fru_type = fru_ptr->fru_type; 594003831d35Sstevel pks_topo->mct_slots[i].fru_unit = fru_ptr->fru_unit; 594103831d35Sstevel pks_topo->mct_slots[i].fru_id = fru_ptr->fru_id; 594203831d35Sstevel pks_topo->mct_slots[i].fru_version = fru_ptr->fru_version; 594303831d35Sstevel /* 594403831d35Sstevel * XXX: need to check healthy regs to set fru_health 594503831d35Sstevel */ 594603831d35Sstevel slotnum = tonga_psl_to_ssl(scsb, i+1); 594703831d35Sstevel val = scsb_fru_op(scsb, SLOT, slotnum, SCTRL_BHLTHY_BASE, 594803831d35Sstevel SCSB_FRU_OP_GET_BITVAL); 594903831d35Sstevel pks_topo->mct_slots[i].fru_health = (val) ? 595003831d35Sstevel MCT_HEALTH_OK : MCT_HEALTH_NOK; 595103831d35Sstevel } 595203831d35Sstevel fru_ptr = mct_system_info.fru_info_list[PDU]; 595303831d35Sstevel for (i = 0; i < pks_topo->max_units[PDU]; ++i, ++fru_ptr) { 595403831d35Sstevel pks_topo->mct_pdu[i].fru_status = fru_ptr->fru_status; 595503831d35Sstevel pks_topo->mct_pdu[i].fru_type = fru_ptr->fru_type; 595603831d35Sstevel pks_topo->mct_pdu[i].fru_unit = fru_ptr->fru_unit; 595703831d35Sstevel pks_topo->mct_pdu[i].fru_id = fru_ptr->fru_id; 595803831d35Sstevel pks_topo->mct_pdu[i].fru_version = fru_ptr->fru_version; 595903831d35Sstevel pks_topo->mct_pdu[i].fru_health = MCT_HEALTH_NA; 596003831d35Sstevel } 596103831d35Sstevel fru_ptr = mct_system_info.fru_info_list[PS]; 596203831d35Sstevel for (i = 0; i < pks_topo->max_units[PS]; ++i, ++fru_ptr) { 596303831d35Sstevel pks_topo->mct_ps[i].fru_status = fru_ptr->fru_status; 596403831d35Sstevel pks_topo->mct_ps[i].fru_type = fru_ptr->fru_type; 596503831d35Sstevel pks_topo->mct_ps[i].fru_unit = fru_ptr->fru_unit; 596603831d35Sstevel pks_topo->mct_ps[i].fru_id = fru_ptr->fru_id; 596703831d35Sstevel pks_topo->mct_ps[i].fru_version = fru_ptr->fru_version; 596803831d35Sstevel pks_topo->mct_ps[i].fru_health = MCT_HEALTH_NA; 596903831d35Sstevel } 597003831d35Sstevel fru_ptr = mct_system_info.fru_info_list[DISK]; 597103831d35Sstevel for (i = 0; i < pks_topo->max_units[DISK]; ++i, ++fru_ptr) { 597203831d35Sstevel pks_topo->mct_disk[i].fru_status = fru_ptr->fru_status; 597303831d35Sstevel pks_topo->mct_disk[i].fru_type = fru_ptr->fru_type; 597403831d35Sstevel pks_topo->mct_disk[i].fru_unit = fru_ptr->fru_unit; 597503831d35Sstevel pks_topo->mct_disk[i].fru_id = fru_ptr->fru_id; 597603831d35Sstevel pks_topo->mct_disk[i].fru_version = fru_ptr->fru_version; 597703831d35Sstevel pks_topo->mct_disk[i].fru_health = MCT_HEALTH_NA; 597803831d35Sstevel } 597903831d35Sstevel fru_ptr = mct_system_info.fru_info_list[FAN]; 598003831d35Sstevel for (i = 0; i < pks_topo->max_units[FAN]; ++i, ++fru_ptr) { 598103831d35Sstevel pks_topo->mct_fan[i].fru_status = fru_ptr->fru_status; 598203831d35Sstevel pks_topo->mct_fan[i].fru_type = fru_ptr->fru_type; 598303831d35Sstevel pks_topo->mct_fan[i].fru_unit = fru_ptr->fru_unit; 598403831d35Sstevel pks_topo->mct_fan[i].fru_id = fru_ptr->fru_id; 598503831d35Sstevel pks_topo->mct_fan[i].fru_version = fru_ptr->fru_version; 598603831d35Sstevel pks_topo->mct_fan[i].fru_health = MCT_HEALTH_NA; 598703831d35Sstevel } 598803831d35Sstevel fru_ptr = mct_system_info.fru_info_list[SCB]; 598903831d35Sstevel for (i = 0; i < pks_topo->max_units[SCB]; ++i, ++fru_ptr) { 599003831d35Sstevel pks_topo->mct_scb[i].fru_status = fru_ptr->fru_status; 599103831d35Sstevel pks_topo->mct_scb[i].fru_type = fru_ptr->fru_type; 599203831d35Sstevel pks_topo->mct_scb[i].fru_unit = fru_ptr->fru_unit; 599303831d35Sstevel pks_topo->mct_scb[i].fru_id = fru_ptr->fru_id; 599403831d35Sstevel pks_topo->mct_scb[i].fru_version = fru_ptr->fru_version; 599503831d35Sstevel /* 599603831d35Sstevel * To get the scsb health, if there was no i2c transaction 599703831d35Sstevel * until this read, generate an i2c transaction. 599803831d35Sstevel */ 599903831d35Sstevel if (scsb->scsb_kstat_flag == B_FALSE) { 600003831d35Sstevel uchar_t data; 6001*07d06da5SSurya Prakki (void) scsb_blind_read(scsb, I2C_WR_RD, 600203831d35Sstevel (uchar_t)SCTRL_PROM_VERSION, 1, &data, 1); 600303831d35Sstevel } 600403831d35Sstevel pks_topo->mct_scb[i].fru_health = ((scsb->scsb_err_flag == 600503831d35Sstevel B_TRUE || scsb->scsb_i2c_errcnt > scsb_err_threshold) 600603831d35Sstevel ? MCT_HEALTH_NOK : MCT_HEALTH_OK); 600703831d35Sstevel #ifdef DEBUG 600803831d35Sstevel if (pks_topo->mct_scb[i].fru_health == MCT_HEALTH_NOK) 600903831d35Sstevel cmn_err(CE_WARN, "SCSB kstat health:%d", pks_topo-> 601003831d35Sstevel mct_scb[i].fru_health); 601103831d35Sstevel #endif 601203831d35Sstevel scsb->scsb_err_flag = B_FALSE; /* clear error flag once read */ 601303831d35Sstevel scsb->scsb_kstat_flag = B_FALSE; /* false? read from i2c */ 601403831d35Sstevel } 601503831d35Sstevel fru_ptr = mct_system_info.fru_info_list[SSB]; 601603831d35Sstevel for (i = 0; i < pks_topo->max_units[SSB]; ++i, ++fru_ptr) { 601703831d35Sstevel pks_topo->mct_ssb[i].fru_status = fru_ptr->fru_status; 601803831d35Sstevel pks_topo->mct_ssb[i].fru_type = fru_ptr->fru_type; 601903831d35Sstevel pks_topo->mct_ssb[i].fru_unit = fru_ptr->fru_unit; 602003831d35Sstevel pks_topo->mct_ssb[i].fru_id = fru_ptr->fru_id; 602103831d35Sstevel pks_topo->mct_ssb[i].fru_version = fru_ptr->fru_version; 602203831d35Sstevel pks_topo->mct_ssb[i].fru_health = MCT_HEALTH_NA; 602303831d35Sstevel } 602403831d35Sstevel fru_ptr = mct_system_info.fru_info_list[ALARM]; 602503831d35Sstevel for (i = 0; i < pks_topo->max_units[ALARM]; ++i, ++fru_ptr) { 602603831d35Sstevel pks_topo->mct_alarm[i].fru_status = fru_ptr->fru_status; 602703831d35Sstevel pks_topo->mct_alarm[i].fru_type = fru_ptr->fru_type; 602803831d35Sstevel pks_topo->mct_alarm[i].fru_unit = fru_ptr->fru_unit; 602903831d35Sstevel pks_topo->mct_alarm[i].fru_id = fru_ptr->fru_id; 603003831d35Sstevel pks_topo->mct_alarm[i].fru_version = fru_ptr->fru_version; 603103831d35Sstevel pks_topo->mct_alarm[i].fru_health = MCT_HEALTH_NA; 603203831d35Sstevel } 603303831d35Sstevel fru_ptr = mct_system_info.fru_info_list[CFTM]; 603403831d35Sstevel for (i = 0; i < pks_topo->max_units[CFTM]; ++i, ++fru_ptr) { 603503831d35Sstevel pks_topo->mct_cftm[i].fru_status = fru_ptr->fru_status; 603603831d35Sstevel pks_topo->mct_cftm[i].fru_type = fru_ptr->fru_type; 603703831d35Sstevel pks_topo->mct_cftm[i].fru_unit = fru_ptr->fru_unit; 603803831d35Sstevel pks_topo->mct_cftm[i].fru_id = fru_ptr->fru_id; 603903831d35Sstevel pks_topo->mct_cftm[i].fru_version = fru_ptr->fru_version; 604003831d35Sstevel pks_topo->mct_cftm[i].fru_health = MCT_HEALTH_NA; 604103831d35Sstevel } 604203831d35Sstevel fru_ptr = mct_system_info.fru_info_list[CRTM]; 604303831d35Sstevel for (i = 0; i < pks_topo->max_units[CRTM]; ++i, ++fru_ptr) { 604403831d35Sstevel pks_topo->mct_crtm[i].fru_status = fru_ptr->fru_status; 604503831d35Sstevel pks_topo->mct_crtm[i].fru_type = fru_ptr->fru_type; 604603831d35Sstevel pks_topo->mct_crtm[i].fru_unit = fru_ptr->fru_unit; 604703831d35Sstevel pks_topo->mct_crtm[i].fru_id = fru_ptr->fru_id; 604803831d35Sstevel pks_topo->mct_crtm[i].fru_version = fru_ptr->fru_version; 604903831d35Sstevel pks_topo->mct_crtm[i].fru_health = MCT_HEALTH_NA; 605003831d35Sstevel } 605103831d35Sstevel fru_ptr = mct_system_info.fru_info_list[PRTM]; 605203831d35Sstevel for (i = 0; i < pks_topo->max_units[PRTM]; ++i, ++fru_ptr) { 605303831d35Sstevel pks_topo->mct_prtm[i].fru_status = fru_ptr->fru_status; 605403831d35Sstevel pks_topo->mct_prtm[i].fru_type = fru_ptr->fru_type; 605503831d35Sstevel pks_topo->mct_prtm[i].fru_unit = fru_ptr->fru_unit; 605603831d35Sstevel pks_topo->mct_prtm[i].fru_id = fru_ptr->fru_id; 605703831d35Sstevel pks_topo->mct_prtm[i].fru_version = fru_ptr->fru_version; 605803831d35Sstevel pks_topo->mct_prtm[i].fru_health = MCT_HEALTH_NA; 605903831d35Sstevel } 606003831d35Sstevel mutex_enter(&scsb->scsb_mutex); 606103831d35Sstevel scsb->scsb_state &= ~SCSB_KS_UPDATE; 606203831d35Sstevel cv_signal(&scsb->scsb_cv); 606303831d35Sstevel mutex_exit(&scsb->scsb_mutex); 606403831d35Sstevel return (error); 606503831d35Sstevel } 606603831d35Sstevel 606703831d35Sstevel static void 606803831d35Sstevel scsb_free_kstats(scsb_state_t *scsb) 606903831d35Sstevel { 607003831d35Sstevel if (!(scsb->scsb_state & SCSB_KSTATS)) 607103831d35Sstevel return; 607203831d35Sstevel /* 607303831d35Sstevel * free the allocated kstat data 607403831d35Sstevel */ 607503831d35Sstevel if (scsb->ks_evcreg != NULL) { 607603831d35Sstevel kstat_delete(scsb->ks_evcreg); 607703831d35Sstevel } 607803831d35Sstevel if (scsb->ks_topology != NULL) { 607903831d35Sstevel kstat_delete(scsb->ks_topology); 608003831d35Sstevel } 608103831d35Sstevel if (scsb->ks_state != NULL) { 608203831d35Sstevel kstat_delete(scsb->ks_state); 608303831d35Sstevel } 608403831d35Sstevel if (scsb->ks_leddata != NULL) { 608503831d35Sstevel kstat_delete(scsb->ks_leddata); 608603831d35Sstevel } 608703831d35Sstevel scsb->ks_leddata = NULL; 608803831d35Sstevel scsb->ks_state = NULL; 608903831d35Sstevel scsb->ks_topology = NULL; 609003831d35Sstevel scsb->ks_evcreg = NULL; 609103831d35Sstevel scsb->scsb_state &= ~SCSB_KSTATS; 609203831d35Sstevel } 609303831d35Sstevel 609403831d35Sstevel 609503831d35Sstevel /* 609603831d35Sstevel * -------------------------------------- 609703831d35Sstevel * Miscellaneous scsb internal functions. 609803831d35Sstevel * -------------------------------------- 609903831d35Sstevel * 610003831d35Sstevel * allocate I2C transfer structure 610103831d35Sstevel */ 610203831d35Sstevel static i2c_transfer_t * 610303831d35Sstevel scsb_alloc_i2ctx(i2c_client_hdl_t phandle, uint_t sleep) 610403831d35Sstevel { 610503831d35Sstevel i2c_transfer_t *tp; 610603831d35Sstevel 610703831d35Sstevel if (i2c_transfer_alloc(phandle, &tp, SCSB_DATA_REGISTERS + 2, 610803831d35Sstevel SCSB_DATA_REGISTERS + 2, sleep) == I2C_FAILURE) { 610903831d35Sstevel return (NULL); 611003831d35Sstevel } 611103831d35Sstevel return (tp); 611203831d35Sstevel } 611303831d35Sstevel 611403831d35Sstevel /* 611503831d35Sstevel * free I2C transfer structure 611603831d35Sstevel */ 611703831d35Sstevel static void 611803831d35Sstevel scsb_free_i2ctx(i2c_client_hdl_t phandle, i2c_transfer_t *tp) 611903831d35Sstevel { 612003831d35Sstevel i2c_transfer_free(phandle, tp); 612103831d35Sstevel } 612203831d35Sstevel 612303831d35Sstevel static void 612403831d35Sstevel update_fru_info(scsb_state_t *scsb, fru_info_t *fru_ptr) 612503831d35Sstevel { 612603831d35Sstevel int index; 612703831d35Sstevel uchar_t reg, bit; 612803831d35Sstevel fru_info_t *acslot_ptr = NULL; 612903831d35Sstevel fru_id_t acslot_id = 0; 613003831d35Sstevel if (scsb_debug & 0x00100001) 6131*07d06da5SSurya Prakki cmn_err(CE_NOTE, "update_fru_info(scsb,0x%p)", (void *)fru_ptr); 613203831d35Sstevel if (fru_ptr == (fru_info_t *)NULL || 613303831d35Sstevel fru_ptr->i2c_info == (fru_i2c_info_t *)NULL) 613403831d35Sstevel return; 613503831d35Sstevel /* 613603831d35Sstevel * If this is an Alarm Card update, then we also need to get 613703831d35Sstevel * Alarm Card Slot fru_ptr to update it's fru_type, and maybe fru_id 613803831d35Sstevel */ 613903831d35Sstevel if (fru_ptr->fru_id == fru_id_table[FRU_INDEX(SCTRL_EVENT_ALARM)]) { 614003831d35Sstevel /* 614103831d35Sstevel * SCTRL_EVENT_SLOT1 == 0x01 so 614203831d35Sstevel * fru_id_table[] index for Slot 1 == 0 614303831d35Sstevel */ 614403831d35Sstevel acslot_id = fru_id_table[(scsb->ac_slotnum - 1)]; 614503831d35Sstevel acslot_ptr = find_fru_info(acslot_id); 614603831d35Sstevel } 614703831d35Sstevel reg = fru_ptr->i2c_info->syscfg_reg; 614803831d35Sstevel bit = fru_ptr->i2c_info->syscfg_bit; 614903831d35Sstevel if (reg == 0 && fru_ptr->fru_type == SCB) { 615003831d35Sstevel if (scsb->scsb_state & SCSB_SCB_PRESENT) 615103831d35Sstevel fru_ptr->fru_status = FRU_PRESENT; 615203831d35Sstevel else 615303831d35Sstevel fru_ptr->fru_status = FRU_NOT_PRESENT; 615403831d35Sstevel } else if (reg) { 615503831d35Sstevel index = SCSB_REG_INDEX(reg); 615603831d35Sstevel if (scsb->scsb_data_reg[index] & (1 << bit)) { 615703831d35Sstevel fru_ptr->fru_status = FRU_PRESENT; 615803831d35Sstevel /* 615903831d35Sstevel * XXX: need to add version register, and maybe a 616003831d35Sstevel * method, to the fru_ptr->i2c_info structure. 616103831d35Sstevel * 616203831d35Sstevel * fru_ptr->fru_version = (fru_version_t)0; 616303831d35Sstevel */ 616403831d35Sstevel /* 616503831d35Sstevel * Because scsb_intr() sometimes gets the AC present 616603831d35Sstevel * INT before the ACSLOT present INT, 616703831d35Sstevel * do not check the ACSLOT fru_status 616803831d35Sstevel * 616903831d35Sstevel * if (acslot_ptr != NULL && acslot_ptr->fru_status == 617003831d35Sstevel * FRU_PRESENT) 617103831d35Sstevel */ 617203831d35Sstevel if (acslot_ptr != NULL) 617303831d35Sstevel acslot_ptr->fru_type = (scsb_utype_t)OC_AC; 617403831d35Sstevel } else { 617503831d35Sstevel fru_ptr->fru_status = FRU_NOT_PRESENT; 617603831d35Sstevel /* 617703831d35Sstevel * fru_ptr->fru_version = (fru_version_t)0; 617803831d35Sstevel */ 617903831d35Sstevel if (acslot_ptr != NULL) { 618003831d35Sstevel /* AC just removed, but AC Slot is occupied? */ 618103831d35Sstevel if (acslot_ptr->fru_status == FRU_PRESENT) 618203831d35Sstevel /* for now it's unknown */ 618303831d35Sstevel acslot_ptr->fru_type = 618403831d35Sstevel (scsb_utype_t)OC_UNKN; 618503831d35Sstevel else 618603831d35Sstevel acslot_ptr->fru_type = 618703831d35Sstevel (scsb_utype_t)OC_UNKN; 618803831d35Sstevel } 618903831d35Sstevel } 619003831d35Sstevel } 619103831d35Sstevel if (scsb_debug & 0x00100000) 619203831d35Sstevel cmn_err(CE_NOTE, 619303831d35Sstevel "update_fru_info: type %d unit %d is %spresent", 619403831d35Sstevel fru_ptr->fru_type, fru_ptr->fru_unit, 619503831d35Sstevel fru_ptr->fru_status == FRU_PRESENT 619603831d35Sstevel ? "" : "not "); 619703831d35Sstevel } 619803831d35Sstevel 619903831d35Sstevel /* 620003831d35Sstevel * Convert EVENT code to FRU index 620103831d35Sstevel * by finding the highest bit number in 32 bit word 620203831d35Sstevel */ 620303831d35Sstevel static int 620403831d35Sstevel event_to_index(uint32_t evcode) 620503831d35Sstevel { 620603831d35Sstevel int i = 0; 620703831d35Sstevel if (evcode == 0) 620803831d35Sstevel return (MCT_MAX_FRUS - 1); 620903831d35Sstevel for (; (evcode >>= 1); i++) 621003831d35Sstevel ; 621103831d35Sstevel return (i); 621203831d35Sstevel } 621303831d35Sstevel 621403831d35Sstevel #ifdef DEBUG 621503831d35Sstevel void 621603831d35Sstevel scsb_debug_prnt(char *fmt, uintptr_t a1, uintptr_t a2, uintptr_t a3, 621703831d35Sstevel uintptr_t a4, uintptr_t a5) 621803831d35Sstevel { 621903831d35Sstevel if (scsb_debug & 0x8000 || 622003831d35Sstevel (*fmt == 'X' && scsb_debug & 0x00010000)) { 622103831d35Sstevel if (*fmt == 'X') 622203831d35Sstevel ++fmt; 622303831d35Sstevel prom_printf("scsb: "); 622403831d35Sstevel prom_printf(fmt, a1, a2, a3, a4, a5); 622503831d35Sstevel prom_printf("\n"); 622603831d35Sstevel } 622703831d35Sstevel } 622803831d35Sstevel #endif 622903831d35Sstevel 623003831d35Sstevel /* 623103831d35Sstevel * event code functions to deliver event codes 623203831d35Sstevel * and to manage: 623303831d35Sstevel * the event code fifo 623403831d35Sstevel * the process handle table for registered processes interested in 623503831d35Sstevel * event codes 623603831d35Sstevel */ 623703831d35Sstevel /* 623803831d35Sstevel * Send signal to processes registered for event code delivery 623903831d35Sstevel */ 624003831d35Sstevel static void 624103831d35Sstevel signal_evc_procs(scsb_state_t *scsb) 624203831d35Sstevel { 624303831d35Sstevel int i = 0, c = 0; 624403831d35Sstevel if (evc_proc_count == 0) 624503831d35Sstevel return; 624603831d35Sstevel for (; i < EVC_PROCS_MAX; ++i) { 624703831d35Sstevel if (evc_procs[i] != NULL) { 624803831d35Sstevel if (proc_signal(evc_procs[i], SIGPOLL)) { 624903831d35Sstevel if (scsb_debug & 0x02000002) 625003831d35Sstevel cmn_err(CE_WARN, 625103831d35Sstevel "scsb:signal_evc_procs: " 625203831d35Sstevel "signal to %d failed", 625319397407SSherry Moore ((struct pid *) 625419397407SSherry Moore evc_procs[i])->pid_id); 625503831d35Sstevel (void) del_event_proc(scsb, 625603831d35Sstevel ((struct pid *)evc_procs[i])->pid_id); 625703831d35Sstevel } 625803831d35Sstevel if (++c >= evc_proc_count) { 625903831d35Sstevel if (scsb_debug & 0x02000000) { 626003831d35Sstevel cmn_err(CE_NOTE, 626103831d35Sstevel "signal_evc_procs: signaled " 626203831d35Sstevel "%d/%d processes", c, 626303831d35Sstevel evc_proc_count); 626403831d35Sstevel } 626503831d35Sstevel break; 626603831d35Sstevel } 626703831d35Sstevel } 626803831d35Sstevel } 626903831d35Sstevel } 627003831d35Sstevel 627103831d35Sstevel /* 627203831d35Sstevel * bump FIFO ptr, taking care of wrap around 627303831d35Sstevel */ 627403831d35Sstevel static uint32_t * 627503831d35Sstevel inc_fifo_ptr(uint32_t *ptr) 627603831d35Sstevel { 627703831d35Sstevel if (++ptr >= evc_fifo + EVC_FIFO_SIZE) 627803831d35Sstevel ptr = evc_fifo; 627903831d35Sstevel return (ptr); 628003831d35Sstevel } 628103831d35Sstevel 628203831d35Sstevel /* ARGSUSED */ 628303831d35Sstevel static void 628403831d35Sstevel reset_evc_fifo(scsb_state_t *scsb) 628503831d35Sstevel { 628603831d35Sstevel evc_wptr = evc_fifo; 628703831d35Sstevel evc_rptr = evc_fifo; 628803831d35Sstevel evc_fifo_count = 0; 628903831d35Sstevel } 629003831d35Sstevel 629103831d35Sstevel /* 629203831d35Sstevel * Called from scsb_intr() when a new event occurs, to put new code in FIFO, 629303831d35Sstevel * and signal any interested processes in evc_procs[]. 629403831d35Sstevel * Always succeeds. 629503831d35Sstevel */ 629603831d35Sstevel static void 629703831d35Sstevel add_event_code(scsb_state_t *scsb, uint32_t event_code) 629803831d35Sstevel { 629903831d35Sstevel if (event_proc_count(scsb) == 0) { 630003831d35Sstevel return; 630103831d35Sstevel } 630203831d35Sstevel *evc_wptr = event_code; 630303831d35Sstevel evc_wptr = inc_fifo_ptr(evc_wptr); 630403831d35Sstevel if (++evc_fifo_count > EVC_FIFO_SIZE) { 630503831d35Sstevel --evc_fifo_count; /* lose the oldest event */ 630603831d35Sstevel evc_rptr = inc_fifo_ptr(evc_rptr); 630703831d35Sstevel } 630803831d35Sstevel if (scsb_debug & 0x01000000) { 630903831d35Sstevel cmn_err(CE_NOTE, "add_event_code: 0x%x, FIFO size = %d", 631003831d35Sstevel event_code, evc_fifo_count); 631103831d35Sstevel } 631203831d35Sstevel signal_evc_procs(scsb); 631303831d35Sstevel } 631403831d35Sstevel 631503831d35Sstevel /* 631603831d35Sstevel * called from check_event_procs() when the last registered process 631703831d35Sstevel * retrieved the oldest event 631803831d35Sstevel */ 631903831d35Sstevel static uint32_t 632003831d35Sstevel del_event_code() 632103831d35Sstevel { 632203831d35Sstevel uint32_t evc = 0; 632303831d35Sstevel if (!evc_fifo_count) 632403831d35Sstevel return (scsb_event_code); 632503831d35Sstevel evc = *evc_rptr; 632603831d35Sstevel evc_rptr = inc_fifo_ptr(evc_rptr); 632703831d35Sstevel --evc_fifo_count; 632803831d35Sstevel if (scsb_debug & 0x01000000) { 632903831d35Sstevel cmn_err(CE_NOTE, "del_event_code: 0x%x, FIFO size = %d", 633003831d35Sstevel evc, evc_fifo_count); 633103831d35Sstevel } 633203831d35Sstevel return (evc); 633303831d35Sstevel } 633403831d35Sstevel 633503831d35Sstevel /* 633603831d35Sstevel * called from check_event_procs() to retrieve the current event code 633703831d35Sstevel */ 633803831d35Sstevel static uint32_t 633903831d35Sstevel get_event_code() 634003831d35Sstevel { 634103831d35Sstevel if (!evc_fifo_count) 634203831d35Sstevel return (0); 634303831d35Sstevel return (*evc_rptr); 634403831d35Sstevel } 634503831d35Sstevel 634603831d35Sstevel /* 634703831d35Sstevel * called from an application interface (ie: an ioctl command) 634803831d35Sstevel * to register a process id interested in SCB events. 634903831d35Sstevel * NOTE: proc_ref() must be called from USER context, so since this is a 635003831d35Sstevel * streams driver, a kstat interface is used for process registration. 635103831d35Sstevel * return: 635203831d35Sstevel * 0 = event_proc was added 635303831d35Sstevel * 1 = out of space 635403831d35Sstevel */ 635503831d35Sstevel /* ARGSUSED */ 635603831d35Sstevel static int 635703831d35Sstevel add_event_proc(scsb_state_t *scsb, pid_t pid) 635803831d35Sstevel { 635903831d35Sstevel int i = 0; 636003831d35Sstevel void *curr_proc; 636103831d35Sstevel pid_t curr_pid; 636203831d35Sstevel if (evc_proc_count >= EVC_PROCS_MAX) 636303831d35Sstevel return (1); 636403831d35Sstevel curr_proc = proc_ref(); 636503831d35Sstevel curr_pid = (pid_t)(((struct pid *)curr_proc)->pid_id); 636603831d35Sstevel if (curr_pid != pid) { 636703831d35Sstevel if (scsb_debug & 0x02000000) { 636803831d35Sstevel cmn_err(CE_WARN, 636903831d35Sstevel "add_event_proc: current %d != requestor %d", 637003831d35Sstevel curr_pid, pid); 637103831d35Sstevel } else { 637203831d35Sstevel proc_unref(curr_proc); 637303831d35Sstevel return (1); 637403831d35Sstevel } 637503831d35Sstevel } 637603831d35Sstevel for (; i < EVC_PROCS_MAX; ++i) { 637703831d35Sstevel if (evc_procs[i] == NULL) { 637803831d35Sstevel evc_procs[i] = curr_proc; 637903831d35Sstevel evc_proc_count++; 638003831d35Sstevel if (scsb_debug & 0x02000000) { 638103831d35Sstevel cmn_err(CE_NOTE, 638203831d35Sstevel "add_event_proc: %d; evc_proc_count=%d", 638303831d35Sstevel pid, evc_proc_count); 638403831d35Sstevel } 638503831d35Sstevel return (0); 638603831d35Sstevel } 638703831d35Sstevel } 638803831d35Sstevel proc_unref(curr_proc); 638903831d35Sstevel return (1); 639003831d35Sstevel } 639103831d35Sstevel 639203831d35Sstevel /* 639303831d35Sstevel * called from an application interface (ie: an ioctl command) 639403831d35Sstevel * to unregister a process id interested in SCB events. 639503831d35Sstevel * return: 639603831d35Sstevel * 0 = event_proc was deleted 639703831d35Sstevel * 1 = event_proc was not found, or table was empty 639803831d35Sstevel */ 639903831d35Sstevel /* ARGSUSED */ 640003831d35Sstevel static int 640103831d35Sstevel del_event_proc(scsb_state_t *scsb, pid_t pid) 640203831d35Sstevel { 640303831d35Sstevel int i = 0; 640403831d35Sstevel int cnt = 0; 640503831d35Sstevel void *this_proc; 640603831d35Sstevel if (evc_proc_count == 0) 640703831d35Sstevel return (1); 640803831d35Sstevel for (; i < EVC_PROCS_MAX; ++i) { 640903831d35Sstevel if (evc_procs[i] == NULL) 641003831d35Sstevel continue; 641103831d35Sstevel this_proc = evc_procs[i]; 641203831d35Sstevel if (pid == ((struct pid *)this_proc)->pid_id) { 641303831d35Sstevel evc_procs[i] = NULL; 641403831d35Sstevel if (--evc_proc_count == 0) { 641503831d35Sstevel /* 641603831d35Sstevel * reset evc fifo cound and pointers 641703831d35Sstevel */ 641803831d35Sstevel reset_evc_fifo(scsb); 641903831d35Sstevel } 642003831d35Sstevel if (scsb_debug & 0x02000000) { 642103831d35Sstevel cmn_err(CE_NOTE, 642203831d35Sstevel "del_event_proc: %d; evc_proc_count=%d", 642303831d35Sstevel pid, evc_proc_count); 642403831d35Sstevel } 642503831d35Sstevel proc_unref(this_proc); 642603831d35Sstevel return (0); 642703831d35Sstevel } 642803831d35Sstevel if (++cnt >= evc_proc_count) 642903831d35Sstevel break; 643003831d35Sstevel } 643103831d35Sstevel return (1); 643203831d35Sstevel } 643303831d35Sstevel 643403831d35Sstevel /* 643503831d35Sstevel * Can be called from an application interface 643603831d35Sstevel * to rewind the pointers and counters, and zero the table 643703831d35Sstevel * return: 643803831d35Sstevel */ 643903831d35Sstevel /* ARGSUSED */ 644003831d35Sstevel static void 644103831d35Sstevel rew_event_proc(scsb_state_t *scsb) 644203831d35Sstevel { 644303831d35Sstevel int i = 0; 644403831d35Sstevel if (scsb_debug & 0x02000001) { 644503831d35Sstevel cmn_err(CE_NOTE, "rew_event_proc: evc_proc_count=%d", 644603831d35Sstevel evc_proc_count); 644703831d35Sstevel } 644803831d35Sstevel for (; i < EVC_PROCS_MAX; ++i) { 644903831d35Sstevel if (evc_procs[i] != NULL) { 645003831d35Sstevel proc_unref(evc_procs[i]); 645103831d35Sstevel evc_procs[i] = NULL; 645203831d35Sstevel } 645303831d35Sstevel } 645403831d35Sstevel evc_proc_count = 0; 645503831d35Sstevel } 645603831d35Sstevel 645703831d35Sstevel /* ARGSUSED */ 645803831d35Sstevel static int 645903831d35Sstevel event_proc_count(scsb_state_t *scsb) 646003831d35Sstevel { 646103831d35Sstevel return (evc_proc_count); 646203831d35Sstevel } 646303831d35Sstevel 646403831d35Sstevel /* 646503831d35Sstevel * return: 646603831d35Sstevel * 1 = pid was found 646703831d35Sstevel * 0 = pid was not found, or table was empty 646803831d35Sstevel */ 646903831d35Sstevel static int 647003831d35Sstevel find_evc_proc(pid_t pid) 647103831d35Sstevel { 647203831d35Sstevel int i = 0; 647303831d35Sstevel int cnt = 0; 647403831d35Sstevel if (evc_proc_count == 0) 647503831d35Sstevel return (0); 647603831d35Sstevel for (; i < EVC_PROCS_MAX; ++i) { 647703831d35Sstevel if (evc_procs[i] == NULL) 647803831d35Sstevel continue; 647903831d35Sstevel if (pid == ((struct pid *)evc_procs[i])->pid_id) 648003831d35Sstevel return (1); 648103831d35Sstevel if (++cnt >= evc_proc_count) 648203831d35Sstevel break; 648303831d35Sstevel } 648403831d35Sstevel return (0); 648503831d35Sstevel } 648603831d35Sstevel 648703831d35Sstevel /* 648803831d35Sstevel * called from update_ks_state() to compare evc_proc_count with 648903831d35Sstevel * evc_requests, also mainted by this same function 649003831d35Sstevel * This function could check the current process id, since this will be a user 649103831d35Sstevel * context call, and only bump evc_requests if the calling process is 649203831d35Sstevel * registered for event code delivery. 649303831d35Sstevel * return: 649403831d35Sstevel * EVC_NO_EVENT_CODE : no event_code on fifo 649503831d35Sstevel * EVC_NO_CURR_PROC : current process not in table, 649603831d35Sstevel * but have an event_code 649703831d35Sstevel * EVC_NEW_EVENT_CODE : return_evc is new ks_state->event_code 649803831d35Sstevel * EVC_OR_EVENT_CODE : OR return_evc with ks_state->event_code 649903831d35Sstevel * EVC_FAILURE : unrecoverable error condition. 650003831d35Sstevel */ 650103831d35Sstevel static int 650203831d35Sstevel check_event_procs(uint32_t *return_evc) 650303831d35Sstevel { 650403831d35Sstevel void *curr_proc; 650503831d35Sstevel pid_t curr_pid = 0; 650603831d35Sstevel int return_val = 0; 650703831d35Sstevel static int evc_requests = 0; 650803831d35Sstevel /* 650903831d35Sstevel * get current process handle, and check the event_procs table 651003831d35Sstevel */ 651103831d35Sstevel if (evc_proc_count == 0) { 651203831d35Sstevel *return_evc = del_event_code(); 651303831d35Sstevel return_val = EVC_NO_CURR_PROC; 651403831d35Sstevel } else { 651503831d35Sstevel curr_proc = proc_ref(); 651603831d35Sstevel curr_pid = ((struct pid *)curr_proc)->pid_id; 651703831d35Sstevel proc_unref(curr_proc); 651803831d35Sstevel if (!find_evc_proc(curr_pid)) { 651903831d35Sstevel *return_evc = get_event_code(); 652003831d35Sstevel return_val = EVC_NO_CURR_PROC; 652103831d35Sstevel } else if (++evc_requests >= evc_proc_count) { 652203831d35Sstevel evc_requests = 0; 652303831d35Sstevel *return_evc = del_event_code(); 652403831d35Sstevel return_val = EVC_NEW_EVENT_CODE; 652503831d35Sstevel } else { 652603831d35Sstevel *return_evc = get_event_code(); 652703831d35Sstevel } 652803831d35Sstevel if (!return_val) 652903831d35Sstevel return_val = EVC_OR_EVENT_CODE; 653003831d35Sstevel } 653103831d35Sstevel if (scsb_debug & 0x02000000) { 653203831d35Sstevel cmn_err(CE_NOTE, "check_event_procs: pid=%d, evc=0x%x, " 653303831d35Sstevel "requests=%d, returning 0x%x", curr_pid, 653403831d35Sstevel *return_evc, evc_requests, return_val); 653503831d35Sstevel } 653603831d35Sstevel return (return_val); 653703831d35Sstevel } 653803831d35Sstevel 653903831d35Sstevel static int 654003831d35Sstevel scsb_queue_put(queue_t *rq, int count, uint32_t *data, char *caller) 654103831d35Sstevel { 654203831d35Sstevel mblk_t *mp; 654303831d35Sstevel if (scsb_debug & 0x4001) { 654403831d35Sstevel cmn_err(CE_NOTE, "scsb_queue_put(0x%p, %d, 0x%x, %s)", 6545*07d06da5SSurya Prakki (void *)rq, count, *data, caller); 654603831d35Sstevel } 654703831d35Sstevel mp = allocb(sizeof (uint32_t) * count, BPRI_HI); 654803831d35Sstevel if (mp == NULL) { 654903831d35Sstevel cmn_err(CE_WARN, "%s: allocb failed", 655003831d35Sstevel caller); 655103831d35Sstevel return (B_FALSE); 655203831d35Sstevel } 655303831d35Sstevel while (count--) { 655403831d35Sstevel *((uint32_t *)mp->b_wptr) = *data; 655503831d35Sstevel mp->b_wptr += sizeof (*data); 655603831d35Sstevel ++data; 655703831d35Sstevel } 655803831d35Sstevel putnext(rq, mp); 655903831d35Sstevel return (B_TRUE); 656003831d35Sstevel } 656103831d35Sstevel 656203831d35Sstevel /* CLONE */ 656303831d35Sstevel static int 656403831d35Sstevel scsb_queue_ops(scsb_state_t *scsb, 656503831d35Sstevel int op, 656603831d35Sstevel int oparg, 656703831d35Sstevel void *opdata, 656803831d35Sstevel char *caller) 656903831d35Sstevel { 657003831d35Sstevel clone_dev_t *clptr; 657103831d35Sstevel int clone, find_open, find_available, retval = QOP_FAILED; 657203831d35Sstevel 657303831d35Sstevel switch (op) { 657403831d35Sstevel case QPUT_INT32: 657503831d35Sstevel if (scsb->scsb_opens && scsb->scsb_rq != NULL && 657603831d35Sstevel scsb_queue_put(scsb->scsb_rq, oparg, 657703831d35Sstevel (uint32_t *)opdata, caller) == B_FALSE) { 657803831d35Sstevel return (QOP_FAILED); 657903831d35Sstevel } 658003831d35Sstevel /*FALLTHROUGH*/ /* to look for opened clones */ 658103831d35Sstevel case QPROCSOFF: 658203831d35Sstevel retval = QOP_OK; 658303831d35Sstevel /*FALLTHROUGH*/ 658403831d35Sstevel case QFIRST_OPEN: 658503831d35Sstevel case QFIND_QUEUE: 658603831d35Sstevel find_open = 1; 658703831d35Sstevel find_available = 0; 658803831d35Sstevel break; 658903831d35Sstevel case QFIRST_AVAILABLE: 659003831d35Sstevel find_available = 1; 659103831d35Sstevel find_open = 0; 659203831d35Sstevel break; 659303831d35Sstevel } 659403831d35Sstevel for (clone = SCSB_CLONES_FIRST; clone < SCSB_CLONES_MAX; clone++) { 659503831d35Sstevel clptr = &scsb->clone_devs[clone]; 659603831d35Sstevel if (find_open && clptr->cl_flags & SCSB_OPEN) { 659703831d35Sstevel if (clptr->cl_rq == NULL) { 659803831d35Sstevel cmn_err(CE_WARN, "%s: Clone %d has no queue", 659903831d35Sstevel caller, clptr->cl_minor); 660003831d35Sstevel return (QOP_FAILED); 660103831d35Sstevel } 660203831d35Sstevel switch (op) { 660303831d35Sstevel case QPROCSOFF: 660403831d35Sstevel qprocsoff(clptr->cl_rq); 660503831d35Sstevel break; 660603831d35Sstevel case QPUT_INT32: 660703831d35Sstevel if (scsb_queue_put(clptr->cl_rq, oparg, 660803831d35Sstevel (uint32_t *)opdata, caller) 660903831d35Sstevel == B_FALSE) { 661003831d35Sstevel retval = QOP_FAILED; 661103831d35Sstevel } 661203831d35Sstevel break; 661303831d35Sstevel case QFIRST_OPEN: 661403831d35Sstevel return (clone); 661503831d35Sstevel case QFIND_QUEUE: 661603831d35Sstevel if (clptr->cl_rq == (queue_t *)opdata) { 661703831d35Sstevel return (clone); 661803831d35Sstevel } 661903831d35Sstevel break; 662003831d35Sstevel } 662103831d35Sstevel } else if (find_available && clptr->cl_flags == 0) { 662203831d35Sstevel switch (op) { 662303831d35Sstevel case QFIRST_AVAILABLE: 662403831d35Sstevel return (clone); 662503831d35Sstevel } 662603831d35Sstevel } 662703831d35Sstevel } 662803831d35Sstevel return (retval); 662903831d35Sstevel } 663003831d35Sstevel 663103831d35Sstevel /* 663203831d35Sstevel * Find out if a bit is set for the FRU type and unit number in the register 663303831d35Sstevel * set defined by the register base table index, base. 663403831d35Sstevel * Returns TRUE if bit is set, or FALSE. 663503831d35Sstevel */ 663603831d35Sstevel static int 663703831d35Sstevel scsb_fru_op(scsb_state_t *scsb, scsb_utype_t fru_type, int unit, int base, 663803831d35Sstevel int op) 663903831d35Sstevel { 664003831d35Sstevel int rc; 664103831d35Sstevel uchar_t reg; 664203831d35Sstevel int tmp, idx, code, offset; 664303831d35Sstevel 664403831d35Sstevel #if 0 664503831d35Sstevel reg = SCSB_REG_ADDR(i); 664603831d35Sstevel ac_mask = 1 << FRU_OFFSET(SCTRL_EVENT_ALARM, SCTRL_RESET_BASE); 664703831d35Sstevel ac_val = scsb->scsb_data_reg[index+1] & ac_mask; 664803831d35Sstevel #endif 664903831d35Sstevel /* get the event code based on which we get the reg and bit offsets */ 665003831d35Sstevel code = FRU_UNIT_TO_EVCODE(fru_type, unit); 665103831d35Sstevel /* get the bit offset in the 8bit register corresponding to the event */ 665203831d35Sstevel offset = FRU_OFFSET(code, base); 665303831d35Sstevel /* register offset from the base register, based on the event code */ 665403831d35Sstevel if ((fru_type == ALARM) && (base == SCTRL_RESET_BASE)) 665503831d35Sstevel tmp = ALARM_RESET_REG_INDEX(code, base); 665603831d35Sstevel else 665703831d35Sstevel tmp = FRU_REG_INDEX(code, base); 665803831d35Sstevel /* get the global offset of the register in the parent address space */ 665903831d35Sstevel reg = SCSB_REG_ADDR(tmp); 666003831d35Sstevel /* get the global index of the register in this SCSB's address space */ 666103831d35Sstevel idx = SCSB_REG_INDEX(reg); 666203831d35Sstevel DEBUG4("scsb_fru_op(start): code=%x, offset=%x, tmp=%x, reg=%x\n", 666303831d35Sstevel code, offset, tmp, reg); 666403831d35Sstevel switch (op) { 666503831d35Sstevel case SCSB_FRU_OP_GET_REG: 666603831d35Sstevel rc = reg; 666703831d35Sstevel break; 666803831d35Sstevel case SCSB_FRU_OP_GET_BITVAL: 666903831d35Sstevel rc = (scsb->scsb_data_reg[idx] & (1 << offset)) 667003831d35Sstevel >> offset; 667103831d35Sstevel break; 667203831d35Sstevel case SCSB_FRU_OP_GET_REGDATA: 667303831d35Sstevel rc = scsb->scsb_data_reg[idx]; 667403831d35Sstevel break; 667503831d35Sstevel case SCSB_FRU_OP_SET_REGBIT: 667603831d35Sstevel rc = (1 << offset) & 0xff; 667703831d35Sstevel break; 667803831d35Sstevel default: 667903831d35Sstevel break; 668003831d35Sstevel } 668103831d35Sstevel DEBUG4("scsb_fru_op: unit=%x, base=%x, op=%d, rc=%x\n", unit, base, 668203831d35Sstevel op, rc); 668303831d35Sstevel return (rc); 668403831d35Sstevel } 668503831d35Sstevel 668603831d35Sstevel /* 668703831d35Sstevel * All HSC related functions can fail, but an attempt is made to atleast 668803831d35Sstevel * return the right shadow state on get-state function when SCB is removed. 668903831d35Sstevel */ 669003831d35Sstevel int 669103831d35Sstevel scsb_get_slot_state(scsb_state_t *scsb, int pslotnum, int *rstate) 669203831d35Sstevel { 669303831d35Sstevel int slotnum, val = 0, rc; 669403831d35Sstevel 669503831d35Sstevel /* 669603831d35Sstevel * When SCB is removed, we could be called with the lock held. 669703831d35Sstevel * We call check_config_status anyway since it is a read-only operation 669803831d35Sstevel * and HSC could be invoking this function at interrupt context. 669903831d35Sstevel * If scsb is already in the doing interrupt postprocess, wait.. 670003831d35Sstevel */ 670103831d35Sstevel 670203831d35Sstevel rc = scsb_check_config_status(scsb); 670303831d35Sstevel 670403831d35Sstevel /* check if error is because SCB is removed */ 670503831d35Sstevel if ((rc != EAGAIN) && (rc != DDI_SUCCESS)) 670603831d35Sstevel return (DDI_FAILURE); 670703831d35Sstevel slotnum = tonga_psl_to_ssl(scsb, pslotnum); 670803831d35Sstevel val = scsb_fru_op(scsb, SLOT, slotnum, SCTRL_SYSCFG_BASE, 670903831d35Sstevel SCSB_FRU_OP_GET_BITVAL); 671003831d35Sstevel if (! val) { 671103831d35Sstevel *rstate = HPC_SLOT_EMPTY; 671203831d35Sstevel return (0); 671303831d35Sstevel } 671403831d35Sstevel /* 671503831d35Sstevel * now, lets determine if it is connected or disconnected. 671603831d35Sstevel * If reset is asserted, then the slot is disconnected. 671703831d35Sstevel */ 671803831d35Sstevel rc = scsb_reset_slot(scsb, pslotnum, SCSB_GET_SLOT_RESET_STATUS); 671903831d35Sstevel /* check if error is because SCB is removed */ 672003831d35Sstevel if ((rc != EAGAIN) && (rc != DDI_SUCCESS)) 672103831d35Sstevel return (DDI_FAILURE); 672203831d35Sstevel val = scsb_fru_op(scsb, SLOT, slotnum, SCTRL_RESET_BASE, 672303831d35Sstevel SCSB_FRU_OP_GET_BITVAL); 672403831d35Sstevel if (val) 672503831d35Sstevel *rstate = HPC_SLOT_DISCONNECTED; 672603831d35Sstevel else { 672703831d35Sstevel if (scsb_fru_op(scsb, SLOT, slotnum, SCTRL_BHLTHY_BASE, 672803831d35Sstevel SCSB_FRU_OP_GET_BITVAL)) { 672903831d35Sstevel *rstate = HPC_SLOT_CONNECTED; 673003831d35Sstevel } else { 673103831d35Sstevel cmn_err(CE_WARN, "%s#%d: Reset Not Asserted on " 673203831d35Sstevel "Healthy# Failed slot %d!", 673303831d35Sstevel ddi_driver_name(scsb->scsb_dev), 673403831d35Sstevel ddi_get_instance(scsb->scsb_dev), slotnum); 673503831d35Sstevel *rstate = HPC_SLOT_DISCONNECTED; 673603831d35Sstevel } 673703831d35Sstevel } 673803831d35Sstevel return (0); 673903831d35Sstevel } 674003831d35Sstevel 674103831d35Sstevel int 674203831d35Sstevel scsb_reset_slot(scsb_state_t *scsb, int pslotnum, int reset_flag) 674303831d35Sstevel { 674403831d35Sstevel int slotnum, error, val, alarm_card = 0; 674503831d35Sstevel i2c_transfer_t *i2cxferp; 674603831d35Sstevel uchar_t reg; 674703831d35Sstevel int index, condition_exists = 0, ac_val; 674803831d35Sstevel 674903831d35Sstevel if (scsb_debug & 0x8001) 675003831d35Sstevel cmn_err(CE_NOTE, "scsb_reset_slot(%d), flag %x", pslotnum, 675103831d35Sstevel reset_flag); 675203831d35Sstevel if (scsb->scsb_state & SCSB_FROZEN) 675303831d35Sstevel return (EAGAIN); 675403831d35Sstevel if ((i2cxferp = scsb_alloc_i2ctx(scsb->scsb_phandle, 675503831d35Sstevel I2C_NOSLEEP)) == NULL) { 675603831d35Sstevel return (ENOMEM); 675703831d35Sstevel } 675803831d35Sstevel slotnum = tonga_psl_to_ssl(scsb, pslotnum); 675903831d35Sstevel 676003831d35Sstevel if (scsb_is_alarm_card_slot(scsb, pslotnum) == B_TRUE) { 676103831d35Sstevel DEBUG0("alarm card reset/unreset op:\n"); 676203831d35Sstevel alarm_card = 1; 676303831d35Sstevel } 676403831d35Sstevel reg = SCSB_REG_ADDR(SCTRL_RESET_BASE); 676503831d35Sstevel index = SCSB_REG_INDEX(reg); 676603831d35Sstevel 676703831d35Sstevel mutex_enter(&scsb->scsb_mutex); 676803831d35Sstevel i2cxferp->i2c_flags = I2C_WR_RD; 676903831d35Sstevel i2cxferp->i2c_rlen = SCTRL_RESET_NUMREGS; 677003831d35Sstevel i2cxferp->i2c_wbuf[0] = reg; 677103831d35Sstevel i2cxferp->i2c_wlen = 1; 677203831d35Sstevel scsb->scsb_kstat_flag = B_TRUE; /* we did an i2c transaction */ 677303831d35Sstevel if ((error = nct_i2c_transfer(scsb->scsb_phandle, i2cxferp)) == 0) { 677403831d35Sstevel scsb->scsb_i2c_errcnt = 0; 677503831d35Sstevel /* 677603831d35Sstevel * XXX: following statements assume 2 reset registers, 677703831d35Sstevel * which is the case for our current SCB revisions. 677803831d35Sstevel */ 677903831d35Sstevel scsb->scsb_data_reg[index] = i2cxferp->i2c_rbuf[0]; 678003831d35Sstevel scsb->scsb_data_reg[index+1] = i2cxferp->i2c_rbuf[1]; 678103831d35Sstevel } else { 678203831d35Sstevel scsb->scsb_i2c_errcnt++; 678303831d35Sstevel if (scsb->scsb_i2c_errcnt > scsb_err_threshold) 678403831d35Sstevel scsb->scsb_err_flag = B_TRUE; /* latch until kstat */ 678503831d35Sstevel if (!(scsb->scsb_state & SCSB_SSB_PRESENT)) { 678603831d35Sstevel if (scsb->scsb_i2c_errcnt >= scsb_freeze_count) 678703831d35Sstevel mutex_exit(&scsb->scsb_mutex); 678803831d35Sstevel scsb_freeze(scsb); 678903831d35Sstevel mutex_enter(&scsb->scsb_mutex); 679003831d35Sstevel } 679103831d35Sstevel cmn_err(CE_WARN, "%s#%d: scsb_reset_slot: error" 679203831d35Sstevel " reading Reset regs\n", 679303831d35Sstevel ddi_driver_name(scsb->scsb_dev), 679403831d35Sstevel ddi_get_instance(scsb->scsb_dev)); 679503831d35Sstevel error = DDI_FAILURE; 679603831d35Sstevel } 679703831d35Sstevel 679803831d35Sstevel DEBUG2("pre-reset regs = %x,%x\n", scsb->scsb_data_reg[index], 679903831d35Sstevel scsb->scsb_data_reg[index+1]); 680003831d35Sstevel if ((reset_flag == SCSB_GET_SLOT_RESET_STATUS) || (error)) { 680103831d35Sstevel mutex_exit(&scsb->scsb_mutex); 680203831d35Sstevel scsb_free_i2ctx(scsb->scsb_phandle, i2cxferp); 680303831d35Sstevel return (error); 680403831d35Sstevel } 680503831d35Sstevel 680603831d35Sstevel val = scsb_fru_op(scsb, SLOT, slotnum, SCTRL_RESET_BASE, 680703831d35Sstevel SCSB_FRU_OP_GET_BITVAL); 680803831d35Sstevel if (alarm_card) { 680903831d35Sstevel ac_val = scsb_fru_op(scsb, ALARM, 1, SCTRL_RESET_BASE, 681003831d35Sstevel SCSB_FRU_OP_GET_BITVAL); 681103831d35Sstevel } 681203831d35Sstevel if (val && (reset_flag == SCSB_RESET_SLOT)) { 681303831d35Sstevel if (alarm_card) { 681403831d35Sstevel if (ac_val) { 681503831d35Sstevel condition_exists = 1; 681603831d35Sstevel DEBUG0("Alarm_RST# already active.\n"); 681703831d35Sstevel } 681803831d35Sstevel #ifndef lint 681903831d35Sstevel else 682003831d35Sstevel DEBUG1("Alarm_RST# not active! " 682103831d35Sstevel "Slot%d_RST# active!\n", pslotnum); 682203831d35Sstevel #endif 682303831d35Sstevel } else { 682403831d35Sstevel condition_exists = 1; 682503831d35Sstevel DEBUG1("Slot%d_RST# already active!\n", pslotnum); 682603831d35Sstevel } 682703831d35Sstevel } 682803831d35Sstevel else 682903831d35Sstevel if ((val == 0) && (reset_flag == SCSB_UNRESET_SLOT)) { 683003831d35Sstevel if (alarm_card) { 683103831d35Sstevel if (!ac_val) { 683203831d35Sstevel DEBUG0("Alarm_RST# not active.\n"); 683303831d35Sstevel condition_exists = 1; 683403831d35Sstevel } 683503831d35Sstevel #ifndef lint 683603831d35Sstevel else 683703831d35Sstevel DEBUG1("Alarm_RST# active" 683803831d35Sstevel " Slot%d_RST# not active!\n", 683903831d35Sstevel pslotnum); 684003831d35Sstevel #endif 684103831d35Sstevel } else { 684203831d35Sstevel condition_exists = 1; 684303831d35Sstevel DEBUG1("Slot%d_RST# already not active!\n", 684403831d35Sstevel pslotnum); 684503831d35Sstevel } 684603831d35Sstevel } 684703831d35Sstevel 684803831d35Sstevel if (! condition_exists) { 684903831d35Sstevel i2cxferp->i2c_flags = I2C_WR; 685003831d35Sstevel i2cxferp->i2c_wlen = 2; 685103831d35Sstevel i2cxferp->i2c_wbuf[0] = scsb_fru_op(scsb, SLOT, slotnum, 685203831d35Sstevel SCTRL_RESET_BASE, SCSB_FRU_OP_GET_REG); 685303831d35Sstevel if (reset_flag == SCSB_RESET_SLOT) { 685403831d35Sstevel i2cxferp->i2c_wbuf[1] = 685503831d35Sstevel scsb_fru_op(scsb, SLOT, slotnum, 685603831d35Sstevel SCTRL_RESET_BASE, 685703831d35Sstevel SCSB_FRU_OP_GET_REGDATA) | 685803831d35Sstevel scsb_fru_op(scsb, SLOT, slotnum, 685903831d35Sstevel SCTRL_RESET_BASE, 686003831d35Sstevel SCSB_FRU_OP_SET_REGBIT); 686103831d35Sstevel #ifdef DEBUG /* dont reset Alarm Card line unless in debug mode */ 686203831d35Sstevel if (alarm_card) 686303831d35Sstevel i2cxferp->i2c_wbuf[1] |= 686403831d35Sstevel scsb_fru_op(scsb, ALARM, 1, 686503831d35Sstevel SCTRL_RESET_BASE, 686603831d35Sstevel SCSB_FRU_OP_SET_REGBIT); 686703831d35Sstevel #endif 686803831d35Sstevel } else { 686903831d35Sstevel i2cxferp->i2c_wbuf[1] = 687003831d35Sstevel scsb_fru_op(scsb, SLOT, slotnum, 687103831d35Sstevel SCTRL_RESET_BASE, 687203831d35Sstevel SCSB_FRU_OP_GET_REGDATA) & 687303831d35Sstevel ~(scsb_fru_op(scsb, SLOT, slotnum, 687403831d35Sstevel SCTRL_RESET_BASE, 687503831d35Sstevel SCSB_FRU_OP_SET_REGBIT)); 687603831d35Sstevel #ifdef DEBUG /* dont Unreset Alarm Card line unless in debug mode */ 687703831d35Sstevel if (alarm_card) 687803831d35Sstevel i2cxferp->i2c_wbuf[1] &= 687903831d35Sstevel scsb_fru_op(scsb, ALARM, 1, 688003831d35Sstevel SCTRL_RESET_BASE, 688103831d35Sstevel SCSB_FRU_OP_SET_REGBIT); 688203831d35Sstevel #endif 688303831d35Sstevel } 688403831d35Sstevel 688503831d35Sstevel if (error = nct_i2c_transfer(scsb->scsb_phandle, i2cxferp)) { 688603831d35Sstevel scsb->scsb_i2c_errcnt++; 688703831d35Sstevel if (scsb->scsb_i2c_errcnt > scsb_err_threshold) 688803831d35Sstevel scsb->scsb_err_flag = B_TRUE; /* latch error */ 688903831d35Sstevel mutex_exit(&scsb->scsb_mutex); 689003831d35Sstevel if (!(scsb->scsb_state & SCSB_SSB_PRESENT)) { 689103831d35Sstevel if (scsb->scsb_i2c_errcnt >= scsb_freeze_count) 689203831d35Sstevel scsb_freeze(scsb); 689303831d35Sstevel } 689403831d35Sstevel cmn_err(CE_WARN, "%s#%d: reset_slot: error writing to" 689503831d35Sstevel " Reset regs (op=%d, data=%x)\n", 689603831d35Sstevel ddi_driver_name(scsb->scsb_dev), 689703831d35Sstevel ddi_get_instance(scsb->scsb_dev), 689803831d35Sstevel reset_flag, i2cxferp->i2c_wbuf[1]); 689903831d35Sstevel scsb_free_i2ctx(scsb->scsb_phandle, i2cxferp); 690003831d35Sstevel return (DDI_FAILURE); 690103831d35Sstevel } 690203831d35Sstevel 690303831d35Sstevel scsb->scsb_i2c_errcnt = 0; 690403831d35Sstevel /* now read back and update our scsb structure */ 690503831d35Sstevel i2cxferp->i2c_flags = I2C_WR_RD; 690603831d35Sstevel i2cxferp->i2c_rlen = SCTRL_RESET_NUMREGS; 690703831d35Sstevel i2cxferp->i2c_wbuf[0] = reg; 690803831d35Sstevel i2cxferp->i2c_wlen = 1; 690903831d35Sstevel if ((error = nct_i2c_transfer(scsb->scsb_phandle, 691003831d35Sstevel i2cxferp)) == 0) { 691103831d35Sstevel scsb->scsb_i2c_errcnt = 0; 691203831d35Sstevel scsb->scsb_data_reg[index] = i2cxferp->i2c_rbuf[0]; 691303831d35Sstevel scsb->scsb_data_reg[index+1] = i2cxferp->i2c_rbuf[1]; 691403831d35Sstevel } else { 691503831d35Sstevel scsb->scsb_i2c_errcnt++; 691603831d35Sstevel if (scsb->scsb_i2c_errcnt > scsb_err_threshold) 691703831d35Sstevel scsb->scsb_err_flag = B_TRUE; /* latch error */ 691803831d35Sstevel mutex_exit(&scsb->scsb_mutex); 691903831d35Sstevel if (!(scsb->scsb_state & SCSB_SSB_PRESENT)) { 692003831d35Sstevel if (scsb->scsb_i2c_errcnt >= scsb_freeze_count) 692103831d35Sstevel scsb_freeze(scsb); 692203831d35Sstevel } 692303831d35Sstevel cmn_err(CE_WARN, "%s#%d: scsb_reset_slot: error" 692403831d35Sstevel " reading Reset regs (post reset)\n", 692503831d35Sstevel ddi_driver_name(scsb->scsb_dev), 692603831d35Sstevel ddi_get_instance(scsb->scsb_dev)); 692703831d35Sstevel scsb_free_i2ctx(scsb->scsb_phandle, i2cxferp); 692803831d35Sstevel return (DDI_FAILURE); 692903831d35Sstevel } 693003831d35Sstevel /* XXX: P1.5 */ 693103831d35Sstevel DEBUG2("post-reset regs = %x,%x\n", scsb->scsb_data_reg[index], 693203831d35Sstevel scsb->scsb_data_reg[index+1]); 693303831d35Sstevel val = scsb_fru_op(scsb, SLOT, slotnum, SCTRL_RESET_BASE, 693403831d35Sstevel SCSB_FRU_OP_GET_BITVAL); 693503831d35Sstevel #ifdef DEBUG 693603831d35Sstevel if (alarm_card) 693703831d35Sstevel ac_val = scsb_fru_op(scsb, ALARM, 1, SCTRL_RESET_BASE, 693803831d35Sstevel SCSB_FRU_OP_GET_BITVAL); 693903831d35Sstevel #endif 694003831d35Sstevel if (val && (reset_flag == SCSB_UNRESET_SLOT)) { 694103831d35Sstevel cmn_err(CE_WARN, "Cannot UnReset Slot %d (reg=%x)\n", 694203831d35Sstevel pslotnum, 694303831d35Sstevel scsb_fru_op(scsb, SLOT, slotnum, 694403831d35Sstevel SCTRL_RESET_BASE, 694503831d35Sstevel SCSB_FRU_OP_GET_REGDATA)); 694603831d35Sstevel #ifdef DEBUG 694703831d35Sstevel if (alarm_card) { 694803831d35Sstevel if (ac_val) 694903831d35Sstevel cmn_err(CE_WARN, "Cannot Unreset " 695003831d35Sstevel "Alarm_RST#.\n"); 695103831d35Sstevel } 695203831d35Sstevel #endif 695303831d35Sstevel } 695403831d35Sstevel else 695503831d35Sstevel if ((val == 0) && (reset_flag == SCSB_RESET_SLOT)) { 695603831d35Sstevel cmn_err(CE_WARN, "Cannot Reset Slot %d, " 695703831d35Sstevel "reg=%x\n", pslotnum, 695803831d35Sstevel scsb_fru_op(scsb, SLOT, slotnum, 695903831d35Sstevel SCTRL_RESET_BASE, 696003831d35Sstevel SCSB_FRU_OP_GET_REGDATA)); 696103831d35Sstevel #ifdef DEBUG 696203831d35Sstevel if (alarm_card) { 696303831d35Sstevel if (!ac_val) 696403831d35Sstevel cmn_err(CE_WARN, "Cannot reset " 696503831d35Sstevel "Alarm_RST#.\n"); 696603831d35Sstevel } 696703831d35Sstevel #endif 696803831d35Sstevel } 696903831d35Sstevel } 697003831d35Sstevel 697103831d35Sstevel mutex_exit(&scsb->scsb_mutex); 697203831d35Sstevel scsb_free_i2ctx(scsb->scsb_phandle, i2cxferp); 697303831d35Sstevel 697403831d35Sstevel return (error); 697503831d35Sstevel } 697603831d35Sstevel 697703831d35Sstevel int 697803831d35Sstevel scsb_connect_slot(scsb_state_t *scsb, int pslotnum, int healthy) 697903831d35Sstevel { 698003831d35Sstevel int slotnum, count = 0, val; 698103831d35Sstevel int slot_flag = 0; 698203831d35Sstevel 698303831d35Sstevel /* 698403831d35Sstevel * If Power needs to be handled, it should be done here. 698503831d35Sstevel * Since there is no power handling for now, lets disable 698603831d35Sstevel * reset, wait for healthy to come on and then call it 698703831d35Sstevel * connected. 698803831d35Sstevel * If HLTHY# does not come on (in how long is the question) 698903831d35Sstevel * then we stay disconnected. 699003831d35Sstevel */ 699103831d35Sstevel slotnum = tonga_psl_to_ssl(scsb, pslotnum); 699203831d35Sstevel 699303831d35Sstevel /* 699403831d35Sstevel * P1.5 doesnt require polling healthy as we get an 699503831d35Sstevel * interrupt. So we could just update our state as disconnected 699603831d35Sstevel * and return waiting for the healthy# interrupt. To make it 699703831d35Sstevel * more efficient, lets poll for healthy# a short while since we are 699803831d35Sstevel * in the interrupt context anyway. If we dont get a healthy# we 699903831d35Sstevel * return, and then wait for the interrupt. Probably the warning 700003831d35Sstevel * message needs to be removed then. Need a PROM check flag here. 700103831d35Sstevel */ 700203831d35Sstevel while ((healthy == B_FALSE) && (count < scsb_healthy_poll_count)) { 700303831d35Sstevel if (scsb_read_bhealthy(scsb) != 0) 700403831d35Sstevel return (DDI_FAILURE); 700503831d35Sstevel val = scsb_fru_op(scsb, SLOT, slotnum, SCTRL_BHLTHY_BASE, 700603831d35Sstevel SCSB_FRU_OP_GET_BITVAL); 700703831d35Sstevel if (val) { 700803831d35Sstevel healthy = B_TRUE; 700903831d35Sstevel break; 701003831d35Sstevel } 701103831d35Sstevel count++; 701203831d35Sstevel drv_usecwait(100); /* cant delay(9f) in intr context */ 701303831d35Sstevel } 701403831d35Sstevel 701503831d35Sstevel if (healthy == B_FALSE && count == scsb_healthy_poll_count) { 701603831d35Sstevel if (scsb_debug & 0x00004000) 701703831d35Sstevel cmn_err(CE_WARN, "%s#%d: no HEALTHY# signal on" 701803831d35Sstevel " slot %d", ddi_driver_name(scsb->scsb_dev), 701903831d35Sstevel ddi_get_instance(scsb->scsb_dev), pslotnum); 702003831d35Sstevel } 702103831d35Sstevel 702203831d35Sstevel if ((scsb_is_alarm_card_slot(scsb, pslotnum) == B_TRUE) && 702303831d35Sstevel (scsb->scsb_hsc_state & SCSB_ALARM_CARD_PRES)) 702403831d35Sstevel slot_flag = ALARM_CARD_ON_SLOT; 702503831d35Sstevel return (hsc_slot_occupancy(pslotnum, 1, slot_flag, healthy)); 702603831d35Sstevel } 702703831d35Sstevel 702803831d35Sstevel int 702903831d35Sstevel scsb_disconnect_slot(scsb_state_t *scsb, int occupied, int slotnum) 703003831d35Sstevel { 703103831d35Sstevel int slot_flag = 0; 703203831d35Sstevel 703303831d35Sstevel /* Reset is must at extraction. Move on even if failure. */ 703403831d35Sstevel if (scsb_reset_slot(scsb, slotnum, SCSB_RESET_SLOT) != 0) { 703503831d35Sstevel /* 703603831d35Sstevel * If board is still in slot, which means there is a manual 703703831d35Sstevel * disconnection in progress, return failure. 703803831d35Sstevel * Otherwise, a board was removed anyway; so we need to 703903831d35Sstevel * update the status and move on. 704003831d35Sstevel */ 704103831d35Sstevel if (occupied == B_TRUE) 704203831d35Sstevel return (DDI_FAILURE); 704303831d35Sstevel } 704403831d35Sstevel /* 704503831d35Sstevel * the following bug needs to be fixed. 704603831d35Sstevel * When this function is called from scsb_intr, scsb_state already 704703831d35Sstevel * clears the 'AC card present' bit. 704803831d35Sstevel * However, hsc module doesn't depend on slot_flag during removal. 704903831d35Sstevel */ 705003831d35Sstevel if ((scsb_is_alarm_card_slot(scsb, slotnum) == B_TRUE) && 705103831d35Sstevel (scsb->scsb_hsc_state & SCSB_ALARM_CARD_PRES)) 705203831d35Sstevel slot_flag = ALARM_CARD_ON_SLOT; 705303831d35Sstevel return (hsc_slot_occupancy(slotnum, occupied, slot_flag, B_FALSE)); 705403831d35Sstevel } 705503831d35Sstevel 705603831d35Sstevel static int 705703831d35Sstevel scsb_is_alarm_card_slot(scsb_state_t *scsb, int slotnum) 705803831d35Sstevel { 705903831d35Sstevel return ((scsb->ac_slotnum == slotnum)? B_TRUE:B_FALSE); 706003831d35Sstevel } 706103831d35Sstevel 706203831d35Sstevel /* 706303831d35Sstevel * Invoked both by the hsc and the scsb module to exchanges necessary 706403831d35Sstevel * information regarding the alarm card. 706503831d35Sstevel * scsb calls this function to unconfigure the alarm card while the 706603831d35Sstevel * hsc calls this function at different times to check busy status, 706703831d35Sstevel * and during post hotswap insert operation so that the user process 706803831d35Sstevel * if one waiting can configure the alarm card. 706903831d35Sstevel */ 707003831d35Sstevel int 707103831d35Sstevel scsb_hsc_ac_op(scsb_state_t *scsb, int pslotnum, int op) 707203831d35Sstevel { 707303831d35Sstevel int rc = B_FALSE; 707403831d35Sstevel uint32_t event_code; 707503831d35Sstevel 707603831d35Sstevel if (!(scsb->scsb_hsc_state & SCSB_HSC_INIT && 707703831d35Sstevel scsb->scsb_hsc_state & SCSB_ALARM_CARD_PRES)) { 707803831d35Sstevel cmn_err(CE_WARN, 707903831d35Sstevel "scsb: HSC not initialized or AC not present!"); 708003831d35Sstevel return (rc); 708103831d35Sstevel } 708203831d35Sstevel switch (op) { 708303831d35Sstevel /* hsc -> scsb */ 708403831d35Sstevel case SCSB_HSC_AC_BUSY: 708503831d35Sstevel if (scsb->scsb_hsc_state & SCSB_ALARM_CARD_IN_USE) 708603831d35Sstevel rc = B_TRUE; 708703831d35Sstevel break; 708803831d35Sstevel 708903831d35Sstevel /* API -> scsb */ 709003831d35Sstevel /* 709103831d35Sstevel * NOTE: this could be called multiple times from envmond if 709203831d35Sstevel * the daemon is reinitialized with SIGHUP, or stopped and 709303831d35Sstevel * restarted. 709403831d35Sstevel */ 709503831d35Sstevel case SCSB_HSC_AC_SET_BUSY: 709603831d35Sstevel DEBUG0("AC SET BUSY\n"); 709703831d35Sstevel if (scsb_debug & 0x00010000) { 709803831d35Sstevel cmn_err(CE_NOTE, 709903831d35Sstevel "scsb_hsc_ac_op(SCSB_HSC_AC_SET_BUSY)"); 710003831d35Sstevel } 710103831d35Sstevel scsb->scsb_hsc_state |= SCSB_ALARM_CARD_IN_USE; 710203831d35Sstevel rc = B_TRUE; 710303831d35Sstevel break; 710403831d35Sstevel 710503831d35Sstevel /* hsc -> scsb */ 710603831d35Sstevel case SCSB_HSC_AC_CONFIGURED: 710703831d35Sstevel DEBUG0("AC configured\n"); 710803831d35Sstevel if (scsb_debug & 0x00010000) { 710903831d35Sstevel cmn_err(CE_NOTE, 711003831d35Sstevel "scsb_hsc_ac_op(SCSB_HSC_AC_CONFIGURED)"); 711103831d35Sstevel } 711203831d35Sstevel /* 711303831d35Sstevel * wakeup anyone waiting on AC to be configured 711403831d35Sstevel * Send the ALARM_CARD_CONFIGURE Event to all scsb 711503831d35Sstevel * open streams. 711603831d35Sstevel */ 711703831d35Sstevel event_code = SCTRL_EVENT_ALARM_INSERTION; 711803831d35Sstevel (void) scsb_queue_ops(scsb, QPUT_INT32, 1, 711903831d35Sstevel &event_code, "scsb_hsc_ac_op"); 712003831d35Sstevel rc = B_TRUE; 712103831d35Sstevel break; 712203831d35Sstevel 712303831d35Sstevel /* hsc -> scsb */ 712403831d35Sstevel case SCSB_HSC_AC_REMOVAL_ALERT: 712503831d35Sstevel DEBUG0("AC removal alert\n"); 712603831d35Sstevel if (scsb_debug & 0x00010000) { 712703831d35Sstevel cmn_err(CE_NOTE, 712803831d35Sstevel "scsb_hsc_ac_op(SCSB_HSC_AC_REMOVAL_ALERT)"); 712903831d35Sstevel } 713003831d35Sstevel /* 713103831d35Sstevel * Inform (envmond)alarmcard.so that it should save 713203831d35Sstevel * the AC configuration, stop the 713303831d35Sstevel * heartbeat, and shutdown the RSC link. 713403831d35Sstevel */ 713503831d35Sstevel event_code = SCTRL_EVENT_ALARM_REMOVAL; 713603831d35Sstevel (void) scsb_queue_ops(scsb, QPUT_INT32, 1, 713703831d35Sstevel &event_code, "scsb_hsc_ac_op"); 713803831d35Sstevel rc = B_TRUE; 713903831d35Sstevel break; 714003831d35Sstevel 714103831d35Sstevel /* API -> scsb -> hsc */ 714203831d35Sstevel case SCSB_HSC_AC_UNCONFIGURE: 714303831d35Sstevel DEBUG0("AC unconfigure\n"); 714403831d35Sstevel if (scsb_debug & 0x00010000) { 714503831d35Sstevel cmn_err(CE_NOTE, 714603831d35Sstevel "scsb_hsc_ac_op(SCSB_HSC_AC_UNCONFIG" 714703831d35Sstevel "URE), AC NOT BUSY"); 714803831d35Sstevel } 714903831d35Sstevel /* 715003831d35Sstevel * send notification back to HSC to 715103831d35Sstevel * unconfigure the AC, now that the env monitor 715203831d35Sstevel * has given permission to do so. 715303831d35Sstevel */ 715403831d35Sstevel scsb->scsb_hsc_state &= ~SCSB_ALARM_CARD_IN_USE; 7155*07d06da5SSurya Prakki hsc_ac_op((int)scsb->scsb_instance, pslotnum, 715603831d35Sstevel SCSB_HSC_AC_UNCONFIGURE, NULL); 715703831d35Sstevel rc = B_TRUE; 715803831d35Sstevel break; 715903831d35Sstevel default: 716003831d35Sstevel break; 716103831d35Sstevel } 716203831d35Sstevel 716303831d35Sstevel return (rc); 716403831d35Sstevel } 716503831d35Sstevel 716603831d35Sstevel static void 716703831d35Sstevel scsb_healthy_intr(scsb_state_t *scsb, int pslotnum) 716803831d35Sstevel { 716903831d35Sstevel int val, slotnum; 717003831d35Sstevel int healthy = B_FALSE; 717103831d35Sstevel 717203831d35Sstevel DEBUG1("Healthy Intr on slot %d\n", pslotnum); 717303831d35Sstevel /* 717403831d35Sstevel * The interrupt source register can have the healthy 717503831d35Sstevel * bit set for non-existing slot, e.g slot 7 on Tonga. 717603831d35Sstevel * It can also be seen on the Tonga CPU slot. So we make 717703831d35Sstevel * sure we have a valid slot before proceeding. 717803831d35Sstevel */ 717903831d35Sstevel if (scsb->scsb_state & SCSB_IS_TONGA) { 718003831d35Sstevel if (pslotnum > TG_MAX_SLOTS || pslotnum == SC_TG_CPU_SLOT) { 718103831d35Sstevel if (scsb_debug & 0x08000000) 718203831d35Sstevel cmn_err(CE_NOTE, "Healthy interrupt bit set for" 718303831d35Sstevel " slot %d", pslotnum); 718403831d35Sstevel return; 718503831d35Sstevel } 718603831d35Sstevel } else { 718703831d35Sstevel if (pslotnum > MC_MAX_SLOTS || pslotnum == SC_MC_CPU_SLOT || 718803831d35Sstevel (scsb->scsb_hsc_state & SCSB_HSC_CTC_PRES && 718903831d35Sstevel pslotnum == SC_MC_CTC_SLOT)) { 719003831d35Sstevel if (scsb_debug & 0x08000000) 719103831d35Sstevel cmn_err(CE_NOTE, "Healthy interrupt bit set for" 719203831d35Sstevel " slot %d", pslotnum); 719303831d35Sstevel return; 719403831d35Sstevel } 719503831d35Sstevel } 719603831d35Sstevel 719703831d35Sstevel /* 719803831d35Sstevel * The board healthy registers are already read before entering 719903831d35Sstevel * this routine 720003831d35Sstevel */ 720103831d35Sstevel slotnum = tonga_psl_to_ssl(scsb, pslotnum); 720203831d35Sstevel 720303831d35Sstevel /* 720403831d35Sstevel * P1.5. Following works since slots 1 through 8 are in the same reg 720503831d35Sstevel */ 720603831d35Sstevel val = scsb_fru_op(scsb, SLOT, slotnum, SCTRL_BHLTHY_BASE, 720703831d35Sstevel SCSB_FRU_OP_GET_BITVAL); 720803831d35Sstevel if (val) 720903831d35Sstevel healthy = B_TRUE; 7210*07d06da5SSurya Prakki (void) scsb_hsc_board_healthy(pslotnum, healthy); 721103831d35Sstevel } 721203831d35Sstevel 721303831d35Sstevel /* 721403831d35Sstevel * This function will try to read from scsb irrespective of whether 721503831d35Sstevel * SSB is present or SCB is frozen, to get the health kstat information. 721603831d35Sstevel */ 721703831d35Sstevel static int 721803831d35Sstevel scsb_blind_read(scsb_state_t *scsb, int op, uchar_t reg, int len, 721903831d35Sstevel uchar_t *rwbuf, int i2c_alloc) 722003831d35Sstevel { 722103831d35Sstevel i2c_transfer_t *i2cxferp; 722203831d35Sstevel int i, rlen, wlen, error = 0; 722303831d35Sstevel 722403831d35Sstevel if (scsb_debug & 0x0800) { 722503831d35Sstevel cmn_err(CE_NOTE, "scsb_rdwr_register(scsb,%s,%x,%x,buf):", 722603831d35Sstevel (op == I2C_WR) ? "write" : "read", reg, len); 722703831d35Sstevel } 722803831d35Sstevel 722903831d35Sstevel if (i2c_alloc) { 723003831d35Sstevel i2cxferp = scsb_alloc_i2ctx(scsb->scsb_phandle, I2C_NOSLEEP); 723103831d35Sstevel if (i2cxferp == NULL) { 723203831d35Sstevel if (scsb_debug & 0x0042) 723303831d35Sstevel cmn_err(CE_WARN, "scsb_rdwr_register: " 723403831d35Sstevel "i2ctx allocation failure"); 723503831d35Sstevel return (ENOMEM); 723603831d35Sstevel } 723703831d35Sstevel } else { 723803831d35Sstevel i2cxferp = scsb->scsb_i2ctp; 723903831d35Sstevel } 724003831d35Sstevel switch (op) { 724103831d35Sstevel case I2C_WR: 724203831d35Sstevel wlen = len + 1; /* add the address */ 724303831d35Sstevel rlen = 0; 724403831d35Sstevel i2cxferp->i2c_wbuf[0] = reg; 724503831d35Sstevel for (i = 0; i < len; ++i) { 724603831d35Sstevel i2cxferp->i2c_wbuf[1 + i] = rwbuf[i]; 724703831d35Sstevel if (scsb_debug & 0x0080) 724803831d35Sstevel cmn_err(CE_NOTE, 724903831d35Sstevel "scsb_rdwr_register: writing rwbuf[%d]=0x%x", 725003831d35Sstevel i, rwbuf[i]); 725103831d35Sstevel } 725203831d35Sstevel break; 725303831d35Sstevel case I2C_WR_RD: 725403831d35Sstevel wlen = 1; /* for the address */ 725503831d35Sstevel rlen = len; 725603831d35Sstevel i2cxferp->i2c_wbuf[0] = reg; 725703831d35Sstevel break; 725803831d35Sstevel default: 725903831d35Sstevel if (i2c_alloc) 726003831d35Sstevel scsb_free_i2ctx(scsb->scsb_phandle, i2cxferp); 726103831d35Sstevel return (EINVAL); 726203831d35Sstevel } 726303831d35Sstevel /* select the register address */ 726403831d35Sstevel i2cxferp->i2c_flags = op; 726503831d35Sstevel i2cxferp->i2c_rlen = rlen; 726603831d35Sstevel i2cxferp->i2c_wlen = wlen; 726703831d35Sstevel i2cxferp->i2c_wbuf[0] = reg; 726803831d35Sstevel scsb->scsb_kstat_flag = B_TRUE; /* we did a i2c transaction */ 726903831d35Sstevel if (error = nct_i2c_transfer(scsb->scsb_phandle, i2cxferp)) { 727003831d35Sstevel error = EIO; 727103831d35Sstevel } else if (rlen) { 727203831d35Sstevel /* copy to rwbuf[] */ 727303831d35Sstevel for (i = 0; i < len; ++i) { 727403831d35Sstevel rwbuf[i] = i2cxferp->i2c_rbuf[i]; 727503831d35Sstevel if (scsb_debug & 0x0080) 727603831d35Sstevel cmn_err(CE_NOTE, 727703831d35Sstevel "scsb_rdwr_register: read rwbuf[%d]=0x%x", 727803831d35Sstevel i, rwbuf[i]); 727903831d35Sstevel } 728003831d35Sstevel } 728103831d35Sstevel if (i2c_alloc) 728203831d35Sstevel scsb_free_i2ctx(scsb->scsb_phandle, i2cxferp); 728303831d35Sstevel if (error) { 728403831d35Sstevel scsb->scsb_i2c_errcnt++; 728503831d35Sstevel if (scsb->scsb_i2c_errcnt > scsb_err_threshold) 728603831d35Sstevel scsb->scsb_err_flag = B_TRUE; /* latch error */ 728703831d35Sstevel } else { 728803831d35Sstevel scsb->scsb_i2c_errcnt = 0; 728903831d35Sstevel } 729003831d35Sstevel 729103831d35Sstevel return (error); 729203831d35Sstevel } 729303831d35Sstevel 729403831d35Sstevel /* 729503831d35Sstevel * This function will quiesce the PSM_INT line by masking the 729603831d35Sstevel * global PSM_INT and writing 1 to SCB_INIT ( for P1.5 and later ) 729703831d35Sstevel * This effectively translates to writing 0x20 to 0xE1 register. 729803831d35Sstevel */ 729903831d35Sstevel static int 730003831d35Sstevel scsb_quiesce_psmint(scsb_state_t *scsb) 730103831d35Sstevel { 730203831d35Sstevel register int i; 730303831d35Sstevel uchar_t reg, wdata = 0; 730403831d35Sstevel uchar_t tmp_reg, intr_addr, clr_bits = 0; 730503831d35Sstevel int error, iid, intr_idx, offset; 730603831d35Sstevel 730703831d35Sstevel /* 730803831d35Sstevel * For P1.5, set the SCB_INIT bit in the System Command register, 730903831d35Sstevel * and disable global PSM_INT. Before this we need to read the 731003831d35Sstevel * interrupt source register corresponding to INIT_SCB and 731103831d35Sstevel * clear if set. 731203831d35Sstevel */ 731303831d35Sstevel if (IS_SCB_P15) { 731403831d35Sstevel /* 731503831d35Sstevel * Read INTSRC6 and write back 0x20 in case INIT_SCB is set 731603831d35Sstevel */ 731703831d35Sstevel intr_addr = SCSB_REG_ADDR(SCTRL_INTSRC_BASE); 731803831d35Sstevel tmp_reg = SCSB_REG_ADDR(SCTRL_INTSRC_SCB_P15); 731903831d35Sstevel iid = SCSB_REG_INDEX(intr_addr); 732003831d35Sstevel intr_idx = SCSB_REG_INDEX(tmp_reg) - iid; 732103831d35Sstevel offset = FRU_OFFSET(SCTRL_EVENT_SCB, SCTRL_INTPTR_BASE); 732203831d35Sstevel clr_bits = 1 << offset; 732303831d35Sstevel 732403831d35Sstevel error = scsb_rdwr_register(scsb, I2C_WR_RD, tmp_reg, 732503831d35Sstevel 1, &scb_intr_regs[intr_idx], 0); 732603831d35Sstevel /* 732703831d35Sstevel * Now mask the global PSM_INT and write INIT_SCB in case 732803831d35Sstevel * this is an INIT_SCB interrupt 732903831d35Sstevel */ 733003831d35Sstevel wdata = 1 << SYS_OFFSET(SCTRL_SYS_SCB_INIT); 733103831d35Sstevel i = SYS_REG_INDEX(SCTRL_SYS_SCB_INIT, SCTRL_SYS_CMD_BASE); 733203831d35Sstevel reg = SCSB_REG_ADDR(i); 733303831d35Sstevel error = scsb_rdwr_register(scsb, I2C_WR, reg, 1, 733403831d35Sstevel &wdata, 0); 733503831d35Sstevel 733603831d35Sstevel if (scb_intr_regs[intr_idx] & clr_bits) { 733703831d35Sstevel /* 733803831d35Sstevel * There is an SCB_INIT interrupt, which we must clear 733903831d35Sstevel * first to keep SCB_INIT from keeping PSM_INT asserted. 734003831d35Sstevel */ 734103831d35Sstevel error = scsb_rdwr_register(scsb, I2C_WR, tmp_reg, 734203831d35Sstevel 1, &clr_bits, 0); 734303831d35Sstevel } 734403831d35Sstevel 734503831d35Sstevel if (error) { 734603831d35Sstevel cmn_err(CE_WARN, "scsb%d:scsb_quiesce_psmint: " 734703831d35Sstevel " I2C TRANSFER Failed", scsb->scsb_instance); 734803831d35Sstevel if (scsb_debug & 0x0006) { 734903831d35Sstevel cmn_err(CE_NOTE, "scsb_attach: " 735003831d35Sstevel " failed to set SCB_INIT"); 735103831d35Sstevel } 735203831d35Sstevel } 735303831d35Sstevel scsb->scsb_state &= ~SCSB_PSM_INT_ENABLED; 735403831d35Sstevel } else { /* P1.0 or earlier */ 735503831d35Sstevel /* 735603831d35Sstevel * read the interrupt source registers, and then 735703831d35Sstevel * write them back. 735803831d35Sstevel */ 735903831d35Sstevel /* read the interrupt register from scsb */ 736003831d35Sstevel if (error = scsb_rdwr_register(scsb, I2C_WR_RD, intr_addr, 736103831d35Sstevel SCTRL_INTR_NUMREGS, scb_intr_regs, 0)) { 736203831d35Sstevel cmn_err(CE_WARN, "scsb_intr: " 736303831d35Sstevel " Failed read of interrupt registers."); 736403831d35Sstevel scsb->scsb_state &= ~SCSB_IN_INTR; 736503831d35Sstevel } 736603831d35Sstevel 736703831d35Sstevel /* 736803831d35Sstevel * Write to the interrupt source registers to stop scsb 736903831d35Sstevel * from interrupting. 737003831d35Sstevel */ 737103831d35Sstevel if (error = scsb_rdwr_register(scsb, I2C_WR, intr_addr, 737203831d35Sstevel SCTRL_INTR_NUMREGS, scb_intr_regs, 0)) { 737303831d35Sstevel cmn_err(CE_WARN, "scsb_intr: Failed write to interrupt" 737403831d35Sstevel " registers."); 737503831d35Sstevel scsb->scsb_state &= ~SCSB_IN_INTR; 737603831d35Sstevel } 737703831d35Sstevel 737803831d35Sstevel } 737903831d35Sstevel 738003831d35Sstevel if (error) 738103831d35Sstevel return (DDI_FAILURE); 738203831d35Sstevel else 738303831d35Sstevel return (DDI_SUCCESS); 738403831d35Sstevel } 738503831d35Sstevel 738603831d35Sstevel /* 738703831d35Sstevel * Enables or disables the global PSM_INT interrupt for P1.5, depending 738803831d35Sstevel * on the flag, flag = 0 => disable, else enable. 738903831d35Sstevel */ 739003831d35Sstevel static int 739103831d35Sstevel scsb_toggle_psmint(scsb_state_t *scsb, int enable) 739203831d35Sstevel { 739303831d35Sstevel int i; 739403831d35Sstevel uchar_t reg, on = 0, rmask = 0x0, off = 0; 739503831d35Sstevel 739603831d35Sstevel if (enable == B_TRUE) { 739703831d35Sstevel on = 1 << SYS_OFFSET(SCTRL_SYS_PSM_INT_ENABLE); 739803831d35Sstevel } else { 739903831d35Sstevel off = 1 << SYS_OFFSET(SCTRL_SYS_PSM_INT_ENABLE); 740003831d35Sstevel } 740103831d35Sstevel 740203831d35Sstevel i = SYS_REG_INDEX(SCTRL_SYS_PSM_INT_ENABLE, SCTRL_SYS_CMD_BASE); 740303831d35Sstevel reg = SCSB_REG_ADDR(i); 740403831d35Sstevel if (scsb_write_mask(scsb, reg, rmask, on, off)) { 740503831d35Sstevel cmn_err(CE_WARN, "scsb_toggle_psmint: Cannot turn %s PSM_INT", 740603831d35Sstevel enable == 1 ? "on" : "off"); 740703831d35Sstevel return (DDI_FAILURE); 740803831d35Sstevel } 740903831d35Sstevel if (enable == 0) { 741003831d35Sstevel scsb->scsb_state &= ~SCSB_PSM_INT_ENABLED; 741103831d35Sstevel } else { 741203831d35Sstevel scsb->scsb_state |= SCSB_PSM_INT_ENABLED; 741303831d35Sstevel } 741403831d35Sstevel 741503831d35Sstevel return (DDI_SUCCESS); 741603831d35Sstevel } 741703831d35Sstevel 741803831d35Sstevel /* 741903831d35Sstevel * This routine is to be used by all the drivers using this i2c bus 742003831d35Sstevel * to synchronize their transfer operations. 742103831d35Sstevel */ 742203831d35Sstevel int 742303831d35Sstevel nct_i2c_transfer(i2c_client_hdl_t i2c_hdl, i2c_transfer_t *i2c_tran) 742403831d35Sstevel { 742503831d35Sstevel int retval, initmux = nct_mutex_init; 742603831d35Sstevel 742703831d35Sstevel /* 742803831d35Sstevel * If scsb interrupt mutex is initialized, also hold the 742903831d35Sstevel * interrupt mutex to let the i2c_transfer() to complete 743003831d35Sstevel */ 743103831d35Sstevel 743203831d35Sstevel if (initmux & MUTEX_INIT) { 743303831d35Sstevel mutex_enter(scb_intr_mutex); 743403831d35Sstevel } 743503831d35Sstevel 743603831d35Sstevel retval = i2c_transfer(i2c_hdl, i2c_tran); 743703831d35Sstevel 743803831d35Sstevel if (initmux & MUTEX_INIT) { 743903831d35Sstevel mutex_exit(scb_intr_mutex); 744003831d35Sstevel } 744103831d35Sstevel 744203831d35Sstevel return (retval); 744303831d35Sstevel } 7444