11708Sstevel /*
21708Sstevel * CDDL HEADER START
31708Sstevel *
41708Sstevel * The contents of this file are subject to the terms of the
51708Sstevel * Common Development and Distribution License (the "License").
61708Sstevel * You may not use this file except in compliance with the License.
71708Sstevel *
81708Sstevel * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
91708Sstevel * or http://www.opensolaris.org/os/licensing.
101708Sstevel * See the License for the specific language governing permissions
111708Sstevel * and limitations under the License.
121708Sstevel *
131708Sstevel * When distributing Covered Code, include this CDDL HEADER in each
141708Sstevel * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
151708Sstevel * If applicable, add the following below this CDDL HEADER, with the
161708Sstevel * fields enclosed by brackets "[]" replaced with your own identifying
171708Sstevel * information: Portions Copyright [yyyy] [name of copyright owner]
181708Sstevel *
191708Sstevel * CDDL HEADER END
201708Sstevel */
211708Sstevel
221708Sstevel /*
23*11311SSurya.Prakki@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
241708Sstevel * Use is subject to license terms.
251708Sstevel */
261708Sstevel
271708Sstevel
281708Sstevel #include <sys/time.h>
291708Sstevel #include <sys/errno.h>
301708Sstevel #include <sys/kmem.h>
311708Sstevel #include <sys/stat.h>
321708Sstevel #include <sys/cmn_err.h>
331708Sstevel
341708Sstevel #include <sys/conf.h>
351708Sstevel #include <sys/modctl.h>
361708Sstevel #include <sys/devops.h>
371708Sstevel #include <sys/ddi.h>
381708Sstevel #include <sys/sunddi.h>
391708Sstevel #include <sys/callb.h>
401708Sstevel #include <sys/disp.h>
411708Sstevel #include <sys/strlog.h>
421708Sstevel
431708Sstevel #include <sys/sgevents.h>
441708Sstevel #include <sys/serengeti.h>
451708Sstevel #include <sys/sgsbbc.h>
461708Sstevel #include <sys/sgsbbc_iosram.h>
471708Sstevel #include <sys/sgsbbc_mailbox.h>
481708Sstevel #include <sys/uadmin.h>
491708Sstevel #include <sys/machsystm.h>
501708Sstevel #include <sys/sysevent.h>
511708Sstevel #include <sys/sysevent/dr.h>
521708Sstevel #include <sys/sysevent/eventdefs.h>
531708Sstevel #include <sys/file.h>
541708Sstevel #include <sys/lw8.h>
551708Sstevel #include <sys/lw8_impl.h>
561708Sstevel #include <sys/plat_ecc_unum.h>
571708Sstevel
581708Sstevel /*
591708Sstevel * Global Variables - can be patched from Solaris
601708Sstevel * ==============================================
611708Sstevel */
621708Sstevel
631708Sstevel /*
641708Sstevel * Module Variables
651708Sstevel * ================
661708Sstevel */
671708Sstevel
681708Sstevel /*
691708Sstevel * functions local to this driver.
701708Sstevel */
711708Sstevel static int lw8_attach(dev_info_t *dip, ddi_attach_cmd_t cmd);
721708Sstevel static int lw8_detach(dev_info_t *dip, ddi_detach_cmd_t cmd);
731708Sstevel static int lw8_add_intr_handlers(void);
741708Sstevel static int lw8_remove_intr_handlers(void);
751708Sstevel static void lw8_wakeup_sleepers(void);
761708Sstevel static uint_t lw8_fast_shutdown(char *arg);
771708Sstevel static uint_t lw8_slow_shutdown(char *arg);
781708Sstevel static uint_t lw8_event_data_handler(char *);
791708Sstevel static uint_t lw8_dr_data_handler(char *);
801708Sstevel static uint_t lw8_env_data_handler(char *);
811708Sstevel static uint_t lw8_cap_ecc_msg_handler(char *);
821708Sstevel static int lw8_open(dev_t *dev_p, int flag, int otyp, cred_t *cred_p);
831708Sstevel static int lw8_close(dev_t dev, int flag, int otyp, cred_t *cred_p);
841708Sstevel static int lw8_ioctl(dev_t dev, int cmd, intptr_t arg, int mode,
851708Sstevel cred_t *cred_p, int *rval_p);
861708Sstevel static void lw8_logger_start(void);
871708Sstevel static void lw8_logger_destroy(void);
881708Sstevel static void lw8_logger_wakeup(void);
891708Sstevel
901708Sstevel /*
911708Sstevel * Driver entry points
921708Sstevel */
931708Sstevel static struct cb_ops lw8_cb_ops = {
941708Sstevel lw8_open, /* open */
951708Sstevel lw8_close, /* close */
961708Sstevel nodev, /* strategy() */
971708Sstevel nodev, /* print() */
981708Sstevel nodev, /* dump() */
991708Sstevel nodev, /* read() */
1001708Sstevel nodev, /* write() */
1011708Sstevel lw8_ioctl, /* ioctl() */
1021708Sstevel nodev, /* devmap() */
1031708Sstevel nodev, /* mmap() */
1041708Sstevel ddi_segmap, /* segmap() */
1051708Sstevel nochpoll, /* poll() */
1061708Sstevel ddi_prop_op, /* prop_op() */
1071708Sstevel NULL, /* cb_str */
1081708Sstevel D_NEW | D_MP /* cb_flag */
1091708Sstevel };
1101708Sstevel
1111708Sstevel
1121708Sstevel static struct dev_ops lw8_ops = {
1131708Sstevel DEVO_REV,
1141708Sstevel 0, /* ref count */
1151708Sstevel ddi_getinfo_1to1, /* getinfo() */
1161708Sstevel nulldev, /* identify() */
1171708Sstevel nulldev, /* probe() */
1181708Sstevel lw8_attach, /* attach() */
1191708Sstevel lw8_detach, /* detach */
1201708Sstevel nodev, /* reset */
1211708Sstevel &lw8_cb_ops, /* pointer to cb_ops structure */
1221708Sstevel (struct bus_ops *)NULL,
1237656SSherry.Moore@Sun.COM nulldev, /* power() */
1247656SSherry.Moore@Sun.COM ddi_quiesce_not_needed, /* quiesce() */
1251708Sstevel };
1261708Sstevel
1271708Sstevel /*
1281708Sstevel * Loadable module support.
1291708Sstevel */
1301708Sstevel extern struct mod_ops mod_driverops;
1311708Sstevel
1321708Sstevel static struct modldrv modldrv = {
1331708Sstevel &mod_driverops, /* Type of module. This is a driver */
1347656SSherry.Moore@Sun.COM "Netra-T12 control driver", /* Name of the module */
1351708Sstevel &lw8_ops /* pointer to the dev_ops structure */
1361708Sstevel };
1371708Sstevel
1381708Sstevel static struct modlinkage modlinkage = {
1391708Sstevel MODREV_1,
1401708Sstevel &modldrv,
1411708Sstevel NULL
1421708Sstevel };
1431708Sstevel
1441708Sstevel /*
1451708Sstevel * messages
1461708Sstevel */
1471708Sstevel #define SHUTDOWN_EVENT_MSG "lw8: system shutdown due to " \
1481708Sstevel "SC request.\n"
1491708Sstevel #define VOLTAGE_EVENT_MSG "lw8: system shutdown due to " \
1501708Sstevel "voltage out of range.\n"
1511708Sstevel #define TEMPERATURE_EVENT_MSG "lw8: system shutdown due to " \
1521708Sstevel "temperature exceeding limits.\n"
1531708Sstevel #define FANFAIL_EVENT_MSG "lw8: system shutdown due to " \
1541708Sstevel "too many fan failures.\n"
1551708Sstevel #define NO_SCC_EVENT_MSG "lw8: system shutdown due to " \
1561708Sstevel "no system configuration card.\n"
1571708Sstevel
1581708Sstevel /*
1591708Sstevel * led table - the following provides a cache of the led state - needed
1601708Sstevel * to avoid the overhead of readoing from the SC each time
1611708Sstevel */
1621708Sstevel
1631708Sstevel struct led_info {
1641708Sstevel char id[MAX_ID_LEN];
1651708Sstevel int position;
1661708Sstevel int status;
1671708Sstevel char color[MAX_COLOR_LEN];
1681708Sstevel };
1691708Sstevel
1701708Sstevel static struct fru_led_info {
1711708Sstevel char location[MAX_LOCATION_LEN];
1721708Sstevel struct led_info led_info[MAX_LEDS_PER_FRU];
1731708Sstevel } fru_led_table[MAX_FRUS] = {
1741708Sstevel "SB0", {"fault", LOM_LED_POSITION_FRU, 0, "amber",
1751708Sstevel "power", LOM_LED_POSITION_FRU, 0, "green",
1761708Sstevel "ok_to_remove", LOM_LED_POSITION_FRU, 0, "amber"},
1771708Sstevel "PS0", {"fault", LOM_LED_POSITION_FRU, 0, "amber",
1781708Sstevel "power", LOM_LED_POSITION_FRU, 0, "green",
1791708Sstevel "predicted_fault", LOM_LED_POSITION_FRU, 0, "amber"},
1801708Sstevel "SB2", {"fault", LOM_LED_POSITION_FRU, 0, "amber",
1811708Sstevel "power", LOM_LED_POSITION_FRU, 0, "green",
1821708Sstevel "ok_to_remove", LOM_LED_POSITION_FRU, 0, "amber"},
1831708Sstevel "PS1", {"fault", LOM_LED_POSITION_FRU, 0, "amber",
1841708Sstevel "power", LOM_LED_POSITION_FRU, 0, "green",
1851708Sstevel "predicted_fault", LOM_LED_POSITION_FRU, 0, "amber"},
1861708Sstevel "SB4", {"fault", LOM_LED_POSITION_FRU, 0, "amber",
1871708Sstevel "power", LOM_LED_POSITION_FRU, 0, "green",
1881708Sstevel "ok_to_remove", LOM_LED_POSITION_FRU, 0, "amber"},
1891708Sstevel "PS2", {"fault", LOM_LED_POSITION_FRU, 0, "amber",
1901708Sstevel "power", LOM_LED_POSITION_FRU, 0, "green",
1911708Sstevel "predicted_fault", LOM_LED_POSITION_FRU, 0, "amber"},
1921708Sstevel "IB6", {"fault", LOM_LED_POSITION_FRU, 0, "amber",
1931708Sstevel "power", LOM_LED_POSITION_FRU, 0, "green",
1941708Sstevel "ok_to_remove", LOM_LED_POSITION_FRU, 0, "amber"},
1951708Sstevel "PS3", {"fault", LOM_LED_POSITION_FRU, 0, "amber",
1961708Sstevel "power", LOM_LED_POSITION_FRU, 0, "green",
1971708Sstevel "predicted_fault", LOM_LED_POSITION_FRU, 0, "amber"},
1981708Sstevel "FT0", {"fault", LOM_LED_POSITION_FRU, 0, "amber",
1991708Sstevel "power", LOM_LED_POSITION_FRU, 0, "green",
2001708Sstevel "ok_to_remove", LOM_LED_POSITION_FRU, 0, "amber"},
2011708Sstevel "FAN0", {"fault", LOM_LED_POSITION_LOCATION, 0, "amber"},
2021708Sstevel "FAN1", {"fault", LOM_LED_POSITION_LOCATION, 0, "amber"},
2031708Sstevel "FAN2", {"fault", LOM_LED_POSITION_LOCATION, 0, "amber"},
2041708Sstevel "FAN3", {"fault", LOM_LED_POSITION_LOCATION, 0, "amber"},
2051708Sstevel "FAN4", {"fault", LOM_LED_POSITION_LOCATION, 0, "amber"},
2061708Sstevel "FAN5", {"fault", LOM_LED_POSITION_LOCATION, 0, "amber"},
2071708Sstevel "FAN6", {"fault", LOM_LED_POSITION_LOCATION, 0, "amber"},
2081708Sstevel "FAN7", {"fault", LOM_LED_POSITION_LOCATION, 0, "amber"},
2091708Sstevel "FAN8", {"fault", LOM_LED_POSITION_LOCATION, 0, "amber"},
2101708Sstevel "FAN9", {"fault", LOM_LED_POSITION_LOCATION, 0, "amber"},
2111708Sstevel "DISK0", {"fault", LOM_LED_POSITION_LOCATION, 0, "amber",
2121708Sstevel "power", LOM_LED_POSITION_LOCATION, 0, "green",
2131708Sstevel "ok_to_remove", LOM_LED_POSITION_LOCATION, 0, "blue"},
2141708Sstevel "DISK1", {"fault", LOM_LED_POSITION_LOCATION, 0, "amber",
2151708Sstevel "power", LOM_LED_POSITION_LOCATION, 0, "green",
2161708Sstevel "ok_to_remove", LOM_LED_POSITION_LOCATION, 0, "blue"},
2171708Sstevel "RP0", {"fault", LOM_LED_POSITION_FRU, 0, "amber",
2181708Sstevel "power", LOM_LED_POSITION_FRU, 0, "green",
2191708Sstevel "ok_to_remove", LOM_LED_POSITION_FRU, 0, "amber"},
2201708Sstevel "RP2", {"fault", LOM_LED_POSITION_FRU, 0, "amber",
2211708Sstevel "power", LOM_LED_POSITION_FRU, 0, "green",
2221708Sstevel "ok_to_remove", LOM_LED_POSITION_FRU, 0, "amber"},
2231708Sstevel "chassis", {"fault", LOM_LED_POSITION_FRU, 0, "amber",
2241708Sstevel "power", LOM_LED_POSITION_FRU, 0, "green",
2251708Sstevel "locator", LOM_LED_POSITION_FRU, 0, "white",
2261708Sstevel "top_access", LOM_LED_POSITION_FRU, 0, "amber",
2271708Sstevel "alarm1", LOM_LED_POSITION_FRU, 0, "amber",
2281708Sstevel "alarm2", LOM_LED_POSITION_FRU, 0, "amber",
2291708Sstevel "system", LOM_LED_POSITION_FRU, 0, "green",
2301708Sstevel "supplyA", LOM_LED_POSITION_FRU, 0, "green",
2311708Sstevel "supplyB", LOM_LED_POSITION_FRU, 0, "green"},
2321708Sstevel };
2331708Sstevel
2341708Sstevel char *fru_locn[MAX_LOCATION_LEN] = {
2351708Sstevel "SB0",
2361708Sstevel "PS0",
2371708Sstevel "SB2",
2381708Sstevel "PS1",
2391708Sstevel "SB4",
2401708Sstevel "PS2",
2411708Sstevel "IB6",
2421708Sstevel "PS3",
2431708Sstevel "SCC",
2441708Sstevel "SSC1",
2451708Sstevel };
2461708Sstevel
2471708Sstevel /*
2481708Sstevel * mutexes which protect the interrupt handlers.
2491708Sstevel */
2501708Sstevel static kmutex_t lw8_shutdown_hdlr_lock;
2511708Sstevel static kmutex_t lw8_dr_hdlr_lock;
2521708Sstevel static kmutex_t lw8_env_hdlr_lock;
2531708Sstevel static kmutex_t lw8_event_mutex;
2541708Sstevel static kmutex_t lw8_logger_lock;
2551708Sstevel static kmutex_t lw8_cap_msg_hdlr_lock;
2561708Sstevel static kcondvar_t lw8_event_cv;
2571708Sstevel static kcondvar_t lw8_logger_sig_cv;
2581708Sstevel
2591708Sstevel /*
2601708Sstevel * state booleans
2611708Sstevel */
2621708Sstevel static boolean_t lw8_event_pending = B_FALSE;
2631708Sstevel static boolean_t led_state_cached = B_FALSE;
2641708Sstevel
2651708Sstevel /*
2661708Sstevel * Payloads of the event handlers.
2671708Sstevel */
2681708Sstevel static lw8_event_t lw8_shutdown_payload;
2691708Sstevel static sbbc_msg_t lw8_shutdown_payload_msg;
2701708Sstevel static sg_system_fru_descriptor_t lw8_dr_payload;
2711708Sstevel static sbbc_msg_t lw8_dr_payload_msg;
2721708Sstevel static sg_event_fan_status_t lw8_env_payload;
2731708Sstevel static sbbc_msg_t lw8_env_payload_msg;
2741708Sstevel static plat_capability_data_t lw8_cap_payload;
2751708Sstevel static sbbc_msg_t lw8_cap_payload_msg;
2761708Sstevel
2771708Sstevel /*
2781708Sstevel * The IDs of the soft interrupts
2791708Sstevel */
2801708Sstevel static ddi_softintr_t lw8_slow_shutdown_softint_id;
2811708Sstevel static ddi_softintr_t lw8_fast_shutdown_softint_id;
2821708Sstevel
2831708Sstevel /*
2841708Sstevel * Logger commands..
2851708Sstevel */
2861708Sstevel #define LW8_LOGGER_EXITNOW -1
2871708Sstevel #define LW8_LOGGER_WAIT 0
2881708Sstevel #define LW8_LOGGER_PROCESSNOW 1
2891708Sstevel
2901708Sstevel /*
2911708Sstevel * Logger thread state
2921708Sstevel */
2931708Sstevel static int lw8_logger_sig = LW8_LOGGER_WAIT;
2941708Sstevel static kt_did_t lw8_logger_tid = 0;
2951708Sstevel
2961708Sstevel extern pri_t maxclsyspri;
2971708Sstevel
2981708Sstevel int
_init(void)2991708Sstevel _init(void)
3001708Sstevel {
3011708Sstevel int error = 0;
3021708Sstevel
3031708Sstevel mutex_init(&lw8_shutdown_hdlr_lock, NULL, MUTEX_DEFAULT, NULL);
3041708Sstevel mutex_init(&lw8_dr_hdlr_lock, NULL, MUTEX_DEFAULT, NULL);
3051708Sstevel mutex_init(&lw8_env_hdlr_lock, NULL, MUTEX_DEFAULT, NULL);
3061708Sstevel mutex_init(&lw8_cap_msg_hdlr_lock, NULL, MUTEX_DEFAULT, NULL);
3071708Sstevel mutex_init(&lw8_event_mutex, NULL, MUTEX_DRIVER, NULL);
3081708Sstevel mutex_init(&lw8_logger_lock, NULL, MUTEX_DRIVER, NULL);
3091708Sstevel cv_init(&lw8_event_cv, NULL, CV_DRIVER, NULL);
3101708Sstevel cv_init(&lw8_logger_sig_cv, NULL, CV_DRIVER, NULL);
3111708Sstevel
3121708Sstevel error = mod_install(&modlinkage);
3131708Sstevel if (error) {
3141708Sstevel cv_destroy(&lw8_logger_sig_cv);
3151708Sstevel cv_destroy(&lw8_event_cv);
3161708Sstevel mutex_destroy(&lw8_logger_lock);
3171708Sstevel mutex_destroy(&lw8_event_mutex);
3181708Sstevel mutex_destroy(&lw8_env_hdlr_lock);
3191708Sstevel mutex_destroy(&lw8_cap_msg_hdlr_lock);
3201708Sstevel mutex_destroy(&lw8_dr_hdlr_lock);
3211708Sstevel mutex_destroy(&lw8_shutdown_hdlr_lock);
3221708Sstevel }
3231708Sstevel return (error);
3241708Sstevel }
3251708Sstevel
3261708Sstevel
3271708Sstevel int
_info(struct modinfo * modinfop)3281708Sstevel _info(struct modinfo *modinfop)
3291708Sstevel {
3301708Sstevel return (mod_info(&modlinkage, modinfop));
3311708Sstevel }
3321708Sstevel
3331708Sstevel
3341708Sstevel int
_fini(void)3351708Sstevel _fini(void)
3361708Sstevel {
3371708Sstevel int error = 0;
3381708Sstevel
3391708Sstevel error = mod_remove(&modlinkage);
3401708Sstevel if (error)
3411708Sstevel return (error);
3421708Sstevel cv_destroy(&lw8_logger_sig_cv);
3431708Sstevel cv_destroy(&lw8_event_cv);
3441708Sstevel mutex_destroy(&lw8_logger_lock);
3451708Sstevel mutex_destroy(&lw8_event_mutex);
3461708Sstevel mutex_destroy(&lw8_env_hdlr_lock);
3471708Sstevel mutex_destroy(&lw8_cap_msg_hdlr_lock);
3481708Sstevel mutex_destroy(&lw8_dr_hdlr_lock);
3491708Sstevel mutex_destroy(&lw8_shutdown_hdlr_lock);
3501708Sstevel return (error);
3511708Sstevel }
3521708Sstevel
3531708Sstevel
3541708Sstevel static int
lw8_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)3551708Sstevel lw8_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
3561708Sstevel {
3571708Sstevel int instance;
3581708Sstevel int err;
3591708Sstevel
3601708Sstevel switch (cmd) {
3611708Sstevel case DDI_ATTACH:
3621708Sstevel /*
3631708Sstevel * only allow one instance
3641708Sstevel */
3651708Sstevel instance = ddi_get_instance(dip);
3661708Sstevel if (instance != 0)
3671708Sstevel return (DDI_FAILURE);
3681708Sstevel
3691708Sstevel err = ddi_create_minor_node(dip, "lw8", S_IFCHR,
3707656SSherry.Moore@Sun.COM instance, DDI_PSEUDO, NULL);
3711708Sstevel if (err != DDI_SUCCESS)
3721708Sstevel return (DDI_FAILURE);
3731708Sstevel
3741708Sstevel err = ddi_add_softintr(dip, DDI_SOFTINT_LOW,
3751708Sstevel &lw8_slow_shutdown_softint_id, NULL, NULL,
3761708Sstevel lw8_slow_shutdown, NULL);
3771708Sstevel if (err != 0) {
3781708Sstevel cmn_err(CE_WARN, "Failed to add polling softint"
3791708Sstevel "handler for lw8. Err=%d", err);
3801708Sstevel ddi_remove_minor_node(dip, NULL);
3811708Sstevel return (DDI_FAILURE);
3821708Sstevel }
3831708Sstevel
3841708Sstevel err = ddi_add_softintr(dip, DDI_SOFTINT_LOW,
3851708Sstevel &lw8_fast_shutdown_softint_id, NULL, NULL,
3861708Sstevel lw8_fast_shutdown, NULL);
3871708Sstevel if (err != 0) {
3881708Sstevel cmn_err(CE_WARN, "Failed to add polling softint"
3891708Sstevel "handler for lw8. Err=%d", err);
3901708Sstevel ddi_remove_softintr(lw8_slow_shutdown_softint_id);
3911708Sstevel ddi_remove_minor_node(dip, NULL);
3921708Sstevel return (DDI_FAILURE);
3931708Sstevel }
3941708Sstevel
3951708Sstevel lw8_logger_start();
3961708Sstevel
3971708Sstevel /*
3981708Sstevel * Add the handlers which watch for unsolicited messages
3991708Sstevel * and post event to Sysevent Framework.
4001708Sstevel */
4011708Sstevel err = lw8_add_intr_handlers();
4021708Sstevel if (err != DDI_SUCCESS) {
4031708Sstevel cmn_err(CE_WARN, "Failed to add event handlers");
4041708Sstevel lw8_logger_destroy();
4051708Sstevel ddi_remove_softintr(lw8_fast_shutdown_softint_id);
4061708Sstevel ddi_remove_softintr(lw8_slow_shutdown_softint_id);
4071708Sstevel ddi_remove_minor_node(dip, NULL);
4081708Sstevel return (DDI_FAILURE);
4091708Sstevel }
4101708Sstevel
4111708Sstevel ddi_report_dev(dip);
4121708Sstevel return (DDI_SUCCESS);
4131708Sstevel case DDI_RESUME:
4141708Sstevel return (DDI_SUCCESS);
4151708Sstevel default:
4161708Sstevel return (DDI_FAILURE);
4171708Sstevel }
4181708Sstevel }
4191708Sstevel
4201708Sstevel
4211708Sstevel static int
lw8_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)4221708Sstevel lw8_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
4231708Sstevel {
4241708Sstevel int instance;
4251708Sstevel int err;
4261708Sstevel
4271708Sstevel switch (cmd) {
4281708Sstevel case DDI_DETACH:
4291708Sstevel instance = ddi_get_instance(dip);
4301708Sstevel if (instance != 0)
4311708Sstevel return (DDI_FAILURE);
4321708Sstevel
4331708Sstevel /*
4341708Sstevel * Remove the handlers which watch for unsolicited messages
4351708Sstevel * and post event to Sysevent Framework.
4361708Sstevel */
4371708Sstevel err = lw8_remove_intr_handlers();
4381708Sstevel if (err != DDI_SUCCESS) {
4391708Sstevel cmn_err(CE_WARN, "Failed to remove event handlers");
4401708Sstevel return (DDI_FAILURE);
4411708Sstevel }
4421708Sstevel lw8_logger_destroy();
4431708Sstevel ddi_remove_softintr(lw8_slow_shutdown_softint_id);
4441708Sstevel ddi_remove_softintr(lw8_fast_shutdown_softint_id);
4451708Sstevel ddi_remove_minor_node(dip, NULL);
4461708Sstevel return (DDI_SUCCESS);
4471708Sstevel case DDI_SUSPEND:
4481708Sstevel return (DDI_SUCCESS);
4491708Sstevel default:
4501708Sstevel return (DDI_FAILURE);
4511708Sstevel }
4521708Sstevel }
4531708Sstevel
4541708Sstevel static int
lw8_add_intr_handlers()4551708Sstevel lw8_add_intr_handlers()
4561708Sstevel {
4571708Sstevel int err;
4581708Sstevel
4591708Sstevel lw8_shutdown_payload_msg.msg_buf = (caddr_t)&lw8_shutdown_payload;
4601708Sstevel lw8_shutdown_payload_msg.msg_len = sizeof (lw8_shutdown_payload);
4611708Sstevel err = sbbc_mbox_reg_intr(MBOX_EVENT_LW8, lw8_event_data_handler,
4621708Sstevel &lw8_shutdown_payload_msg, NULL, &lw8_shutdown_hdlr_lock);
4631708Sstevel if (err != 0) {
4641708Sstevel cmn_err(CE_WARN, "Failed to register MBOX_EVENT_LW8 "
4657656SSherry.Moore@Sun.COM " handler. Err=%d", err);
4661708Sstevel return (DDI_FAILURE);
4671708Sstevel }
4681708Sstevel
4691708Sstevel lw8_dr_payload_msg.msg_buf = (caddr_t)&lw8_dr_payload;
4701708Sstevel lw8_dr_payload_msg.msg_len = sizeof (lw8_dr_payload);
4711708Sstevel err = sbbc_mbox_reg_intr(MBOX_EVENT_GENERIC, lw8_dr_data_handler,
4727656SSherry.Moore@Sun.COM &lw8_dr_payload_msg, NULL, &lw8_dr_hdlr_lock);
4731708Sstevel if (err != 0) {
4741708Sstevel cmn_err(CE_WARN, "Failed to register MBOX_EVENT_GENERIC "
4757656SSherry.Moore@Sun.COM " handler. Err=%d", err);
476*11311SSurya.Prakki@Sun.COM (void) sbbc_mbox_unreg_intr(MBOX_EVENT_LW8,
477*11311SSurya.Prakki@Sun.COM lw8_event_data_handler);
4781708Sstevel return (DDI_FAILURE);
4791708Sstevel }
4801708Sstevel
4811708Sstevel lw8_env_payload_msg.msg_buf = (caddr_t)&lw8_env_payload;
4821708Sstevel lw8_env_payload_msg.msg_len = sizeof (lw8_env_payload);
4831708Sstevel err = sbbc_mbox_reg_intr(MBOX_EVENT_ENV, lw8_env_data_handler,
4847656SSherry.Moore@Sun.COM &lw8_env_payload_msg, NULL, &lw8_env_hdlr_lock);
4851708Sstevel if (err != 0) {
4861708Sstevel cmn_err(CE_WARN, "Failed to register MBOX_EVENT_ENV "
4877656SSherry.Moore@Sun.COM " handler. Err=%d", err);
488*11311SSurya.Prakki@Sun.COM (void) sbbc_mbox_unreg_intr(MBOX_EVENT_GENERIC,
489*11311SSurya.Prakki@Sun.COM lw8_dr_data_handler);
490*11311SSurya.Prakki@Sun.COM (void) sbbc_mbox_unreg_intr(MBOX_EVENT_LW8,
491*11311SSurya.Prakki@Sun.COM lw8_event_data_handler);
4921708Sstevel return (DDI_FAILURE);
4931708Sstevel }
4941708Sstevel
4951708Sstevel lw8_cap_payload_msg.msg_buf = (caddr_t)&lw8_cap_payload;
4961708Sstevel lw8_cap_payload_msg.msg_len = sizeof (lw8_cap_payload);
4971708Sstevel err = sbbc_mbox_reg_intr(INFO_MBOX, lw8_cap_ecc_msg_handler,
4981708Sstevel &lw8_cap_payload_msg, NULL, &lw8_cap_msg_hdlr_lock);
4991708Sstevel if (err != 0) {
5001708Sstevel cmn_err(CE_WARN, "Failed to register INFO_MBOX "
5011708Sstevel " handler. Err=%d", err);
502*11311SSurya.Prakki@Sun.COM (void) sbbc_mbox_unreg_intr(MBOX_EVENT_GENERIC,
503*11311SSurya.Prakki@Sun.COM lw8_dr_data_handler);
504*11311SSurya.Prakki@Sun.COM (void) sbbc_mbox_unreg_intr(MBOX_EVENT_LW8,
505*11311SSurya.Prakki@Sun.COM lw8_event_data_handler);
506*11311SSurya.Prakki@Sun.COM (void) sbbc_mbox_unreg_intr(INFO_MBOX,
507*11311SSurya.Prakki@Sun.COM lw8_cap_ecc_msg_handler);
5081708Sstevel return (DDI_FAILURE);
5091708Sstevel }
5101708Sstevel
5111708Sstevel return (DDI_SUCCESS);
5121708Sstevel }
5131708Sstevel
5141708Sstevel static int
lw8_remove_intr_handlers(void)5151708Sstevel lw8_remove_intr_handlers(void)
5161708Sstevel {
5171708Sstevel int rv = DDI_SUCCESS;
5181708Sstevel int err;
5191708Sstevel
5201708Sstevel err = sbbc_mbox_unreg_intr(MBOX_EVENT_LW8, lw8_event_data_handler);
5211708Sstevel if (err != 0) {
5221708Sstevel cmn_err(CE_WARN, "Failed to unregister MBOX_EVENT_LW8 "
5237656SSherry.Moore@Sun.COM "handler. Err=%d", err);
5241708Sstevel rv = DDI_FAILURE;
5251708Sstevel }
5261708Sstevel err = sbbc_mbox_unreg_intr(MBOX_EVENT_GENERIC, lw8_dr_data_handler);
5271708Sstevel if (err != 0) {
5281708Sstevel cmn_err(CE_WARN, "Failed to unregister MBOX_EVENT_GENERIC "
5297656SSherry.Moore@Sun.COM "handler. Err=%d", err);
5301708Sstevel rv = DDI_FAILURE;
5311708Sstevel }
5321708Sstevel err = sbbc_mbox_unreg_intr(MBOX_EVENT_ENV, lw8_env_data_handler);
5331708Sstevel if (err != 0) {
5341708Sstevel cmn_err(CE_WARN, "Failed to unregister MBOX_EVENT_ENV "
5357656SSherry.Moore@Sun.COM "handler. Err=%d", err);
5361708Sstevel rv = DDI_FAILURE;
5371708Sstevel }
5381708Sstevel err = sbbc_mbox_unreg_intr(INFO_MBOX, lw8_cap_ecc_msg_handler);
5391708Sstevel if (err != 0) {
5401708Sstevel cmn_err(CE_WARN, "Failed to unregister INFO_MBOX "
5411708Sstevel "handler. Err=%d", err);
5421708Sstevel rv = DDI_FAILURE;
5431708Sstevel }
5441708Sstevel return (rv);
5451708Sstevel }
5461708Sstevel
5471708Sstevel static uint_t
lw8_dr_data_handler(char * arg)5481708Sstevel lw8_dr_data_handler(char *arg)
5491708Sstevel {
5501708Sstevel sg_system_fru_descriptor_t *payload;
5511708Sstevel sbbc_msg_t *msg;
5521708Sstevel int hint;
5531708Sstevel sysevent_t *ev;
5541708Sstevel sysevent_id_t eid;
5551708Sstevel int rv = 0;
5561708Sstevel sysevent_value_t evnt_val;
5571708Sstevel sysevent_attr_list_t *evnt_attr_list = NULL;
5581708Sstevel char attach_pnt[MAXPATHLEN];
5591708Sstevel
5601708Sstevel msg = (sbbc_msg_t *)arg;
5611708Sstevel if (msg == NULL) {
5621708Sstevel return (DDI_INTR_CLAIMED);
5631708Sstevel }
5641708Sstevel payload = (sg_system_fru_descriptor_t *)msg->msg_buf;
5651708Sstevel if (payload == NULL) {
5661708Sstevel return (DDI_INTR_CLAIMED);
5671708Sstevel }
5681708Sstevel if (payload->slot < 0 || payload->slot >= sizeof (fru_locn) /
5691708Sstevel sizeof (char *)) {
5701708Sstevel return (DDI_INTR_CLAIMED);
5711708Sstevel }
5721708Sstevel
5731708Sstevel /*
5741708Sstevel * if not SB send sysevent (SBs send sysevent from ssm driver)
5751708Sstevel */
5761708Sstevel if (strncmp(fru_locn[payload->slot], "SB", 2) != 0) {
5771708Sstevel switch (payload->event_details) {
5781708Sstevel case SG_EVT_BOARD_ABSENT:
5791708Sstevel hint = SE_HINT_REMOVE;
5801708Sstevel break;
5811708Sstevel case SG_EVT_BOARD_PRESENT:
5821708Sstevel hint = SE_HINT_INSERT;
5831708Sstevel break;
5841708Sstevel default:
5851708Sstevel hint = SE_NO_HINT;
5861708Sstevel break;
5871708Sstevel }
5881708Sstevel (void) snprintf(attach_pnt, sizeof (attach_pnt), "ssm0:N0.%s",
5891708Sstevel fru_locn[payload->slot]);
5901708Sstevel ev = sysevent_alloc(EC_DR, ESC_DR_AP_STATE_CHANGE, EP_DDI,
5911708Sstevel KM_NOSLEEP);
5921708Sstevel if (ev == NULL) {
5931708Sstevel cmn_err(CE_WARN, "Failed to allocate %s event", EC_DR);
5941708Sstevel return (DDI_INTR_CLAIMED);
5951708Sstevel }
5961708Sstevel evnt_val.value_type = SE_DATA_TYPE_STRING;
5971708Sstevel evnt_val.value.sv_string = attach_pnt;
5981708Sstevel rv = sysevent_add_attr(&evnt_attr_list, DR_AP_ID, &evnt_val,
5991708Sstevel KM_NOSLEEP);
6001708Sstevel if (rv != 0) {
6011708Sstevel cmn_err(CE_WARN, "Failed to add attr [%s] for %s event",
6021708Sstevel DR_AP_ID, EC_DR);
6031708Sstevel sysevent_free(ev);
6041708Sstevel return (DDI_INTR_CLAIMED);
6051708Sstevel }
6061708Sstevel
6071708Sstevel /*
6081708Sstevel * Add the hint
6091708Sstevel */
6101708Sstevel evnt_val.value_type = SE_DATA_TYPE_STRING;
6111708Sstevel evnt_val.value.sv_string = SE_HINT2STR(hint);
6121708Sstevel rv = sysevent_add_attr(&evnt_attr_list, DR_HINT, &evnt_val,
6131708Sstevel KM_NOSLEEP);
6141708Sstevel if (rv != 0) {
6151708Sstevel cmn_err(CE_WARN, "Failed to add attr [%s] for %s event",
6161708Sstevel DR_HINT, EC_DR);
6171708Sstevel sysevent_free_attr(evnt_attr_list);
6181708Sstevel sysevent_free(ev);
6191708Sstevel return (DDI_INTR_CLAIMED);
6201708Sstevel }
6211708Sstevel if (sysevent_attach_attributes(ev, evnt_attr_list) != 0) {
6221708Sstevel cmn_err(CE_WARN, "Failed to attach attr list for %s "
6231708Sstevel "event", EC_DR);
6241708Sstevel sysevent_free_attr(evnt_attr_list);
6251708Sstevel sysevent_free(ev);
6261708Sstevel return (DDI_INTR_CLAIMED);
6271708Sstevel }
6281708Sstevel rv = log_sysevent(ev, KM_NOSLEEP, &eid);
6291708Sstevel if (rv != 0) {
6301708Sstevel cmn_err(CE_WARN,
6311708Sstevel "lw8_dr_event_handler: failed to log event");
6321708Sstevel }
6331708Sstevel sysevent_free(ev);
6341708Sstevel }
6351708Sstevel lw8_wakeup_sleepers();
6361708Sstevel return (DDI_INTR_CLAIMED);
6371708Sstevel }
6381708Sstevel
6391708Sstevel static uint_t
lw8_cap_ecc_msg_handler(char * addr)6401708Sstevel lw8_cap_ecc_msg_handler(char *addr)
6411708Sstevel {
6421708Sstevel sbbc_msg_t *msg = NULL;
6431708Sstevel plat_capability_data_t *cap = NULL;
6441708Sstevel
6451708Sstevel msg = (sbbc_msg_t *)addr;
6461708Sstevel if (msg == NULL || msg->msg_buf == NULL)
6471708Sstevel return (DDI_INTR_CLAIMED);
6481708Sstevel
6491708Sstevel cap = (plat_capability_data_t *)msg->msg_buf;
6501708Sstevel switch (cap->capd_msg_type) {
6511708Sstevel case PLAT_ECC_CAPABILITY_MESSAGE:
6521708Sstevel plat_ecc_capability_sc_set(cap->capd_capability);
6531708Sstevel break;
6541708Sstevel default:
6551708Sstevel break;
6561708Sstevel }
6571708Sstevel
6581708Sstevel return (DDI_INTR_CLAIMED);
6591708Sstevel }
6601708Sstevel
6611708Sstevel /*ARGSUSED*/
6621708Sstevel static uint_t
lw8_env_data_handler(char * arg)6631708Sstevel lw8_env_data_handler(char *arg)
6641708Sstevel {
6651708Sstevel lw8_wakeup_sleepers();
6661708Sstevel return (DDI_INTR_CLAIMED);
6671708Sstevel }
6681708Sstevel
6691708Sstevel /*
6701708Sstevel * wakeup sleepers + mark led cache for this fru as invalid
6711708Sstevel */
6721708Sstevel static void
lw8_wakeup_sleepers()6731708Sstevel lw8_wakeup_sleepers()
6741708Sstevel {
6751708Sstevel mutex_enter(&lw8_event_mutex);
6761708Sstevel lw8_event_pending = B_TRUE;
6771708Sstevel cv_broadcast(&lw8_event_cv);
6781708Sstevel led_state_cached = B_FALSE;
6791708Sstevel mutex_exit(&lw8_event_mutex);
6801708Sstevel }
6811708Sstevel
6821708Sstevel /*
6831708Sstevel * This function is triggered by a soft interrupt and it's purpose is to call
6841708Sstevel * to kadmin() to shutdown the system.
6851708Sstevel */
6861708Sstevel /*ARGSUSED*/
6871708Sstevel static uint_t
lw8_fast_shutdown(char * arg)6881708Sstevel lw8_fast_shutdown(char *arg)
6891708Sstevel {
6901708Sstevel (void) kadmin(A_SHUTDOWN, AD_POWEROFF, NULL, kcred);
6911708Sstevel
6921708Sstevel /*
6931708Sstevel * If kadmin fails for some reason then we bring the system down
6941708Sstevel * via power_down(), or failing that using halt().
6951708Sstevel */
6961708Sstevel power_down("kadmin() failed, trying power_down()");
6971708Sstevel
6981708Sstevel halt("power_down() failed, trying halt()");
6991708Sstevel
7001708Sstevel /*
7011708Sstevel * We should never make it this far, so something must have gone
7021708Sstevel * horribly, horribly wrong.
7031708Sstevel */
7041708Sstevel /*NOTREACHED*/
7052840Scarlsonj return (DDI_INTR_UNCLAIMED);
7061708Sstevel }
7071708Sstevel
7081708Sstevel /*
7091708Sstevel * This function is triggered by a soft interrupt and it's purpose is to call
7101708Sstevel * to do_shutdown() to shutdown the system.
7111708Sstevel */
7121708Sstevel /*ARGSUSED*/
7131708Sstevel static uint_t
lw8_slow_shutdown(char * arg)7141708Sstevel lw8_slow_shutdown(char *arg)
7151708Sstevel {
7161708Sstevel do_shutdown();
7171708Sstevel return (DDI_SUCCESS);
7181708Sstevel }
7191708Sstevel
7201708Sstevel static uint_t
lw8_event_data_handler(char * arg)7211708Sstevel lw8_event_data_handler(char *arg)
7221708Sstevel {
7231708Sstevel lw8_event_t *payload;
7241708Sstevel sbbc_msg_t *msg;
7251708Sstevel
7261708Sstevel if (arg == NULL) {
7271708Sstevel return (DDI_INTR_CLAIMED);
7281708Sstevel }
7291708Sstevel
7301708Sstevel msg = (sbbc_msg_t *)arg;
7311708Sstevel if (msg->msg_buf == NULL) {
7321708Sstevel return (DDI_INTR_CLAIMED);
7331708Sstevel }
7341708Sstevel
7351708Sstevel payload = (lw8_event_t *)msg->msg_buf;
7361708Sstevel switch (payload->event_type) {
7371708Sstevel case LW8_EVENT_REQUESTED_SHUTDOWN:
7381708Sstevel
7391708Sstevel /*
7401708Sstevel * Let the user know why the domain is going down.
7411708Sstevel */
7421708Sstevel cmn_err(CE_WARN, "%s", SHUTDOWN_EVENT_MSG);
7431708Sstevel ddi_trigger_softintr(lw8_slow_shutdown_softint_id);
7441708Sstevel
7451708Sstevel /*NOTREACHED*/
7461708Sstevel break;
7471708Sstevel
7481708Sstevel case LW8_EVENT_VOLTAGE_SHUTDOWN:
7491708Sstevel
7501708Sstevel /*
7511708Sstevel * Let the user know why the domain is going down.
7521708Sstevel */
7531708Sstevel cmn_err(CE_WARN, "%s", VOLTAGE_EVENT_MSG);
7541708Sstevel ddi_trigger_softintr(lw8_fast_shutdown_softint_id);
7551708Sstevel
7561708Sstevel /*NOTREACHED*/
7571708Sstevel break;
7581708Sstevel
7591708Sstevel case LW8_EVENT_TEMPERATURE_SHUTDOWN:
7601708Sstevel
7611708Sstevel /*
7621708Sstevel * Let the user know why the domain is going down.
7631708Sstevel */
7641708Sstevel cmn_err(CE_WARN, "%s", TEMPERATURE_EVENT_MSG);
7651708Sstevel ddi_trigger_softintr(lw8_fast_shutdown_softint_id);
7661708Sstevel
7671708Sstevel /*NOTREACHED*/
7681708Sstevel break;
7691708Sstevel
7701708Sstevel case LW8_EVENT_FANFAIL_SHUTDOWN:
7711708Sstevel
7721708Sstevel /*
7731708Sstevel * Let the user know why the domain is going down.
7741708Sstevel */
7751708Sstevel cmn_err(CE_WARN, "%s", FANFAIL_EVENT_MSG);
7761708Sstevel ddi_trigger_softintr(lw8_fast_shutdown_softint_id);
7771708Sstevel
7781708Sstevel /*NOTREACHED*/
7791708Sstevel break;
7801708Sstevel
7811708Sstevel case LW8_EVENT_NO_SCC_SHUTDOWN:
7821708Sstevel
7831708Sstevel /*
7841708Sstevel * Let the user know why the domain is going down.
7851708Sstevel */
7861708Sstevel cmn_err(CE_WARN, "%s", NO_SCC_EVENT_MSG);
7871708Sstevel ddi_trigger_softintr(lw8_fast_shutdown_softint_id);
7881708Sstevel
7891708Sstevel /*NOTREACHED*/
7901708Sstevel break;
7911708Sstevel
7921708Sstevel case LW8_EVENT_NEW_LOG_MSG:
7931708Sstevel
7941708Sstevel /*
7951708Sstevel * Wake up the log retrieval thread.
7961708Sstevel */
7971708Sstevel lw8_logger_wakeup();
7981708Sstevel
7991708Sstevel break;
8001708Sstevel
8011708Sstevel default:
8021708Sstevel return (DDI_INTR_CLAIMED);
8031708Sstevel }
8041708Sstevel
8051708Sstevel return (DDI_INTR_CLAIMED);
8061708Sstevel }
8071708Sstevel
8081708Sstevel /*ARGSUSED*/
8091708Sstevel static int
lw8_open(dev_t * dev_p,int flag,int otyp,cred_t * cred_p)8101708Sstevel lw8_open(dev_t *dev_p, int flag, int otyp, cred_t *cred_p)
8111708Sstevel {
8121708Sstevel int error = 0;
8131708Sstevel int instance = getminor(*dev_p);
8141708Sstevel static fn_t f = "lw8_open";
8151708Sstevel
8161708Sstevel if (instance != 0)
8171708Sstevel return (ENXIO);
8181708Sstevel
8191708Sstevel if ((error = drv_priv(cred_p)) != 0) {
8201708Sstevel cmn_err(CE_WARN, "lw8:%s: inst %d drv_priv failed",
8211708Sstevel f, instance);
8221708Sstevel return (error);
8231708Sstevel }
8241708Sstevel return (error);
8251708Sstevel }
8261708Sstevel
8271708Sstevel /*ARGSUSED*/
8281708Sstevel static int
lw8_close(dev_t dev,int flag,int otyp,cred_t * cred_p)8291708Sstevel lw8_close(dev_t dev, int flag, int otyp, cred_t *cred_p)
8301708Sstevel {
8311708Sstevel return (DDI_SUCCESS);
8321708Sstevel }
8331708Sstevel
8341708Sstevel static int
lw8_lomcmd(int cmd,intptr_t arg)8351708Sstevel lw8_lomcmd(int cmd, intptr_t arg)
8361708Sstevel {
8371708Sstevel sbbc_msg_t request, *reqp = &request;
8381708Sstevel sbbc_msg_t response, *resp = &response;
8391708Sstevel int rv = 0;
8401708Sstevel lom_eventreq_t *eventreqp;
8411708Sstevel
8421708Sstevel bzero((caddr_t)&request, sizeof (request));
8431708Sstevel reqp->msg_type.type = LW8_MBOX;
8441708Sstevel reqp->msg_type.sub_type = cmd;
8451708Sstevel bzero((caddr_t)&response, sizeof (response));
8461708Sstevel resp->msg_type.type = LW8_MBOX;
8471708Sstevel resp->msg_type.sub_type = cmd;
8481708Sstevel
8491708Sstevel switch (cmd) {
8501708Sstevel case LW8_MBOX_GET_INFO:
8511708Sstevel reqp->msg_len = 0;
8521708Sstevel reqp->msg_buf = (caddr_t)NULL;
8531708Sstevel resp->msg_len = sizeof (lom2_info_t);
8541708Sstevel resp->msg_buf = (caddr_t)arg;
8551708Sstevel break;
8561708Sstevel case LW8_MBOX_SET_CTL:
8571708Sstevel reqp->msg_len = sizeof (lom_ctl2_t);
8581708Sstevel reqp->msg_buf = (caddr_t)arg;
8591708Sstevel resp->msg_len = 0;
8601708Sstevel resp->msg_buf = (caddr_t)NULL;
8611708Sstevel break;
8621708Sstevel case LW8_MBOX_UPDATE_FW:
8631708Sstevel reqp->msg_len = sizeof (lom_prog_t);
8641708Sstevel reqp->msg_buf = (caddr_t)arg;
8651708Sstevel resp->msg_len = 0;
8661708Sstevel resp->msg_buf = (caddr_t)NULL;
8671708Sstevel break;
8681708Sstevel case LW8_MBOX_GET_LED:
8691708Sstevel reqp->msg_len = sizeof (lw8_get_led_payload_t);
8701708Sstevel reqp->msg_buf = (caddr_t)arg;
8711708Sstevel resp->msg_len = sizeof (lw8_get_led_payload_t);
8721708Sstevel resp->msg_buf = (caddr_t)arg;
8731708Sstevel break;
8741708Sstevel case LW8_MBOX_SET_LED:
8751708Sstevel reqp->msg_len = sizeof (lw8_set_led_payload_t);
8761708Sstevel reqp->msg_buf = (caddr_t)arg;
8771708Sstevel resp->msg_len = 0;
8781708Sstevel resp->msg_buf = (caddr_t)NULL;
8791708Sstevel break;
8801708Sstevel case LW8_MBOX_GET_EVENTS:
8811708Sstevel /*
8821708Sstevel * cast as lom_eventreq_t to minimise data traffic
8831708Sstevel */
8841708Sstevel eventreqp = (lom_eventreq_t *)arg;
8851708Sstevel reqp->msg_len = sizeof (lom_eventreq_t);
8861708Sstevel reqp->msg_buf = (caddr_t)arg;
8871708Sstevel resp->msg_len = sizeof (lom_eventreq_t) +
8881708Sstevel (eventreqp->num * MAX_EVENT_STR);
8891708Sstevel resp->msg_buf = (caddr_t)arg;
8901708Sstevel break;
8911708Sstevel case LW8_MBOX_GET_NEXT_MSG:
8921708Sstevel reqp->msg_len = 0;
8931708Sstevel reqp->msg_buf = (caddr_t)NULL;
8941708Sstevel resp->msg_len = sizeof (lw8_logmsg_t);
8951708Sstevel resp->msg_buf = (caddr_t)arg;
8961708Sstevel break;
8971708Sstevel default:
8981708Sstevel return (EINVAL);
8991708Sstevel }
9001708Sstevel
9011708Sstevel rv = sbbc_mbox_request_response(reqp, resp,
9021708Sstevel LW8_DEFAULT_MAX_MBOX_WAIT_TIME);
9031708Sstevel
9041708Sstevel if ((rv) || (resp->msg_status != SG_MBOX_STATUS_SUCCESS)) {
9051708Sstevel
9061708Sstevel /* errors from sgsbbc */
9071708Sstevel if (resp->msg_status > 0) {
9081708Sstevel return (resp->msg_status);
9091708Sstevel }
9101708Sstevel
9111708Sstevel /* errors from SCAPP */
9121708Sstevel switch (resp->msg_status) {
9131708Sstevel
9141708Sstevel case SG_MBOX_STATUS_COMMAND_FAILURE:
9151708Sstevel /* internal SCAPP error */
9161708Sstevel return (EINTR);
9171708Sstevel
9181708Sstevel case SG_MBOX_STATUS_HARDWARE_FAILURE:
9191708Sstevel /* seprom read/write errors */
9201708Sstevel return (EIO);
9211708Sstevel
9221708Sstevel case SG_MBOX_STATUS_ILLEGAL_PARAMETER:
9231708Sstevel /* illegal ioctl parameter */
9241708Sstevel return (EINVAL);
9251708Sstevel
9261708Sstevel case SG_MBOX_STATUS_BOARD_ACCESS_DENIED:
9271708Sstevel /* board access denied */
9281708Sstevel return (EACCES);
9291708Sstevel
9301708Sstevel case SG_MBOX_STATUS_STALE_CONTENTS:
9311708Sstevel /* stale contents */
9321708Sstevel return (ESTALE);
9331708Sstevel
9341708Sstevel case SG_MBOX_STATUS_STALE_OBJECT:
9351708Sstevel /* stale handle */
9361708Sstevel return (ENOENT);
9371708Sstevel
9381708Sstevel case SG_MBOX_STATUS_NO_SEPROM_SPACE:
9391708Sstevel /* seprom lacks space */
9401708Sstevel return (ENOSPC);
9411708Sstevel
9421708Sstevel case SG_MBOX_STATUS_NO_MEMORY:
9431708Sstevel /* user prog. lacks space */
9441708Sstevel return (ENOMEM);
9451708Sstevel
9461708Sstevel case SG_MBOX_STATUS_NOT_SUPPORTED:
9471708Sstevel /* unsupported operation */
9481708Sstevel return (ENOTSUP);
9491708Sstevel
9501708Sstevel default:
9511708Sstevel return (EIO);
9521708Sstevel }
9531708Sstevel }
9541708Sstevel return (0);
9551708Sstevel }
9561708Sstevel
9571708Sstevel /*
9581708Sstevel * set the requested led, and mark cache as empty
9591708Sstevel */
9601708Sstevel static int
lw8_setled(lom_set_led_t * set_ledp)9611708Sstevel lw8_setled(lom_set_led_t *set_ledp)
9621708Sstevel {
9631708Sstevel int retval;
9641708Sstevel int i, j;
9651708Sstevel struct led_info *lip;
9661708Sstevel lw8_set_led_payload_t lw8_set_led;
9671708Sstevel
9681708Sstevel for (i = 0; i < MAX_FRUS; i++) {
9691708Sstevel if (strncmp(set_ledp->location, fru_led_table[i].location,
9701708Sstevel MAX_LOCATION_LEN) != 0)
9711708Sstevel continue;
9721708Sstevel for (j = 0; j < MAX_LEDS_PER_FRU; j++) {
9731708Sstevel lip = &fru_led_table[i].led_info[j];
9741708Sstevel if (lip->id == NULL)
9751708Sstevel continue;
9761708Sstevel if (strncmp(set_ledp->id, lip->id, MAX_ID_LEN) != 0)
9771708Sstevel continue;
9781708Sstevel lw8_set_led.value = set_ledp->status;
9791708Sstevel
9801708Sstevel /*
9811708Sstevel * to minimise data transfer, the SC maintains
9821708Sstevel * just 3 values per fru - except for
9831708Sstevel * the chassis itself at the end which has
9841708Sstevel * MAX_LEDS_PER_FRU
9851708Sstevel */
9861708Sstevel lw8_set_led.offset = (i * 3) + j;
9871708Sstevel retval = lw8_lomcmd(LW8_MBOX_SET_LED,
9881708Sstevel (intptr_t)&lw8_set_led);
9891708Sstevel if (retval != 0)
9901708Sstevel return (retval);
9911708Sstevel mutex_enter(&lw8_event_mutex);
9921708Sstevel led_state_cached = B_FALSE;
9931708Sstevel mutex_exit(&lw8_event_mutex);
9941708Sstevel return (0);
9951708Sstevel }
9961708Sstevel }
9971708Sstevel return (EINVAL);
9981708Sstevel }
9991708Sstevel
10001708Sstevel /*
10011708Sstevel * read led value from cache if possible, otherwise read from sc and
10021708Sstevel * update the cache
10031708Sstevel */
10041708Sstevel static int
lw8_getled(lom_get_led_t * get_ledp)10051708Sstevel lw8_getled(lom_get_led_t *get_ledp)
10061708Sstevel {
10071708Sstevel int retval;
10081708Sstevel int i, j, k;
10091708Sstevel struct led_info *lip;
10101708Sstevel lw8_get_led_payload_t lw8_get_led;
10111708Sstevel
10121708Sstevel for (i = 0; i < MAX_FRUS; i++) {
10131708Sstevel if (strncmp(get_ledp->location, fru_led_table[i].location,
10141708Sstevel MAX_LOCATION_LEN) != 0)
10151708Sstevel continue;
10161708Sstevel if (get_ledp->id[0] == '\0') {
10171708Sstevel (void) strncpy(get_ledp->next_id,
10181708Sstevel fru_led_table[i].led_info[0].id, MAX_ID_LEN);
10191708Sstevel return (0);
10201708Sstevel }
10211708Sstevel for (j = 0; j < MAX_LEDS_PER_FRU; j++) {
10221708Sstevel lip = &fru_led_table[i].led_info[j];
10231708Sstevel if (lip->id == NULL)
10241708Sstevel continue;
10251708Sstevel if (strncmp(get_ledp->id, lip->id, MAX_ID_LEN) != 0)
10261708Sstevel continue;
10271708Sstevel mutex_enter(&lw8_event_mutex);
10281708Sstevel if (!led_state_cached) {
10291708Sstevel mutex_exit(&lw8_event_mutex);
10301708Sstevel retval = lw8_lomcmd(LW8_MBOX_GET_LED,
10311708Sstevel (intptr_t)&lw8_get_led);
10321708Sstevel if (retval != 0)
10331708Sstevel return (retval);
10341708Sstevel mutex_enter(&lw8_event_mutex);
10351708Sstevel
10361708Sstevel /*
10371708Sstevel * to minimise data transfer, the
10381708Sstevel * lw8_get_led_payload_t structure just has 3
10391708Sstevel * values per fru - except for the chassis
10401708Sstevel * itself at the end which has MAX_LEDS_PER_FRU
10411708Sstevel */
10421708Sstevel for (k = 0; k < (MAX_FRUS - 1) * 3; k++) {
10431708Sstevel fru_led_table[k / 3].led_info[k % 3].
10441708Sstevel status = lw8_get_led.value[k];
10451708Sstevel }
10461708Sstevel for (k = 0; k < MAX_LEDS_PER_FRU; k++) {
10471708Sstevel fru_led_table[MAX_FRUS - 1].led_info[k].
10481708Sstevel status = lw8_get_led.value[k +
10491708Sstevel ((MAX_FRUS - 1) * 3)];
10501708Sstevel }
10511708Sstevel led_state_cached = B_TRUE;
10521708Sstevel }
10531708Sstevel get_ledp->status = lip->status;
10541708Sstevel mutex_exit(&lw8_event_mutex);
10551708Sstevel get_ledp->position = lip->position;
10561708Sstevel (void) strncpy(get_ledp->color, lip->color,
10571708Sstevel MAX_COLOR_LEN);
10581708Sstevel if (j == MAX_LEDS_PER_FRU - 1) {
10591708Sstevel get_ledp->next_id[0] = '\0';
10601708Sstevel return (0);
10611708Sstevel }
10621708Sstevel (void) strncpy(get_ledp->next_id,
10631708Sstevel fru_led_table[i].led_info[j + 1].id, MAX_ID_LEN);
10641708Sstevel return (0);
10651708Sstevel }
10661708Sstevel }
10671708Sstevel if (get_ledp->id[0] == '\0') {
10681708Sstevel get_ledp->next_id[0] = '\0';
10691708Sstevel return (0);
10701708Sstevel }
10711708Sstevel return (EINVAL);
10721708Sstevel }
10731708Sstevel
10741708Sstevel /*ARGSUSED*/
10751708Sstevel static int
lw8_ioctl(dev_t dev,int cmd,intptr_t arg,int mode,cred_t * cred_p,int * rval_p)10761708Sstevel lw8_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *cred_p,
10771708Sstevel int *rval_p)
10781708Sstevel {
10791708Sstevel int instance = getminor(dev);
10801708Sstevel lom2_info_t lw8_info2;
10811708Sstevel lom_ctl_t lw8_ctl;
10821708Sstevel lom_ctl2_t lw8_ctl2;
10831708Sstevel lom_mprog_t lw8_mprog;
10841708Sstevel lom_fled_info_t lw8_fled_info;
10851708Sstevel lom_info_t lw8_info;
10861708Sstevel lom_aldata_t lw8_aldata;
10871708Sstevel lom_get_led_t lw8_get_led;
10881708Sstevel lom_set_led_t lw8_set_led;
10891708Sstevel lom_prog_t *lw8_progp;
10901708Sstevel lom_eventlog2_t *lw8_eventlogp;
10911708Sstevel lom_eventresp_t *lw8_eventresp;
10921708Sstevel int retval = 0;
10931708Sstevel int i, j;
10941708Sstevel
10951708Sstevel if (instance != 0)
10961708Sstevel return (ENXIO);
10971708Sstevel
10981708Sstevel switch (cmd) {
10991708Sstevel case LOMIOCWTMON:
11001708Sstevel mutex_enter(&lw8_event_mutex);
11011708Sstevel if (!lw8_event_pending) {
11021708Sstevel if (cv_wait_sig(&lw8_event_cv, &lw8_event_mutex) == 0) {
11031708Sstevel mutex_exit(&lw8_event_mutex);
11041708Sstevel retval = EINTR;
11051708Sstevel break;
11061708Sstevel }
11071708Sstevel }
11081708Sstevel lw8_event_pending = B_FALSE;
11091708Sstevel mutex_exit(&lw8_event_mutex);
11101708Sstevel break;
11111708Sstevel case LOMIOCMREAD:
11121708Sstevel bzero((caddr_t)&lw8_mprog, sizeof (lw8_mprog));
11131708Sstevel lw8_mprog.config = 4;
11141708Sstevel if (ddi_copyout((caddr_t)&lw8_mprog, (caddr_t)arg,
11151708Sstevel sizeof (lw8_mprog), mode) != 0) {
11161708Sstevel retval = EFAULT;
11171708Sstevel }
11181708Sstevel break;
11191708Sstevel case LOMIOCCTL2:
11201708Sstevel if (ddi_copyin((caddr_t)arg, (caddr_t)&lw8_ctl2,
11211708Sstevel sizeof (lw8_ctl2), mode) != 0) {
11221708Sstevel retval = EFAULT;
11231708Sstevel break;
11241708Sstevel }
11251708Sstevel retval = lw8_lomcmd(LW8_MBOX_SET_CTL, (intptr_t)&lw8_ctl2);
11261708Sstevel break;
11271708Sstevel case LOMIOCPROG:
11281708Sstevel lw8_progp = kmem_alloc(sizeof (*lw8_progp), KM_SLEEP);
11291708Sstevel if (ddi_copyin((caddr_t)arg, (caddr_t)lw8_progp,
11301708Sstevel sizeof (*lw8_progp), mode) != 0) {
11311708Sstevel kmem_free(lw8_progp, sizeof (*lw8_progp));
11321708Sstevel retval = EFAULT;
11331708Sstevel break;
11341708Sstevel }
11351708Sstevel retval = lw8_lomcmd(LW8_MBOX_UPDATE_FW, (intptr_t)lw8_progp);
11361708Sstevel kmem_free(lw8_progp, sizeof (*lw8_progp));
11371708Sstevel break;
11381708Sstevel case LOMIOCINFO2:
11391708Sstevel bzero((caddr_t)&lw8_info2, sizeof (lw8_info2));
11401708Sstevel retval = lw8_lomcmd(LW8_MBOX_GET_INFO, (intptr_t)&lw8_info2);
11411708Sstevel if (retval != 0)
11421708Sstevel break;
11431708Sstevel if (ddi_copyout((caddr_t)&lw8_info2, (caddr_t)arg,
11441708Sstevel sizeof (lw8_info2), mode) != 0) {
11451708Sstevel retval = EFAULT;
11461708Sstevel }
11471708Sstevel break;
11481708Sstevel case LOMIOCINFO:
11491708Sstevel bzero((caddr_t)&lw8_info2, sizeof (lw8_info2));
11501708Sstevel retval = lw8_lomcmd(LW8_MBOX_GET_INFO, (intptr_t)&lw8_info2);
11511708Sstevel if (retval != 0)
11521708Sstevel break;
11531708Sstevel bzero((caddr_t)&lw8_info, sizeof (lw8_info));
11541708Sstevel lw8_info.ser_char = lw8_info2.escape_chars[0];
11551708Sstevel lw8_info.fver = lw8_info2.fver;
11561708Sstevel lw8_info.fchksum = lw8_info2.fchksum;
11571708Sstevel lw8_info.prod_rev = lw8_info2.prod_rev;
1158*11311SSurya.Prakki@Sun.COM (void) strncpy(lw8_info.prod_id, lw8_info2.prod_id, MAX_ID_LEN);
11591708Sstevel if (ddi_copyout((caddr_t)&lw8_info, (caddr_t)arg,
11601708Sstevel sizeof (lw8_info), mode) != 0) {
11611708Sstevel retval = EFAULT;
11621708Sstevel }
11631708Sstevel break;
11641708Sstevel case LOMIOCFLEDSTATE:
11651708Sstevel bzero((caddr_t)&lw8_get_led, sizeof (lw8_get_led));
11661708Sstevel (void) strncpy(lw8_get_led.location, "chassis",
11671708Sstevel MAX_LOCATION_LEN);
11681708Sstevel (void) strncpy(lw8_get_led.id, "fault", MAX_ID_LEN);
11691708Sstevel retval = lw8_getled(&lw8_get_led);
11701708Sstevel if (retval != 0)
11711708Sstevel break;
11721708Sstevel lw8_fled_info.on = lw8_get_led.status;
11731708Sstevel if (ddi_copyout((caddr_t)&lw8_fled_info, (caddr_t)arg,
11741708Sstevel sizeof (lw8_fled_info), mode) != 0) {
11751708Sstevel retval = EFAULT;
11761708Sstevel }
11771708Sstevel break;
11781708Sstevel case LOMIOCALSTATE:
11791708Sstevel if (ddi_copyin((caddr_t)arg, (caddr_t)&lw8_aldata,
11801708Sstevel sizeof (lw8_aldata), mode) != 0) {
11811708Sstevel retval = EFAULT;
11821708Sstevel break;
11831708Sstevel }
11841708Sstevel bzero((caddr_t)&lw8_get_led, sizeof (lw8_get_led));
11851708Sstevel (void) strncpy(lw8_get_led.location, "chassis",
11861708Sstevel MAX_LOCATION_LEN);
11871708Sstevel if (lw8_aldata.alarm_no == 3)
11881708Sstevel (void) snprintf(lw8_get_led.id, MAX_ID_LEN, "system");
11891708Sstevel else
11901708Sstevel (void) snprintf(lw8_get_led.id, MAX_ID_LEN, "alarm%d",
11911708Sstevel lw8_aldata.alarm_no);
11921708Sstevel retval = lw8_getled(&lw8_get_led);
11931708Sstevel if (retval != 0)
11941708Sstevel break;
11951708Sstevel lw8_aldata.state = lw8_get_led.status;
11961708Sstevel if (ddi_copyout((caddr_t)&lw8_aldata, (caddr_t)arg,
11971708Sstevel sizeof (lw8_aldata), mode) != 0) {
11981708Sstevel retval = EFAULT;
11991708Sstevel }
12001708Sstevel break;
12011708Sstevel case LOMIOCGETLED:
12021708Sstevel if (ddi_copyin((caddr_t)arg, (caddr_t)&lw8_get_led,
12031708Sstevel sizeof (lw8_get_led), mode) != 0) {
12041708Sstevel retval = EFAULT;
12051708Sstevel break;
12061708Sstevel }
12071708Sstevel retval = lw8_getled(&lw8_get_led);
12081708Sstevel if (retval != 0)
12091708Sstevel break;
12101708Sstevel if (ddi_copyout((caddr_t)&lw8_get_led, (caddr_t)arg,
12111708Sstevel sizeof (lw8_get_led), mode) != 0) {
12121708Sstevel retval = EFAULT;
12131708Sstevel }
12141708Sstevel break;
12151708Sstevel case LOMIOCEVENTLOG2:
12161708Sstevel lw8_eventlogp = kmem_alloc(sizeof (*lw8_eventlogp), KM_SLEEP);
12171708Sstevel lw8_eventresp = kmem_zalloc(sizeof (*lw8_eventresp), KM_SLEEP);
12181708Sstevel if (ddi_copyin((caddr_t)arg, (caddr_t)lw8_eventlogp,
12191708Sstevel sizeof (*lw8_eventlogp), mode) != 0) {
12201708Sstevel kmem_free(lw8_eventlogp, sizeof (*lw8_eventlogp));
12211708Sstevel kmem_free(lw8_eventresp, sizeof (*lw8_eventresp));
12221708Sstevel retval = EFAULT;
12231708Sstevel break;
12241708Sstevel }
12251708Sstevel lw8_eventresp->num = lw8_eventlogp->num;
12261708Sstevel lw8_eventresp->level = lw8_eventlogp->level;
12271708Sstevel retval = lw8_lomcmd(LW8_MBOX_GET_EVENTS,
12281708Sstevel (intptr_t)lw8_eventresp);
12291708Sstevel if (retval == 0) {
12301708Sstevel lw8_eventlogp->num = lw8_eventresp->num;
12311708Sstevel for (i = 0; i < lw8_eventresp->num; i++) {
12321708Sstevel for (j = 0; j < MAX_EVENT_STR; j++) {
12331708Sstevel lw8_eventlogp->string[i][j] =
12341708Sstevel lw8_eventresp->string[i][j];
12351708Sstevel }
12361708Sstevel }
12371708Sstevel if (ddi_copyout((caddr_t)lw8_eventlogp, (caddr_t)arg,
12381708Sstevel sizeof (*lw8_eventlogp), mode) != 0) {
12391708Sstevel retval = EFAULT;
12401708Sstevel }
12411708Sstevel }
12421708Sstevel kmem_free(lw8_eventlogp, sizeof (*lw8_eventlogp));
12431708Sstevel kmem_free(lw8_eventresp, sizeof (*lw8_eventresp));
12441708Sstevel break;
12451708Sstevel case LOMIOCALCTL:
12461708Sstevel if (ddi_copyin((caddr_t)arg, (caddr_t)&lw8_aldata,
12471708Sstevel sizeof (lw8_aldata), mode) != 0) {
12481708Sstevel retval = EFAULT;
12491708Sstevel break;
12501708Sstevel }
12511708Sstevel bzero((caddr_t)&lw8_set_led, sizeof (lw8_set_led));
12521708Sstevel (void) strncpy(lw8_set_led.location, "chassis",
12531708Sstevel MAX_LOCATION_LEN);
12541708Sstevel if (lw8_aldata.alarm_no == 3)
12551708Sstevel (void) snprintf(lw8_set_led.id, MAX_ID_LEN, "system");
12561708Sstevel else
12571708Sstevel (void) snprintf(lw8_set_led.id, MAX_ID_LEN, "alarm%d",
12581708Sstevel lw8_aldata.alarm_no);
12591708Sstevel lw8_set_led.status = lw8_aldata.state;
12601708Sstevel retval = lw8_setled(&lw8_set_led);
12611708Sstevel break;
12621708Sstevel case LOMIOCSETLED:
12631708Sstevel if (ddi_copyin((caddr_t)arg, (caddr_t)&lw8_set_led,
12641708Sstevel sizeof (lw8_set_led), mode) != 0) {
12651708Sstevel retval = EFAULT;
12661708Sstevel break;
12671708Sstevel }
12681708Sstevel retval = lw8_setled(&lw8_set_led);
12691708Sstevel break;
12701708Sstevel case LOMIOCCTL:
12711708Sstevel /*
12721708Sstevel * for this ioctl, as well as setting the fault led in the
12731708Sstevel * LOMIOCCTL case in lw8_lomcmd(), we also need to set the
12741708Sstevel * escape character. To do this we must use LW8_MBOX_SET_CTL,
12751708Sstevel * but this also needs the serial_event value which we have
12761708Sstevel * to get via LW8_MBOX_GET_INFO
12771708Sstevel */
12781708Sstevel if (ddi_copyin((caddr_t)arg, (caddr_t)&lw8_ctl,
12791708Sstevel sizeof (lw8_ctl), mode) != 0) {
12801708Sstevel retval = EFAULT;
12811708Sstevel break;
12821708Sstevel }
12831708Sstevel bzero((caddr_t)&lw8_info2, sizeof (lw8_info2));
12841708Sstevel retval = lw8_lomcmd(LW8_MBOX_GET_INFO, (intptr_t)&lw8_info2);
12851708Sstevel if (retval != 0)
12861708Sstevel break;
12871708Sstevel bzero((caddr_t)&lw8_ctl2, sizeof (lw8_ctl2));
12881708Sstevel lw8_ctl2.escape_chars[0] = lw8_ctl.ser_char;
12891708Sstevel lw8_ctl2.serial_events = lw8_info2.serial_events;
12901708Sstevel retval = lw8_lomcmd(LW8_MBOX_SET_CTL, (intptr_t)&lw8_ctl2);
12911708Sstevel if (retval != 0)
12921708Sstevel break;
12931708Sstevel
12941708Sstevel /*
12951708Sstevel * if fault_led != 0, then set the led
12961708Sstevel */
12971708Sstevel if (lw8_ctl.fault_led == 0)
12981708Sstevel break;
12991708Sstevel bzero((caddr_t)&lw8_set_led, sizeof (lw8_set_led));
13001708Sstevel (void) strncpy(lw8_set_led.location, "chassis",
13011708Sstevel MAX_LOCATION_LEN);
13021708Sstevel (void) strncpy(lw8_set_led.id, "fault", MAX_ID_LEN);
13031708Sstevel lw8_set_led.status = lw8_ctl.fault_led - 1;
13041708Sstevel retval = lw8_setled(&lw8_set_led);
13051708Sstevel break;
13061708Sstevel default:
13071708Sstevel retval = ENOTSUP;
13081708Sstevel break;
13091708Sstevel }
13101708Sstevel return (retval);
13111708Sstevel }
13121708Sstevel
13131708Sstevel /* ARGSUSED */
13141708Sstevel static void
lw8_logger(caddr_t arg)13151708Sstevel lw8_logger(caddr_t arg)
13161708Sstevel {
13171708Sstevel callb_cpr_t cprinfo;
13181708Sstevel lw8_logmsg_t *lw8_logmsgp;
13191708Sstevel boolean_t more_waiting;
13201708Sstevel char level;
13211708Sstevel int retval;
13221708Sstevel
13231708Sstevel CALLB_CPR_INIT(&cprinfo, &lw8_logger_lock, callb_generic_cpr,
13241708Sstevel "lw8_logger");
13251708Sstevel
13261708Sstevel lw8_logmsgp = kmem_zalloc(sizeof (*lw8_logmsgp), KM_SLEEP);
13271708Sstevel mutex_enter(&lw8_logger_lock);
13281708Sstevel for (;;) {
13291708Sstevel
13301708Sstevel /*
13311708Sstevel * Wait for someone to tell me to continue.
13321708Sstevel */
13331708Sstevel while (lw8_logger_sig == LW8_LOGGER_WAIT) {
13341708Sstevel CALLB_CPR_SAFE_BEGIN(&cprinfo);
13351708Sstevel cv_wait(&lw8_logger_sig_cv, &lw8_logger_lock);
13361708Sstevel CALLB_CPR_SAFE_END(&cprinfo, &lw8_logger_lock);
13371708Sstevel }
13381708Sstevel
13391708Sstevel /* LW8_LOGGER_EXITNOW implies signal by _detach(). */
13401708Sstevel if (lw8_logger_sig == LW8_LOGGER_EXITNOW) {
13411708Sstevel lw8_logger_sig = LW8_LOGGER_WAIT;
13421708Sstevel
13431708Sstevel kmem_free(lw8_logmsgp, sizeof (*lw8_logmsgp));
13441708Sstevel
13451708Sstevel /* lw8_logger_lock is held at this point! */
13461708Sstevel CALLB_CPR_EXIT(&cprinfo);
13471708Sstevel
13481708Sstevel thread_exit();
13491708Sstevel /* NOTREACHED */
13501708Sstevel }
13511708Sstevel
13521708Sstevel ASSERT(lw8_logger_sig == LW8_LOGGER_PROCESSNOW);
13531708Sstevel lw8_logger_sig = LW8_LOGGER_WAIT;
13541708Sstevel
13551708Sstevel mutex_exit(&lw8_logger_lock);
13561708Sstevel
13571708Sstevel /* Do lw8_event logging */
13581708Sstevel
13591708Sstevel /*
13601708Sstevel * Get one message per iteration. We do not sleep if
13611708Sstevel * there are more to process. This makes exit from the
13621708Sstevel * routine much more reliable.
13631708Sstevel */
13641708Sstevel more_waiting = B_FALSE;
13651708Sstevel
13661708Sstevel retval = lw8_lomcmd(LW8_MBOX_GET_NEXT_MSG,
13671708Sstevel (intptr_t)lw8_logmsgp);
13681708Sstevel if (retval == 0) {
13691708Sstevel if (lw8_logmsgp->msg_valid) {
13701708Sstevel
13711708Sstevel switch (lw8_logmsgp->level) {
13721708Sstevel case 0: /* LOG_EMERG */
13731708Sstevel level = SL_FATAL;
13741708Sstevel break;
13751708Sstevel case 1: /* LOG_ALERT */
13761708Sstevel level = SL_FATAL;
13771708Sstevel break;
13781708Sstevel case 2: /* LOG_CRIT */
13791708Sstevel level = SL_FATAL;
13801708Sstevel break;
13811708Sstevel case 3: /* LOG_ERR */
13821708Sstevel level = SL_ERROR;
13831708Sstevel break;
13841708Sstevel case 4: /* LOG_WARNING */
13851708Sstevel level = SL_WARN;
13861708Sstevel break;
13871708Sstevel case 5: /* LOG_NOTICE */
13881708Sstevel level = SL_NOTE;
13891708Sstevel break;
13901708Sstevel case 6: /* LOG_INFO */
13911708Sstevel level = SL_NOTE;
13921708Sstevel break;
13931708Sstevel case 7: /* LOG_DEBUG */
13941708Sstevel level = SL_TRACE;
13951708Sstevel break;
13961708Sstevel default: /* unknown */
13971708Sstevel level = SL_NOTE;
13981708Sstevel break;
13991708Sstevel }
14001708Sstevel
14011708Sstevel /* Ensure NUL termination */
14021708Sstevel lw8_logmsgp->msg[
14037656SSherry.Moore@Sun.COM sizeof (lw8_logmsgp->msg) - 1] = '\0';
1404*11311SSurya.Prakki@Sun.COM (void) strlog(0, 0, 0, SL_CONSOLE | level,
14051708Sstevel lw8_logmsgp->msg);
14061708Sstevel }
14071708Sstevel
14081708Sstevel if (lw8_logmsgp->num_remaining > 0)
14091708Sstevel more_waiting = B_TRUE;
14101708Sstevel }
14111708Sstevel
14121708Sstevel /*
14131708Sstevel * Re-enter the lock to prepare for another iteration.
14141708Sstevel * We must have the lock here to protect lw8_logger_sig.
14151708Sstevel */
14161708Sstevel mutex_enter(&lw8_logger_lock);
14171708Sstevel if ((lw8_logger_sig == LW8_LOGGER_WAIT) && more_waiting)
14181708Sstevel /* We need to get more events */
14191708Sstevel lw8_logger_sig = LW8_LOGGER_PROCESSNOW;
14201708Sstevel }
14211708Sstevel }
14221708Sstevel
14231708Sstevel static void
lw8_logger_start(void)14241708Sstevel lw8_logger_start(void)
14251708Sstevel {
14261708Sstevel kthread_t *tp;
14271708Sstevel
14281708Sstevel mutex_enter(&lw8_logger_lock);
14291708Sstevel
14301708Sstevel if (lw8_logger_tid == 0) {
14311708Sstevel /* Force retrieval of any pending messages */
14321708Sstevel lw8_logger_sig = LW8_LOGGER_PROCESSNOW;
14331708Sstevel
14341708Sstevel tp = thread_create(NULL, 0, lw8_logger, NULL, 0,
14351708Sstevel &p0, TS_RUN, maxclsyspri);
14361708Sstevel lw8_logger_tid = tp->t_did;
14371708Sstevel }
14381708Sstevel
14391708Sstevel mutex_exit(&lw8_logger_lock);
14401708Sstevel }
14411708Sstevel
14421708Sstevel static void
lw8_logger_destroy(void)14431708Sstevel lw8_logger_destroy(void)
14441708Sstevel {
14451708Sstevel kt_did_t tid;
14461708Sstevel
14471708Sstevel mutex_enter(&lw8_logger_lock);
14481708Sstevel tid = lw8_logger_tid;
14491708Sstevel if (tid != 0) {
14501708Sstevel lw8_logger_sig = LW8_LOGGER_EXITNOW;
14511708Sstevel cv_signal(&lw8_logger_sig_cv);
14521708Sstevel lw8_logger_tid = 0;
14531708Sstevel }
14541708Sstevel mutex_exit(&lw8_logger_lock);
14551708Sstevel
14561708Sstevel /*
14571708Sstevel * Wait for lw8_logger() to finish.
14581708Sstevel */
14591708Sstevel if (tid != 0)
14601708Sstevel thread_join(tid);
14611708Sstevel }
14621708Sstevel
14631708Sstevel static void
lw8_logger_wakeup(void)14641708Sstevel lw8_logger_wakeup(void)
14651708Sstevel {
14661708Sstevel mutex_enter(&lw8_logger_lock);
14671708Sstevel
14681708Sstevel if (lw8_logger_sig != LW8_LOGGER_EXITNOW)
14691708Sstevel lw8_logger_sig = LW8_LOGGER_PROCESSNOW;
14701708Sstevel cv_signal(&lw8_logger_sig_cv);
14711708Sstevel
14721708Sstevel mutex_exit(&lw8_logger_lock);
14731708Sstevel }
1474