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 #include <sys/time.h> 2903831d35Sstevel #include <sys/errno.h> 3003831d35Sstevel #include <sys/kmem.h> 3103831d35Sstevel #include <sys/stat.h> 3203831d35Sstevel #include <sys/cmn_err.h> 3303831d35Sstevel 3403831d35Sstevel #include <sys/conf.h> 3503831d35Sstevel #include <sys/modctl.h> 3603831d35Sstevel #include <sys/devops.h> 3703831d35Sstevel #include <sys/ddi.h> 3803831d35Sstevel #include <sys/sunddi.h> 3903831d35Sstevel #include <sys/callb.h> 4003831d35Sstevel #include <sys/disp.h> 4103831d35Sstevel #include <sys/strlog.h> 4203831d35Sstevel 4303831d35Sstevel #include <sys/sgevents.h> 4403831d35Sstevel #include <sys/serengeti.h> 4503831d35Sstevel #include <sys/sgsbbc.h> 4603831d35Sstevel #include <sys/sgsbbc_iosram.h> 4703831d35Sstevel #include <sys/sgsbbc_mailbox.h> 4803831d35Sstevel #include <sys/uadmin.h> 4903831d35Sstevel #include <sys/machsystm.h> 5003831d35Sstevel #include <sys/sysevent.h> 5103831d35Sstevel #include <sys/sysevent/dr.h> 5203831d35Sstevel #include <sys/sysevent/eventdefs.h> 5303831d35Sstevel #include <sys/file.h> 5403831d35Sstevel #include <sys/lw8.h> 5503831d35Sstevel #include <sys/lw8_impl.h> 5603831d35Sstevel #include <sys/plat_ecc_unum.h> 5703831d35Sstevel 5803831d35Sstevel /* 5903831d35Sstevel * Global Variables - can be patched from Solaris 6003831d35Sstevel * ============================================== 6103831d35Sstevel */ 6203831d35Sstevel 6303831d35Sstevel /* 6403831d35Sstevel * Module Variables 6503831d35Sstevel * ================ 6603831d35Sstevel */ 6703831d35Sstevel 6803831d35Sstevel /* 6903831d35Sstevel * functions local to this driver. 7003831d35Sstevel */ 7103831d35Sstevel static int lw8_attach(dev_info_t *dip, ddi_attach_cmd_t cmd); 7203831d35Sstevel static int lw8_detach(dev_info_t *dip, ddi_detach_cmd_t cmd); 7303831d35Sstevel static int lw8_add_intr_handlers(void); 7403831d35Sstevel static int lw8_remove_intr_handlers(void); 7503831d35Sstevel static void lw8_wakeup_sleepers(void); 7603831d35Sstevel static uint_t lw8_fast_shutdown(char *arg); 7703831d35Sstevel static uint_t lw8_slow_shutdown(char *arg); 7803831d35Sstevel static uint_t lw8_event_data_handler(char *); 7903831d35Sstevel static uint_t lw8_dr_data_handler(char *); 8003831d35Sstevel static uint_t lw8_env_data_handler(char *); 8103831d35Sstevel static uint_t lw8_cap_ecc_msg_handler(char *); 8203831d35Sstevel static int lw8_open(dev_t *dev_p, int flag, int otyp, cred_t *cred_p); 8303831d35Sstevel static int lw8_close(dev_t dev, int flag, int otyp, cred_t *cred_p); 8403831d35Sstevel static int lw8_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, 8503831d35Sstevel cred_t *cred_p, int *rval_p); 8603831d35Sstevel static void lw8_logger_start(void); 8703831d35Sstevel static void lw8_logger_destroy(void); 8803831d35Sstevel static void lw8_logger_wakeup(void); 8903831d35Sstevel 9003831d35Sstevel /* 9103831d35Sstevel * Driver entry points 9203831d35Sstevel */ 9303831d35Sstevel static struct cb_ops lw8_cb_ops = { 9403831d35Sstevel lw8_open, /* open */ 9503831d35Sstevel lw8_close, /* close */ 9603831d35Sstevel nodev, /* strategy() */ 9703831d35Sstevel nodev, /* print() */ 9803831d35Sstevel nodev, /* dump() */ 9903831d35Sstevel nodev, /* read() */ 10003831d35Sstevel nodev, /* write() */ 10103831d35Sstevel lw8_ioctl, /* ioctl() */ 10203831d35Sstevel nodev, /* devmap() */ 10303831d35Sstevel nodev, /* mmap() */ 10403831d35Sstevel ddi_segmap, /* segmap() */ 10503831d35Sstevel nochpoll, /* poll() */ 10603831d35Sstevel ddi_prop_op, /* prop_op() */ 10703831d35Sstevel NULL, /* cb_str */ 10803831d35Sstevel D_NEW | D_MP /* cb_flag */ 10903831d35Sstevel }; 11003831d35Sstevel 11103831d35Sstevel 11203831d35Sstevel static struct dev_ops lw8_ops = { 11303831d35Sstevel DEVO_REV, 11403831d35Sstevel 0, /* ref count */ 11503831d35Sstevel ddi_getinfo_1to1, /* getinfo() */ 11603831d35Sstevel nulldev, /* identify() */ 11703831d35Sstevel nulldev, /* probe() */ 11803831d35Sstevel lw8_attach, /* attach() */ 11903831d35Sstevel lw8_detach, /* detach */ 12003831d35Sstevel nodev, /* reset */ 12103831d35Sstevel &lw8_cb_ops, /* pointer to cb_ops structure */ 12203831d35Sstevel (struct bus_ops *)NULL, 12319397407SSherry Moore nulldev, /* power() */ 12419397407SSherry Moore ddi_quiesce_not_needed, /* quiesce() */ 12503831d35Sstevel }; 12603831d35Sstevel 12703831d35Sstevel /* 12803831d35Sstevel * Loadable module support. 12903831d35Sstevel */ 13003831d35Sstevel extern struct mod_ops mod_driverops; 13103831d35Sstevel 13203831d35Sstevel static struct modldrv modldrv = { 13303831d35Sstevel &mod_driverops, /* Type of module. This is a driver */ 13419397407SSherry Moore "Netra-T12 control driver", /* Name of the module */ 13503831d35Sstevel &lw8_ops /* pointer to the dev_ops structure */ 13603831d35Sstevel }; 13703831d35Sstevel 13803831d35Sstevel static struct modlinkage modlinkage = { 13903831d35Sstevel MODREV_1, 14003831d35Sstevel &modldrv, 14103831d35Sstevel NULL 14203831d35Sstevel }; 14303831d35Sstevel 14403831d35Sstevel /* 14503831d35Sstevel * messages 14603831d35Sstevel */ 14703831d35Sstevel #define SHUTDOWN_EVENT_MSG "lw8: system shutdown due to " \ 14803831d35Sstevel "SC request.\n" 14903831d35Sstevel #define VOLTAGE_EVENT_MSG "lw8: system shutdown due to " \ 15003831d35Sstevel "voltage out of range.\n" 15103831d35Sstevel #define TEMPERATURE_EVENT_MSG "lw8: system shutdown due to " \ 15203831d35Sstevel "temperature exceeding limits.\n" 15303831d35Sstevel #define FANFAIL_EVENT_MSG "lw8: system shutdown due to " \ 15403831d35Sstevel "too many fan failures.\n" 15503831d35Sstevel #define NO_SCC_EVENT_MSG "lw8: system shutdown due to " \ 15603831d35Sstevel "no system configuration card.\n" 15703831d35Sstevel 15803831d35Sstevel /* 15903831d35Sstevel * led table - the following provides a cache of the led state - needed 16003831d35Sstevel * to avoid the overhead of readoing from the SC each time 16103831d35Sstevel */ 16203831d35Sstevel 16303831d35Sstevel struct led_info { 16403831d35Sstevel char id[MAX_ID_LEN]; 16503831d35Sstevel int position; 16603831d35Sstevel int status; 16703831d35Sstevel char color[MAX_COLOR_LEN]; 16803831d35Sstevel }; 16903831d35Sstevel 17003831d35Sstevel static struct fru_led_info { 17103831d35Sstevel char location[MAX_LOCATION_LEN]; 17203831d35Sstevel struct led_info led_info[MAX_LEDS_PER_FRU]; 17303831d35Sstevel } fru_led_table[MAX_FRUS] = { 17403831d35Sstevel "SB0", {"fault", LOM_LED_POSITION_FRU, 0, "amber", 17503831d35Sstevel "power", LOM_LED_POSITION_FRU, 0, "green", 17603831d35Sstevel "ok_to_remove", LOM_LED_POSITION_FRU, 0, "amber"}, 17703831d35Sstevel "PS0", {"fault", LOM_LED_POSITION_FRU, 0, "amber", 17803831d35Sstevel "power", LOM_LED_POSITION_FRU, 0, "green", 17903831d35Sstevel "predicted_fault", LOM_LED_POSITION_FRU, 0, "amber"}, 18003831d35Sstevel "SB2", {"fault", LOM_LED_POSITION_FRU, 0, "amber", 18103831d35Sstevel "power", LOM_LED_POSITION_FRU, 0, "green", 18203831d35Sstevel "ok_to_remove", LOM_LED_POSITION_FRU, 0, "amber"}, 18303831d35Sstevel "PS1", {"fault", LOM_LED_POSITION_FRU, 0, "amber", 18403831d35Sstevel "power", LOM_LED_POSITION_FRU, 0, "green", 18503831d35Sstevel "predicted_fault", LOM_LED_POSITION_FRU, 0, "amber"}, 18603831d35Sstevel "SB4", {"fault", LOM_LED_POSITION_FRU, 0, "amber", 18703831d35Sstevel "power", LOM_LED_POSITION_FRU, 0, "green", 18803831d35Sstevel "ok_to_remove", LOM_LED_POSITION_FRU, 0, "amber"}, 18903831d35Sstevel "PS2", {"fault", LOM_LED_POSITION_FRU, 0, "amber", 19003831d35Sstevel "power", LOM_LED_POSITION_FRU, 0, "green", 19103831d35Sstevel "predicted_fault", LOM_LED_POSITION_FRU, 0, "amber"}, 19203831d35Sstevel "IB6", {"fault", LOM_LED_POSITION_FRU, 0, "amber", 19303831d35Sstevel "power", LOM_LED_POSITION_FRU, 0, "green", 19403831d35Sstevel "ok_to_remove", LOM_LED_POSITION_FRU, 0, "amber"}, 19503831d35Sstevel "PS3", {"fault", LOM_LED_POSITION_FRU, 0, "amber", 19603831d35Sstevel "power", LOM_LED_POSITION_FRU, 0, "green", 19703831d35Sstevel "predicted_fault", LOM_LED_POSITION_FRU, 0, "amber"}, 19803831d35Sstevel "FT0", {"fault", LOM_LED_POSITION_FRU, 0, "amber", 19903831d35Sstevel "power", LOM_LED_POSITION_FRU, 0, "green", 20003831d35Sstevel "ok_to_remove", LOM_LED_POSITION_FRU, 0, "amber"}, 20103831d35Sstevel "FAN0", {"fault", LOM_LED_POSITION_LOCATION, 0, "amber"}, 20203831d35Sstevel "FAN1", {"fault", LOM_LED_POSITION_LOCATION, 0, "amber"}, 20303831d35Sstevel "FAN2", {"fault", LOM_LED_POSITION_LOCATION, 0, "amber"}, 20403831d35Sstevel "FAN3", {"fault", LOM_LED_POSITION_LOCATION, 0, "amber"}, 20503831d35Sstevel "FAN4", {"fault", LOM_LED_POSITION_LOCATION, 0, "amber"}, 20603831d35Sstevel "FAN5", {"fault", LOM_LED_POSITION_LOCATION, 0, "amber"}, 20703831d35Sstevel "FAN6", {"fault", LOM_LED_POSITION_LOCATION, 0, "amber"}, 20803831d35Sstevel "FAN7", {"fault", LOM_LED_POSITION_LOCATION, 0, "amber"}, 20903831d35Sstevel "FAN8", {"fault", LOM_LED_POSITION_LOCATION, 0, "amber"}, 21003831d35Sstevel "FAN9", {"fault", LOM_LED_POSITION_LOCATION, 0, "amber"}, 21103831d35Sstevel "DISK0", {"fault", LOM_LED_POSITION_LOCATION, 0, "amber", 21203831d35Sstevel "power", LOM_LED_POSITION_LOCATION, 0, "green", 21303831d35Sstevel "ok_to_remove", LOM_LED_POSITION_LOCATION, 0, "blue"}, 21403831d35Sstevel "DISK1", {"fault", LOM_LED_POSITION_LOCATION, 0, "amber", 21503831d35Sstevel "power", LOM_LED_POSITION_LOCATION, 0, "green", 21603831d35Sstevel "ok_to_remove", LOM_LED_POSITION_LOCATION, 0, "blue"}, 21703831d35Sstevel "RP0", {"fault", LOM_LED_POSITION_FRU, 0, "amber", 21803831d35Sstevel "power", LOM_LED_POSITION_FRU, 0, "green", 21903831d35Sstevel "ok_to_remove", LOM_LED_POSITION_FRU, 0, "amber"}, 22003831d35Sstevel "RP2", {"fault", LOM_LED_POSITION_FRU, 0, "amber", 22103831d35Sstevel "power", LOM_LED_POSITION_FRU, 0, "green", 22203831d35Sstevel "ok_to_remove", LOM_LED_POSITION_FRU, 0, "amber"}, 22303831d35Sstevel "chassis", {"fault", LOM_LED_POSITION_FRU, 0, "amber", 22403831d35Sstevel "power", LOM_LED_POSITION_FRU, 0, "green", 22503831d35Sstevel "locator", LOM_LED_POSITION_FRU, 0, "white", 22603831d35Sstevel "top_access", LOM_LED_POSITION_FRU, 0, "amber", 22703831d35Sstevel "alarm1", LOM_LED_POSITION_FRU, 0, "amber", 22803831d35Sstevel "alarm2", LOM_LED_POSITION_FRU, 0, "amber", 22903831d35Sstevel "system", LOM_LED_POSITION_FRU, 0, "green", 23003831d35Sstevel "supplyA", LOM_LED_POSITION_FRU, 0, "green", 23103831d35Sstevel "supplyB", LOM_LED_POSITION_FRU, 0, "green"}, 23203831d35Sstevel }; 23303831d35Sstevel 23403831d35Sstevel char *fru_locn[MAX_LOCATION_LEN] = { 23503831d35Sstevel "SB0", 23603831d35Sstevel "PS0", 23703831d35Sstevel "SB2", 23803831d35Sstevel "PS1", 23903831d35Sstevel "SB4", 24003831d35Sstevel "PS2", 24103831d35Sstevel "IB6", 24203831d35Sstevel "PS3", 24303831d35Sstevel "SCC", 24403831d35Sstevel "SSC1", 24503831d35Sstevel }; 24603831d35Sstevel 24703831d35Sstevel /* 24803831d35Sstevel * mutexes which protect the interrupt handlers. 24903831d35Sstevel */ 25003831d35Sstevel static kmutex_t lw8_shutdown_hdlr_lock; 25103831d35Sstevel static kmutex_t lw8_dr_hdlr_lock; 25203831d35Sstevel static kmutex_t lw8_env_hdlr_lock; 25303831d35Sstevel static kmutex_t lw8_event_mutex; 25403831d35Sstevel static kmutex_t lw8_logger_lock; 25503831d35Sstevel static kmutex_t lw8_cap_msg_hdlr_lock; 25603831d35Sstevel static kcondvar_t lw8_event_cv; 25703831d35Sstevel static kcondvar_t lw8_logger_sig_cv; 25803831d35Sstevel 25903831d35Sstevel /* 26003831d35Sstevel * state booleans 26103831d35Sstevel */ 26203831d35Sstevel static boolean_t lw8_event_pending = B_FALSE; 26303831d35Sstevel static boolean_t led_state_cached = B_FALSE; 26403831d35Sstevel 26503831d35Sstevel /* 26603831d35Sstevel * Payloads of the event handlers. 26703831d35Sstevel */ 26803831d35Sstevel static lw8_event_t lw8_shutdown_payload; 26903831d35Sstevel static sbbc_msg_t lw8_shutdown_payload_msg; 27003831d35Sstevel static sg_system_fru_descriptor_t lw8_dr_payload; 27103831d35Sstevel static sbbc_msg_t lw8_dr_payload_msg; 27203831d35Sstevel static sg_event_fan_status_t lw8_env_payload; 27303831d35Sstevel static sbbc_msg_t lw8_env_payload_msg; 27403831d35Sstevel static plat_capability_data_t lw8_cap_payload; 27503831d35Sstevel static sbbc_msg_t lw8_cap_payload_msg; 27603831d35Sstevel 27703831d35Sstevel /* 27803831d35Sstevel * The IDs of the soft interrupts 27903831d35Sstevel */ 28003831d35Sstevel static ddi_softintr_t lw8_slow_shutdown_softint_id; 28103831d35Sstevel static ddi_softintr_t lw8_fast_shutdown_softint_id; 28203831d35Sstevel 28303831d35Sstevel /* 28403831d35Sstevel * Logger commands.. 28503831d35Sstevel */ 28603831d35Sstevel #define LW8_LOGGER_EXITNOW -1 28703831d35Sstevel #define LW8_LOGGER_WAIT 0 28803831d35Sstevel #define LW8_LOGGER_PROCESSNOW 1 28903831d35Sstevel 29003831d35Sstevel /* 29103831d35Sstevel * Logger thread state 29203831d35Sstevel */ 29303831d35Sstevel static int lw8_logger_sig = LW8_LOGGER_WAIT; 29403831d35Sstevel static kt_did_t lw8_logger_tid = 0; 29503831d35Sstevel 29603831d35Sstevel extern pri_t maxclsyspri; 29703831d35Sstevel 29803831d35Sstevel int 29903831d35Sstevel _init(void) 30003831d35Sstevel { 30103831d35Sstevel int error = 0; 30203831d35Sstevel 30303831d35Sstevel mutex_init(&lw8_shutdown_hdlr_lock, NULL, MUTEX_DEFAULT, NULL); 30403831d35Sstevel mutex_init(&lw8_dr_hdlr_lock, NULL, MUTEX_DEFAULT, NULL); 30503831d35Sstevel mutex_init(&lw8_env_hdlr_lock, NULL, MUTEX_DEFAULT, NULL); 30603831d35Sstevel mutex_init(&lw8_cap_msg_hdlr_lock, NULL, MUTEX_DEFAULT, NULL); 30703831d35Sstevel mutex_init(&lw8_event_mutex, NULL, MUTEX_DRIVER, NULL); 30803831d35Sstevel mutex_init(&lw8_logger_lock, NULL, MUTEX_DRIVER, NULL); 30903831d35Sstevel cv_init(&lw8_event_cv, NULL, CV_DRIVER, NULL); 31003831d35Sstevel cv_init(&lw8_logger_sig_cv, NULL, CV_DRIVER, NULL); 31103831d35Sstevel 31203831d35Sstevel error = mod_install(&modlinkage); 31303831d35Sstevel if (error) { 31403831d35Sstevel cv_destroy(&lw8_logger_sig_cv); 31503831d35Sstevel cv_destroy(&lw8_event_cv); 31603831d35Sstevel mutex_destroy(&lw8_logger_lock); 31703831d35Sstevel mutex_destroy(&lw8_event_mutex); 31803831d35Sstevel mutex_destroy(&lw8_env_hdlr_lock); 31903831d35Sstevel mutex_destroy(&lw8_cap_msg_hdlr_lock); 32003831d35Sstevel mutex_destroy(&lw8_dr_hdlr_lock); 32103831d35Sstevel mutex_destroy(&lw8_shutdown_hdlr_lock); 32203831d35Sstevel } 32303831d35Sstevel return (error); 32403831d35Sstevel } 32503831d35Sstevel 32603831d35Sstevel 32703831d35Sstevel int 32803831d35Sstevel _info(struct modinfo *modinfop) 32903831d35Sstevel { 33003831d35Sstevel return (mod_info(&modlinkage, modinfop)); 33103831d35Sstevel } 33203831d35Sstevel 33303831d35Sstevel 33403831d35Sstevel int 33503831d35Sstevel _fini(void) 33603831d35Sstevel { 33703831d35Sstevel int error = 0; 33803831d35Sstevel 33903831d35Sstevel error = mod_remove(&modlinkage); 34003831d35Sstevel if (error) 34103831d35Sstevel return (error); 34203831d35Sstevel cv_destroy(&lw8_logger_sig_cv); 34303831d35Sstevel cv_destroy(&lw8_event_cv); 34403831d35Sstevel mutex_destroy(&lw8_logger_lock); 34503831d35Sstevel mutex_destroy(&lw8_event_mutex); 34603831d35Sstevel mutex_destroy(&lw8_env_hdlr_lock); 34703831d35Sstevel mutex_destroy(&lw8_cap_msg_hdlr_lock); 34803831d35Sstevel mutex_destroy(&lw8_dr_hdlr_lock); 34903831d35Sstevel mutex_destroy(&lw8_shutdown_hdlr_lock); 35003831d35Sstevel return (error); 35103831d35Sstevel } 35203831d35Sstevel 35303831d35Sstevel 35403831d35Sstevel static int 35503831d35Sstevel lw8_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 35603831d35Sstevel { 35703831d35Sstevel int instance; 35803831d35Sstevel int err; 35903831d35Sstevel 36003831d35Sstevel switch (cmd) { 36103831d35Sstevel case DDI_ATTACH: 36203831d35Sstevel /* 36303831d35Sstevel * only allow one instance 36403831d35Sstevel */ 36503831d35Sstevel instance = ddi_get_instance(dip); 36603831d35Sstevel if (instance != 0) 36703831d35Sstevel return (DDI_FAILURE); 36803831d35Sstevel 36903831d35Sstevel err = ddi_create_minor_node(dip, "lw8", S_IFCHR, 37003831d35Sstevel instance, DDI_PSEUDO, NULL); 37103831d35Sstevel if (err != DDI_SUCCESS) 37203831d35Sstevel return (DDI_FAILURE); 37303831d35Sstevel 37403831d35Sstevel err = ddi_add_softintr(dip, DDI_SOFTINT_LOW, 37503831d35Sstevel &lw8_slow_shutdown_softint_id, NULL, NULL, 37603831d35Sstevel lw8_slow_shutdown, NULL); 37703831d35Sstevel if (err != 0) { 37803831d35Sstevel cmn_err(CE_WARN, "Failed to add polling softint" 37903831d35Sstevel "handler for lw8. Err=%d", err); 38003831d35Sstevel ddi_remove_minor_node(dip, NULL); 38103831d35Sstevel return (DDI_FAILURE); 38203831d35Sstevel } 38303831d35Sstevel 38403831d35Sstevel err = ddi_add_softintr(dip, DDI_SOFTINT_LOW, 38503831d35Sstevel &lw8_fast_shutdown_softint_id, NULL, NULL, 38603831d35Sstevel lw8_fast_shutdown, NULL); 38703831d35Sstevel if (err != 0) { 38803831d35Sstevel cmn_err(CE_WARN, "Failed to add polling softint" 38903831d35Sstevel "handler for lw8. Err=%d", err); 39003831d35Sstevel ddi_remove_softintr(lw8_slow_shutdown_softint_id); 39103831d35Sstevel ddi_remove_minor_node(dip, NULL); 39203831d35Sstevel return (DDI_FAILURE); 39303831d35Sstevel } 39403831d35Sstevel 39503831d35Sstevel lw8_logger_start(); 39603831d35Sstevel 39703831d35Sstevel /* 39803831d35Sstevel * Add the handlers which watch for unsolicited messages 39903831d35Sstevel * and post event to Sysevent Framework. 40003831d35Sstevel */ 40103831d35Sstevel err = lw8_add_intr_handlers(); 40203831d35Sstevel if (err != DDI_SUCCESS) { 40303831d35Sstevel cmn_err(CE_WARN, "Failed to add event handlers"); 40403831d35Sstevel lw8_logger_destroy(); 40503831d35Sstevel ddi_remove_softintr(lw8_fast_shutdown_softint_id); 40603831d35Sstevel ddi_remove_softintr(lw8_slow_shutdown_softint_id); 40703831d35Sstevel ddi_remove_minor_node(dip, NULL); 40803831d35Sstevel return (DDI_FAILURE); 40903831d35Sstevel } 41003831d35Sstevel 41103831d35Sstevel ddi_report_dev(dip); 41203831d35Sstevel return (DDI_SUCCESS); 41303831d35Sstevel case DDI_RESUME: 41403831d35Sstevel return (DDI_SUCCESS); 41503831d35Sstevel default: 41603831d35Sstevel return (DDI_FAILURE); 41703831d35Sstevel } 41803831d35Sstevel } 41903831d35Sstevel 42003831d35Sstevel 42103831d35Sstevel static int 42203831d35Sstevel lw8_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 42303831d35Sstevel { 42403831d35Sstevel int instance; 42503831d35Sstevel int err; 42603831d35Sstevel 42703831d35Sstevel switch (cmd) { 42803831d35Sstevel case DDI_DETACH: 42903831d35Sstevel instance = ddi_get_instance(dip); 43003831d35Sstevel if (instance != 0) 43103831d35Sstevel return (DDI_FAILURE); 43203831d35Sstevel 43303831d35Sstevel /* 43403831d35Sstevel * Remove the handlers which watch for unsolicited messages 43503831d35Sstevel * and post event to Sysevent Framework. 43603831d35Sstevel */ 43703831d35Sstevel err = lw8_remove_intr_handlers(); 43803831d35Sstevel if (err != DDI_SUCCESS) { 43903831d35Sstevel cmn_err(CE_WARN, "Failed to remove event handlers"); 44003831d35Sstevel return (DDI_FAILURE); 44103831d35Sstevel } 44203831d35Sstevel lw8_logger_destroy(); 44303831d35Sstevel ddi_remove_softintr(lw8_slow_shutdown_softint_id); 44403831d35Sstevel ddi_remove_softintr(lw8_fast_shutdown_softint_id); 44503831d35Sstevel ddi_remove_minor_node(dip, NULL); 44603831d35Sstevel return (DDI_SUCCESS); 44703831d35Sstevel case DDI_SUSPEND: 44803831d35Sstevel return (DDI_SUCCESS); 44903831d35Sstevel default: 45003831d35Sstevel return (DDI_FAILURE); 45103831d35Sstevel } 45203831d35Sstevel } 45303831d35Sstevel 45403831d35Sstevel static int 45503831d35Sstevel lw8_add_intr_handlers() 45603831d35Sstevel { 45703831d35Sstevel int err; 45803831d35Sstevel 45903831d35Sstevel lw8_shutdown_payload_msg.msg_buf = (caddr_t)&lw8_shutdown_payload; 46003831d35Sstevel lw8_shutdown_payload_msg.msg_len = sizeof (lw8_shutdown_payload); 46103831d35Sstevel err = sbbc_mbox_reg_intr(MBOX_EVENT_LW8, lw8_event_data_handler, 46203831d35Sstevel &lw8_shutdown_payload_msg, NULL, &lw8_shutdown_hdlr_lock); 46303831d35Sstevel if (err != 0) { 46403831d35Sstevel cmn_err(CE_WARN, "Failed to register MBOX_EVENT_LW8 " 46503831d35Sstevel " handler. Err=%d", err); 46603831d35Sstevel return (DDI_FAILURE); 46703831d35Sstevel } 46803831d35Sstevel 46903831d35Sstevel lw8_dr_payload_msg.msg_buf = (caddr_t)&lw8_dr_payload; 47003831d35Sstevel lw8_dr_payload_msg.msg_len = sizeof (lw8_dr_payload); 47103831d35Sstevel err = sbbc_mbox_reg_intr(MBOX_EVENT_GENERIC, lw8_dr_data_handler, 47203831d35Sstevel &lw8_dr_payload_msg, NULL, &lw8_dr_hdlr_lock); 47303831d35Sstevel if (err != 0) { 47403831d35Sstevel cmn_err(CE_WARN, "Failed to register MBOX_EVENT_GENERIC " 47503831d35Sstevel " handler. Err=%d", err); 476*07d06da5SSurya Prakki (void) sbbc_mbox_unreg_intr(MBOX_EVENT_LW8, 477*07d06da5SSurya Prakki lw8_event_data_handler); 47803831d35Sstevel return (DDI_FAILURE); 47903831d35Sstevel } 48003831d35Sstevel 48103831d35Sstevel lw8_env_payload_msg.msg_buf = (caddr_t)&lw8_env_payload; 48203831d35Sstevel lw8_env_payload_msg.msg_len = sizeof (lw8_env_payload); 48303831d35Sstevel err = sbbc_mbox_reg_intr(MBOX_EVENT_ENV, lw8_env_data_handler, 48403831d35Sstevel &lw8_env_payload_msg, NULL, &lw8_env_hdlr_lock); 48503831d35Sstevel if (err != 0) { 48603831d35Sstevel cmn_err(CE_WARN, "Failed to register MBOX_EVENT_ENV " 48703831d35Sstevel " handler. Err=%d", err); 488*07d06da5SSurya Prakki (void) sbbc_mbox_unreg_intr(MBOX_EVENT_GENERIC, 489*07d06da5SSurya Prakki lw8_dr_data_handler); 490*07d06da5SSurya Prakki (void) sbbc_mbox_unreg_intr(MBOX_EVENT_LW8, 491*07d06da5SSurya Prakki lw8_event_data_handler); 49203831d35Sstevel return (DDI_FAILURE); 49303831d35Sstevel } 49403831d35Sstevel 49503831d35Sstevel lw8_cap_payload_msg.msg_buf = (caddr_t)&lw8_cap_payload; 49603831d35Sstevel lw8_cap_payload_msg.msg_len = sizeof (lw8_cap_payload); 49703831d35Sstevel err = sbbc_mbox_reg_intr(INFO_MBOX, lw8_cap_ecc_msg_handler, 49803831d35Sstevel &lw8_cap_payload_msg, NULL, &lw8_cap_msg_hdlr_lock); 49903831d35Sstevel if (err != 0) { 50003831d35Sstevel cmn_err(CE_WARN, "Failed to register INFO_MBOX " 50103831d35Sstevel " handler. Err=%d", err); 502*07d06da5SSurya Prakki (void) sbbc_mbox_unreg_intr(MBOX_EVENT_GENERIC, 503*07d06da5SSurya Prakki lw8_dr_data_handler); 504*07d06da5SSurya Prakki (void) sbbc_mbox_unreg_intr(MBOX_EVENT_LW8, 505*07d06da5SSurya Prakki lw8_event_data_handler); 506*07d06da5SSurya Prakki (void) sbbc_mbox_unreg_intr(INFO_MBOX, 507*07d06da5SSurya Prakki lw8_cap_ecc_msg_handler); 50803831d35Sstevel return (DDI_FAILURE); 50903831d35Sstevel } 51003831d35Sstevel 51103831d35Sstevel return (DDI_SUCCESS); 51203831d35Sstevel } 51303831d35Sstevel 51403831d35Sstevel static int 51503831d35Sstevel lw8_remove_intr_handlers(void) 51603831d35Sstevel { 51703831d35Sstevel int rv = DDI_SUCCESS; 51803831d35Sstevel int err; 51903831d35Sstevel 52003831d35Sstevel err = sbbc_mbox_unreg_intr(MBOX_EVENT_LW8, lw8_event_data_handler); 52103831d35Sstevel if (err != 0) { 52203831d35Sstevel cmn_err(CE_WARN, "Failed to unregister MBOX_EVENT_LW8 " 52303831d35Sstevel "handler. Err=%d", err); 52403831d35Sstevel rv = DDI_FAILURE; 52503831d35Sstevel } 52603831d35Sstevel err = sbbc_mbox_unreg_intr(MBOX_EVENT_GENERIC, lw8_dr_data_handler); 52703831d35Sstevel if (err != 0) { 52803831d35Sstevel cmn_err(CE_WARN, "Failed to unregister MBOX_EVENT_GENERIC " 52903831d35Sstevel "handler. Err=%d", err); 53003831d35Sstevel rv = DDI_FAILURE; 53103831d35Sstevel } 53203831d35Sstevel err = sbbc_mbox_unreg_intr(MBOX_EVENT_ENV, lw8_env_data_handler); 53303831d35Sstevel if (err != 0) { 53403831d35Sstevel cmn_err(CE_WARN, "Failed to unregister MBOX_EVENT_ENV " 53503831d35Sstevel "handler. Err=%d", err); 53603831d35Sstevel rv = DDI_FAILURE; 53703831d35Sstevel } 53803831d35Sstevel err = sbbc_mbox_unreg_intr(INFO_MBOX, lw8_cap_ecc_msg_handler); 53903831d35Sstevel if (err != 0) { 54003831d35Sstevel cmn_err(CE_WARN, "Failed to unregister INFO_MBOX " 54103831d35Sstevel "handler. Err=%d", err); 54203831d35Sstevel rv = DDI_FAILURE; 54303831d35Sstevel } 54403831d35Sstevel return (rv); 54503831d35Sstevel } 54603831d35Sstevel 54703831d35Sstevel static uint_t 54803831d35Sstevel lw8_dr_data_handler(char *arg) 54903831d35Sstevel { 55003831d35Sstevel sg_system_fru_descriptor_t *payload; 55103831d35Sstevel sbbc_msg_t *msg; 55203831d35Sstevel int hint; 55303831d35Sstevel sysevent_t *ev; 55403831d35Sstevel sysevent_id_t eid; 55503831d35Sstevel int rv = 0; 55603831d35Sstevel sysevent_value_t evnt_val; 55703831d35Sstevel sysevent_attr_list_t *evnt_attr_list = NULL; 55803831d35Sstevel char attach_pnt[MAXPATHLEN]; 55903831d35Sstevel 56003831d35Sstevel msg = (sbbc_msg_t *)arg; 56103831d35Sstevel if (msg == NULL) { 56203831d35Sstevel return (DDI_INTR_CLAIMED); 56303831d35Sstevel } 56403831d35Sstevel payload = (sg_system_fru_descriptor_t *)msg->msg_buf; 56503831d35Sstevel if (payload == NULL) { 56603831d35Sstevel return (DDI_INTR_CLAIMED); 56703831d35Sstevel } 56803831d35Sstevel if (payload->slot < 0 || payload->slot >= sizeof (fru_locn) / 56903831d35Sstevel sizeof (char *)) { 57003831d35Sstevel return (DDI_INTR_CLAIMED); 57103831d35Sstevel } 57203831d35Sstevel 57303831d35Sstevel /* 57403831d35Sstevel * if not SB send sysevent (SBs send sysevent from ssm driver) 57503831d35Sstevel */ 57603831d35Sstevel if (strncmp(fru_locn[payload->slot], "SB", 2) != 0) { 57703831d35Sstevel switch (payload->event_details) { 57803831d35Sstevel case SG_EVT_BOARD_ABSENT: 57903831d35Sstevel hint = SE_HINT_REMOVE; 58003831d35Sstevel break; 58103831d35Sstevel case SG_EVT_BOARD_PRESENT: 58203831d35Sstevel hint = SE_HINT_INSERT; 58303831d35Sstevel break; 58403831d35Sstevel default: 58503831d35Sstevel hint = SE_NO_HINT; 58603831d35Sstevel break; 58703831d35Sstevel } 58803831d35Sstevel (void) snprintf(attach_pnt, sizeof (attach_pnt), "ssm0:N0.%s", 58903831d35Sstevel fru_locn[payload->slot]); 59003831d35Sstevel ev = sysevent_alloc(EC_DR, ESC_DR_AP_STATE_CHANGE, EP_DDI, 59103831d35Sstevel KM_NOSLEEP); 59203831d35Sstevel if (ev == NULL) { 59303831d35Sstevel cmn_err(CE_WARN, "Failed to allocate %s event", EC_DR); 59403831d35Sstevel return (DDI_INTR_CLAIMED); 59503831d35Sstevel } 59603831d35Sstevel evnt_val.value_type = SE_DATA_TYPE_STRING; 59703831d35Sstevel evnt_val.value.sv_string = attach_pnt; 59803831d35Sstevel rv = sysevent_add_attr(&evnt_attr_list, DR_AP_ID, &evnt_val, 59903831d35Sstevel KM_NOSLEEP); 60003831d35Sstevel if (rv != 0) { 60103831d35Sstevel cmn_err(CE_WARN, "Failed to add attr [%s] for %s event", 60203831d35Sstevel DR_AP_ID, EC_DR); 60303831d35Sstevel sysevent_free(ev); 60403831d35Sstevel return (DDI_INTR_CLAIMED); 60503831d35Sstevel } 60603831d35Sstevel 60703831d35Sstevel /* 60803831d35Sstevel * Add the hint 60903831d35Sstevel */ 61003831d35Sstevel evnt_val.value_type = SE_DATA_TYPE_STRING; 61103831d35Sstevel evnt_val.value.sv_string = SE_HINT2STR(hint); 61203831d35Sstevel rv = sysevent_add_attr(&evnt_attr_list, DR_HINT, &evnt_val, 61303831d35Sstevel KM_NOSLEEP); 61403831d35Sstevel if (rv != 0) { 61503831d35Sstevel cmn_err(CE_WARN, "Failed to add attr [%s] for %s event", 61603831d35Sstevel DR_HINT, EC_DR); 61703831d35Sstevel sysevent_free_attr(evnt_attr_list); 61803831d35Sstevel sysevent_free(ev); 61903831d35Sstevel return (DDI_INTR_CLAIMED); 62003831d35Sstevel } 62103831d35Sstevel if (sysevent_attach_attributes(ev, evnt_attr_list) != 0) { 62203831d35Sstevel cmn_err(CE_WARN, "Failed to attach attr list for %s " 62303831d35Sstevel "event", EC_DR); 62403831d35Sstevel sysevent_free_attr(evnt_attr_list); 62503831d35Sstevel sysevent_free(ev); 62603831d35Sstevel return (DDI_INTR_CLAIMED); 62703831d35Sstevel } 62803831d35Sstevel rv = log_sysevent(ev, KM_NOSLEEP, &eid); 62903831d35Sstevel if (rv != 0) { 63003831d35Sstevel cmn_err(CE_WARN, 63103831d35Sstevel "lw8_dr_event_handler: failed to log event"); 63203831d35Sstevel } 63303831d35Sstevel sysevent_free(ev); 63403831d35Sstevel } 63503831d35Sstevel lw8_wakeup_sleepers(); 63603831d35Sstevel return (DDI_INTR_CLAIMED); 63703831d35Sstevel } 63803831d35Sstevel 63903831d35Sstevel static uint_t 64003831d35Sstevel lw8_cap_ecc_msg_handler(char *addr) 64103831d35Sstevel { 64203831d35Sstevel sbbc_msg_t *msg = NULL; 64303831d35Sstevel plat_capability_data_t *cap = NULL; 64403831d35Sstevel 64503831d35Sstevel msg = (sbbc_msg_t *)addr; 64603831d35Sstevel if (msg == NULL || msg->msg_buf == NULL) 64703831d35Sstevel return (DDI_INTR_CLAIMED); 64803831d35Sstevel 64903831d35Sstevel cap = (plat_capability_data_t *)msg->msg_buf; 65003831d35Sstevel switch (cap->capd_msg_type) { 65103831d35Sstevel case PLAT_ECC_CAPABILITY_MESSAGE: 65203831d35Sstevel plat_ecc_capability_sc_set(cap->capd_capability); 65303831d35Sstevel break; 65403831d35Sstevel default: 65503831d35Sstevel break; 65603831d35Sstevel } 65703831d35Sstevel 65803831d35Sstevel return (DDI_INTR_CLAIMED); 65903831d35Sstevel } 66003831d35Sstevel 66103831d35Sstevel /*ARGSUSED*/ 66203831d35Sstevel static uint_t 66303831d35Sstevel lw8_env_data_handler(char *arg) 66403831d35Sstevel { 66503831d35Sstevel lw8_wakeup_sleepers(); 66603831d35Sstevel return (DDI_INTR_CLAIMED); 66703831d35Sstevel } 66803831d35Sstevel 66903831d35Sstevel /* 67003831d35Sstevel * wakeup sleepers + mark led cache for this fru as invalid 67103831d35Sstevel */ 67203831d35Sstevel static void 67303831d35Sstevel lw8_wakeup_sleepers() 67403831d35Sstevel { 67503831d35Sstevel mutex_enter(&lw8_event_mutex); 67603831d35Sstevel lw8_event_pending = B_TRUE; 67703831d35Sstevel cv_broadcast(&lw8_event_cv); 67803831d35Sstevel led_state_cached = B_FALSE; 67903831d35Sstevel mutex_exit(&lw8_event_mutex); 68003831d35Sstevel } 68103831d35Sstevel 68203831d35Sstevel /* 68303831d35Sstevel * This function is triggered by a soft interrupt and it's purpose is to call 68403831d35Sstevel * to kadmin() to shutdown the system. 68503831d35Sstevel */ 68603831d35Sstevel /*ARGSUSED*/ 68703831d35Sstevel static uint_t 68803831d35Sstevel lw8_fast_shutdown(char *arg) 68903831d35Sstevel { 69003831d35Sstevel (void) kadmin(A_SHUTDOWN, AD_POWEROFF, NULL, kcred); 69103831d35Sstevel 69203831d35Sstevel /* 69303831d35Sstevel * If kadmin fails for some reason then we bring the system down 69403831d35Sstevel * via power_down(), or failing that using halt(). 69503831d35Sstevel */ 69603831d35Sstevel power_down("kadmin() failed, trying power_down()"); 69703831d35Sstevel 69803831d35Sstevel halt("power_down() failed, trying halt()"); 69903831d35Sstevel 70003831d35Sstevel /* 70103831d35Sstevel * We should never make it this far, so something must have gone 70203831d35Sstevel * horribly, horribly wrong. 70303831d35Sstevel */ 70403831d35Sstevel /*NOTREACHED*/ 705055d7c80Scarlsonj return (DDI_INTR_UNCLAIMED); 70603831d35Sstevel } 70703831d35Sstevel 70803831d35Sstevel /* 70903831d35Sstevel * This function is triggered by a soft interrupt and it's purpose is to call 71003831d35Sstevel * to do_shutdown() to shutdown the system. 71103831d35Sstevel */ 71203831d35Sstevel /*ARGSUSED*/ 71303831d35Sstevel static uint_t 71403831d35Sstevel lw8_slow_shutdown(char *arg) 71503831d35Sstevel { 71603831d35Sstevel do_shutdown(); 71703831d35Sstevel return (DDI_SUCCESS); 71803831d35Sstevel } 71903831d35Sstevel 72003831d35Sstevel static uint_t 72103831d35Sstevel lw8_event_data_handler(char *arg) 72203831d35Sstevel { 72303831d35Sstevel lw8_event_t *payload; 72403831d35Sstevel sbbc_msg_t *msg; 72503831d35Sstevel 72603831d35Sstevel if (arg == NULL) { 72703831d35Sstevel return (DDI_INTR_CLAIMED); 72803831d35Sstevel } 72903831d35Sstevel 73003831d35Sstevel msg = (sbbc_msg_t *)arg; 73103831d35Sstevel if (msg->msg_buf == NULL) { 73203831d35Sstevel return (DDI_INTR_CLAIMED); 73303831d35Sstevel } 73403831d35Sstevel 73503831d35Sstevel payload = (lw8_event_t *)msg->msg_buf; 73603831d35Sstevel switch (payload->event_type) { 73703831d35Sstevel case LW8_EVENT_REQUESTED_SHUTDOWN: 73803831d35Sstevel 73903831d35Sstevel /* 74003831d35Sstevel * Let the user know why the domain is going down. 74103831d35Sstevel */ 74203831d35Sstevel cmn_err(CE_WARN, "%s", SHUTDOWN_EVENT_MSG); 74303831d35Sstevel ddi_trigger_softintr(lw8_slow_shutdown_softint_id); 74403831d35Sstevel 74503831d35Sstevel /*NOTREACHED*/ 74603831d35Sstevel break; 74703831d35Sstevel 74803831d35Sstevel case LW8_EVENT_VOLTAGE_SHUTDOWN: 74903831d35Sstevel 75003831d35Sstevel /* 75103831d35Sstevel * Let the user know why the domain is going down. 75203831d35Sstevel */ 75303831d35Sstevel cmn_err(CE_WARN, "%s", VOLTAGE_EVENT_MSG); 75403831d35Sstevel ddi_trigger_softintr(lw8_fast_shutdown_softint_id); 75503831d35Sstevel 75603831d35Sstevel /*NOTREACHED*/ 75703831d35Sstevel break; 75803831d35Sstevel 75903831d35Sstevel case LW8_EVENT_TEMPERATURE_SHUTDOWN: 76003831d35Sstevel 76103831d35Sstevel /* 76203831d35Sstevel * Let the user know why the domain is going down. 76303831d35Sstevel */ 76403831d35Sstevel cmn_err(CE_WARN, "%s", TEMPERATURE_EVENT_MSG); 76503831d35Sstevel ddi_trigger_softintr(lw8_fast_shutdown_softint_id); 76603831d35Sstevel 76703831d35Sstevel /*NOTREACHED*/ 76803831d35Sstevel break; 76903831d35Sstevel 77003831d35Sstevel case LW8_EVENT_FANFAIL_SHUTDOWN: 77103831d35Sstevel 77203831d35Sstevel /* 77303831d35Sstevel * Let the user know why the domain is going down. 77403831d35Sstevel */ 77503831d35Sstevel cmn_err(CE_WARN, "%s", FANFAIL_EVENT_MSG); 77603831d35Sstevel ddi_trigger_softintr(lw8_fast_shutdown_softint_id); 77703831d35Sstevel 77803831d35Sstevel /*NOTREACHED*/ 77903831d35Sstevel break; 78003831d35Sstevel 78103831d35Sstevel case LW8_EVENT_NO_SCC_SHUTDOWN: 78203831d35Sstevel 78303831d35Sstevel /* 78403831d35Sstevel * Let the user know why the domain is going down. 78503831d35Sstevel */ 78603831d35Sstevel cmn_err(CE_WARN, "%s", NO_SCC_EVENT_MSG); 78703831d35Sstevel ddi_trigger_softintr(lw8_fast_shutdown_softint_id); 78803831d35Sstevel 78903831d35Sstevel /*NOTREACHED*/ 79003831d35Sstevel break; 79103831d35Sstevel 79203831d35Sstevel case LW8_EVENT_NEW_LOG_MSG: 79303831d35Sstevel 79403831d35Sstevel /* 79503831d35Sstevel * Wake up the log retrieval thread. 79603831d35Sstevel */ 79703831d35Sstevel lw8_logger_wakeup(); 79803831d35Sstevel 79903831d35Sstevel break; 80003831d35Sstevel 80103831d35Sstevel default: 80203831d35Sstevel return (DDI_INTR_CLAIMED); 80303831d35Sstevel } 80403831d35Sstevel 80503831d35Sstevel return (DDI_INTR_CLAIMED); 80603831d35Sstevel } 80703831d35Sstevel 80803831d35Sstevel /*ARGSUSED*/ 80903831d35Sstevel static int 81003831d35Sstevel lw8_open(dev_t *dev_p, int flag, int otyp, cred_t *cred_p) 81103831d35Sstevel { 81203831d35Sstevel int error = 0; 81303831d35Sstevel int instance = getminor(*dev_p); 81403831d35Sstevel static fn_t f = "lw8_open"; 81503831d35Sstevel 81603831d35Sstevel if (instance != 0) 81703831d35Sstevel return (ENXIO); 81803831d35Sstevel 81903831d35Sstevel if ((error = drv_priv(cred_p)) != 0) { 82003831d35Sstevel cmn_err(CE_WARN, "lw8:%s: inst %d drv_priv failed", 82103831d35Sstevel f, instance); 82203831d35Sstevel return (error); 82303831d35Sstevel } 82403831d35Sstevel return (error); 82503831d35Sstevel } 82603831d35Sstevel 82703831d35Sstevel /*ARGSUSED*/ 82803831d35Sstevel static int 82903831d35Sstevel lw8_close(dev_t dev, int flag, int otyp, cred_t *cred_p) 83003831d35Sstevel { 83103831d35Sstevel return (DDI_SUCCESS); 83203831d35Sstevel } 83303831d35Sstevel 83403831d35Sstevel static int 83503831d35Sstevel lw8_lomcmd(int cmd, intptr_t arg) 83603831d35Sstevel { 83703831d35Sstevel sbbc_msg_t request, *reqp = &request; 83803831d35Sstevel sbbc_msg_t response, *resp = &response; 83903831d35Sstevel int rv = 0; 84003831d35Sstevel lom_eventreq_t *eventreqp; 84103831d35Sstevel 84203831d35Sstevel bzero((caddr_t)&request, sizeof (request)); 84303831d35Sstevel reqp->msg_type.type = LW8_MBOX; 84403831d35Sstevel reqp->msg_type.sub_type = cmd; 84503831d35Sstevel bzero((caddr_t)&response, sizeof (response)); 84603831d35Sstevel resp->msg_type.type = LW8_MBOX; 84703831d35Sstevel resp->msg_type.sub_type = cmd; 84803831d35Sstevel 84903831d35Sstevel switch (cmd) { 85003831d35Sstevel case LW8_MBOX_GET_INFO: 85103831d35Sstevel reqp->msg_len = 0; 85203831d35Sstevel reqp->msg_buf = (caddr_t)NULL; 85303831d35Sstevel resp->msg_len = sizeof (lom2_info_t); 85403831d35Sstevel resp->msg_buf = (caddr_t)arg; 85503831d35Sstevel break; 85603831d35Sstevel case LW8_MBOX_SET_CTL: 85703831d35Sstevel reqp->msg_len = sizeof (lom_ctl2_t); 85803831d35Sstevel reqp->msg_buf = (caddr_t)arg; 85903831d35Sstevel resp->msg_len = 0; 86003831d35Sstevel resp->msg_buf = (caddr_t)NULL; 86103831d35Sstevel break; 86203831d35Sstevel case LW8_MBOX_UPDATE_FW: 86303831d35Sstevel reqp->msg_len = sizeof (lom_prog_t); 86403831d35Sstevel reqp->msg_buf = (caddr_t)arg; 86503831d35Sstevel resp->msg_len = 0; 86603831d35Sstevel resp->msg_buf = (caddr_t)NULL; 86703831d35Sstevel break; 86803831d35Sstevel case LW8_MBOX_GET_LED: 86903831d35Sstevel reqp->msg_len = sizeof (lw8_get_led_payload_t); 87003831d35Sstevel reqp->msg_buf = (caddr_t)arg; 87103831d35Sstevel resp->msg_len = sizeof (lw8_get_led_payload_t); 87203831d35Sstevel resp->msg_buf = (caddr_t)arg; 87303831d35Sstevel break; 87403831d35Sstevel case LW8_MBOX_SET_LED: 87503831d35Sstevel reqp->msg_len = sizeof (lw8_set_led_payload_t); 87603831d35Sstevel reqp->msg_buf = (caddr_t)arg; 87703831d35Sstevel resp->msg_len = 0; 87803831d35Sstevel resp->msg_buf = (caddr_t)NULL; 87903831d35Sstevel break; 88003831d35Sstevel case LW8_MBOX_GET_EVENTS: 88103831d35Sstevel /* 88203831d35Sstevel * cast as lom_eventreq_t to minimise data traffic 88303831d35Sstevel */ 88403831d35Sstevel eventreqp = (lom_eventreq_t *)arg; 88503831d35Sstevel reqp->msg_len = sizeof (lom_eventreq_t); 88603831d35Sstevel reqp->msg_buf = (caddr_t)arg; 88703831d35Sstevel resp->msg_len = sizeof (lom_eventreq_t) + 88803831d35Sstevel (eventreqp->num * MAX_EVENT_STR); 88903831d35Sstevel resp->msg_buf = (caddr_t)arg; 89003831d35Sstevel break; 89103831d35Sstevel case LW8_MBOX_GET_NEXT_MSG: 89203831d35Sstevel reqp->msg_len = 0; 89303831d35Sstevel reqp->msg_buf = (caddr_t)NULL; 89403831d35Sstevel resp->msg_len = sizeof (lw8_logmsg_t); 89503831d35Sstevel resp->msg_buf = (caddr_t)arg; 89603831d35Sstevel break; 89703831d35Sstevel default: 89803831d35Sstevel return (EINVAL); 89903831d35Sstevel } 90003831d35Sstevel 90103831d35Sstevel rv = sbbc_mbox_request_response(reqp, resp, 90203831d35Sstevel LW8_DEFAULT_MAX_MBOX_WAIT_TIME); 90303831d35Sstevel 90403831d35Sstevel if ((rv) || (resp->msg_status != SG_MBOX_STATUS_SUCCESS)) { 90503831d35Sstevel 90603831d35Sstevel /* errors from sgsbbc */ 90703831d35Sstevel if (resp->msg_status > 0) { 90803831d35Sstevel return (resp->msg_status); 90903831d35Sstevel } 91003831d35Sstevel 91103831d35Sstevel /* errors from SCAPP */ 91203831d35Sstevel switch (resp->msg_status) { 91303831d35Sstevel 91403831d35Sstevel case SG_MBOX_STATUS_COMMAND_FAILURE: 91503831d35Sstevel /* internal SCAPP error */ 91603831d35Sstevel return (EINTR); 91703831d35Sstevel 91803831d35Sstevel case SG_MBOX_STATUS_HARDWARE_FAILURE: 91903831d35Sstevel /* seprom read/write errors */ 92003831d35Sstevel return (EIO); 92103831d35Sstevel 92203831d35Sstevel case SG_MBOX_STATUS_ILLEGAL_PARAMETER: 92303831d35Sstevel /* illegal ioctl parameter */ 92403831d35Sstevel return (EINVAL); 92503831d35Sstevel 92603831d35Sstevel case SG_MBOX_STATUS_BOARD_ACCESS_DENIED: 92703831d35Sstevel /* board access denied */ 92803831d35Sstevel return (EACCES); 92903831d35Sstevel 93003831d35Sstevel case SG_MBOX_STATUS_STALE_CONTENTS: 93103831d35Sstevel /* stale contents */ 93203831d35Sstevel return (ESTALE); 93303831d35Sstevel 93403831d35Sstevel case SG_MBOX_STATUS_STALE_OBJECT: 93503831d35Sstevel /* stale handle */ 93603831d35Sstevel return (ENOENT); 93703831d35Sstevel 93803831d35Sstevel case SG_MBOX_STATUS_NO_SEPROM_SPACE: 93903831d35Sstevel /* seprom lacks space */ 94003831d35Sstevel return (ENOSPC); 94103831d35Sstevel 94203831d35Sstevel case SG_MBOX_STATUS_NO_MEMORY: 94303831d35Sstevel /* user prog. lacks space */ 94403831d35Sstevel return (ENOMEM); 94503831d35Sstevel 94603831d35Sstevel case SG_MBOX_STATUS_NOT_SUPPORTED: 94703831d35Sstevel /* unsupported operation */ 94803831d35Sstevel return (ENOTSUP); 94903831d35Sstevel 95003831d35Sstevel default: 95103831d35Sstevel return (EIO); 95203831d35Sstevel } 95303831d35Sstevel } 95403831d35Sstevel return (0); 95503831d35Sstevel } 95603831d35Sstevel 95703831d35Sstevel /* 95803831d35Sstevel * set the requested led, and mark cache as empty 95903831d35Sstevel */ 96003831d35Sstevel static int 96103831d35Sstevel lw8_setled(lom_set_led_t *set_ledp) 96203831d35Sstevel { 96303831d35Sstevel int retval; 96403831d35Sstevel int i, j; 96503831d35Sstevel struct led_info *lip; 96603831d35Sstevel lw8_set_led_payload_t lw8_set_led; 96703831d35Sstevel 96803831d35Sstevel for (i = 0; i < MAX_FRUS; i++) { 96903831d35Sstevel if (strncmp(set_ledp->location, fru_led_table[i].location, 97003831d35Sstevel MAX_LOCATION_LEN) != 0) 97103831d35Sstevel continue; 97203831d35Sstevel for (j = 0; j < MAX_LEDS_PER_FRU; j++) { 97303831d35Sstevel lip = &fru_led_table[i].led_info[j]; 97403831d35Sstevel if (lip->id == NULL) 97503831d35Sstevel continue; 97603831d35Sstevel if (strncmp(set_ledp->id, lip->id, MAX_ID_LEN) != 0) 97703831d35Sstevel continue; 97803831d35Sstevel lw8_set_led.value = set_ledp->status; 97903831d35Sstevel 98003831d35Sstevel /* 98103831d35Sstevel * to minimise data transfer, the SC maintains 98203831d35Sstevel * just 3 values per fru - except for 98303831d35Sstevel * the chassis itself at the end which has 98403831d35Sstevel * MAX_LEDS_PER_FRU 98503831d35Sstevel */ 98603831d35Sstevel lw8_set_led.offset = (i * 3) + j; 98703831d35Sstevel retval = lw8_lomcmd(LW8_MBOX_SET_LED, 98803831d35Sstevel (intptr_t)&lw8_set_led); 98903831d35Sstevel if (retval != 0) 99003831d35Sstevel return (retval); 99103831d35Sstevel mutex_enter(&lw8_event_mutex); 99203831d35Sstevel led_state_cached = B_FALSE; 99303831d35Sstevel mutex_exit(&lw8_event_mutex); 99403831d35Sstevel return (0); 99503831d35Sstevel } 99603831d35Sstevel } 99703831d35Sstevel return (EINVAL); 99803831d35Sstevel } 99903831d35Sstevel 100003831d35Sstevel /* 100103831d35Sstevel * read led value from cache if possible, otherwise read from sc and 100203831d35Sstevel * update the cache 100303831d35Sstevel */ 100403831d35Sstevel static int 100503831d35Sstevel lw8_getled(lom_get_led_t *get_ledp) 100603831d35Sstevel { 100703831d35Sstevel int retval; 100803831d35Sstevel int i, j, k; 100903831d35Sstevel struct led_info *lip; 101003831d35Sstevel lw8_get_led_payload_t lw8_get_led; 101103831d35Sstevel 101203831d35Sstevel for (i = 0; i < MAX_FRUS; i++) { 101303831d35Sstevel if (strncmp(get_ledp->location, fru_led_table[i].location, 101403831d35Sstevel MAX_LOCATION_LEN) != 0) 101503831d35Sstevel continue; 101603831d35Sstevel if (get_ledp->id[0] == '\0') { 101703831d35Sstevel (void) strncpy(get_ledp->next_id, 101803831d35Sstevel fru_led_table[i].led_info[0].id, MAX_ID_LEN); 101903831d35Sstevel return (0); 102003831d35Sstevel } 102103831d35Sstevel for (j = 0; j < MAX_LEDS_PER_FRU; j++) { 102203831d35Sstevel lip = &fru_led_table[i].led_info[j]; 102303831d35Sstevel if (lip->id == NULL) 102403831d35Sstevel continue; 102503831d35Sstevel if (strncmp(get_ledp->id, lip->id, MAX_ID_LEN) != 0) 102603831d35Sstevel continue; 102703831d35Sstevel mutex_enter(&lw8_event_mutex); 102803831d35Sstevel if (!led_state_cached) { 102903831d35Sstevel mutex_exit(&lw8_event_mutex); 103003831d35Sstevel retval = lw8_lomcmd(LW8_MBOX_GET_LED, 103103831d35Sstevel (intptr_t)&lw8_get_led); 103203831d35Sstevel if (retval != 0) 103303831d35Sstevel return (retval); 103403831d35Sstevel mutex_enter(&lw8_event_mutex); 103503831d35Sstevel 103603831d35Sstevel /* 103703831d35Sstevel * to minimise data transfer, the 103803831d35Sstevel * lw8_get_led_payload_t structure just has 3 103903831d35Sstevel * values per fru - except for the chassis 104003831d35Sstevel * itself at the end which has MAX_LEDS_PER_FRU 104103831d35Sstevel */ 104203831d35Sstevel for (k = 0; k < (MAX_FRUS - 1) * 3; k++) { 104303831d35Sstevel fru_led_table[k / 3].led_info[k % 3]. 104403831d35Sstevel status = lw8_get_led.value[k]; 104503831d35Sstevel } 104603831d35Sstevel for (k = 0; k < MAX_LEDS_PER_FRU; k++) { 104703831d35Sstevel fru_led_table[MAX_FRUS - 1].led_info[k]. 104803831d35Sstevel status = lw8_get_led.value[k + 104903831d35Sstevel ((MAX_FRUS - 1) * 3)]; 105003831d35Sstevel } 105103831d35Sstevel led_state_cached = B_TRUE; 105203831d35Sstevel } 105303831d35Sstevel get_ledp->status = lip->status; 105403831d35Sstevel mutex_exit(&lw8_event_mutex); 105503831d35Sstevel get_ledp->position = lip->position; 105603831d35Sstevel (void) strncpy(get_ledp->color, lip->color, 105703831d35Sstevel MAX_COLOR_LEN); 105803831d35Sstevel if (j == MAX_LEDS_PER_FRU - 1) { 105903831d35Sstevel get_ledp->next_id[0] = '\0'; 106003831d35Sstevel return (0); 106103831d35Sstevel } 106203831d35Sstevel (void) strncpy(get_ledp->next_id, 106303831d35Sstevel fru_led_table[i].led_info[j + 1].id, MAX_ID_LEN); 106403831d35Sstevel return (0); 106503831d35Sstevel } 106603831d35Sstevel } 106703831d35Sstevel if (get_ledp->id[0] == '\0') { 106803831d35Sstevel get_ledp->next_id[0] = '\0'; 106903831d35Sstevel return (0); 107003831d35Sstevel } 107103831d35Sstevel return (EINVAL); 107203831d35Sstevel } 107303831d35Sstevel 107403831d35Sstevel /*ARGSUSED*/ 107503831d35Sstevel static int 107603831d35Sstevel lw8_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *cred_p, 107703831d35Sstevel int *rval_p) 107803831d35Sstevel { 107903831d35Sstevel int instance = getminor(dev); 108003831d35Sstevel lom2_info_t lw8_info2; 108103831d35Sstevel lom_ctl_t lw8_ctl; 108203831d35Sstevel lom_ctl2_t lw8_ctl2; 108303831d35Sstevel lom_mprog_t lw8_mprog; 108403831d35Sstevel lom_fled_info_t lw8_fled_info; 108503831d35Sstevel lom_info_t lw8_info; 108603831d35Sstevel lom_aldata_t lw8_aldata; 108703831d35Sstevel lom_get_led_t lw8_get_led; 108803831d35Sstevel lom_set_led_t lw8_set_led; 108903831d35Sstevel lom_prog_t *lw8_progp; 109003831d35Sstevel lom_eventlog2_t *lw8_eventlogp; 109103831d35Sstevel lom_eventresp_t *lw8_eventresp; 109203831d35Sstevel int retval = 0; 109303831d35Sstevel int i, j; 109403831d35Sstevel 109503831d35Sstevel if (instance != 0) 109603831d35Sstevel return (ENXIO); 109703831d35Sstevel 109803831d35Sstevel switch (cmd) { 109903831d35Sstevel case LOMIOCWTMON: 110003831d35Sstevel mutex_enter(&lw8_event_mutex); 110103831d35Sstevel if (!lw8_event_pending) { 110203831d35Sstevel if (cv_wait_sig(&lw8_event_cv, &lw8_event_mutex) == 0) { 110303831d35Sstevel mutex_exit(&lw8_event_mutex); 110403831d35Sstevel retval = EINTR; 110503831d35Sstevel break; 110603831d35Sstevel } 110703831d35Sstevel } 110803831d35Sstevel lw8_event_pending = B_FALSE; 110903831d35Sstevel mutex_exit(&lw8_event_mutex); 111003831d35Sstevel break; 111103831d35Sstevel case LOMIOCMREAD: 111203831d35Sstevel bzero((caddr_t)&lw8_mprog, sizeof (lw8_mprog)); 111303831d35Sstevel lw8_mprog.config = 4; 111403831d35Sstevel if (ddi_copyout((caddr_t)&lw8_mprog, (caddr_t)arg, 111503831d35Sstevel sizeof (lw8_mprog), mode) != 0) { 111603831d35Sstevel retval = EFAULT; 111703831d35Sstevel } 111803831d35Sstevel break; 111903831d35Sstevel case LOMIOCCTL2: 112003831d35Sstevel if (ddi_copyin((caddr_t)arg, (caddr_t)&lw8_ctl2, 112103831d35Sstevel sizeof (lw8_ctl2), mode) != 0) { 112203831d35Sstevel retval = EFAULT; 112303831d35Sstevel break; 112403831d35Sstevel } 112503831d35Sstevel retval = lw8_lomcmd(LW8_MBOX_SET_CTL, (intptr_t)&lw8_ctl2); 112603831d35Sstevel break; 112703831d35Sstevel case LOMIOCPROG: 112803831d35Sstevel lw8_progp = kmem_alloc(sizeof (*lw8_progp), KM_SLEEP); 112903831d35Sstevel if (ddi_copyin((caddr_t)arg, (caddr_t)lw8_progp, 113003831d35Sstevel sizeof (*lw8_progp), mode) != 0) { 113103831d35Sstevel kmem_free(lw8_progp, sizeof (*lw8_progp)); 113203831d35Sstevel retval = EFAULT; 113303831d35Sstevel break; 113403831d35Sstevel } 113503831d35Sstevel retval = lw8_lomcmd(LW8_MBOX_UPDATE_FW, (intptr_t)lw8_progp); 113603831d35Sstevel kmem_free(lw8_progp, sizeof (*lw8_progp)); 113703831d35Sstevel break; 113803831d35Sstevel case LOMIOCINFO2: 113903831d35Sstevel bzero((caddr_t)&lw8_info2, sizeof (lw8_info2)); 114003831d35Sstevel retval = lw8_lomcmd(LW8_MBOX_GET_INFO, (intptr_t)&lw8_info2); 114103831d35Sstevel if (retval != 0) 114203831d35Sstevel break; 114303831d35Sstevel if (ddi_copyout((caddr_t)&lw8_info2, (caddr_t)arg, 114403831d35Sstevel sizeof (lw8_info2), mode) != 0) { 114503831d35Sstevel retval = EFAULT; 114603831d35Sstevel } 114703831d35Sstevel break; 114803831d35Sstevel case LOMIOCINFO: 114903831d35Sstevel bzero((caddr_t)&lw8_info2, sizeof (lw8_info2)); 115003831d35Sstevel retval = lw8_lomcmd(LW8_MBOX_GET_INFO, (intptr_t)&lw8_info2); 115103831d35Sstevel if (retval != 0) 115203831d35Sstevel break; 115303831d35Sstevel bzero((caddr_t)&lw8_info, sizeof (lw8_info)); 115403831d35Sstevel lw8_info.ser_char = lw8_info2.escape_chars[0]; 115503831d35Sstevel lw8_info.fver = lw8_info2.fver; 115603831d35Sstevel lw8_info.fchksum = lw8_info2.fchksum; 115703831d35Sstevel lw8_info.prod_rev = lw8_info2.prod_rev; 1158*07d06da5SSurya Prakki (void) strncpy(lw8_info.prod_id, lw8_info2.prod_id, MAX_ID_LEN); 115903831d35Sstevel if (ddi_copyout((caddr_t)&lw8_info, (caddr_t)arg, 116003831d35Sstevel sizeof (lw8_info), mode) != 0) { 116103831d35Sstevel retval = EFAULT; 116203831d35Sstevel } 116303831d35Sstevel break; 116403831d35Sstevel case LOMIOCFLEDSTATE: 116503831d35Sstevel bzero((caddr_t)&lw8_get_led, sizeof (lw8_get_led)); 116603831d35Sstevel (void) strncpy(lw8_get_led.location, "chassis", 116703831d35Sstevel MAX_LOCATION_LEN); 116803831d35Sstevel (void) strncpy(lw8_get_led.id, "fault", MAX_ID_LEN); 116903831d35Sstevel retval = lw8_getled(&lw8_get_led); 117003831d35Sstevel if (retval != 0) 117103831d35Sstevel break; 117203831d35Sstevel lw8_fled_info.on = lw8_get_led.status; 117303831d35Sstevel if (ddi_copyout((caddr_t)&lw8_fled_info, (caddr_t)arg, 117403831d35Sstevel sizeof (lw8_fled_info), mode) != 0) { 117503831d35Sstevel retval = EFAULT; 117603831d35Sstevel } 117703831d35Sstevel break; 117803831d35Sstevel case LOMIOCALSTATE: 117903831d35Sstevel if (ddi_copyin((caddr_t)arg, (caddr_t)&lw8_aldata, 118003831d35Sstevel sizeof (lw8_aldata), mode) != 0) { 118103831d35Sstevel retval = EFAULT; 118203831d35Sstevel break; 118303831d35Sstevel } 118403831d35Sstevel bzero((caddr_t)&lw8_get_led, sizeof (lw8_get_led)); 118503831d35Sstevel (void) strncpy(lw8_get_led.location, "chassis", 118603831d35Sstevel MAX_LOCATION_LEN); 118703831d35Sstevel if (lw8_aldata.alarm_no == 3) 118803831d35Sstevel (void) snprintf(lw8_get_led.id, MAX_ID_LEN, "system"); 118903831d35Sstevel else 119003831d35Sstevel (void) snprintf(lw8_get_led.id, MAX_ID_LEN, "alarm%d", 119103831d35Sstevel lw8_aldata.alarm_no); 119203831d35Sstevel retval = lw8_getled(&lw8_get_led); 119303831d35Sstevel if (retval != 0) 119403831d35Sstevel break; 119503831d35Sstevel lw8_aldata.state = lw8_get_led.status; 119603831d35Sstevel if (ddi_copyout((caddr_t)&lw8_aldata, (caddr_t)arg, 119703831d35Sstevel sizeof (lw8_aldata), mode) != 0) { 119803831d35Sstevel retval = EFAULT; 119903831d35Sstevel } 120003831d35Sstevel break; 120103831d35Sstevel case LOMIOCGETLED: 120203831d35Sstevel if (ddi_copyin((caddr_t)arg, (caddr_t)&lw8_get_led, 120303831d35Sstevel sizeof (lw8_get_led), mode) != 0) { 120403831d35Sstevel retval = EFAULT; 120503831d35Sstevel break; 120603831d35Sstevel } 120703831d35Sstevel retval = lw8_getled(&lw8_get_led); 120803831d35Sstevel if (retval != 0) 120903831d35Sstevel break; 121003831d35Sstevel if (ddi_copyout((caddr_t)&lw8_get_led, (caddr_t)arg, 121103831d35Sstevel sizeof (lw8_get_led), mode) != 0) { 121203831d35Sstevel retval = EFAULT; 121303831d35Sstevel } 121403831d35Sstevel break; 121503831d35Sstevel case LOMIOCEVENTLOG2: 121603831d35Sstevel lw8_eventlogp = kmem_alloc(sizeof (*lw8_eventlogp), KM_SLEEP); 121703831d35Sstevel lw8_eventresp = kmem_zalloc(sizeof (*lw8_eventresp), KM_SLEEP); 121803831d35Sstevel if (ddi_copyin((caddr_t)arg, (caddr_t)lw8_eventlogp, 121903831d35Sstevel sizeof (*lw8_eventlogp), mode) != 0) { 122003831d35Sstevel kmem_free(lw8_eventlogp, sizeof (*lw8_eventlogp)); 122103831d35Sstevel kmem_free(lw8_eventresp, sizeof (*lw8_eventresp)); 122203831d35Sstevel retval = EFAULT; 122303831d35Sstevel break; 122403831d35Sstevel } 122503831d35Sstevel lw8_eventresp->num = lw8_eventlogp->num; 122603831d35Sstevel lw8_eventresp->level = lw8_eventlogp->level; 122703831d35Sstevel retval = lw8_lomcmd(LW8_MBOX_GET_EVENTS, 122803831d35Sstevel (intptr_t)lw8_eventresp); 122903831d35Sstevel if (retval == 0) { 123003831d35Sstevel lw8_eventlogp->num = lw8_eventresp->num; 123103831d35Sstevel for (i = 0; i < lw8_eventresp->num; i++) { 123203831d35Sstevel for (j = 0; j < MAX_EVENT_STR; j++) { 123303831d35Sstevel lw8_eventlogp->string[i][j] = 123403831d35Sstevel lw8_eventresp->string[i][j]; 123503831d35Sstevel } 123603831d35Sstevel } 123703831d35Sstevel if (ddi_copyout((caddr_t)lw8_eventlogp, (caddr_t)arg, 123803831d35Sstevel sizeof (*lw8_eventlogp), mode) != 0) { 123903831d35Sstevel retval = EFAULT; 124003831d35Sstevel } 124103831d35Sstevel } 124203831d35Sstevel kmem_free(lw8_eventlogp, sizeof (*lw8_eventlogp)); 124303831d35Sstevel kmem_free(lw8_eventresp, sizeof (*lw8_eventresp)); 124403831d35Sstevel break; 124503831d35Sstevel case LOMIOCALCTL: 124603831d35Sstevel if (ddi_copyin((caddr_t)arg, (caddr_t)&lw8_aldata, 124703831d35Sstevel sizeof (lw8_aldata), mode) != 0) { 124803831d35Sstevel retval = EFAULT; 124903831d35Sstevel break; 125003831d35Sstevel } 125103831d35Sstevel bzero((caddr_t)&lw8_set_led, sizeof (lw8_set_led)); 125203831d35Sstevel (void) strncpy(lw8_set_led.location, "chassis", 125303831d35Sstevel MAX_LOCATION_LEN); 125403831d35Sstevel if (lw8_aldata.alarm_no == 3) 125503831d35Sstevel (void) snprintf(lw8_set_led.id, MAX_ID_LEN, "system"); 125603831d35Sstevel else 125703831d35Sstevel (void) snprintf(lw8_set_led.id, MAX_ID_LEN, "alarm%d", 125803831d35Sstevel lw8_aldata.alarm_no); 125903831d35Sstevel lw8_set_led.status = lw8_aldata.state; 126003831d35Sstevel retval = lw8_setled(&lw8_set_led); 126103831d35Sstevel break; 126203831d35Sstevel case LOMIOCSETLED: 126303831d35Sstevel if (ddi_copyin((caddr_t)arg, (caddr_t)&lw8_set_led, 126403831d35Sstevel sizeof (lw8_set_led), mode) != 0) { 126503831d35Sstevel retval = EFAULT; 126603831d35Sstevel break; 126703831d35Sstevel } 126803831d35Sstevel retval = lw8_setled(&lw8_set_led); 126903831d35Sstevel break; 127003831d35Sstevel case LOMIOCCTL: 127103831d35Sstevel /* 127203831d35Sstevel * for this ioctl, as well as setting the fault led in the 127303831d35Sstevel * LOMIOCCTL case in lw8_lomcmd(), we also need to set the 127403831d35Sstevel * escape character. To do this we must use LW8_MBOX_SET_CTL, 127503831d35Sstevel * but this also needs the serial_event value which we have 127603831d35Sstevel * to get via LW8_MBOX_GET_INFO 127703831d35Sstevel */ 127803831d35Sstevel if (ddi_copyin((caddr_t)arg, (caddr_t)&lw8_ctl, 127903831d35Sstevel sizeof (lw8_ctl), mode) != 0) { 128003831d35Sstevel retval = EFAULT; 128103831d35Sstevel break; 128203831d35Sstevel } 128303831d35Sstevel bzero((caddr_t)&lw8_info2, sizeof (lw8_info2)); 128403831d35Sstevel retval = lw8_lomcmd(LW8_MBOX_GET_INFO, (intptr_t)&lw8_info2); 128503831d35Sstevel if (retval != 0) 128603831d35Sstevel break; 128703831d35Sstevel bzero((caddr_t)&lw8_ctl2, sizeof (lw8_ctl2)); 128803831d35Sstevel lw8_ctl2.escape_chars[0] = lw8_ctl.ser_char; 128903831d35Sstevel lw8_ctl2.serial_events = lw8_info2.serial_events; 129003831d35Sstevel retval = lw8_lomcmd(LW8_MBOX_SET_CTL, (intptr_t)&lw8_ctl2); 129103831d35Sstevel if (retval != 0) 129203831d35Sstevel break; 129303831d35Sstevel 129403831d35Sstevel /* 129503831d35Sstevel * if fault_led != 0, then set the led 129603831d35Sstevel */ 129703831d35Sstevel if (lw8_ctl.fault_led == 0) 129803831d35Sstevel break; 129903831d35Sstevel bzero((caddr_t)&lw8_set_led, sizeof (lw8_set_led)); 130003831d35Sstevel (void) strncpy(lw8_set_led.location, "chassis", 130103831d35Sstevel MAX_LOCATION_LEN); 130203831d35Sstevel (void) strncpy(lw8_set_led.id, "fault", MAX_ID_LEN); 130303831d35Sstevel lw8_set_led.status = lw8_ctl.fault_led - 1; 130403831d35Sstevel retval = lw8_setled(&lw8_set_led); 130503831d35Sstevel break; 130603831d35Sstevel default: 130703831d35Sstevel retval = ENOTSUP; 130803831d35Sstevel break; 130903831d35Sstevel } 131003831d35Sstevel return (retval); 131103831d35Sstevel } 131203831d35Sstevel 131303831d35Sstevel /* ARGSUSED */ 131403831d35Sstevel static void 131503831d35Sstevel lw8_logger(caddr_t arg) 131603831d35Sstevel { 131703831d35Sstevel callb_cpr_t cprinfo; 131803831d35Sstevel lw8_logmsg_t *lw8_logmsgp; 131903831d35Sstevel boolean_t more_waiting; 132003831d35Sstevel char level; 132103831d35Sstevel int retval; 132203831d35Sstevel 132303831d35Sstevel CALLB_CPR_INIT(&cprinfo, &lw8_logger_lock, callb_generic_cpr, 132403831d35Sstevel "lw8_logger"); 132503831d35Sstevel 132603831d35Sstevel lw8_logmsgp = kmem_zalloc(sizeof (*lw8_logmsgp), KM_SLEEP); 132703831d35Sstevel mutex_enter(&lw8_logger_lock); 132803831d35Sstevel for (;;) { 132903831d35Sstevel 133003831d35Sstevel /* 133103831d35Sstevel * Wait for someone to tell me to continue. 133203831d35Sstevel */ 133303831d35Sstevel while (lw8_logger_sig == LW8_LOGGER_WAIT) { 133403831d35Sstevel CALLB_CPR_SAFE_BEGIN(&cprinfo); 133503831d35Sstevel cv_wait(&lw8_logger_sig_cv, &lw8_logger_lock); 133603831d35Sstevel CALLB_CPR_SAFE_END(&cprinfo, &lw8_logger_lock); 133703831d35Sstevel } 133803831d35Sstevel 133903831d35Sstevel /* LW8_LOGGER_EXITNOW implies signal by _detach(). */ 134003831d35Sstevel if (lw8_logger_sig == LW8_LOGGER_EXITNOW) { 134103831d35Sstevel lw8_logger_sig = LW8_LOGGER_WAIT; 134203831d35Sstevel 134303831d35Sstevel kmem_free(lw8_logmsgp, sizeof (*lw8_logmsgp)); 134403831d35Sstevel 134503831d35Sstevel /* lw8_logger_lock is held at this point! */ 134603831d35Sstevel CALLB_CPR_EXIT(&cprinfo); 134703831d35Sstevel 134803831d35Sstevel thread_exit(); 134903831d35Sstevel /* NOTREACHED */ 135003831d35Sstevel } 135103831d35Sstevel 135203831d35Sstevel ASSERT(lw8_logger_sig == LW8_LOGGER_PROCESSNOW); 135303831d35Sstevel lw8_logger_sig = LW8_LOGGER_WAIT; 135403831d35Sstevel 135503831d35Sstevel mutex_exit(&lw8_logger_lock); 135603831d35Sstevel 135703831d35Sstevel /* Do lw8_event logging */ 135803831d35Sstevel 135903831d35Sstevel /* 136003831d35Sstevel * Get one message per iteration. We do not sleep if 136103831d35Sstevel * there are more to process. This makes exit from the 136203831d35Sstevel * routine much more reliable. 136303831d35Sstevel */ 136403831d35Sstevel more_waiting = B_FALSE; 136503831d35Sstevel 136603831d35Sstevel retval = lw8_lomcmd(LW8_MBOX_GET_NEXT_MSG, 136703831d35Sstevel (intptr_t)lw8_logmsgp); 136803831d35Sstevel if (retval == 0) { 136903831d35Sstevel if (lw8_logmsgp->msg_valid) { 137003831d35Sstevel 137103831d35Sstevel switch (lw8_logmsgp->level) { 137203831d35Sstevel case 0: /* LOG_EMERG */ 137303831d35Sstevel level = SL_FATAL; 137403831d35Sstevel break; 137503831d35Sstevel case 1: /* LOG_ALERT */ 137603831d35Sstevel level = SL_FATAL; 137703831d35Sstevel break; 137803831d35Sstevel case 2: /* LOG_CRIT */ 137903831d35Sstevel level = SL_FATAL; 138003831d35Sstevel break; 138103831d35Sstevel case 3: /* LOG_ERR */ 138203831d35Sstevel level = SL_ERROR; 138303831d35Sstevel break; 138403831d35Sstevel case 4: /* LOG_WARNING */ 138503831d35Sstevel level = SL_WARN; 138603831d35Sstevel break; 138703831d35Sstevel case 5: /* LOG_NOTICE */ 138803831d35Sstevel level = SL_NOTE; 138903831d35Sstevel break; 139003831d35Sstevel case 6: /* LOG_INFO */ 139103831d35Sstevel level = SL_NOTE; 139203831d35Sstevel break; 139303831d35Sstevel case 7: /* LOG_DEBUG */ 139403831d35Sstevel level = SL_TRACE; 139503831d35Sstevel break; 139603831d35Sstevel default: /* unknown */ 139703831d35Sstevel level = SL_NOTE; 139803831d35Sstevel break; 139903831d35Sstevel } 140003831d35Sstevel 140103831d35Sstevel /* Ensure NUL termination */ 140203831d35Sstevel lw8_logmsgp->msg[ 140303831d35Sstevel sizeof (lw8_logmsgp->msg) - 1] = '\0'; 1404*07d06da5SSurya Prakki (void) strlog(0, 0, 0, SL_CONSOLE | level, 140503831d35Sstevel lw8_logmsgp->msg); 140603831d35Sstevel } 140703831d35Sstevel 140803831d35Sstevel if (lw8_logmsgp->num_remaining > 0) 140903831d35Sstevel more_waiting = B_TRUE; 141003831d35Sstevel } 141103831d35Sstevel 141203831d35Sstevel /* 141303831d35Sstevel * Re-enter the lock to prepare for another iteration. 141403831d35Sstevel * We must have the lock here to protect lw8_logger_sig. 141503831d35Sstevel */ 141603831d35Sstevel mutex_enter(&lw8_logger_lock); 141703831d35Sstevel if ((lw8_logger_sig == LW8_LOGGER_WAIT) && more_waiting) 141803831d35Sstevel /* We need to get more events */ 141903831d35Sstevel lw8_logger_sig = LW8_LOGGER_PROCESSNOW; 142003831d35Sstevel } 142103831d35Sstevel } 142203831d35Sstevel 142303831d35Sstevel static void 142403831d35Sstevel lw8_logger_start(void) 142503831d35Sstevel { 142603831d35Sstevel kthread_t *tp; 142703831d35Sstevel 142803831d35Sstevel mutex_enter(&lw8_logger_lock); 142903831d35Sstevel 143003831d35Sstevel if (lw8_logger_tid == 0) { 143103831d35Sstevel /* Force retrieval of any pending messages */ 143203831d35Sstevel lw8_logger_sig = LW8_LOGGER_PROCESSNOW; 143303831d35Sstevel 143403831d35Sstevel tp = thread_create(NULL, 0, lw8_logger, NULL, 0, 143503831d35Sstevel &p0, TS_RUN, maxclsyspri); 143603831d35Sstevel lw8_logger_tid = tp->t_did; 143703831d35Sstevel } 143803831d35Sstevel 143903831d35Sstevel mutex_exit(&lw8_logger_lock); 144003831d35Sstevel } 144103831d35Sstevel 144203831d35Sstevel static void 144303831d35Sstevel lw8_logger_destroy(void) 144403831d35Sstevel { 144503831d35Sstevel kt_did_t tid; 144603831d35Sstevel 144703831d35Sstevel mutex_enter(&lw8_logger_lock); 144803831d35Sstevel tid = lw8_logger_tid; 144903831d35Sstevel if (tid != 0) { 145003831d35Sstevel lw8_logger_sig = LW8_LOGGER_EXITNOW; 145103831d35Sstevel cv_signal(&lw8_logger_sig_cv); 145203831d35Sstevel lw8_logger_tid = 0; 145303831d35Sstevel } 145403831d35Sstevel mutex_exit(&lw8_logger_lock); 145503831d35Sstevel 145603831d35Sstevel /* 145703831d35Sstevel * Wait for lw8_logger() to finish. 145803831d35Sstevel */ 145903831d35Sstevel if (tid != 0) 146003831d35Sstevel thread_join(tid); 146103831d35Sstevel } 146203831d35Sstevel 146303831d35Sstevel static void 146403831d35Sstevel lw8_logger_wakeup(void) 146503831d35Sstevel { 146603831d35Sstevel mutex_enter(&lw8_logger_lock); 146703831d35Sstevel 146803831d35Sstevel if (lw8_logger_sig != LW8_LOGGER_EXITNOW) 146903831d35Sstevel lw8_logger_sig = LW8_LOGGER_PROCESSNOW; 147003831d35Sstevel cv_signal(&lw8_logger_sig_cv); 147103831d35Sstevel 147203831d35Sstevel mutex_exit(&lw8_logger_lock); 147303831d35Sstevel } 1474