Merge commit '37e84ab74e939caf52150fc3352081786ecc0c29' into merges
[unleashed.git] / usr / src / uts / common / io / bscv.c
blob6f39a39c814803e0da29672b3bc34e124f37217f
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
19 * CDDL HEADER END
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
28 * bscv.c - multi-threaded lom driver for the Stiletto platform.
32 * Included files.
35 #include <sys/note.h>
36 #include <sys/types.h>
37 #include <sys/param.h>
38 #include <sys/uio.h>
39 #include <sys/open.h>
40 #include <sys/cred.h>
41 #include <sys/stream.h>
42 #include <sys/systm.h>
43 #include <sys/conf.h>
44 #include <sys/reboot.h>
45 #include <sys/modctl.h>
46 #include <sys/mkdev.h>
47 #include <sys/errno.h>
48 #include <sys/debug.h>
49 #include <sys/kmem.h>
50 #include <sys/consdev.h>
51 #include <sys/file.h>
52 #include <sys/stat.h>
53 #include <sys/disp.h>
54 #include <sys/ddi.h>
55 #include <sys/sunddi.h>
56 #include <sys/stream.h>
57 #include <sys/strlog.h>
58 #include <sys/log.h>
59 #include <sys/utsname.h>
60 #include <sys/callb.h>
61 #include <sys/sysevent.h>
62 #include <sys/nvpair.h>
63 #include <sys/sysevent/eventdefs.h>
64 #include <sys/sysevent/domain.h>
65 #include <sys/sysevent/env.h>
66 #include <sys/sysevent/dr.h>
68 #include <sys/lom_io.h>
69 #include <sys/bscbus.h>
70 #include <sys/bscv_impl.h>
73 * Variables defined here and visible internally only
76 static void *bscv_statep = NULL;
79 * Forward declarations
82 static int bscv_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
83 static int bscv_attach(dev_info_t *, ddi_attach_cmd_t);
84 static int bscv_detach(dev_info_t *, ddi_detach_cmd_t);
85 static int bscv_quiesce(dev_info_t *);
86 static int bscv_map_regs(bscv_soft_state_t *);
87 static void bscv_unmap_regs(bscv_soft_state_t *);
88 static void bscv_map_chan_logical_physical(bscv_soft_state_t *);
90 static int bscv_open(dev_t *, int, int, cred_t *);
91 static int bscv_close(dev_t, int, int, cred_t *);
92 static void bscv_full_stop(bscv_soft_state_t *);
94 static void bscv_enter(bscv_soft_state_t *);
95 static int bscv_tryenter(bscv_soft_state_t *ssp);
96 static void bscv_exit(bscv_soft_state_t *);
97 #ifdef DEBUG
98 static int bscv_held(bscv_soft_state_t *);
99 #endif /* DEBUG */
101 static void bscv_put8(bscv_soft_state_t *, int, bscv_addr_t, uint8_t);
102 static void bscv_put16(bscv_soft_state_t *, int, bscv_addr_t, uint16_t);
103 static void bscv_put32(bscv_soft_state_t *, int, bscv_addr_t, uint32_t);
104 static uint8_t bscv_get8(bscv_soft_state_t *, int, bscv_addr_t);
105 static uint16_t bscv_get16(bscv_soft_state_t *, int, bscv_addr_t);
106 static uint32_t bscv_get32(bscv_soft_state_t *, int, bscv_addr_t);
107 static void bscv_setclear8(bscv_soft_state_t *, int,
108 bscv_addr_t, uint8_t, uint8_t);
109 static void bscv_setclear8_volatile(bscv_soft_state_t *, int,
110 bscv_addr_t, uint8_t, uint8_t);
111 static void bscv_rep_rw8(bscv_soft_state_t *, int,
112 uint8_t *, bscv_addr_t, size_t, uint_t, boolean_t);
113 static uint8_t bscv_get8_cached(bscv_soft_state_t *, bscv_addr_t);
115 static uint8_t bscv_get8_locked(bscv_soft_state_t *, int, bscv_addr_t, int *);
116 static void bscv_rep_get8_locked(bscv_soft_state_t *, int,
117 uint8_t *, bscv_addr_t, size_t, uint_t, int *);
119 static boolean_t bscv_faulty(bscv_soft_state_t *);
120 static void bscv_clear_fault(bscv_soft_state_t *);
121 static void bscv_set_fault(bscv_soft_state_t *);
122 static boolean_t bscv_session_error(bscv_soft_state_t *);
123 static int bscv_retcode(bscv_soft_state_t *);
124 static int bscv_should_retry(bscv_soft_state_t *);
125 static void bscv_locked_result(bscv_soft_state_t *, int *);
127 static void bscv_put8_once(bscv_soft_state_t *, int, bscv_addr_t, uint8_t);
128 static uint8_t bscv_get8_once(bscv_soft_state_t *, int, bscv_addr_t);
129 static uint32_t bscv_probe(bscv_soft_state_t *, int, uint32_t *);
130 static void bscv_resync_comms(bscv_soft_state_t *, int);
132 static boolean_t bscv_window_setup(bscv_soft_state_t *);
133 static int bscv_eerw(bscv_soft_state_t *, uint32_t, uint8_t *,
134 unsigned, boolean_t);
136 static int bscv_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
137 static int bscv_ioc_dogstate(bscv_soft_state_t *, intptr_t, int);
138 static int bscv_ioc_psustate(bscv_soft_state_t *, intptr_t, int);
139 static int bscv_ioc_fanstate(bscv_soft_state_t *, intptr_t, int);
140 static int bscv_ioc_fledstate(bscv_soft_state_t *, intptr_t, int);
141 static int bscv_ioc_ledstate(bscv_soft_state_t *, intptr_t, int);
142 static int bscv_ioc_info(bscv_soft_state_t *, intptr_t, int);
143 static int bscv_ioc_mread(bscv_soft_state_t *, intptr_t, int);
144 static int bscv_ioc_volts(bscv_soft_state_t *, intptr_t, int);
145 static int bscv_ioc_stats(bscv_soft_state_t *, intptr_t, int);
146 static int bscv_ioc_temp(bscv_soft_state_t *, intptr_t, int);
147 static int bscv_ioc_cons(bscv_soft_state_t *, intptr_t, int);
148 static int bscv_ioc_eventlog2(bscv_soft_state_t *, intptr_t, int);
149 static int bscv_ioc_info2(bscv_soft_state_t *, intptr_t, int);
150 static int bscv_ioc_test(bscv_soft_state_t *, intptr_t, int);
151 static int bscv_ioc_mprog2(bscv_soft_state_t *, intptr_t, int);
152 static int bscv_ioc_mread2(bscv_soft_state_t *, intptr_t, int);
154 static void bscv_event_daemon(void *);
155 static void bscv_start_event_daemon(bscv_soft_state_t *);
156 static int bscv_stop_event_daemon(bscv_soft_state_t *);
157 static int bscv_pause_event_daemon(bscv_soft_state_t *);
158 static void bscv_resume_event_daemon(bscv_soft_state_t *);
159 static void bscv_event_process(bscv_soft_state_t *ssp, boolean_t);
160 static int bscv_event_validate(bscv_soft_state_t *, uint32_t, uint8_t);
161 static void bscv_event_process_one(bscv_soft_state_t *, lom_event_t *);
162 static void bscv_build_eventstring(bscv_soft_state_t *,
163 lom_event_t *, char *, char *);
164 static int bscv_level_of_event(lom_event_t *);
165 static void bscv_status(bscv_soft_state_t *, uint8_t, uint8_t);
166 char *bscv_get_label(char [][MAX_LOM2_NAME_STR], int, int);
167 static void bscv_generic_sysevent(bscv_soft_state_t *, char *, char *, char *,
168 char *, int32_t, char *);
169 static void bscv_sysevent(bscv_soft_state_t *, lom_event_t *);
171 static int bscv_prog(bscv_soft_state_t *, intptr_t, int);
172 static int bscv_prog_image(bscv_soft_state_t *, boolean_t,
173 uint8_t *, int, uint32_t);
174 static int bscv_prog_receive_image(bscv_soft_state_t *, lom_prog_t *,
175 uint8_t *, int);
176 static void bscv_leave_programming_mode(bscv_soft_state_t *, boolean_t);
177 static int bscv_prog_stop_lom(bscv_soft_state_t *);
178 static int bscv_prog_start_lom(bscv_soft_state_t *);
180 static int bscv_attach_common(bscv_soft_state_t *);
181 static int bscv_cleanup(bscv_soft_state_t *);
182 static void bscv_setup_capability(bscv_soft_state_t *);
183 static int bscv_probe_check(bscv_soft_state_t *);
184 static void bscv_setup_hostname(bscv_soft_state_t *);
185 static void bscv_read_hostname(bscv_soft_state_t *, char *);
186 static void bscv_write_hostname(bscv_soft_state_t *, char *, uint8_t);
187 static void bscv_setup_static_info(bscv_soft_state_t *);
188 static uint8_t bscv_read_env_name(bscv_soft_state_t *, uint8_t,
189 uint8_t, uint8_t, char [][MAX_LOM2_NAME_STR], int);
190 static void bscv_setup_events(bscv_soft_state_t *);
192 static void bscv_trace(bscv_soft_state_t *, char, const char *,
193 const char *, ...) __unused;
196 static void bscv_setup_watchdog(bscv_soft_state_t *ssp);
197 static void bscv_write_wdog_cfg(bscv_soft_state_t *,
198 uint_t, boolean_t, uint8_t);
200 #if defined(__i386) || defined(__amd64)
201 static void bscv_inform_bsc(bscv_soft_state_t *, uint32_t);
202 static void bscv_watchdog_pat_request(void *);
203 static void bscv_watchdog_cfg_request(bscv_soft_state_t *, uint8_t);
204 static uint_t bscv_set_watchdog_timer(bscv_soft_state_t *, uint_t);
205 static void bscv_clear_watchdog_timer(bscv_soft_state_t *);
207 static boolean_t bscv_panic_callback(void *, int);
208 static void bscv_watchdog_cyclic_add(bscv_soft_state_t *);
209 static void bscv_watchdog_cyclic_remove(bscv_soft_state_t *);
211 static uint8_t wdog_reset_on_timeout = 1;
213 #define WDOG_ON 1
214 #define WDOG_OFF 0
215 #define CLK_WATCHDOG_DEFAULT 10 /* 10 seconds */
216 #define WATCHDOG_PAT_INTERVAL 1000000000 /* 1 second */
218 static int bscv_watchdog_enable;
219 static int bscv_watchdog_available;
220 static int watchdog_activated;
221 static uint_t bscv_watchdog_timeout_seconds;
222 #endif /* __i386 || __amd64 */
226 * Local Definitions
228 #define STATUS_READ_LIMIT 8 /* Read up to 8 status changes at a time */
229 #define MYNAME "bscv"
230 #define BSCV_INST_TO_MINOR(i) (i)
231 #define BSCV_MINOR_TO_INST(m) (m)
234 * Strings for daemon event reporting
237 static char *eventSubsysStrings[] =
238 { "", /* 00 */
239 "Alarm ", /* 01 */
240 "temperature sensor ", /* 02 */
241 "overheat sensor ", /* 03 */
242 "Fan ", /* 04 */
243 "supply rail ", /* 05 */
244 "circuit breaker ", /* 06 */
245 "PSU ", /* 07 */
246 "user ", /* 08 */
247 "phonehome ", /* 09; unutilized */
248 "LOM ", /* 0a */
249 "host ", /* 0b */
250 "event log ", /* 0c */
251 "", /* 0d; EVENT_SUBSYS_EXTRA unutilized */
252 "LED ", /* 0e */
255 static char *eventTypeStrings[] =
257 "[null event]", /* 00 */
258 "ON", /* 01 */
259 "OFF", /* 02 */
260 "state change", /* 03 */
261 "power on", /* 04 */
262 "power off", /* 05 */
263 "powered off unexpectedly", /* 06 */
264 "reset unexpectedly", /* 07 */
265 "booted", /* 08 */
266 "watchdog enabled", /* 09 */
267 "watchdog disabled", /* 0a */
268 "watchdog triggered", /* 0b */
269 "failed", /* 0c */
270 "recovered", /* 0d */
271 "reset", /* 0e */
272 "XIR reset", /* 0f */
273 "console selected", /* 10 */
274 "time reference", /* 11 */
275 "script failure", /* 12 */
276 "modem access failure", /* 13 */
277 "modem dialing failure", /* 14 */
278 "bad checksum", /* 15 */
279 "added", /* 16 */
280 "removed", /* 17 */
281 "changed", /* 18 */
282 "login", /* 19 */
283 "password changed", /* 1a */
284 "login failed", /* 1b */
285 "logout", /* 1c */
286 "flash download", /* 1d */
287 "data lost", /* 1e */
288 "device busy", /* 1f */
289 "fault led state", /* 20 */
290 "overheat", /* 21 */
291 "severe overheat", /* 22 */
292 "no overheat", /* 23 */
293 "SCC", /* 24 */
294 "device inaccessible", /* 25 */
295 "Hostname change", /* 26 */
296 "CPU signature timeout", /* 27 */
297 "Bootmode change", /* 28 */
298 "Watchdog change policy", /* 29 */
299 "Watchdog change timeout", /* 2a */
303 * These store to mapping between the logical service, e.g. chan_prog for
304 * programming, and the actual Xbus channel which carries that traffic.
305 * Any services can be shared on the same channel apart from chan_wdogpat.
307 static int chan_general; /* General Traffic */
308 static int chan_wdogpat; /* Watchdog Patting */
309 static int chan_cpusig; /* CPU signatures */
310 static int chan_eeprom; /* EEPROM I/O */
311 static int chan_prog; /* Programming */
314 * cb_ops structure defining the driver entry points
317 static struct cb_ops bscv_cb_ops = {
318 bscv_open, /* open */
319 bscv_close, /* close */
320 nodev, /* strategy */
321 nodev, /* print */
322 nodev, /* dump */
323 nodev, /* read */
324 nodev, /* write */
325 bscv_ioctl, /* ioctl */
326 nodev, /* devmap */
327 nodev, /* mmap */
328 nodev, /* segmap */
329 nochpoll, /* poll */
330 ddi_prop_op, /* prop op */
331 NULL, /* ! STREAMS */
332 D_NEW | D_MP /* MT/MP Safe */
336 * dev_ops structure defining autoconfiguration driver autoconfiguration
337 * routines
340 static struct dev_ops bscv_dev_ops = {
341 DEVO_REV, /* devo_rev */
342 0, /* devo_refcnt */
343 bscv_getinfo, /* devo_getinfo */
344 nulldev, /* devo_identify */
345 nulldev, /* devo_probe */
346 bscv_attach, /* devo_attach */
347 bscv_detach, /* devo_detach */
348 nodev, /* devo_reset */
349 &bscv_cb_ops, /* devo_cb_ops */
350 NULL, /* devo_bus_ops */
351 NULL, /* devo_power */
352 bscv_quiesce, /* devo_quiesce */
356 * module configuration section
359 #ifdef DEBUG
360 #define BSCV_VERSION_STRING "bscv driver - Debug"
361 #else /* DEBUG */
362 #define BSCV_VERSION_STRING "bscv driver"
363 #endif /* DEBUG */
365 static struct modldrv modldrv = {
366 &mod_driverops,
367 BSCV_VERSION_STRING,
368 &bscv_dev_ops,
371 static struct modlinkage modlinkage = {
372 MODREV_1,
373 &modldrv,
374 NULL
377 #ifdef DEBUG
378 /* Tracing is enabled if value is non-zero. */
379 static int bscv_trace_flag = 1;
381 #define BSCV_TRACE if (bscv_trace_flag != 0) bscv_trace
382 #else
383 #define BSCV_TRACE
384 #endif
387 * kernel accessible routines. These routines are necessarily global so the
388 * driver can be loaded, and unloaded successfully
392 * function - _init
393 * description - initializes the driver state structure and installs the
394 * driver module into the kernel
395 * inputs - none
396 * outputs - success or failure of module installation
400 _init(void)
402 register int e;
404 if ((e = ddi_soft_state_init(&bscv_statep,
405 sizeof (bscv_soft_state_t), 1)) != 0) {
406 return (e);
409 if ((e = mod_install(&modlinkage)) != 0) {
410 ddi_soft_state_fini(&bscv_statep);
413 return (e);
417 * function - _info
418 * description - provide information about a kernel loaded module
419 * inputs - module infomation
420 * outputs - success or failure of information request
424 _info(struct modinfo *modinfop)
426 return (mod_info(&modlinkage, modinfop));
430 * function - _fini
431 * description - removes a module from the kernel and frees the driver soft
432 * state memory
433 * inputs - none
434 * outputs - success or failure of module removal
438 _fini(void)
440 register int e;
442 if ((e = mod_remove(&modlinkage)) != 0) {
443 return (e);
446 ddi_soft_state_fini(&bscv_statep);
448 return (e);
452 * function - bscv_getinfo
453 * description - routine used to provide information on the driver
454 * inputs - device information structure, command, command arg, storage
455 * area for the result
456 * outputs - DDI_SUCCESS or DDI_FAILURE
459 /*ARGSUSED*/
460 static int
461 bscv_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result)
463 bscv_soft_state_t *ssp;
464 dev_t dev = (dev_t)arg;
465 int instance;
466 int error;
468 instance = DEVICETOINSTANCE(dev);
470 switch (cmd) {
471 case DDI_INFO_DEVT2INSTANCE:
472 *result = (void *)(uintptr_t)instance;
473 error = DDI_SUCCESS;
474 break;
476 case DDI_INFO_DEVT2DEVINFO:
477 ssp = ddi_get_soft_state(bscv_statep, instance);
478 if (ssp == NULL)
479 return (DDI_FAILURE);
480 *result = (void *) ssp->dip;
481 error = DDI_SUCCESS;
482 break;
484 default:
485 error = DDI_FAILURE;
486 break;
489 return (error);
494 * function - bscv_attach
495 * description - this routine is responsible for setting aside memory for the
496 * driver data structures, initialising the mutexes and creating
497 * the device minor nodes. Additionally, this routine calls the
498 * the callback routine.
499 * inputs - device information structure, DDI_ATTACH command
500 * outputs - DDI_SUCCESS or DDI_FAILURE
504 bscv_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
506 bscv_soft_state_t *ssp;
507 int instance;
509 switch (cmd) {
510 case DDI_ATTACH:
512 instance = ddi_get_instance(dip);
514 if (ddi_soft_state_zalloc(bscv_statep, instance) !=
515 DDI_SUCCESS) {
516 return (DDI_FAILURE);
520 ssp = ddi_get_soft_state(bscv_statep, instance);
522 ssp->progress = 0;
524 ssp->dip = dip;
525 ssp->instance = instance;
526 ssp->event_waiting = B_FALSE;
527 ssp->status_change = B_FALSE;
528 ssp->nodename_change = B_FALSE;
529 ssp->cap0 = 0;
530 ssp->cap1 = 0;
531 ssp->cap2 = 0;
532 ssp->prog_mode_only = B_FALSE;
533 ssp->programming = B_FALSE;
534 ssp->cssp_prog = B_FALSE;
535 ssp->task_flags = 0;
536 ssp->debug = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
537 DDI_PROP_DONTPASS, "debug", 0);
538 ssp->majornum = ddi_driver_major(dip);
539 ssp->minornum = BSCV_INST_TO_MINOR(instance);
540 #if defined(__i386) || defined(__amd64)
541 ssp->last_nodename[0] = '\0';
542 #endif /* __i386 || __amd64 */
545 * initialise the mutexes
548 mutex_init(&ssp->cmd_mutex, NULL, MUTEX_DRIVER, NULL);
550 mutex_init(&ssp->task_mu, NULL, MUTEX_DRIVER, NULL);
551 cv_init(&ssp->task_cv, NULL, CV_DRIVER, NULL);
552 cv_init(&ssp->task_evnt_cv, NULL, CV_DRIVER, NULL);
553 mutex_init(&ssp->prog_mu, NULL, MUTEX_DRIVER, NULL);
554 ssp->progress |= BSCV_LOCKS;
556 BSCV_TRACE(ssp, 'A', "bscv_attach",
557 "bscv_attach: mutexes and condition vars initialised");
559 /* Map in physical communication channels */
561 if (bscv_map_regs(ssp) != DDI_SUCCESS) {
562 (void) bscv_cleanup(ssp);
563 return (DDI_FAILURE);
565 ssp->progress |= BSCV_MAPPED_REGS;
567 /* Associate logical channels to physical channels */
569 bscv_map_chan_logical_physical(ssp);
571 bscv_enter(ssp);
573 bscv_leave_programming_mode(ssp, B_FALSE);
575 if (bscv_attach_common(ssp) == DDI_FAILURE) {
576 bscv_exit(ssp);
577 (void) bscv_cleanup(ssp);
578 return (DDI_FAILURE);
582 bscv_exit(ssp);
585 * now create the minor nodes
587 if (ddi_create_minor_node(ssp->dip, "lom", S_IFCHR,
588 BSCV_INST_TO_MINOR(instance),
589 DDI_PSEUDO, 0) != DDI_SUCCESS) {
590 (void) bscv_cleanup(ssp);
591 return (DDI_FAILURE);
593 BSCV_TRACE(ssp, 'A', "bscv_attach",
594 "bscv_attach: device minor nodes created");
595 ssp->progress |= BSCV_NODES;
597 if (!ssp->prog_mode_only)
598 bscv_start_event_daemon(ssp);
600 #if defined(__i386) || defined(__amd64)
601 bscv_watchdog_enable = 1;
602 bscv_watchdog_available = 1;
603 watchdog_activated = 0;
604 bscv_watchdog_timeout_seconds = CLK_WATCHDOG_DEFAULT;
606 if (bscv_watchdog_enable && (boothowto & RB_DEBUG)) {
607 bscv_watchdog_available = 0;
608 cmn_err(CE_WARN, "bscv: kernel debugger "
609 "detected: hardware watchdog disabled");
613 * Before we enable the watchdog - register the panic
614 * callback so that we get called to stop the watchdog
615 * in the case of a panic.
617 ssp->callb_id = callb_add(bscv_panic_callback,
618 (void *)ssp, CB_CL_PANIC, "");
620 if (bscv_watchdog_available) {
621 (void) bscv_set_watchdog_timer(ssp,
622 CLK_WATCHDOG_DEFAULT);
623 bscv_enter(ssp);
624 bscv_setup_watchdog(ssp); /* starts cyclic callback */
625 bscv_exit(ssp);
627 #endif /* __i386 || __amd64 */
628 ddi_report_dev(dip);
629 return (DDI_SUCCESS);
630 default:
631 return (DDI_FAILURE);
636 * function - bscv_detach
637 * description - routine that prepares a module to be unloaded. It undoes all
638 * the work done by the bscv_attach)() routine. This is
639 * facilitated by the use of the progress indicator
640 * inputs - device information structure, DDI_DETACH command
641 * outputs - DDI_SUCCESS or DDI_FAILURE
644 /*ARGSUSED*/
645 static int
646 bscv_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
648 return (DDI_FAILURE);
652 * quiesce(9E) entry point.
654 * This function is called when the system is single-threaded at high
655 * PIL with preemption disabled. Therefore, this function must not be
656 * blocked.
658 * This function returns DDI_SUCCESS on success, or DDI_FAILURE on failure.
659 * DDI_FAILURE indicates an error condition and should almost never happen.
661 static int
662 bscv_quiesce(dev_info_t *dip)
664 bscv_soft_state_t *ssp;
665 int instance;
668 instance = ddi_get_instance(dip);
669 ssp = ddi_get_soft_state(bscv_statep, instance);
670 if (ssp == NULL) {
671 return (DDI_FAILURE);
673 #ifdef DEBUG
674 /* Disable tracing, as we are executing at High-Interrupt level */
675 bscv_trace_flag = 0;
676 #endif
677 /* quiesce the device */
678 bscv_full_stop(ssp);
680 return (DDI_SUCCESS);
684 * cb_ops routines
688 * function - bscv_open
689 * description - routine to provide association between user fd and device
690 * minor number. This routine is necessarily simple since a
691 * read/write interface is not provided. Additionally, the
692 * driver does not enforce exclusive access (FEXCL) or
693 * non-blocking during an open (FNDELAY). Deferred attach is
694 * supported.
695 * inputs - device number, flag specifying open type, device type,
696 * permissions
697 * outputs - success or failure of operation
700 /*ARGSUSED*/
701 static int
702 bscv_open(dev_t *devp, int flag, int otype, cred_t *cred)
704 bscv_soft_state_t *ssp;
705 int instance;
707 instance = DEVICETOINSTANCE(*devp);
708 ssp = ddi_get_soft_state(bscv_statep, instance);
709 if (ssp == NULL) {
710 return (ENXIO); /* not attached yet */
712 BSCV_TRACE(ssp, 'O', "bscv_open", "instance 0x%x", instance);
714 if (otype != OTYP_CHR) {
715 return (EINVAL);
718 return (0);
722 * function - bscv_close
723 * description - routine to perform the final close on the device. As per the
724 * open routine, neither FEXCL or FNDELAY accesses are enforced
725 * by the driver.
726 * inputs - device number,flag specifying open type, device type,
727 * permissions
728 * outputs - success or failure of operation
731 /*ARGSUSED1*/
732 static int
733 bscv_close(dev_t dev, int flag, int otype, cred_t *cred)
735 bscv_soft_state_t *ssp;
736 int instance;
738 instance = DEVICETOINSTANCE(dev);
739 ssp = ddi_get_soft_state(bscv_statep, instance);
740 if (ssp == NULL) {
741 return (ENXIO);
743 BSCV_TRACE(ssp, 'O', "bscv_close", "instance 0x%x", instance);
745 return (0);
748 static int
749 bscv_map_regs(bscv_soft_state_t *ssp)
751 int i;
752 int retval;
753 int *props;
754 unsigned int nelements;
756 ASSERT(ssp);
758 ssp->nchannels = 0;
761 * Work out how many channels are available by looking at the number
762 * of elements of the regs property array.
764 retval = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, ssp->dip,
765 DDI_PROP_DONTPASS, "reg", &props, &nelements);
767 /* We don't need props anymore. Free memory if it was allocated */
768 if (retval == DDI_PROP_SUCCESS)
769 ddi_prop_free(props);
771 /* Check for sanity of nelements */
772 if (retval != DDI_PROP_SUCCESS) {
773 BSCV_TRACE(ssp, 'A', "bscv_map_regs", "lookup reg returned"
774 " 0x%x", retval);
775 goto cleanup_exit;
776 } else if (nelements % LOMBUS_REGSPEC_SIZE != 0) {
777 BSCV_TRACE(ssp, 'A', "bscv_map_regs", "nelements %d not"
778 " a multiple of %d", nelements, LOMBUS_REGSPEC_SIZE);
779 goto cleanup_exit;
780 } else if (nelements > BSCV_MAXCHANNELS * LOMBUS_REGSPEC_SIZE) {
781 BSCV_TRACE(ssp, 'A', "bscv_map_regs", "nelements %d too large"
782 ", probably a misconfiguration", nelements);
783 goto cleanup_exit;
784 } else if (nelements < BSCV_MINCHANNELS * LOMBUS_REGSPEC_SIZE) {
785 BSCV_TRACE(ssp, 'A', "bscv_map_regs", "nelements %d too small"
786 ", need to have at least a general and a wdog channel",
787 nelements);
788 goto cleanup_exit;
791 ssp->nchannels = nelements / LOMBUS_REGSPEC_SIZE;
793 ssp->attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
794 ssp->attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC;
795 ssp->attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
797 for (i = 0; i < ssp->nchannels; i++) {
798 retval = ddi_regs_map_setup(ssp->dip, i,
799 (caddr_t *)&ssp->channel[i].regs,
800 0, 0, &ssp->attr, &ssp->channel[i].handle);
801 if (retval != DDI_SUCCESS) {
802 BSCV_TRACE(ssp, 'A', "bscv_map_regs", "map failure"
803 " 0x%x on space %d", retval, i);
805 /* Rewind all current mappings - avoiding failed one */
806 i--;
807 for (; i >= 0; i--) {
808 ddi_regs_map_free(&ssp->channel[i].handle);
811 goto cleanup_exit;
815 return (DDI_SUCCESS);
817 cleanup_exit:
819 * It is important to set nchannels to 0 even if, say, only one of
820 * the two required handles was mapped. If we cannot achieve our
821 * minimum config its not safe to do any IO; this keeps our failure
822 * mode handling simpler.
824 ssp->nchannels = 0;
825 return (DDI_FAILURE);
828 static void
829 bscv_unmap_regs(bscv_soft_state_t *ssp)
831 int i;
833 ASSERT(ssp);
835 for (i = 0; i < ssp->nchannels; i++) {
836 ddi_regs_map_free(&ssp->channel[i].handle);
841 * Map logical services onto physical XBus channels.
843 static void
844 bscv_map_chan_logical_physical(bscv_soft_state_t *ssp)
846 ASSERT(ssp);
849 * We can assert that there will always be at least two channels,
850 * to allow watchdog pats to be segregated from all other traffic.
852 chan_general = 0;
853 chan_wdogpat = 1;
856 * By default move all other services onto the generic channel unless
857 * the hardware supports additional channels.
860 chan_cpusig = chan_eeprom = chan_prog = chan_general;
862 if (ssp->nchannels > 2)
863 chan_cpusig = 2;
864 if (ssp->nchannels > 3)
865 chan_eeprom = 3;
866 if (ssp->nchannels > 4)
867 chan_prog = 4;
872 * function - bscv_full_stop
873 * description - gracefully shut the lom down during panic or reboot.
874 * Disables the watchdog and sets up serial event reporting.
875 * inputs - soft state pointer
876 * outputs - none
878 void
879 bscv_full_stop(bscv_soft_state_t *ssp)
881 uint8_t bits2set = 0;
882 uint8_t bits2clear = 0;
883 int obtained_lock;
885 BSCV_TRACE(ssp, 'W', "bscv_full_stop",
886 "turning off watchdog");
889 * Obtain the softstate lock only if it is not already owned,
890 * as this function can be called from a High-level interrupt
891 * context. As a result, our thread cannot sleep.
892 * At end of function, our thread releases the lock only if
893 * it acquired the lock.
895 obtained_lock = (bscv_tryenter(ssp) != 0);
897 #if defined(__i386) || defined(__amd64)
898 if (ddi_in_panic()) {
899 bscv_inform_bsc(ssp, BSC_INFORM_PANIC);
900 } else {
901 bscv_inform_bsc(ssp, BSC_INFORM_OFFLINE);
903 #endif /* __i386 || __amd64 */
905 /* set serial event reporting */
906 switch (ssp->serial_reporting) {
907 case LOM_SER_EVENTS_ON:
908 case LOM_SER_EVENTS_DEF:
909 /* Make sure serial event reporting is on */
910 bits2clear = EBUS_ALARM_NOEVENTS;
911 break;
912 case LOM_SER_EVENTS_OFF:
913 /* Make sure serial event reporting is on */
914 bits2set = EBUS_ALARM_NOEVENTS;
915 break;
916 default:
917 break;
919 bscv_setclear8_volatile(ssp, chan_general,
920 EBUS_IDX_ALARM, bits2set, bits2clear);
922 /* Do not free the lock if our thread did not obtain it. */
923 if (obtained_lock != 0) {
924 bscv_exit(ssp);
929 * LOM I/O routines.
931 * locking
933 * Two sets of routines are provided:
934 * normal - must be called after acquiring an appropriate lock.
935 * locked - perform all the locking required and return any error
936 * code in the supplied 'res' argument. If there is no
937 * error 'res' is not changed.
938 * The locked routines are designed for use in ioctl commands where
939 * only a single operation needs to be performed and the overhead of
940 * locking and result checking adds significantly to code complexity.
942 * locking primitives
944 * bscv_enter() - acquires an I/O lock for the calling thread.
945 * bscv_tryenter() - conditionally acquires an I/O lock for calling thread.
946 * bscv_exit() - releases an I/O lock acquired by bscv_enter().
947 * bscv_held() - used to assert ownership of an I/O lock.
949 * normal I/O routines
951 * Note bscv_{put|get}{16|32} routines are big-endian. This assumes that
952 * the firmware works that way too.
954 * bscv_put8(), bscv_put16, bscv_put32 - write values to the LOM
955 * and handle any retries if necessary.
956 * 16 and 32 bit values are big-endian.
957 * bscv_get8(), bscv_get16, bscv_get32 - read values from the LOM
958 * and handle any retries if necessary.
959 * 16 and 32 bit values are big-endian.
960 * bscv_setclear8() - set or clear the specified bits in the register
961 * at the supplied address.
962 * bscv_setclear8_volatile() - set or clear the specified bits in the
963 * register at the supplied address. If the lom reports
964 * that the registers has changed since the last read
965 * re-read and apply the set or clear to the new bits.
966 * bscv_get8_cached() - Return a cached register value (addr < 0x80).
967 * Does not access the hardware. A read of the hardware
968 * automatically updates this cache.
970 * locked I/O routines
972 * bscv_get8_locked(), bscv_rep_get8_locked().
974 * Call the indicated function from above, but wrapping it with
975 * bscv_enter()/bscv_exit().
978 * Fault management
980 * LOM communications fault are grouped into three categories:
981 * 1) Faulty - the LOM is not responding and no attempt to communicate
982 * with it should be made.
983 * 2) Transient fault - something which might recover after a retry
984 * but which doesn't affect our ability to perform other
985 * commands.
986 * 3) Command error - an inappropriate command was executed. A retry
987 * will not fix it but the command failed.
989 * The current implementation of the bscv driver is not very good at
990 * noticing command errors due to the structure of the original code
991 * that it is based on. It is possible to extend the driver to do this
992 * and would probably involve having a concept of a "session error"
993 * which is less severe than a fault but means that a sequence of
994 * commands had some fault which cannot be recovered.
997 * faults
999 * bscv_faulty() - returns B_TRUE if the LOM (communications) have been
1000 * declared faulty.
1001 * bscv_clear_fault() - marks the LOM as not faulty.
1002 * bscv_set_fault() - marks the LOM as being faulty.
1004 * bscv_clear_fault and bscv_set_fault should generally not be called
1005 * directly.
1007 * command errors/transient faults
1009 * bscv_retcode() - returns the actual error code of the last operation.
1010 * bscv_should_retry() - determines if last operation may suceed if
1011 * retried.
1012 * bscv_locked_result() - Set the result of a locked register access.
1014 * low level I/O primitives
1016 * These are generally not called directly. These perform a single
1017 * access to the LOM device. They do not handle retries.
1019 * bscv_put8_once()
1020 * bscv_get8_once()
1021 * bscv_probe() - perform a probe (NOP) operation to check out lom comms.
1022 * bscv_resync_comms() - resynchronise communications after a transient fault.
1025 static void
1026 bscv_enter(bscv_soft_state_t *ssp)
1028 BSCV_TRACE(ssp, '@', "bscv_enter", "");
1029 mutex_enter(&ssp->cmd_mutex);
1030 ssp->had_session_error = B_FALSE;
1033 static int
1034 bscv_tryenter(bscv_soft_state_t *ssp)
1036 int rv;
1038 BSCV_TRACE(ssp, '@', "bscv_tryenter", "");
1039 if ((rv = mutex_tryenter(&ssp->cmd_mutex)) != 0) {
1040 ssp->had_session_error = B_FALSE;
1042 return (rv);
1045 static void
1046 bscv_exit(bscv_soft_state_t *ssp)
1048 mutex_exit(&ssp->cmd_mutex);
1049 BSCV_TRACE(ssp, '@', "bscv_exit", "");
1052 #ifdef DEBUG
1053 static int
1054 bscv_held(bscv_soft_state_t *ssp)
1056 return (mutex_owned(&ssp->cmd_mutex));
1058 #endif /* DEBUG */
1060 static void
1061 bscv_put8(bscv_soft_state_t *ssp, int chan, bscv_addr_t addr, uint8_t val)
1063 boolean_t needretry;
1064 int num_failures;
1066 ASSERT(bscv_held(ssp));
1068 if (bscv_faulty(ssp)) {
1069 return;
1072 BSCV_TRACE(ssp, '@', "bscv_put8",
1073 "addr 0x%x.%02x <= 0x%02x", addr >> 8, addr & 0xff, val);
1075 for (num_failures = 0;
1076 num_failures < BSC_FAILURE_RETRY_LIMIT;
1077 num_failures++) {
1078 bscv_put8_once(ssp, chan, addr, val);
1079 needretry = bscv_should_retry(ssp);
1080 if (!needretry) {
1081 break;
1084 if (ssp->command_error != 0) {
1085 ssp->had_session_error = B_TRUE;
1088 if (needretry) {
1089 /* Failure - we ran out of retries */
1090 cmn_err(CE_WARN, "bscv_put8: addr 0x%x.%02x retried "
1091 "write %d times, giving up",
1092 addr >> 8, addr & 0xff, num_failures);
1093 bscv_set_fault(ssp);
1094 } else if (num_failures > 0) {
1095 BSCV_TRACE(ssp, 'R', "bscv_put8",
1096 "addr 0x%x.%02x retried write %d times, succeeded",
1097 addr >> 8, addr & 0xff, num_failures);
1101 static void
1102 bscv_put16(bscv_soft_state_t *ssp, int chan, bscv_addr_t addr, uint16_t val)
1104 ASSERT(bscv_held(ssp));
1105 BSCV_TRACE(ssp, '@', "bscv_put16",
1106 "addr 0x%x.%02x <= %04x", addr >> 8, addr & 0xff, val);
1107 bscv_put8(ssp, chan, addr, val >> 8);
1108 bscv_put8(ssp, chan, addr + 1, val & 0xff);
1111 static void
1112 bscv_put32(bscv_soft_state_t *ssp, int chan, bscv_addr_t addr, uint32_t val)
1114 ASSERT(bscv_held(ssp));
1115 BSCV_TRACE(ssp, '@', "bscv_put32",
1116 "addr 0x%x.%02x <= %08x", addr >> 8, addr & 0xff, val);
1117 bscv_put8(ssp, chan, addr, (val >> 24) & 0xff);
1118 bscv_put8(ssp, chan, addr + 1, (val >> 16) & 0xff);
1119 bscv_put8(ssp, chan, addr + 2, (val >> 8) & 0xff);
1120 bscv_put8(ssp, chan, addr + 3, val & 0xff);
1123 static uint8_t
1124 bscv_get8(bscv_soft_state_t *ssp, int chan, bscv_addr_t addr)
1126 uint8_t retval;
1127 boolean_t needretry;
1128 int num_failures;
1130 ASSERT(bscv_held(ssp));
1132 if (bscv_faulty(ssp)) {
1133 return (0);
1136 for (num_failures = 0;
1137 num_failures < BSC_FAILURE_RETRY_LIMIT;
1138 num_failures++) {
1139 retval = bscv_get8_once(ssp, chan, addr);
1140 needretry = bscv_should_retry(ssp);
1141 if (!needretry) {
1142 break;
1145 if (ssp->command_error != 0) {
1146 ssp->had_session_error = B_TRUE;
1149 if (needretry) {
1150 /* Failure */
1151 cmn_err(CE_WARN, "bscv_get8: addr 0x%x.%02x retried "
1152 "read %d times, giving up",
1153 addr >> 8, addr & 0xff, num_failures);
1154 bscv_set_fault(ssp);
1155 } else if (num_failures > 0) {
1156 BSCV_TRACE(ssp, 'R', "bscv_get8",
1157 "addr 0x%x.%02x retried read %d times, succeeded",
1158 addr >> 8, addr & 0xff, num_failures);
1161 BSCV_TRACE(ssp, '@', "bscv_get8",
1162 "addr 0x%x.%02x => %02x", addr >> 8, addr & 0xff, retval);
1163 return (retval);
1166 static uint16_t
1167 bscv_get16(bscv_soft_state_t *ssp, int chan, bscv_addr_t addr)
1169 uint16_t retval;
1171 ASSERT(bscv_held(ssp));
1173 retval = bscv_get8(ssp, chan, addr) << 8;
1174 retval |= bscv_get8(ssp, chan, addr + 1);
1176 BSCV_TRACE(ssp, '@', "bscv_get16",
1177 "addr 0x%x.%02x => %04x", addr >> 8, addr & 0xff, retval);
1178 return (retval);
1181 static uint32_t
1182 bscv_get32(bscv_soft_state_t *ssp, int chan, bscv_addr_t addr)
1184 uint32_t retval;
1186 ASSERT(bscv_held(ssp));
1188 retval = bscv_get8(ssp, chan, addr) << 24;
1189 retval |= bscv_get8(ssp, chan, addr + 1) << 16;
1190 retval |= bscv_get8(ssp, chan, addr + 2) << 8;
1191 retval |= bscv_get8(ssp, chan, addr + 3);
1193 BSCV_TRACE(ssp, '@', "bscv_get32",
1194 "addr 0x%x.%02x => %08x", addr >> 8, addr & 0xff, retval);
1195 return (retval);
1198 static void
1199 bscv_setclear8(bscv_soft_state_t *ssp, int chan,
1200 bscv_addr_t addr, uint8_t set, uint8_t clear)
1202 uint8_t val;
1204 ASSERT(bscv_held(ssp));
1205 ASSERT(addr < BSC_ADDR_CACHE_LIMIT);
1207 val = ssp->lom_regs[addr] | set;
1208 val &= ~clear;
1210 BSCV_TRACE(ssp, '@', "bscv_setclear8",
1211 "addr 0x%x.%02x, set %02x, clear %02x => %02x",
1212 addr >> 8, addr & 0xff,
1213 set, clear, val);
1215 bscv_put8(ssp, chan, addr, val);
1218 static void
1219 bscv_setclear8_volatile(bscv_soft_state_t *ssp, int chan,
1220 bscv_addr_t addr, uint8_t set, uint8_t clear)
1222 uint8_t val;
1223 boolean_t needretry;
1224 int num_failures;
1226 ASSERT(bscv_held(ssp));
1227 ASSERT(addr < BSC_ADDR_CACHE_LIMIT);
1229 if (bscv_faulty(ssp)) {
1230 return;
1233 BSCV_TRACE(ssp, '@', "bscv_setclear8_volatile",
1234 "addr 0x%x.%02x => set %02x clear %02x",
1235 addr >> 8, addr & 0xff, set, clear);
1237 val = bscv_get8_cached(ssp, addr);
1238 for (num_failures = 0;
1239 num_failures < BSC_FAILURE_RETRY_LIMIT;
1240 num_failures++) {
1241 val |= set;
1242 val &= ~clear;
1243 bscv_put8_once(ssp, chan, addr, val);
1244 if (ssp->command_error == EBUS_ERROR_STALEDATA) {
1245 /* Re-read the stale register from the lom */
1246 val = bscv_get8_once(ssp, chan, addr);
1247 needretry = 1;
1248 } else {
1249 needretry = bscv_should_retry(ssp);
1250 if (!needretry) {
1251 break;
1255 if (ssp->command_error != 0) {
1256 ssp->had_session_error = B_TRUE;
1259 if (needretry) {
1260 /* Failure */
1261 cmn_err(CE_WARN, "bscv_setclear8_volatile: addr 0x%x.%02x "
1262 "retried write %d times, giving up",
1263 addr >> 8, addr & 0xff, num_failures);
1264 if (ssp->command_error != EBUS_ERROR_STALEDATA) {
1265 bscv_set_fault(ssp);
1267 } else if (num_failures > 0) {
1268 BSCV_TRACE(ssp, 'R', "bscv_setclear8_volatile",
1269 "addr 0x%x.%02x retried write %d times, succeeded",
1270 addr >> 8, addr & 0xff, num_failures);
1274 static void
1275 bscv_rep_rw8(bscv_soft_state_t *ssp, int chan, uint8_t *host_addr,
1276 bscv_addr_t dev_addr, size_t repcount, uint_t flags,
1277 boolean_t is_write)
1279 size_t inc;
1281 ASSERT(bscv_held(ssp));
1283 inc = (flags & DDI_DEV_AUTOINCR) ? 1 : 0;
1284 for (; repcount--; dev_addr += inc) {
1285 if (flags & DDI_DEV_AUTOINCR) {
1286 if (is_write) {
1287 bscv_put8(ssp, chan, dev_addr, *host_addr++);
1288 } else {
1289 *host_addr++ = bscv_get8(ssp, chan, dev_addr);
1291 } else {
1292 if (is_write) {
1293 bscv_put8_once(ssp, chan,
1294 dev_addr, *host_addr++);
1295 } else {
1296 *host_addr++ = bscv_get8_once(ssp, chan,
1297 dev_addr);
1299 /* We need this because _once routines don't do it */
1300 if (ssp->command_error != 0) {
1301 ssp->had_session_error = B_TRUE;
1304 if (bscv_faulty(ssp) || bscv_session_error(ssp)) {
1306 * No retry here. If we were AUTOINCR then get/put
1307 * will have retried. For NO_AUTOINCR we cannot retry
1308 * because the data would be corrupted.
1310 break;
1315 static uint8_t
1316 bscv_get8_cached(bscv_soft_state_t *ssp, bscv_addr_t addr)
1318 ASSERT(addr < BSC_ADDR_CACHE_LIMIT);
1319 /* Can be called with or without the lock held */
1321 return (ssp->lom_regs[addr]);
1324 static uint8_t
1325 bscv_get8_locked(bscv_soft_state_t *ssp, int chan, bscv_addr_t addr, int *res)
1327 uint8_t retval;
1329 ASSERT(addr < BSC_ADDR_CACHE_LIMIT);
1330 bscv_enter(ssp);
1331 retval = bscv_get8(ssp, chan, addr);
1332 bscv_locked_result(ssp, res);
1333 bscv_exit(ssp);
1334 BSCV_TRACE(ssp, '@', "bscv_get8_locked",
1335 "addr 0x%x.%02x => %02x", addr >> 8, addr & 0xff, retval);
1336 return (retval);
1339 static void
1340 bscv_rep_get8_locked(bscv_soft_state_t *ssp, int chan, uint8_t *host_addr,
1341 bscv_addr_t dev_addr, size_t repcount, uint_t flags, int *res)
1343 bscv_enter(ssp);
1344 bscv_rep_rw8(ssp, chan, host_addr, dev_addr, repcount,
1345 flags, B_FALSE /* read */);
1346 bscv_locked_result(ssp, res);
1347 bscv_exit(ssp);
1350 static boolean_t
1351 bscv_faulty(bscv_soft_state_t *ssp)
1353 ASSERT(bscv_held(ssp));
1354 return (ssp->had_fault);
1357 static void
1358 bscv_clear_fault(bscv_soft_state_t *ssp)
1360 ASSERT(bscv_held(ssp));
1361 BSCV_TRACE(ssp, 'J', "bscv_clear_fault", "clearing fault flag");
1362 ssp->had_fault = B_FALSE;
1363 ssp->had_session_error = B_FALSE;
1366 static void
1367 bscv_set_fault(bscv_soft_state_t *ssp)
1369 ASSERT(bscv_held(ssp));
1370 BSCV_TRACE(ssp, 'J', "bscv_set_fault", "setting fault flag");
1371 ssp->had_fault = B_TRUE;
1374 static boolean_t
1375 bscv_session_error(bscv_soft_state_t *ssp)
1377 ASSERT(bscv_held(ssp));
1378 return (ssp->had_session_error);
1381 static int
1382 bscv_retcode(bscv_soft_state_t *ssp)
1384 BSCV_TRACE(ssp, '@', "bscv_retcode",
1385 "code 0x%x", ssp->command_error);
1386 return (ssp->command_error);
1389 static int
1390 bscv_should_retry(bscv_soft_state_t *ssp)
1392 if ((ssp->command_error == EBUS_ERROR_DEVICEFAIL) ||
1393 (ssp->command_error >= LOMBUS_ERR_BASE)) {
1394 /* This command is due to an I/O fault - retry might fix */
1395 return (1);
1396 } else {
1398 * The command itself was bad - there is no point in fixing
1399 * Note. Whatever happens we should know that if we were
1400 * doing EBUS_IDX_SELFTEST0..EBUS_IDX_SELFTEST7 and we
1401 * had 0x80 set then this is a test error not a retry
1402 * error.
1404 return (0);
1408 static void
1409 bscv_locked_result(bscv_soft_state_t *ssp, int *res)
1411 if (bscv_faulty(ssp) || (bscv_retcode(ssp) != 0)) {
1412 *res = EIO;
1416 static void
1417 bscv_put8_once(bscv_soft_state_t *ssp, int chan, bscv_addr_t addr, uint8_t val)
1419 uint32_t fault;
1421 ASSERT(bscv_held(ssp));
1423 ssp->command_error = 0;
1425 if (bscv_faulty(ssp)) {
1426 /* Bail out things are not working */
1427 return;
1428 } else if (ssp->nchannels == 0) {
1429 /* Didn't manage to map handles so ddi_{get,put}* broken */
1430 BSCV_TRACE(ssp, '@', "bscv_put8_once",
1431 "nchannels is 0x0 so cannot do IO");
1432 return;
1435 /* Clear any pending fault */
1436 ddi_put32(ssp->channel[chan].handle,
1437 (uint32_t *)BSC_NEXUS_ADDR(ssp, chan, 0, LOMBUS_FAULT_REG), 0);
1439 /* Do the access and get fault code - may take a long time */
1440 ddi_put8(ssp->channel[chan].handle,
1441 &ssp->channel[chan].regs[addr], val);
1442 fault = ddi_get32(ssp->channel[chan].handle,
1443 (uint32_t *)BSC_NEXUS_ADDR(ssp, chan, 0, LOMBUS_FAULT_REG));
1445 ssp->command_error = fault;
1447 if (fault == 0) {
1448 /* Things were ok - update cache entry */
1449 if (addr < BSC_ADDR_CACHE_LIMIT) {
1450 /* Store cacheable entries */
1451 ssp->lom_regs[addr] = val;
1453 } else if (fault >= LOMBUS_ERR_BASE) {
1454 /* lombus problem - do a resync session */
1455 cmn_err(CE_WARN, "!bscv_put8_once: Had comms fault "
1456 "for address 0x%x.%02x - data 0x%x, fault 0x%x",
1457 addr >> 8, addr & 0xff, val, fault);
1458 /* Attempt to resync with the lom */
1459 bscv_resync_comms(ssp, chan);
1461 * Note: we do not set fault status here. That
1462 * is done if our caller decides to give up talking to
1463 * the lom. The observant might notice that this means
1464 * that if we mend things on the last attempt we still
1465 * get the fault set - we just live with that!
1469 BSCV_TRACE(ssp, '@', "bscv_put8_once",
1470 "addr 0x%x.%02x <= 0x%02x", addr >> 8, addr & 0xff, val);
1473 static uint8_t
1474 bscv_get8_once(bscv_soft_state_t *ssp, int chan, bscv_addr_t addr)
1476 uint8_t val;
1477 uint32_t fault;
1479 ASSERT(bscv_held(ssp));
1481 ssp->command_error = 0;
1483 if (bscv_faulty(ssp)) {
1484 /* Bail out things are not working */
1485 return (0xff);
1486 } else if (ssp->nchannels == 0) {
1487 /* Didn't manage to map handles so ddi_{get,put}* broken */
1488 BSCV_TRACE(ssp, '@', "bscv_get8_once",
1489 "nchannels is 0x0 so cannot do IO");
1490 return (0xff);
1493 /* Clear any pending fault */
1494 ddi_put32(ssp->channel[chan].handle,
1495 (uint32_t *)BSC_NEXUS_ADDR(ssp, chan, 0, LOMBUS_FAULT_REG), 0);
1497 /* Do the access and get fault code - may take a long time */
1498 val = ddi_get8(ssp->channel[chan].handle,
1499 &ssp->channel[chan].regs[addr]);
1500 fault = ddi_get32(ssp->channel[chan].handle,
1501 (uint32_t *)BSC_NEXUS_ADDR(ssp, chan, 0, LOMBUS_FAULT_REG));
1502 ssp->command_error = fault;
1504 if (fault >= LOMBUS_ERR_BASE) {
1505 /* lombus problem - do a resync session */
1506 cmn_err(CE_WARN, "!bscv_get8_once: Had comms fault "
1507 "for address 0x%x.%02x - data 0x%x, fault 0x%x",
1508 addr >> 8, addr & 0xff, val, fault);
1509 /* Attempt to resync with the lom */
1510 bscv_resync_comms(ssp, chan);
1512 * Note: we do not set fault status here. That
1513 * is done if our caller decides to give up talking to
1514 * the lom. The observant might notice that this means
1515 * that if we mend things on the last attempt we still
1516 * get the fault set - we just live with that!
1520 * FIXME - should report error if you get
1521 * EBUS_ERROR_DEVICEFAIL reported from the BSC. That gets
1522 * logged as a failure in bscv_should_retry and may contribute
1523 * to a permanent failure. Reference issues seen by Mitac.
1526 if (!bscv_faulty(ssp)) {
1527 if (addr < BSC_ADDR_CACHE_LIMIT) {
1528 /* Store cacheable entries */
1529 ssp->lom_regs[addr] = val;
1533 BSCV_TRACE(ssp, '@', "bscv_get8_once",
1534 "addr 0x%x.%02x => 0x%02x", addr >> 8, addr & 0xff, val);
1535 return (val);
1538 static uint32_t
1539 bscv_probe(bscv_soft_state_t *ssp, int chan, uint32_t *fault)
1541 uint32_t async_reg;
1543 if (ssp->nchannels == 0) {
1545 * Failed to map handles, so cannot do any IO. Set the
1546 * fault indicator and return a dummy value.
1548 BSCV_TRACE(ssp, '@', "bscv_probe",
1549 "nchannels is 0x0 so cannot do any IO");
1550 *fault = LOMBUS_ERR_REG_NUM;
1551 return ((~(int8_t)0));
1554 /* Clear faults */
1555 ddi_put32(ssp->channel[chan].handle,
1556 (uint32_t *)BSC_NEXUS_ADDR(ssp, chan, 0, LOMBUS_FAULT_REG), 0);
1557 /* Probe and Check faults */
1558 *fault = ddi_get32(ssp->channel[chan].handle,
1559 (uint32_t *)BSC_NEXUS_ADDR(ssp, chan, 0, LOMBUS_PROBE_REG));
1560 /* Read status */
1561 async_reg = ddi_get32(ssp->channel[chan].handle,
1562 (uint32_t *)BSC_NEXUS_ADDR(ssp, chan, 0, LOMBUS_ASYNC_REG));
1564 BSCV_TRACE(ssp, '@', "bscv_probe",
1565 "async status 0x%x, fault 0x%x", async_reg, *fault);
1566 return (async_reg);
1569 static void
1570 bscv_resync_comms(bscv_soft_state_t *ssp, int chan)
1572 int try;
1573 uint32_t command_error = ssp->command_error;
1574 uint32_t fault = 0;
1576 if (ssp->nchannels == 0) {
1578 * Didn't manage to map handles so ddi_{get,put}* broken.
1579 * Therefore, there is no way to resync comms.
1581 BSCV_TRACE(ssp, '@', "bscv_resync_comms",
1582 "nchannels is 0x0 so not possible to resync comms");
1583 return;
1585 if (command_error >= LOMBUS_ERR_BASE &&
1586 command_error != LOMBUS_ERR_REG_NUM &&
1587 command_error != LOMBUS_ERR_REG_SIZE &&
1588 command_error != LOMBUS_ERR_TIMEOUT) {
1589 /* Resync here to make sure that the lom is talking */
1590 cmn_err(CE_WARN, "!bscv_resync_comms: "
1591 "Attempting comms resync after comms fault 0x%x",
1592 command_error);
1593 for (try = 1; try <= 8; try++) {
1594 /* Probe */
1595 fault = ddi_get32(ssp->channel[chan].handle,
1596 (uint32_t *)BSC_NEXUS_ADDR(ssp, chan, 0,
1597 LOMBUS_PROBE_REG));
1599 if (fault == 0) {
1600 break;
1601 } else {
1602 cmn_err(CE_WARN, "!bscv_resync_comms: "
1603 "comms resync (probing) - try 0x%x "
1604 "had fault 0x%x", try, fault);
1607 if (fault != 0) {
1608 cmn_err(CE_WARN, "!bscv_resync_comms: "
1609 "Failed to resync comms - giving up");
1610 ssp->bad_resync++;
1611 } else {
1612 cmn_err(CE_WARN, "!bscv_resync_comms: "
1613 "resync comms after 0x%x tries", try);
1614 ssp->bad_resync = 0;
1622 * LOMLite configuration/event eeprom access routines
1624 * bscv_window_setup() - Read/Sanity check the eeprom parameters.
1625 * This must be called prior to calling bscv_eerw().
1626 * bscv_eerw() - Read/write data from/to the eeprom.
1630 * function - bscv_window_setup
1631 * description - this routine reads the eeprom parameters and sanity
1632 * checks them to ensure that the lom is talking sense.
1633 * inputs - soft state ptr
1634 * outputs - B_TRUE if the eeprom is ok, B_FALSE if the eeprom is not OK.
1636 static boolean_t
1637 bscv_window_setup(bscv_soft_state_t *ssp)
1639 ASSERT(bscv_held(ssp));
1641 if (ssp->eeinfo_valid) {
1642 /* Already have good cached values */
1643 return (ssp->eeinfo_valid);
1645 ssp->eeprom_size =
1646 bscv_get8(ssp, chan_general, EBUS_IDX_EEPROM_SIZE_KB) * 1024;
1647 ssp->eventlog_start = bscv_get16(ssp, chan_general,
1648 EBUS_IDX_LOG_START_HI);
1651 * The log does not run to the end of the EEPROM because it is a
1652 * logical partition. The last 8K partition is reserved for FRUID
1653 * usage.
1655 ssp->eventlog_size = EBUS_LOG_END - ssp->eventlog_start;
1657 BSCV_TRACE(ssp, 'I', "bscv_window_setup", "eeprom size 0x%x log_start"
1658 " 0x%x log_size 0x%x", ssp->eeprom_size, ssp->eventlog_start,
1659 ssp->eventlog_size);
1661 if (bscv_faulty(ssp) || bscv_session_error(ssp)) {
1662 ssp->eeinfo_valid = B_FALSE;
1663 } else if ((ssp->eeprom_size == 0) ||
1664 (ssp->eventlog_start >= ssp->eeprom_size)) {
1665 /* Sanity check values */
1666 cmn_err(CE_WARN,
1667 "!bscv_window_setup: read invalid eeprom parameters");
1668 ssp->eeinfo_valid = B_FALSE;
1669 } else {
1670 ssp->eeinfo_valid = B_TRUE;
1673 BSCV_TRACE(ssp, 'I', "bscv_window_setup", "returning eeinfo_valid %s",
1674 ssp->eeinfo_valid ? "true" : "false");
1675 return (ssp->eeinfo_valid);
1679 * function - bscv_eerw
1680 * description - this routine reads/write data from/to the eeprom.
1681 * It takes care of setting the window on the eeprom correctly.
1682 * inputs - soft state ptr, eeprom offset, data buffer, size, read/write
1683 * outputs - B_TRUE if the eeprom is ok, B_FALSE if the eeprom is not OK.
1685 static int
1686 bscv_eerw(bscv_soft_state_t *ssp, uint32_t eeoffset, uint8_t *buf,
1687 unsigned size, boolean_t is_write)
1689 uint32_t blk_addr = eeoffset;
1690 unsigned remaining = size;
1691 uint8_t page_idx;
1692 uint8_t this_page;
1693 uint8_t blk_size;
1694 int res = 0;
1696 while (remaining > 0) {
1697 page_idx = blk_addr & 0xff;
1698 if ((page_idx + remaining) > 0x100) {
1699 blk_size = 0x100 - page_idx;
1700 } else {
1701 blk_size = remaining;
1704 /* Select correct eeprom page */
1705 this_page = blk_addr >> 8;
1706 bscv_put8(ssp, chan_eeprom, EBUS_IDX_EEPROM_PAGESEL, this_page);
1708 BSCV_TRACE(ssp, 'M', "lom_eerw",
1709 "%s data @0x%x.%02x, size 0x%x, 0x%x bytes remaining",
1710 is_write ? "writing" : "reading",
1711 this_page, page_idx, blk_size, remaining - blk_size);
1713 bscv_rep_rw8(ssp, chan_eeprom,
1714 buf, BSCVA(EBUS_CMD_SPACE_EEPROM, page_idx),
1715 blk_size, DDI_DEV_AUTOINCR, is_write);
1717 if (bscv_faulty(ssp) || bscv_session_error(ssp)) {
1718 res = EIO;
1719 break;
1722 remaining -= blk_size;
1723 blk_addr += blk_size;
1724 buf += blk_size;
1727 return (res);
1730 static boolean_t
1731 bscv_is_null_event(bscv_soft_state_t *ssp, lom_event_t *e)
1733 ASSERT(e != NULL);
1735 if (EVENT_DECODE_SUBSYS(e->ev_subsys) == EVENT_SUBSYS_NONE &&
1736 e->ev_event == EVENT_NONE) {
1738 * This marks a NULL event.
1740 BSCV_TRACE(ssp, 'E', "bscv_is_null_event",
1741 "EVENT_SUBSYS_NONE/EVENT_NONE null event");
1742 return (B_TRUE);
1743 } else if (e->ev_subsys == 0xff && e->ev_event == 0xff) {
1745 * Under some circumstances, we've seen all 1s to represent
1746 * a manually cleared event log at the BSC prompt. Only
1747 * a test/diagnosis environment is likely to show this.
1749 BSCV_TRACE(ssp, 'E', "bscv_is_null_event", "0xffff null event");
1750 return (B_TRUE);
1751 } else {
1753 * Not a NULL event.
1755 BSCV_TRACE(ssp, 'E', "bscv_is_null_event", "returning False");
1756 return (B_FALSE);
1761 * *********************************************************************
1762 * IOCTL Processing
1763 * *********************************************************************
1767 * function - bscv_ioctl
1768 * description - routine that acts as a high level manager for ioctls. It
1769 * calls the appropriate handler for ioctls on the alarm:mon and
1770 * alarm:ctl minor nodes respectively
1772 * Unsupported ioctls (now deprecated)
1773 * LOMIOCALCTL
1774 * LOMIOCALSTATE
1775 * LOMIOCCLEARLOG
1776 * LOMIOCCTL
1777 * LOMIOCCTL2
1778 * LOMIOCDAEMON
1779 * LOMIOCDMON
1780 * LOMIOCDOGCTL, TSIOCDOGCTL
1781 * LOMIOCDOGPAT, TSIOCDOGPAT
1782 * LOMIOCDOGTIME, TSIOCDOGTIME
1783 * LOMIOCEVENTLOG
1784 * LOMIOCEVNT
1785 * LOMIOCGETMASK
1786 * LOMIOCMPROG
1787 * LOMIOCNBMON, TSIOCNBMON
1788 * LOMIOCSLEEP
1789 * LOMIOCUNLOCK, TSIOCUNLOCK
1790 * LOMIOCWTMON, TSIOCWTMON
1792 * Supported ioctls
1793 * LOMIOCDOGSTATE, TSIOCDOGSTATE
1794 * LOMIOCPROG
1795 * LOMIOCPSUSTATE
1796 * LOMIOCFANSTATE
1797 * LOMIOCFLEDSTATE
1798 * LOMIOCINFO
1799 * LOMIOCMREAD
1800 * LOMIOCVOLTS
1801 * LOMIOCSTATS
1802 * LOMIOCTEMP
1803 * LOMIOCCONS
1804 * LOMIOCEVENTLOG2
1805 * LOMIOCINFO2
1806 * LOMIOCTEST
1807 * LOMIOCMPROG2
1808 * LOMIOCMREAD2
1810 * inputs - device number, command, user space arg, filemode, user
1811 * credentials, return value
1812 * outputs - the return value propagated back by the lower level routines.
1815 /*ARGSUSED*/
1816 static int
1817 bscv_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *cred, int *rvalp)
1819 bscv_soft_state_t *ssp;
1820 int instance;
1821 int res = 0;
1823 instance = DEVICETOINSTANCE(dev);
1824 ssp = ddi_get_soft_state(bscv_statep, instance);
1825 if (ssp == NULL) {
1826 return (ENXIO);
1830 * The Combined Switch and Service Processor takes care of configuration
1831 * and control. The CSSP tells the BSC chip about it; therefore the
1832 * bscv driver doesn't send such configuration and control to the BSC.
1833 * Additionally Watchdog configuration is no longer done from userland
1834 * lom.
1836 switch (cmd) {
1837 case LOMIOCALCTL:
1838 case LOMIOCALSTATE:
1839 case LOMIOCCLEARLOG:
1840 case LOMIOCCTL:
1841 case LOMIOCCTL2:
1842 case LOMIOCDAEMON:
1843 case LOMIOCDMON:
1844 case LOMIOCDOGCTL:
1845 case LOMIOCDOGPAT:
1846 case LOMIOCDOGTIME:
1847 case LOMIOCEVENTLOG:
1848 case LOMIOCEVNT:
1849 case LOMIOCGETMASK:
1850 case LOMIOCMPROG:
1851 case LOMIOCNBMON:
1852 case LOMIOCSLEEP:
1853 case LOMIOCUNLOCK:
1854 case LOMIOCWTMON:
1855 return (ENOTSUP);
1859 * set the default result.
1862 *rvalp = 0;
1864 if (ssp->cssp_prog) {
1865 return (ENXIO);
1866 } else if ((ssp->prog_mode_only || ssp->programming) &&
1867 cmd != LOMIOCPROG) {
1868 return (ENXIO);
1872 * Check that the caller has appropriate access permissions
1873 * (FWRITE set in mode) for those ioctls which change lom
1874 * state
1876 if (!(mode & FWRITE)) {
1877 switch (cmd) {
1878 case LOMIOCMPROG2:
1879 case LOMIOCMREAD2:
1880 case LOMIOCPROG:
1881 case LOMIOCTEST:
1882 return (EACCES);
1883 /* NOTREACHED */
1884 default:
1885 /* Does not require write access */
1886 break;
1890 switch (cmd) {
1892 case LOMIOCDOGSTATE:
1893 res = bscv_ioc_dogstate(ssp, arg, mode);
1894 break;
1896 case LOMIOCPROG:
1897 res = bscv_prog(ssp, arg, mode);
1898 break;
1900 case LOMIOCPSUSTATE:
1901 res = bscv_ioc_psustate(ssp, arg, mode);
1902 break;
1904 case LOMIOCFANSTATE:
1905 res = bscv_ioc_fanstate(ssp, arg, mode);
1906 break;
1908 case LOMIOCFLEDSTATE:
1909 res = bscv_ioc_fledstate(ssp, arg, mode);
1910 break;
1912 case LOMIOCLEDSTATE:
1913 res = bscv_ioc_ledstate(ssp, arg, mode);
1914 break;
1916 case LOMIOCINFO:
1917 res = bscv_ioc_info(ssp, arg, mode);
1918 break;
1920 case LOMIOCMREAD:
1921 res = bscv_ioc_mread(ssp, arg, mode);
1922 break;
1924 case LOMIOCVOLTS:
1925 res = bscv_ioc_volts(ssp, arg, mode);
1926 break;
1928 case LOMIOCSTATS:
1929 res = bscv_ioc_stats(ssp, arg, mode);
1930 break;
1932 case LOMIOCTEMP:
1933 res = bscv_ioc_temp(ssp, arg, mode);
1934 break;
1936 case LOMIOCCONS:
1937 res = bscv_ioc_cons(ssp, arg, mode);
1938 break;
1940 case LOMIOCEVENTLOG2:
1941 res = bscv_ioc_eventlog2(ssp, arg, mode);
1942 break;
1944 case LOMIOCINFO2:
1945 res = bscv_ioc_info2(ssp, arg, mode);
1946 break;
1948 case LOMIOCTEST:
1949 res = bscv_ioc_test(ssp, arg, mode);
1950 break;
1952 case LOMIOCMPROG2:
1953 res = bscv_ioc_mprog2(ssp, arg, mode);
1954 break;
1956 case LOMIOCMREAD2:
1957 res = bscv_ioc_mread2(ssp, arg, mode);
1958 break;
1960 default:
1961 BSCV_TRACE(ssp, 'I', "bscv_ioctl", "Invalid IOCTL 0x%x", cmd);
1962 res = EINVAL;
1964 return (res);
1968 * LOMIOCDOGSTATE
1969 * TSIOCDOGSTATE - indicate whether the alarm watchdog and reset
1970 * circuitry is enabled or not.
1972 static int
1973 bscv_ioc_dogstate(bscv_soft_state_t *ssp, intptr_t arg, int mode)
1975 lom_dogstate_t dogstate;
1976 uint8_t dogval;
1977 int res = 0;
1979 dogval = bscv_get8_locked(ssp, chan_general, EBUS_IDX_WDOG_CTRL, &res);
1980 dogstate.dog_enable = (dogval & EBUS_WDOG_ENABLE) ? 1 : 0;
1981 dogstate.reset_enable = (dogval & EBUS_WDOG_RST) ? 1 : 0;
1982 dogstate.dog_timeout = bscv_get8_locked(ssp, chan_general,
1983 EBUS_IDX_WDOG_TIME, &res);
1985 if ((res == 0) &&
1986 (ddi_copyout((caddr_t)&dogstate,
1987 (caddr_t)arg, sizeof (dogstate), mode) < 0)) {
1988 res = EFAULT;
1990 return (res);
1994 * LOMIOCPSUSTATE - returns full information for 4 PSUs. All this
1995 * information is available from two bytes of LOMlite RAM, but if
1996 * on the first read it is noticed that two or more of the PSUs are
1997 * not present only 1 byte will be read subsequently.
1999 static int
2000 bscv_ioc_psustate(bscv_soft_state_t *ssp, intptr_t arg, int mode)
2002 lom_psudata_t psudata;
2003 uint8_t psustat;
2004 int i;
2005 int res = 0;
2007 for (i = 0; i < MAX_PSUS; i++) {
2008 psustat = bscv_get8_locked(ssp, chan_general,
2009 EBUS_IDX_PSU1_STAT + i, &res);
2010 psudata.fitted[i] = psustat & EBUS_PSU_PRESENT;
2011 psudata.output[i] = psustat & EBUS_PSU_OUTPUT;
2012 psudata.supplyb[i] = psustat & EBUS_PSU_INPUTB;
2013 psudata.supplya[i] = psustat & EBUS_PSU_INPUTA;
2014 psudata.standby[i] = psustat & EBUS_PSU_STANDBY;
2017 if (ddi_copyout((caddr_t)&psudata, (caddr_t)arg, sizeof (psudata),
2018 mode) < 0) {
2019 res = EFAULT;
2021 return (res);
2025 * LOMIOCFANSTATE - returns full information including speed for 4
2026 * fans and the minimum and maximum operating speeds for each fan as
2027 * stored in the READ ONLY EEPROM data. As this EEPROM data is set
2028 * at manufacture time, this data should only be read by the driver
2029 * once and stored locally.
2031 static int
2032 bscv_ioc_fanstate(bscv_soft_state_t *ssp, intptr_t arg, int mode)
2034 lom_fandata_t fandata;
2035 int numfans;
2036 int i;
2037 int res = 0;
2039 bzero(&fandata, sizeof (lom_fandata_t));
2040 numfans = EBUS_CONFIG_NFAN_DEC(bscv_get8_locked(ssp,
2041 chan_general, EBUS_IDX_CONFIG, &res));
2042 for (i = 0; (i < numfans) && (res == 0); i++) {
2043 if (ssp->fanspeed[i] != LOM_FAN_NOT_PRESENT) {
2044 fandata.fitted[i] = 1;
2045 fandata.speed[i] = ssp->fanspeed[i];
2046 fandata.minspeed[i] = bscv_get8_cached(ssp,
2047 EBUS_IDX_FAN1_LOW + i);
2051 if ((res == 0) &&
2052 (ddi_copyout((caddr_t)&fandata, (caddr_t)arg, sizeof (fandata),
2053 mode) < 0)) {
2054 res = EFAULT;
2056 return (res);
2060 * LOMIOCFLEDSTATE - returns the state of the fault LED
2062 static int
2063 bscv_ioc_fledstate(bscv_soft_state_t *ssp, intptr_t arg, int mode)
2065 lom_fled_info_t fled_info;
2066 uint8_t fledstate;
2067 int res = 0;
2069 fledstate = bscv_get8_locked(ssp, chan_general, EBUS_IDX_ALARM, &res);
2071 /* Decode of 0x0F is off and 0x00-0x07 is on. */
2072 if (EBUS_ALARM_LED_DEC(fledstate) == 0x0F) {
2073 fled_info.on = 0;
2074 } else {
2075 /* has +1 here - not 2 as in the info ioctl */
2076 fled_info.on = EBUS_ALARM_LED_DEC(fledstate) + 1;
2078 if ((res == 0) &&
2079 (ddi_copyout((caddr_t)&fled_info, (caddr_t)arg,
2080 sizeof (fled_info), mode) < 0)) {
2081 res = EFAULT;
2083 return (res);
2087 * LOMIOCLEDSTATE - returns the state of the requested LED
2089 static int
2090 bscv_ioc_ledstate(bscv_soft_state_t *ssp, intptr_t arg, int mode)
2092 lom_led_state_t led_state;
2093 int fw_led_state;
2094 int res = 0;
2096 /* copy in arguments supplied */
2097 if (ddi_copyin((caddr_t)arg, (caddr_t)&led_state,
2098 sizeof (lom_led_state_t), mode) < 0) {
2099 return (EFAULT);
2103 * check if led index is -1, if so set it to max value for
2104 * this implementation.
2106 if (led_state.index == -1) {
2107 led_state.index = MAX_LED_ID;
2110 /* is the index in a valid range */
2111 if ((led_state.index > MAX_LED_ID) || (led_state.index < 0)) {
2112 led_state.state = LOM_LED_OUTOFRANGE;
2113 } else {
2114 /* read the relevant led info */
2115 fw_led_state = bscv_get8_locked(ssp, chan_general,
2116 EBUS_IDX_LED1_STATUS + led_state.index, &res);
2118 /* set the state values accordingly */
2119 switch (fw_led_state) {
2120 case LOM_LED_STATE_OFF:
2121 led_state.state = LOM_LED_OFF;
2122 led_state.colour = LOM_LED_COLOUR_ANY;
2123 break;
2124 case LOM_LED_STATE_ON_STEADY:
2125 led_state.state = LOM_LED_ON;
2126 led_state.colour = LOM_LED_COLOUR_ANY;
2127 break;
2128 case LOM_LED_STATE_ON_FLASHING:
2129 case LOM_LED_STATE_ON_SLOWFLASH:
2130 led_state.state = LOM_LED_BLINKING;
2131 led_state.colour = LOM_LED_COLOUR_ANY;
2132 break;
2133 case LOM_LED_STATE_NOT_PRESENT:
2134 led_state.state = LOM_LED_NOT_IMPLEMENTED;
2135 led_state.colour = LOM_LED_COLOUR_NONE;
2136 break;
2137 case LOM_LED_STATE_INACCESSIBLE:
2138 case LOM_LED_STATE_STANDBY:
2139 default:
2140 led_state.state = LOM_LED_ACCESS_ERROR;
2141 led_state.colour = LOM_LED_COLOUR_NONE;
2142 break;
2145 /* set the label info */
2146 (void) strcpy(led_state.label,
2147 ssp->led_names[led_state.index]);
2150 /* copy out lom_state */
2151 if ((res == 0) &&
2152 (ddi_copyout((caddr_t)&led_state, (caddr_t)arg,
2153 sizeof (lom_led_state_t), mode) < 0)) {
2154 res = EFAULT;
2156 return (res);
2160 * LOMIOCINFO - returns with a structure containing any information
2161 * stored on the LOMlite which a user should not need to access but
2162 * may be useful for diagnostic problems. The structure contains: the
2163 * serial escape character, alarm3 mode, version and checksum read from
2164 * RAM and the Product revision and ID read from EEPROM.
2166 static int
2167 bscv_ioc_info(bscv_soft_state_t *ssp, intptr_t arg, int mode)
2169 lom_info_t info;
2170 int i;
2171 uint16_t csum;
2172 int res = 0;
2174 info.ser_char = bscv_get8_locked(ssp, chan_general, EBUS_IDX_ESCAPE,
2175 &res);
2176 info.a3mode = WATCHDOG;
2177 info.fver = bscv_get8_locked(ssp, chan_general, EBUS_IDX_FW_REV, &res);
2178 csum = bscv_get8_locked(ssp, chan_general, EBUS_IDX_CHECK_HI, &res)
2179 << 8;
2180 csum |= bscv_get8_locked(ssp, chan_general, EBUS_IDX_CHECK_LO, &res);
2181 info.fchksum = csum;
2182 info.prod_rev = bscv_get8_locked(ssp, chan_general, EBUS_IDX_MODEL_REV,
2183 &res);
2184 for (i = 0; i < sizeof (info.prod_id); i++) {
2185 info.prod_id[i] = bscv_get8_locked(ssp,
2186 chan_general, EBUS_IDX_MODEL_ID1 + i, &res);
2188 if (bscv_get8_locked(ssp, chan_general, EBUS_IDX_ALARM, &res) &
2189 EBUS_ALARM_NOEVENTS) {
2190 info.events = OFF;
2191 } else {
2192 info.events = ON;
2195 if ((res == 0) &&
2196 (ddi_copyout((caddr_t)&info, (caddr_t)arg, sizeof (info),
2197 mode) < 0)) {
2198 res = EFAULT;
2200 return (res);
2204 * LOMIOCMREAD - used to query the LOMlite configuration parameters
2206 static int
2207 bscv_ioc_mread(bscv_soft_state_t *ssp, intptr_t arg, int mode)
2209 lom_mprog_t mprog;
2210 int i;
2211 int fanz;
2212 int res = 0;
2214 for (i = 0; i < sizeof (mprog.mod_id); i++) {
2215 mprog.mod_id[i] = bscv_get8_locked(ssp, chan_general,
2216 EBUS_IDX_MODEL_ID1 + i, &res);
2218 mprog.mod_rev = bscv_get8_locked(ssp, chan_general, EBUS_IDX_MODEL_REV,
2219 &res);
2220 mprog.config = bscv_get8_locked(ssp, chan_general, EBUS_IDX_CONFIG,
2221 &res);
2223 /* Read the fan calibration values */
2224 fanz = sizeof (mprog.fanhz) / sizeof (mprog.fanhz[0]);
2225 for (i = 0; i < fanz; i++) {
2226 mprog.fanhz[i] = bscv_get8_cached(ssp,
2227 EBUS_IDX_FAN1_CAL + i);
2228 mprog.fanmin[i] = bscv_get8_cached(ssp,
2229 EBUS_IDX_FAN1_LOW + i);
2232 if ((res == 0) &&
2233 (ddi_copyout((caddr_t)&mprog, (caddr_t)arg, sizeof (mprog),
2234 mode) < 0)) {
2235 res = EFAULT;
2237 return (res);
2241 * LOMIOCVOLTS
2243 static int
2244 bscv_ioc_volts(bscv_soft_state_t *ssp, intptr_t arg, int mode)
2246 int i;
2247 uint16_t supply;
2248 int res = 0;
2250 supply = (bscv_get8_locked(ssp, chan_general, EBUS_IDX_SUPPLY_HI, &res)
2251 << 8) | bscv_get8_locked(ssp, chan_general, EBUS_IDX_SUPPLY_LO,
2252 &res);
2254 for (i = 0; i < ssp->volts.num; i++) {
2255 ssp->volts.status[i] = (supply >> i) & 1;
2258 if ((res == 0) &&
2259 (ddi_copyout((caddr_t)&ssp->volts, (caddr_t)arg,
2260 sizeof (ssp->volts), mode) < 0)) {
2261 res = EFAULT;
2263 return (res);
2267 * LOMIOCSTATS
2269 static int
2270 bscv_ioc_stats(bscv_soft_state_t *ssp, intptr_t arg, int mode)
2272 int i;
2273 uint8_t status;
2274 int res = 0;
2276 status = bscv_get8_locked(ssp, chan_general, EBUS_IDX_CBREAK_STATUS,
2277 &res);
2278 for (i = 0; i < ssp->sflags.num; i++) {
2279 ssp->sflags.status[i] = (int)((status >> i) & 1);
2282 if ((res == 0) &&
2283 (ddi_copyout((caddr_t)&ssp->sflags, (caddr_t)arg,
2284 sizeof (ssp->sflags), mode) < 0)) {
2285 res = EFAULT;
2287 return (res);
2291 * LOMIOCTEMP
2293 static int
2294 bscv_ioc_temp(bscv_soft_state_t *ssp, intptr_t arg, int mode)
2296 int i;
2297 int idx;
2298 uint8_t status_ov;
2299 lom_temp_t temps;
2300 int res = 0;
2302 bzero(&temps, sizeof (temps));
2303 idx = 0;
2304 for (i = 0; i < ssp->temps.num; i++) {
2305 if (ssp->temps.temp[i] != LOM_TEMP_STATE_NOT_PRESENT) {
2306 temps.temp[idx] = ssp->temps.temp[i];
2307 bcopy(ssp->temps.name[i], temps.name[idx],
2308 sizeof (temps.name[idx]));
2309 temps.warning[idx] = ssp->temps.warning[i];
2310 temps.shutdown[idx] = ssp->temps.shutdown[i];
2311 idx++;
2314 temps.num = idx;
2316 bcopy(ssp->temps.name_ov, temps.name_ov, sizeof (temps.name_ov));
2317 temps.num_ov = ssp->temps.num_ov;
2318 status_ov = bscv_get8_locked(ssp, chan_general, EBUS_IDX_OTEMP_STATUS,
2319 &res);
2320 for (i = 0; i < ssp->temps.num_ov; i++) {
2321 ssp->temps.status_ov[i] = (status_ov >> i) & 1;
2324 if ((res == 0) &&
2325 (ddi_copyout((caddr_t)&temps, (caddr_t)arg, sizeof (temps),
2326 mode) < 0)) {
2327 res = EFAULT;
2329 return (res);
2333 * LOMIOCCONS
2335 static int
2336 bscv_ioc_cons(bscv_soft_state_t *ssp, intptr_t arg, int mode)
2338 lom_cbuf_t cbuf;
2339 int datasize;
2340 int res = 0;
2342 bzero(&cbuf, sizeof (cbuf));
2343 datasize = EBUS_IDX1_CONS_BUF_END - EBUS_IDX1_CONS_BUF_START + 1;
2344 /* Ensure that we do not overfill cbuf and that it is NUL terminated */
2345 if (datasize > (sizeof (cbuf) - 1)) {
2346 datasize = sizeof (cbuf) - 1;
2348 bscv_rep_get8_locked(ssp, chan_general, (uint8_t *)cbuf.lrbuf,
2349 BSCVA(EBUS_CMD_SPACE1, (EBUS_IDX1_CONS_BUF_END - datasize + 1)),
2350 datasize, DDI_DEV_AUTOINCR, &res);
2351 /* This is always within the array due to the checks above */
2352 cbuf.lrbuf[datasize] = '\0';
2354 if ((res == 0) &&
2355 (ddi_copyout((caddr_t)&cbuf, (caddr_t)arg, sizeof (cbuf),
2356 mode) < 0)) {
2357 res = EFAULT;
2359 return (res);
2363 * LOMIOCEVENTLOG2
2365 static int
2366 bscv_ioc_eventlog2(bscv_soft_state_t *ssp, intptr_t arg, int mode)
2368 lom_eventlog2_t *eventlog2;
2369 int events_recorded;
2370 int level;
2371 uint16_t next_offset;
2372 lom_event_t event;
2373 int res = 0;
2375 eventlog2 = (lom_eventlog2_t *)kmem_zalloc(sizeof (*eventlog2),
2376 KM_SLEEP);
2379 * First get number of events and level requested.
2382 if (ddi_copyin((caddr_t)arg, (caddr_t)eventlog2,
2383 sizeof (lom_eventlog2_t), mode) < 0) {
2384 kmem_free((void *)eventlog2, sizeof (*eventlog2));
2385 return (EFAULT);
2388 bscv_enter(ssp);
2391 * OK we have full private access to the LOM now so loop
2392 * over the eventlog addr spaces until we get the required
2393 * number of events.
2396 if (!bscv_window_setup(ssp)) {
2397 res = EIO;
2398 bscv_exit(ssp);
2399 kmem_free((void *)eventlog2, sizeof (*eventlog2));
2400 return (res);
2404 * Read count, next event ptr MSB,LSB. Note a read of count
2405 * is necessary to latch values for the next event ptr
2407 (void) bscv_get8(ssp, chan_general, EBUS_IDX_UNREAD_EVENTS);
2408 next_offset = bscv_get16(ssp, chan_general, EBUS_IDX_LOG_PTR_HI);
2409 BSCV_TRACE(ssp, 'I', "bscv_ioc_eventlog2", "log_ptr_hi 0x%x",
2410 next_offset);
2412 events_recorded = 0;
2414 while (events_recorded < eventlog2->num) {
2416 * Working backwards - read an event at a time.
2417 * next_offset is one event on from where we want to be!
2418 * Decrement next_offset and maybe wrap to the end of the
2419 * buffer.
2420 * Note the unsigned arithmetic, so check values first!
2422 if (next_offset <= ssp->eventlog_start) {
2423 /* Wrap to the end of the buffer */
2424 next_offset = ssp->eventlog_start + ssp->eventlog_size;
2425 BSCV_TRACE(ssp, 'I', "bscv_ioc_eventlog2", "wrapping"
2426 " around to end of buffer; next_offset 0x%x",
2427 next_offset);
2429 next_offset -= sizeof (event);
2431 if (bscv_eerw(ssp, next_offset, (uint8_t *)&event,
2432 sizeof (event), B_FALSE /* read */) != 0) {
2433 /* Fault reading data - stop */
2434 BSCV_TRACE(ssp, 'I', "bscv_ioc_eventlog2", "read"
2435 " failure for offset 0x%x", next_offset);
2436 res = EIO;
2437 break;
2440 if (bscv_is_null_event(ssp, &event)) {
2442 * No more events in this log so give up.
2444 BSCV_TRACE(ssp, 'I', "bscv_ioc_eventlog2", "no more"
2445 " events left at offset 0x%x", next_offset);
2446 break;
2450 * Are we interested in this event
2453 level = bscv_level_of_event(&event);
2454 if (level <= eventlog2->level) {
2455 /* Arggh why the funny byte ordering 3, 2, 0, 1 */
2456 eventlog2->code[events_recorded] =
2457 ((unsigned)event.ev_event |
2458 ((unsigned)event.ev_subsys << 8) |
2459 ((unsigned)event.ev_resource << 16) |
2460 ((unsigned)event.ev_detail << 24));
2462 eventlog2->time[events_recorded] =
2463 ((unsigned)event.ev_data[0] |
2464 ((unsigned)event.ev_data[1] << 8) |
2465 ((unsigned)event.ev_data[3] << 16) |
2466 ((unsigned)event.ev_data[2] << 24));
2468 bscv_build_eventstring(ssp,
2469 &event, eventlog2->string[events_recorded],
2470 eventlog2->string[events_recorded] +
2471 sizeof (eventlog2->string[events_recorded]));
2472 events_recorded++;
2476 eventlog2->num = events_recorded;
2478 bscv_exit(ssp);
2480 if ((res == 0) &&
2481 (ddi_copyout((caddr_t)eventlog2, (caddr_t)arg,
2482 sizeof (lom_eventlog2_t), mode) < 0)) {
2483 res = EFAULT;
2486 kmem_free((void *)eventlog2, sizeof (lom_eventlog2_t));
2487 return (res);
2491 * LOMIOCINFO2
2493 static int
2494 bscv_ioc_info2(bscv_soft_state_t *ssp, intptr_t arg, int mode)
2496 lom2_info_t info2;
2497 int i;
2498 uint16_t csum;
2499 int res = 0;
2501 bzero(&info2, sizeof (info2));
2503 (void) strncpy(info2.escape_chars, ssp->escape_chars,
2504 sizeof (info2.escape_chars));
2505 info2.serial_events = ssp->reporting_level | ssp->serial_reporting;
2506 info2.a3mode = WATCHDOG;
2508 info2.fver = bscv_get8_locked(ssp, chan_general, EBUS_IDX_FW_REV, &res);
2509 csum = bscv_get8_locked(ssp, chan_general, EBUS_IDX_CHECK_HI, &res)
2510 << 8;
2511 csum |= bscv_get8_locked(ssp, chan_general, EBUS_IDX_CHECK_LO, &res);
2512 info2.fchksum = csum;
2513 info2.prod_rev = bscv_get8_locked(ssp, chan_general,
2514 EBUS_IDX_MODEL_REV, &res);
2515 for (i = 0; i < sizeof (info2.prod_id); i++) {
2516 info2.prod_id[i] = bscv_get8_locked(ssp, chan_general,
2517 EBUS_IDX_MODEL_ID1 + i, &res);
2519 info2.serial_config = bscv_get8_locked(ssp, chan_general,
2520 EBUS_IDX_SER_TIMEOUT, &res);
2521 if (bscv_get8_locked(ssp, chan_general, EBUS_IDX_CONFIG_MISC, &res) &
2522 EBUS_CONFIG_MISC_SECURITY_ENABLED) {
2523 info2.serial_config |= LOM_SER_SECURITY;
2525 if (bscv_get8_locked(ssp, chan_general, EBUS_IDX_CONFIG_MISC, &res) &
2526 EBUS_CONFIG_MISC_AUTO_CONSOLE) {
2527 info2.serial_config |= LOM_SER_RETURN;
2529 if (bscv_get8_locked(ssp, chan_general, EBUS_IDX_WDOG_CTRL, &res) &
2530 EBUS_WDOG_BREAK_DISABLE) {
2531 info2.serial_config |= LOM_DISABLE_WDOG_BREAK;
2533 info2.baud_rate = bscv_get8_locked(ssp, chan_general,
2534 EBUS_IDX_SER_BAUD, &res);
2535 info2.serial_hw_config =
2536 ((int)bscv_get8_locked(ssp, chan_general,
2537 EBUS_IDX_SER_CHARMODE, &res) |
2538 ((int)bscv_get8_locked(ssp, chan_general,
2539 EBUS_IDX_SER_FLOWCTL, &res) << 8) |
2540 ((int)bscv_get8_locked(ssp, chan_general,
2541 EBUS_IDX_SER_MODEMTYPE, &res) << 16));
2544 * There is no phone home support on the blade platform. We hardcode
2545 * FALSE and NUL for config and script respectively.
2547 info2.phone_home_config = B_FALSE;
2548 info2.phone_home_script[0] = '\0';
2550 for (i = 0; i < ssp->num_fans; i++) {
2551 (void) strcpy(info2.fan_names[i], ssp->fan_names[i]);
2554 if ((res == 0) &&
2555 (ddi_copyout((caddr_t)&info2, (caddr_t)arg, sizeof (info2),
2556 mode) < 0)) {
2557 res = EFAULT;
2559 return (res);
2563 * LOMIOCTEST
2565 static int
2566 bscv_ioc_test(bscv_soft_state_t *ssp, intptr_t arg, int mode)
2568 uint32_t test;
2569 uint8_t testnum;
2570 uint8_t testarg;
2571 int res = 0;
2573 if (ddi_copyin((caddr_t)arg, (caddr_t)&test, sizeof (test),
2574 mode) < 0) {
2575 return (EFAULT);
2579 * Extract num iterations.
2582 testarg = (test & 0xff00) >> 8;
2583 testnum = test & 0xff;
2585 BSCV_TRACE(ssp, 'F', "bscv_ioc_test",
2586 "LOMIOCTEST data 0x%x (test 0x%x, arg 0x%x)",
2587 test, (EBUS_IDX_SELFTEST0 + testnum), testarg);
2589 switch (testnum + EBUS_IDX_SELFTEST0) {
2590 default:
2591 /* Invalid test */
2592 res = EINVAL;
2593 break;
2595 case EBUS_IDX_SELFTEST0: /* power on self-test result */
2596 case EBUS_IDX_SELFTEST1: /* not used currently */
2597 case EBUS_IDX_SELFTEST2: /* not used currently */
2598 case EBUS_IDX_SELFTEST3: /* not used currently */
2599 case EBUS_IDX_SELFTEST4: /* not used currently */
2600 case EBUS_IDX_SELFTEST5: /* not used currently */
2601 case EBUS_IDX_SELFTEST6: /* LED self-test */
2602 case EBUS_IDX_SELFTEST7: /* platform-specific tests */
2603 /* Run the test */
2605 /* Stop other things and then run the test */
2606 bscv_enter(ssp);
2609 * Then we simply write the argument to the relevant register
2610 * and wait for the return code.
2612 bscv_put8(ssp, chan_general,
2613 EBUS_IDX_SELFTEST0 + testnum, testarg);
2614 if (bscv_faulty(ssp)) {
2615 res = EIO;
2616 } else {
2617 /* Get hold of the SunVTS error code */
2618 test = bscv_retcode(ssp);
2621 bscv_exit(ssp);
2622 break;
2625 BSCV_TRACE(ssp, 'F', "bscv_ioc_test",
2626 "LOMIOCTEST status 0x%x, res 0x%x", test, res);
2627 if ((res == 0) &&
2628 (ddi_copyout((caddr_t)&test, (caddr_t)arg, sizeof (test),
2629 mode) < 0)) {
2630 res = EFAULT;
2632 return (res);
2636 * LOMIOCMPROG2
2638 static int
2639 bscv_ioc_mprog2(bscv_soft_state_t *ssp, intptr_t arg, int mode)
2641 lom2_mprog_t mprog2;
2642 uint32_t base_addr;
2643 uint32_t data_size;
2644 uint32_t eeprom_size;
2645 int res = 0;
2647 if (ddi_copyin((caddr_t)arg, (caddr_t)&mprog2, sizeof (mprog2),
2648 mode) < 0) {
2649 return (EFAULT);
2653 * Note that originally this was accessed as 255 byte pages
2654 * in address spaces 240-255. We have to emulate this behaviour.
2656 if ((mprog2.addr_space < 240) || (mprog2.addr_space > 255)) {
2657 return (EINVAL);
2660 bscv_enter(ssp);
2662 /* Calculate required data location */
2663 data_size = 255;
2664 base_addr = (mprog2.addr_space - 240) * data_size;
2666 eeprom_size = bscv_get8(ssp, chan_general, EBUS_IDX_EEPROM_SIZE_KB) *
2667 1024;
2669 if (bscv_faulty(ssp)) {
2670 bscv_exit(ssp);
2671 return (EIO);
2672 } else if ((base_addr + data_size) > eeprom_size) {
2673 BSCV_TRACE(ssp, 'M', "bscv_ioc_mprog2",
2674 "Request extends past end of eeprom");
2675 bscv_exit(ssp);
2676 return (ENXIO);
2679 bscv_put8(ssp, chan_general, EBUS_IDX_CMD_RES, EBUS_CMD_UNLOCK1);
2680 if (bscv_faulty(ssp)) {
2681 BSCV_TRACE(ssp, 'M', "bscv_ioc_mprog2", "ML1 Write failed");
2682 bscv_exit(ssp);
2683 return (EIO);
2686 bscv_put8(ssp, chan_general, EBUS_IDX_CMD_RES, EBUS_CMD_UNLOCK2);
2687 if (bscv_faulty(ssp)) {
2688 BSCV_TRACE(ssp, 'M', "bscv_ioc_mprog2", "ML2 Write failed");
2689 bscv_exit(ssp);
2690 return (EIO);
2693 if (bscv_eerw(ssp, base_addr, &mprog2.data[0],
2694 data_size, B_TRUE /* write */) != 0) {
2695 res = EIO;
2698 /* Read a probe key to release the lock. */
2699 (void) bscv_get8(ssp, chan_general, EBUS_IDX_PROBEAA);
2701 if (bscv_faulty(ssp)) {
2702 res = EIO;
2704 bscv_exit(ssp);
2706 return (res);
2710 * LOMIOCMREAD2
2712 static int
2713 bscv_ioc_mread2(bscv_soft_state_t *ssp, intptr_t arg, int mode)
2715 lom2_mprog_t mprog2;
2716 uint32_t base_addr;
2717 uint32_t data_size;
2718 uint32_t eeprom_size;
2719 int res = 0;
2721 if (ddi_copyin((caddr_t)arg, (caddr_t)&mprog2, sizeof (mprog2),
2722 mode) < 0) {
2723 return (EFAULT);
2727 * Need to stop the queue and then just read
2728 * the bytes blind to the relevant addresses.
2729 * Note that originally this was accessed as 255 byte pages
2730 * in address spaces 240-255. We have to emulate this behaviour.
2732 if ((mprog2.addr_space < 240) || (mprog2.addr_space > 255)) {
2733 return (EINVAL);
2736 bscv_enter(ssp);
2738 /* Calculate required data location */
2739 data_size = 255;
2740 base_addr = (mprog2.addr_space - 240) * data_size;
2741 eeprom_size = bscv_get8(ssp, chan_general, EBUS_IDX_EEPROM_SIZE_KB) *
2742 1024;
2744 if (bscv_faulty(ssp)) {
2745 bscv_exit(ssp);
2746 return (EIO);
2747 } else if ((base_addr + data_size) > eeprom_size) {
2748 BSCV_TRACE(ssp, 'M', "bscv_ioc_mread2",
2749 "Request extends past end of eeprom");
2750 bscv_exit(ssp);
2751 return (ENXIO);
2754 if (bscv_eerw(ssp, base_addr, &mprog2.data[0],
2755 data_size, B_FALSE /* read */) != 0) {
2756 res = EIO;
2759 if (bscv_faulty(ssp)) {
2760 res = EIO;
2762 bscv_exit(ssp);
2764 if ((res == 0) &&
2765 (ddi_copyout((caddr_t)&mprog2, (caddr_t)arg, sizeof (mprog2),
2766 mode) < 0)) {
2767 res = EFAULT;
2769 return (res);
2772 static void
2773 bscv_get_state_changes(bscv_soft_state_t *ssp)
2775 int i = STATUS_READ_LIMIT;
2776 uint8_t change;
2777 uint8_t detail;
2779 ASSERT(bscv_held(ssp));
2781 while (i-- && !ssp->cssp_prog) {
2782 /* Are there any changes to process? */
2783 change = bscv_get8(ssp, chan_general, EBUS_IDX_STATE_CHNG);
2784 change &= EBUS_STATE_MASK;
2785 if (!change)
2786 break;
2788 /* Clarify the pending change */
2789 detail = bscv_get8(ssp, chan_general, EBUS_IDX_EVENT_DETAIL);
2791 bscv_status(ssp, change, detail);
2794 BSCV_TRACE(ssp, 'D', "bscv_get_state_changes",
2795 "loop index %d ssp->cssp_prog 0x%x", i, ssp->cssp_prog);
2799 * *********************************************************************
2800 * Event Processing
2801 * *********************************************************************
2805 * function - bscv_event_daemon
2806 * description - Perform periodic lom tasks in a separate thread.
2807 * inputs - LOM soft state structure pointer
2808 * outputs - none.
2810 static void
2811 bscv_event_daemon(void *arg)
2813 bscv_soft_state_t *ssp = (void *)arg;
2814 boolean_t do_events;
2815 boolean_t do_status;
2816 boolean_t do_nodename;
2817 boolean_t do_watchdog;
2818 uint32_t async_reg;
2819 uint32_t fault;
2820 clock_t poll_period = BSC_EVENT_POLL_NORMAL;
2821 int fault_cnt = 0;
2823 BSCV_TRACE(ssp, 'D', "bscv_event_daemon",
2824 "bscv_event_daemon: started");
2826 /* Acquire task daemon lock. */
2827 mutex_enter(&ssp->task_mu);
2829 ssp->task_flags |= TASK_ALIVE_FLG;
2831 for (;;) {
2832 if ((ssp->task_flags & TASK_STOP_FLG) != 0) {
2833 /* Stop request seen - terminate */
2834 break;
2836 if ((ssp->task_flags & TASK_PAUSE_FLG) == 0) {
2837 /* Poll for events reported to the nexus */
2838 mutex_exit(&ssp->task_mu);
2839 /* Probe and Check faults */
2840 bscv_enter(ssp);
2841 async_reg = bscv_probe(ssp, chan_general, &fault);
2842 BSCV_TRACE(ssp, 'D', "bscv_event_daemon",
2843 "process event: async_reg 0x%x, fault 0x%x",
2844 async_reg, fault);
2846 if (!fault) {
2847 /* Treat non-fault conditions */
2849 if (ssp->cssp_prog || ssp->prog_mode_only) {
2851 * The BSC has become available again.
2853 fault_cnt = 0;
2854 ssp->cssp_prog = B_FALSE;
2855 ssp->prog_mode_only = B_FALSE;
2856 (void) bscv_attach_common(ssp);
2857 } else if (fault_cnt > 0) {
2858 /* Previous fault has cleared */
2859 bscv_clear_fault(ssp);
2860 fault_cnt = 0;
2861 cmn_err(CE_WARN,
2862 "!bscv_event_daemon previous fault "
2863 "cleared.");
2864 } else if (bscv_faulty(ssp)) {
2865 /* Previous fault has cleared */
2866 bscv_clear_fault(ssp);
2867 /* Sleep to avoid busy waiting */
2868 ssp->event_sleep = B_TRUE;
2870 poll_period = BSC_EVENT_POLL_NORMAL;
2872 if (async_reg) {
2873 ssp->status_change = B_TRUE;
2874 ssp->event_waiting = B_TRUE;
2876 } else if (ssp->cssp_prog) {
2878 * Expect radio silence or error values
2879 * when the CSSP is upgrading the BSC firmware
2880 * so throw away any fault indication.
2882 fault = B_FALSE;
2883 } else if (fault_cnt == BSC_PROBE_FAULT_LIMIT) {
2884 /* Count previous faults and maybe fail */
2885 /* Declare the lom broken */
2886 bscv_set_fault(ssp);
2887 poll_period = BSC_EVENT_POLL_FAULTY;
2888 cmn_err(CE_WARN,
2889 "!bscv_event_daemon had faults probing "
2890 "lom - marking it as faulty.");
2892 * Increment fault_cnt to ensure that
2893 * next time we do not report a message
2894 * i.e. we drop out of the bottom
2896 fault_cnt = BSC_PROBE_FAULT_LIMIT + 1;
2897 ssp->event_sleep = B_TRUE;
2898 } else if (fault_cnt < BSC_PROBE_FAULT_LIMIT) {
2899 if (bscv_faulty(ssp)) {
2900 poll_period = BSC_EVENT_POLL_FAULTY;
2902 * No recovery messages in this case
2903 * because there was never a fault
2904 * message here.
2906 fault_cnt = 0;
2907 } else {
2908 /* Getting ready to explode */
2909 fault_cnt++;
2910 cmn_err(CE_WARN,
2911 "!bscv_event_daemon had fault 0x%x",
2912 fault);
2914 ssp->event_sleep = B_TRUE;
2916 bscv_exit(ssp);
2917 mutex_enter(&ssp->task_mu);
2920 #if defined(__i386) || defined(__amd64)
2922 * we have no platmod hook on Solaris x86 to report
2923 * a change to the nodename so we keep a copy so
2924 * we can detect a change and request that the bsc
2925 * be updated when appropriate.
2927 if (strcmp(ssp->last_nodename, utsname.nodename) != 0) {
2929 BSCV_TRACE(ssp, 'X', "bscv_event_daemon",
2930 "utsname.nodename='%s' possible change detected",
2931 utsname.nodename);
2932 ssp->nodename_change = B_TRUE;
2933 (void) strncpy(ssp->last_nodename, utsname.nodename,
2934 sizeof (ssp->last_nodename));
2935 /* enforce null termination */
2936 ssp->last_nodename[sizeof (ssp->last_nodename) - 1] =
2937 '\0';
2939 #endif /* __i386 || __amd64 */
2941 if (((ssp->task_flags & TASK_PAUSE_FLG) == 0) &&
2942 fault_cnt == 0 && ssp->cssp_prog == B_FALSE &&
2943 (ssp->event_waiting || ssp->status_change ||
2944 ssp->nodename_change || ssp->watchdog_change)) {
2946 do_events = ssp->event_waiting;
2947 ssp->event_waiting = B_FALSE;
2948 ssp->task_flags |= do_events ?
2949 TASK_EVENT_PENDING_FLG : 0;
2950 do_status = ssp->status_change;
2951 ssp->status_change = B_FALSE;
2952 do_nodename = ssp->nodename_change;
2953 ssp->nodename_change = B_FALSE;
2954 do_watchdog = ssp->watchdog_change;
2955 if (ssp->watchdog_change) {
2956 ssp->watchdog_change = B_FALSE;
2959 mutex_exit(&ssp->task_mu);
2961 * We must not hold task_mu whilst processing
2962 * events because this can lead to priority
2963 * inversion and hence our interrupts getting
2964 * locked out.
2966 bscv_enter(ssp);
2967 if (do_events) {
2968 bscv_event_process(ssp, do_events);
2970 if (do_nodename) {
2971 BSCV_TRACE(ssp, 'D', "bscv_event_daemon",
2972 "do_nodename task");
2973 bscv_setup_hostname(ssp);
2975 if (do_watchdog) {
2976 BSCV_TRACE(ssp, 'D', "bscv_event_daemon",
2977 "do_watchdog task");
2978 bscv_setup_watchdog(ssp);
2981 * Pending status changes are dealt with last because
2982 * if we see that the BSC is about to be programmed,
2983 * then it will expect us to to quiescent in the
2984 * first second so it can cleanly tear down its comms
2985 * protocols; this takes ~100 ms.
2987 if (do_status) {
2988 bscv_get_state_changes(ssp);
2990 if (bscv_session_error(ssp)) {
2992 * Had fault during event session. We always
2993 * sleep after one of these because there
2994 * may be a problem with the lom which stops
2995 * us doing useful work in the event daemon.
2996 * If we don't sleep then we may livelock.
2998 BSCV_TRACE(ssp, 'D', "bscv_event_daemon",
2999 "had session error - sleeping");
3000 ssp->event_sleep = B_TRUE;
3002 bscv_exit(ssp);
3004 mutex_enter(&ssp->task_mu);
3006 if (ssp->task_flags & TASK_EVENT_PENDING_FLG) {
3008 * We have read any events which were
3009 * pending. Let the consumer continue.
3010 * Ignore the race condition with new events
3011 * arriving - just let the consumer have
3012 * whatever was pending when they asked.
3014 ssp->event_active_count++;
3015 ssp->task_flags &= ~(TASK_EVENT_PENDING_FLG |
3016 TASK_EVENT_CONSUMER_FLG);
3017 cv_broadcast(&ssp->task_evnt_cv);
3019 } else {
3020 /* There was nothing to do - sleep */
3021 ssp->event_sleep = B_TRUE;
3024 if (ssp->event_sleep) {
3025 ssp->task_flags |= TASK_SLEEPING_FLG;
3026 /* Sleep until there is something to do */
3027 (void) cv_reltimedwait(&ssp->task_cv,
3028 &ssp->task_mu, poll_period, TR_CLOCK_TICK);
3029 ssp->task_flags &= ~TASK_SLEEPING_FLG;
3030 ssp->event_sleep = B_FALSE;
3034 if (ssp->task_flags & TASK_EVENT_CONSUMER_FLG) {
3036 * We are going away so wake up any event consumer.
3037 * Pretend that any pending events have been processed.
3039 ssp->event_active_count += 2;
3040 cv_broadcast(&ssp->task_evnt_cv);
3043 ASSERT(!(ssp->task_flags & TASK_EVENT_PENDING_FLG));
3044 ssp->task_flags &=
3045 ~(TASK_STOP_FLG | TASK_ALIVE_FLG | TASK_EVENT_CONSUMER_FLG);
3046 mutex_exit(&ssp->task_mu);
3048 BSCV_TRACE(ssp, 'D', "bscv_event_daemon",
3049 "exiting.");
3053 * function - bscv_start_event_daemon
3054 * description - Create the event daemon thread.
3055 * inputs - LOM soft state structure pointer
3056 * outputs - none
3058 static void
3059 bscv_start_event_daemon(bscv_soft_state_t *ssp)
3061 if (ssp->progress & BSCV_THREAD)
3062 return;
3064 /* Start the event thread after the queue has started */
3065 (void) thread_create(NULL, 0, (void (*)())bscv_event_daemon, ssp,
3066 0, &p0, TS_RUN, minclsyspri);
3068 ssp->progress |= BSCV_THREAD;
3072 * function - bscv_stop_event_daemon
3073 * description - Attempt to stop the event daemon thread.
3074 * inputs - LOM soft state structure pointer
3075 * outputs - DDI_SUCCESS OR DDI_FAILURE
3077 static int
3078 bscv_stop_event_daemon(bscv_soft_state_t *ssp)
3080 int try;
3081 int res = DDI_SUCCESS;
3083 mutex_enter(&ssp->task_mu);
3085 /* Wait for task daemon to stop running. */
3086 for (try = 0;
3087 ((ssp->task_flags & TASK_ALIVE_FLG) && try < 10);
3088 try++) {
3089 /* Signal that the task daemon should stop */
3090 ssp->task_flags |= TASK_STOP_FLG;
3091 cv_signal(&ssp->task_cv);
3092 /* Release task daemon lock. */
3093 mutex_exit(&ssp->task_mu);
3095 * TODO - when the driver is modified to support
3096 * system suspend or if this routine gets called
3097 * during panic we should use drv_usecwait() rather
3098 * than delay in those circumstances.
3100 ddi_sleep(1);
3101 mutex_enter(&ssp->task_mu);
3104 if (ssp->task_flags & TASK_ALIVE_FLG) {
3105 res = DDI_FAILURE;
3107 mutex_exit(&ssp->task_mu);
3109 return (res);
3113 * function - bscv_pause_event_daemon
3114 * description - Attempt to pause the event daemon thread.
3115 * inputs - LOM soft state structure pointer
3116 * outputs - DDI_SUCCESS OR DDI_FAILURE
3118 static int
3119 bscv_pause_event_daemon(bscv_soft_state_t *ssp)
3121 int try;
3123 if (!(ssp->progress & BSCV_THREAD)) {
3124 /* Nothing to do */
3125 return (BSCV_SUCCESS);
3128 BSCV_TRACE(ssp, 'D', "bscv_pause_event_daemon",
3129 "Attempting to pause event daemon");
3131 mutex_enter(&ssp->task_mu);
3132 /* Signal that the task daemon should pause */
3133 ssp->task_flags |= TASK_PAUSE_FLG;
3135 /* Wait for task daemon to pause. */
3136 for (try = 0;
3137 (!(ssp->task_flags & TASK_SLEEPING_FLG) &&
3138 (ssp->task_flags & TASK_ALIVE_FLG) &&
3139 try < 10);
3140 try++) {
3141 /* Paranoia */
3142 ssp->task_flags |= TASK_PAUSE_FLG;
3143 cv_signal(&ssp->task_cv);
3144 /* Release task daemon lock. */
3145 mutex_exit(&ssp->task_mu);
3146 ddi_sleep(1);
3147 mutex_enter(&ssp->task_mu);
3149 if ((ssp->task_flags & TASK_SLEEPING_FLG) ||
3150 !(ssp->task_flags & TASK_ALIVE_FLG)) {
3151 mutex_exit(&ssp->task_mu);
3152 BSCV_TRACE(ssp, 'D', "bscv_pause_event_daemon",
3153 "Pause event daemon - success");
3154 return (BSCV_SUCCESS);
3156 mutex_exit(&ssp->task_mu);
3157 BSCV_TRACE(ssp, 'D', "bscv_pause_event_daemon",
3158 "Pause event daemon - failed");
3159 return (BSCV_FAILURE);
3163 * function - bscv_resume_event_daemon
3164 * description - Resumethe event daemon thread.
3165 * inputs - LOM soft state structure pointer
3166 * outputs - None.
3168 static void
3169 bscv_resume_event_daemon(bscv_soft_state_t *ssp)
3171 if (!(ssp->progress & BSCV_THREAD)) {
3172 /* Nothing to do */
3173 return;
3176 mutex_enter(&ssp->task_mu);
3177 /* Allow the task daemon to resume event processing */
3178 ssp->task_flags &= ~TASK_PAUSE_FLG;
3179 cv_signal(&ssp->task_cv);
3180 mutex_exit(&ssp->task_mu);
3182 BSCV_TRACE(ssp, 'D', "bscv_pause_event_daemon",
3183 "Event daemon resumed");
3187 * function - bscv_event_process
3188 * description - process (report) events
3189 * inputs - Soft state ptr, process event request
3190 * outputs - none
3192 static void
3193 bscv_event_process(bscv_soft_state_t *ssp, boolean_t do_events)
3195 uint32_t currptr;
3196 unsigned int count;
3198 /* Raw values read from the lom */
3199 uint8_t evcount;
3200 uint16_t logptr;
3202 lom_event_t event;
3204 if (do_events) {
3206 * Read count, next event ptr MSB,LSB. Note a read of count
3207 * latches values for the next event ptr
3209 evcount = bscv_get8(ssp, chan_general, EBUS_IDX_UNREAD_EVENTS);
3210 logptr = bscv_get16(ssp, chan_general, EBUS_IDX_LOG_PTR_HI);
3212 /* Sanity check the values from the lom */
3213 count = bscv_event_validate(ssp, logptr, evcount);
3215 if (count == -1) {
3217 * Nothing to do - or badly configured event log.
3218 * We really do not want to touch the lom in this
3219 * case because any data that we access may be bad!
3220 * This differs from zero because if we have zero
3221 * to read the lom probably things that unread is
3222 * non-zero and we want that to be set to zero!
3223 * Signal event fault to make the thread wait
3224 * before attempting to re-read the log.
3226 ssp->event_sleep = B_TRUE;
3228 goto logdone;
3230 if (ssp->event_fault_reported) {
3231 /* Clear down any old status - things are fixed */
3232 cmn_err(CE_NOTE, "Event pointer fault recovered.");
3233 ssp->event_fault_reported = B_FALSE;
3236 /* Compute the first entry that we need to read. */
3237 currptr = logptr - ssp->eventlog_start;
3238 currptr += ssp->eventlog_size;
3239 currptr -= (count * sizeof (event));
3240 currptr %= ssp->eventlog_size;
3241 currptr += ssp->eventlog_start;
3243 BSCV_TRACE(ssp, 'E', "bscv_event_process",
3244 "processing %d events from 0x%x in 0x%x:0x%x",
3245 count, currptr,
3246 ssp->eventlog_start,
3247 ssp->eventlog_start + ssp->eventlog_size);
3249 for (; count > 0; count--) {
3250 /* Ensure window is positioned correctly */
3251 if (bscv_eerw(ssp, currptr, (uint8_t *)&event,
3252 sizeof (event), B_FALSE /* read */) != 0) {
3253 /* Fault reading data - stop */
3254 break;
3257 bscv_event_process_one(ssp, &event);
3258 bscv_sysevent(ssp, &event);
3260 currptr += sizeof (event);
3261 if (currptr >= ssp->eventlog_start +
3262 ssp->eventlog_size) {
3263 currptr = ssp->eventlog_start;
3267 * Clear event count - write the evcount value to remove that
3268 * many from the unread total.
3269 * Adjust the value to reflect how many we have left to
3270 * read just in case we had a failure reading events.
3272 if (count == 0) {
3273 /*EMPTY*/
3274 ASSERT(logptr == currptr);
3275 } else if (count > evcount) {
3276 evcount = 0;
3277 } else {
3278 evcount -= count;
3280 bscv_put8(ssp, chan_general, EBUS_IDX_UNREAD_EVENTS, evcount);
3281 /* Remember where we were for next time */
3282 ssp->oldeeptr = currptr;
3283 ssp->oldeeptr_valid = B_TRUE;
3284 logdone:
3290 * function - bscv_event_validate
3291 * description - validate the event data supplied by the lom and determine
3292 * how many (if any) events to read.
3293 * This function performs complex checks to ensure that
3294 * events are not lost due to lom resets or host resets.
3295 * A combination of lom reset and host reset (i.e. power fail)
3296 * may cause some events to not be reported.
3297 * inputs - Soft state ptr, next event pointer, number of unread events.
3298 * outputs - the number of events to read. -1 on error.
3299 * zero is a valid value because it forces the loms unread
3300 * count to be cleared.
3302 static int
3303 bscv_event_validate(bscv_soft_state_t *ssp, uint32_t newptr, uint8_t unread)
3305 uint32_t oldptr;
3306 unsigned int count;
3308 if (!bscv_window_setup(ssp)) {
3309 /* Problem with lom eeprom setup we cannot do anything */
3310 return (-1);
3313 /* Sanity check the event pointers */
3314 if ((newptr < ssp->eventlog_start) ||
3315 (newptr >= (ssp->eventlog_start + ssp->eventlog_size))) {
3316 if (!ssp->event_fault_reported) {
3317 cmn_err(CE_WARN, "Event pointer out of range. "
3318 "Cannot read events.");
3319 ssp->event_fault_reported = B_TRUE;
3321 return (-1);
3323 oldptr = ssp->oldeeptr;
3324 /* Now sanity check log pointer against count */
3325 if (newptr < oldptr) {
3327 * Must have wrapped add eventlog_size to get the
3328 * correct relative values - this makes the checks
3329 * below work!
3331 newptr += ssp->eventlog_size;
3333 if (!ssp->oldeeptr_valid) {
3334 /* We have just started up - we have to trust lom */
3335 count = unread;
3336 } else if ((unread == 0) && (newptr == oldptr)) {
3337 /* Nothing to do - we were just polling */
3338 return (-1);
3339 } else if (oldptr + (unread * sizeof (lom_event_t)) == newptr) {
3340 /* Ok - got as many events as we expected */
3341 count = unread;
3342 } else if (oldptr + (unread * sizeof (lom_event_t)) > newptr) {
3344 * Errrm more messages than there should have been.
3345 * Possible causes:
3346 * 1. the event log has filled - we have been
3347 * away for a long time
3348 * 2. software bug in lom or driver.
3349 * 3. something that I haven't thought of!
3350 * Always warn about this we should really never
3351 * see it!
3353 count = (newptr - oldptr) / sizeof (lom_event_t);
3354 BSCV_TRACE(ssp, 'E', "bscv_event_process",
3355 "bscv_event_process: lom reported "
3356 "more events (%d) than expected (%d).",
3357 unread, count);
3358 cmn_err(CE_CONT, "only processing %d events", count);
3359 } else {
3360 /* Less messages - perhaps the lom has been reset */
3361 count = (newptr - oldptr) / sizeof (lom_event_t);
3362 BSCV_TRACE(ssp, 'E', "bscv_event_process",
3363 "lom reported less events (%d) than expected (%d)"
3364 " - the lom may have been reset",
3365 unread, count);
3367 /* Whatever happens only read a maximum of 255 entries */
3368 if ((count >= 0xff)) {
3369 cmn_err(CE_WARN,
3370 "bscv_event_process: too many events (%d) to "
3371 "process - some may have been lost", count);
3372 count = 0xff;
3374 return (count);
3378 * function - bscv_event_process_one
3379 * description - reports on state changes to the host.
3381 * inputs - LOM soft state structure pointer.
3383 * outputs - none.
3386 static void
3387 bscv_event_process_one(bscv_soft_state_t *ssp, lom_event_t *event)
3389 int level;
3390 char eventstr[100];
3391 int msg_type = 0;
3393 if (bscv_is_null_event(ssp, event)) {
3394 /* Cleared entry - do not report it */
3395 return;
3398 level = bscv_level_of_event(event);
3400 switch (level) {
3401 default:
3402 msg_type = CE_NOTE;
3403 break;
3405 case EVENT_LEVEL_FATAL:
3406 case EVENT_LEVEL_FAULT:
3407 msg_type = CE_WARN;
3408 break;
3411 bscv_build_eventstring(ssp, event, eventstr, eventstr +
3412 sizeof (eventstr));
3414 if (level <= ssp->reporting_level) {
3416 * The message is important enough to be shown on the console
3417 * as well as the log.
3419 cmn_err(msg_type, "%s", eventstr);
3420 } else {
3422 * The message goes only to the log.
3424 cmn_err(msg_type, "!%s", eventstr);
3429 * time formats
3431 * The BSC represents times as seconds since epoch 1970. Currently it gives
3432 * us 32 bits, unsigned. In the future this might change to a 64-bit count,
3433 * to allow a greater range.
3435 * Timestamp values below BSC_TIME_SANITY do not represent an absolute time,
3436 * but instead represent an offset from the last reset. This must be
3437 * borne in mind by output routines.
3440 typedef uint32_t bsctime_t;
3442 #define BSC_TIME_SANITY 1000000000
3445 * render a formatted time for display
3448 static size_t
3449 bscv_event_snprintgmttime(char *buf, size_t bufsz, todinfo_t t)
3451 int year;
3453 /* tod_year is base 1900 so this code needs to adjust */
3454 year = 1900 + t.tod_year;
3456 return (snprintf(buf, bufsz, "%04d-%02d-%02d %02d:%02d:%02dZ",
3457 year, t.tod_month, t.tod_day, t.tod_hour,
3458 t.tod_min, t.tod_sec));
3462 * function - bscv_build_eventstring
3463 * description - reports on state changes to the host.
3465 * inputs - LOM soft state structure pointer.
3467 * outputs - none.
3470 static void
3471 bscv_build_eventstring(bscv_soft_state_t *ssp, lom_event_t *event,
3472 char *buf, char *bufend)
3474 uint8_t subsystem;
3475 uint8_t eventtype;
3476 bsctime_t bsctm;
3478 BSCV_TRACE(ssp, 'S', "bscv_build_eventstring", "event %2x%2x%2x%2x",
3479 event->ev_subsys, event->ev_event,
3480 event->ev_resource, event->ev_detail);
3481 BSCV_TRACE(ssp, 'S', "bscv_build_eventstring", "time %2x%2x%2x%2x",
3482 event->ev_data[0], event->ev_data[1],
3483 event->ev_data[2], event->ev_data[3]);
3486 * We accept bad subsystems and event type codes here.
3487 * The code decodes as much as possible and then produces
3488 * suitable output.
3490 subsystem = EVENT_DECODE_SUBSYS(event->ev_subsys);
3491 eventtype = event->ev_event;
3493 /* time */
3494 bsctm = (((uint32_t)event->ev_data[0]) << 24) |
3495 (((uint32_t)event->ev_data[1]) << 16) |
3496 (((uint32_t)event->ev_data[2]) << 8) |
3497 ((uint32_t)event->ev_data[3]);
3498 if (bsctm < BSC_TIME_SANITY) {
3499 /* offset */
3500 buf += snprintf(buf, bufend-buf, "+P%dd%02dh%02dm%02ds",
3501 (int)(bsctm/86400), (int)(bsctm/3600%24),
3502 (int)(bsctm/60%60), (int)(bsctm%60));
3503 } else {
3504 /* absolute time */
3505 mutex_enter(&tod_lock);
3506 buf += bscv_event_snprintgmttime(buf, bufend-buf,
3507 utc_to_tod(bsctm));
3508 mutex_exit(&tod_lock);
3510 buf += snprintf(buf, bufend-buf, " ");
3512 /* subsysp */
3513 if (subsystem <
3514 (sizeof (eventSubsysStrings)/sizeof (*eventSubsysStrings))) {
3515 buf += snprintf(buf, bufend - buf, "%s",
3516 eventSubsysStrings[subsystem]);
3517 } else {
3518 buf += snprintf(buf, bufend - buf,
3519 "unknown subsystem %d ", subsystem);
3522 /* resource */
3523 switch (subsystem) {
3524 case EVENT_SUBSYS_ALARM:
3525 case EVENT_SUBSYS_TEMP:
3526 case EVENT_SUBSYS_OVERTEMP:
3527 case EVENT_SUBSYS_FAN:
3528 case EVENT_SUBSYS_SUPPLY:
3529 case EVENT_SUBSYS_BREAKER:
3530 case EVENT_SUBSYS_PSU:
3531 buf += snprintf(buf, bufend - buf, "%d ", event->ev_resource);
3532 break;
3533 case EVENT_SUBSYS_LED:
3534 buf += snprintf(buf, bufend - buf, "%s ", bscv_get_label(
3535 ssp->led_names, MAX_LED_ID, event->ev_resource - 1));
3536 break;
3537 default:
3538 break;
3541 /* fatal */
3542 if (event->ev_subsys & EVENT_MASK_FAULT) {
3543 if (event->ev_subsys & EVENT_MASK_FATAL) {
3544 buf += snprintf(buf, bufend - buf, "FATAL FAULT: ");
3545 } else {
3546 buf += snprintf(buf, bufend - buf, "FAULT: ");
3550 /* eventp */
3551 if (eventtype <
3552 (sizeof (eventTypeStrings)/sizeof (*eventTypeStrings))) {
3553 buf += snprintf(buf, bufend - buf, "%s",
3554 eventTypeStrings[eventtype]);
3555 } else {
3556 buf += snprintf(buf, bufend - buf,
3557 "unknown event 0x%02x%02x%02x%02x",
3558 event->ev_subsys, event->ev_event,
3559 event->ev_resource, event->ev_detail);
3562 /* detail */
3563 switch (subsystem) {
3564 case EVENT_SUBSYS_TEMP:
3565 if ((eventtype != EVENT_RECOVERED) &&
3566 eventtype != EVENT_DEVICE_INACCESSIBLE) {
3567 buf += snprintf(buf, bufend - buf, " - %d degC",
3568 (int8_t)event->ev_detail);
3570 break;
3571 case EVENT_SUBSYS_FAN:
3572 if (eventtype == EVENT_FAILED) {
3573 buf += snprintf(buf, bufend - buf,
3574 " %d%%", event->ev_detail);
3576 break;
3577 case EVENT_SUBSYS_LOM:
3578 switch (eventtype) {
3579 case EVENT_FLASH_DOWNLOAD:
3580 buf += snprintf(buf, bufend - buf,
3581 ": v%d.%d to v%d.%d",
3582 (event->ev_resource >> 4),
3583 (event->ev_resource & 0x0f),
3584 (event->ev_detail >> 4),
3585 (event->ev_detail & 0x0f));
3586 break;
3587 case EVENT_WATCHDOG_TRIGGER:
3588 buf += snprintf(buf, bufend - buf,
3589 event->ev_detail ? "- soft" : " - hard");
3590 break;
3591 case EVENT_UNEXPECTED_RESET:
3592 if (event->ev_detail &
3593 LOM_UNEXPECTEDRESET_MASK_BADTRAP) {
3594 buf += snprintf(buf, bufend - buf,
3595 " - unclaimed exception 0x%x",
3596 event->ev_detail &
3597 ~LOM_UNEXPECTEDRESET_MASK_BADTRAP);
3599 break;
3600 case EVENT_RESET:
3601 switch (event->ev_detail) {
3602 case LOM_RESET_DETAIL_BYUSER:
3603 buf += snprintf(buf, bufend - buf, " by user");
3604 break;
3605 case LOM_RESET_DETAIL_REPROGRAMMING:
3606 buf += snprintf(buf, bufend - buf,
3607 " after flash download");
3608 break;
3609 default:
3610 buf += snprintf(buf, bufend - buf,
3611 " - unknown reason");
3612 break;
3614 break;
3615 default:
3616 break;
3618 break;
3619 case EVENT_SUBSYS_LED:
3620 switch (event->ev_detail) {
3621 case LOM_LED_STATE_OFF:
3622 buf += snprintf(buf, bufend - buf, ": OFF");
3623 break;
3624 case LOM_LED_STATE_ON_STEADY:
3625 buf += snprintf(buf, bufend - buf, ": ON");
3626 break;
3627 case LOM_LED_STATE_ON_FLASHING:
3628 case LOM_LED_STATE_ON_SLOWFLASH:
3629 buf += snprintf(buf, bufend - buf, ": BLINKING");
3630 break;
3631 case LOM_LED_STATE_INACCESSIBLE:
3632 buf += snprintf(buf, bufend - buf, ": inaccessible");
3633 break;
3634 case LOM_LED_STATE_STANDBY:
3635 buf += snprintf(buf, bufend - buf, ": standby");
3636 break;
3637 case LOM_LED_STATE_NOT_PRESENT:
3638 buf += snprintf(buf, bufend - buf, ": not present");
3639 break;
3640 default:
3641 buf += snprintf(buf, bufend - buf, ": 0x%x",
3642 event->ev_resource);
3643 break;
3645 break;
3646 case EVENT_SUBSYS_USER:
3647 switch (eventtype) {
3648 case EVENT_USER_ADDED:
3649 case EVENT_USER_REMOVED:
3650 case EVENT_USER_PERMSCHANGED:
3651 case EVENT_USER_LOGIN:
3652 case EVENT_USER_PASSWORD_CHANGE:
3653 case EVENT_USER_LOGINFAIL:
3654 case EVENT_USER_LOGOUT:
3655 buf += snprintf(buf, bufend - buf, " %d",
3656 event->ev_resource);
3657 default:
3658 break;
3660 break;
3661 case EVENT_SUBSYS_PSU:
3662 if (event->ev_detail & LOM_PSU_NOACCESS) {
3663 buf += snprintf(buf, bufend - buf, " - inaccessible");
3664 } else if ((event->ev_detail & LOM_PSU_STATUS_MASK)
3665 == LOM_PSU_STATUS_MASK) {
3666 buf += snprintf(buf, bufend - buf, " - OK");
3667 } else {
3668 buf += snprintf(buf, bufend - buf, " -");
3670 * If both inputs are seen to have failed then simply
3671 * indicate that the PSU input has failed
3673 if (!(event->ev_detail &
3674 (LOM_PSU_INPUT_A_OK | LOM_PSU_INPUT_B_OK))) {
3675 buf += snprintf(buf, bufend - buf, " Input");
3676 } else {
3677 /* At least one input is ok */
3678 if (!(event->ev_detail & LOM_PSU_INPUT_A_OK)) {
3679 buf += snprintf(buf, bufend - buf,
3680 " InA");
3682 if (!(event->ev_detail & LOM_PSU_INPUT_B_OK)) {
3683 buf += snprintf(buf, bufend - buf,
3684 " InB");
3687 * Only flag an output error if an input is
3688 * still present
3690 if (!(event->ev_detail & LOM_PSU_OUTPUT_OK)) {
3691 buf += snprintf(buf, bufend - buf,
3692 " Output");
3695 buf += snprintf(buf, bufend - buf, " failed");
3697 break;
3698 case EVENT_SUBSYS_NONE:
3699 if (eventtype == EVENT_FAULT_LED) {
3700 switch (event->ev_detail) {
3701 case 0:
3702 buf += snprintf(buf, bufend - buf, " - ON");
3703 break;
3704 case 255:
3705 buf += snprintf(buf, bufend - buf, " - OFF");
3706 break;
3707 default:
3708 buf += snprintf(buf, bufend - buf,
3709 " - %dHz", event->ev_detail);
3710 break;
3713 break;
3714 case EVENT_SUBSYS_HOST:
3715 if (eventtype == EVENT_BOOTMODE_CHANGE) {
3716 switch (event->ev_detail &
3717 ~EBUS_BOOTMODE_FORCE_CONSOLE) {
3718 case EBUS_BOOTMODE_FORCE_NOBOOT:
3719 buf += snprintf(buf, bufend - buf,
3720 " - no boot");
3721 break;
3722 case EBUS_BOOTMODE_RESET_DEFAULT:
3723 buf += snprintf(buf, bufend - buf,
3724 " - reset defaults");
3725 break;
3726 case EBUS_BOOTMODE_FULLDIAG:
3727 buf += snprintf(buf, bufend - buf,
3728 " - full diag");
3729 break;
3730 case EBUS_BOOTMODE_SKIPDIAG:
3731 buf += snprintf(buf, bufend - buf,
3732 " - skip diag");
3733 break;
3734 default:
3735 break;
3738 if (eventtype == EVENT_SCC_STATUS) {
3739 switch (event->ev_detail) {
3740 case 0:
3741 buf += snprintf(buf, bufend - buf,
3742 " - inserted");
3743 break;
3744 case 1:
3745 buf += snprintf(buf, bufend - buf,
3746 " - removed");
3747 break;
3748 default:
3749 break;
3752 break;
3754 default:
3755 break;
3758 /* shutd */
3759 if (event->ev_subsys & EVENT_MASK_SHUTDOWN_REQD) {
3760 buf += snprintf(buf, bufend - buf, " - shutdown req'd");
3763 buf += snprintf(buf, bufend - buf, "\n");
3765 if (buf >= bufend) {
3766 /* Ensure newline at end of string */
3767 bufend[-2] = '\n';
3768 bufend[-1] = '\0';
3769 #ifdef DEBUG
3770 cmn_err(CE_WARN, "!bscv_build_eventstring: buffer too small!");
3771 #endif /* DEBUG */
3776 * function - bscv_level_of_event
3777 * description - This routine determines which level an event should be
3778 * reported at.
3779 * inputs - lom event structure pointer
3780 * outputs - event level.
3782 static int
3783 bscv_level_of_event(lom_event_t *event)
3785 int level;
3787 * This is the same criteria that the firmware uses except we
3788 * log the fault led on as being EVENT_LEVEL_FAULT
3790 if (EVENT_DECODE_SUBSYS(event->ev_subsys) == EVENT_SUBSYS_USER) {
3791 level = EVENT_LEVEL_USER;
3792 } else if ((EVENT_DECODE_SUBSYS(event->ev_subsys) ==
3793 EVENT_SUBSYS_ALARM) && (event->ev_event == EVENT_STATE_ON)) {
3794 level = EVENT_LEVEL_FAULT;
3795 } else if ((EVENT_DECODE_SUBSYS(event->ev_subsys) ==
3796 EVENT_SUBSYS_NONE) &&
3797 (event->ev_event == EVENT_FAULT_LED) &&
3798 (event->ev_detail != 0xff)) {
3799 level = EVENT_LEVEL_FAULT;
3800 } else if ((EVENT_DECODE_SUBSYS(event->ev_subsys) ==
3801 EVENT_SUBSYS_LOM) && event->ev_event == EVENT_TIME_REFERENCE) {
3802 level = EVENT_LEVEL_NOTICE;
3803 } else if (event->ev_event == EVENT_RECOVERED) {
3805 * All recovery messages need to be reported to the console
3806 * because during boot, the faults which occurred whilst
3807 * Solaris was not running are relayed to the console. There
3808 * is a case whereby a fatal fault (eg. over temp) could
3809 * have occurred and then recovered. The recovery condition
3810 * needs to be reported so the user doesn't think that the
3811 * failure (over temp) is still present.
3813 level = EVENT_LEVEL_FAULT;
3814 } else if (EVENT_DECODE_FAULT(event->ev_subsys) == 0) {
3815 /* None of FAULT, FATAL or SHUTDOWN REQD are set */
3816 level = EVENT_LEVEL_NOTICE;
3817 } else if (EVENT_DECODE_FAULT(event->ev_subsys) == EVENT_MASK_FAULT) {
3818 /* Only FAULT set i.e not FATAL or SHUTDOWN REQD */
3819 level = EVENT_LEVEL_FAULT;
3820 } else {
3821 level = EVENT_LEVEL_FATAL;
3824 return (level);
3828 * function - bscv_status
3829 * description - This routine is called when any change in the LOMlite2 status
3830 * is indicated by the status registers.
3832 * inputs - LOM soft state structure pointer
3834 * outputs - none.
3836 static void
3837 bscv_status(bscv_soft_state_t *ssp, uint8_t state_chng, uint8_t dev_no)
3839 int8_t temp;
3840 uint8_t fanspeed;
3842 ASSERT(bscv_held(ssp));
3844 BSCV_TRACE(ssp, 'D', "bscv_status", "state_chng 0x%x dev_no 0x%x",
3845 state_chng, dev_no);
3848 * The device that has changed is given by the state change
3849 * register and the event detail register so react
3850 * accordingly.
3853 if (state_chng == EBUS_STATE_NOTIFY) {
3855 * The BSC is indicating a self state change
3857 if (dev_no == EBUS_DETAIL_FLASH) {
3858 ssp->cssp_prog = B_TRUE;
3859 BSCV_TRACE(ssp, 'D', "bscv_status",
3860 "ssp->cssp_prog changed to 0x%x",
3861 ssp->cssp_prog);
3863 * It takes the BSC at least 100 ms to
3864 * clear down the comms protocol.
3865 * We back-off from talking to the
3866 * BSC during this period.
3868 delay(BSC_EVENT_POLL_NORMAL);
3869 BSCV_TRACE(ssp, 'D', "bscv_status",
3870 "completed delay");
3871 } else if (dev_no == EBUS_DETAIL_RESET) {
3873 * The bsc has reset
3875 BSCV_TRACE(ssp, 'D', "bscv_status",
3876 "BSC reset occured, re-synching");
3877 (void) bscv_attach_common(ssp);
3878 BSCV_TRACE(ssp, 'D', "bscv_status",
3879 "completed attach_common");
3884 if ((state_chng & EBUS_STATE_FAN) && ((dev_no - 1) < MAX_FANS)) {
3885 fanspeed = bscv_get8(ssp, chan_general,
3886 EBUS_IDX_FAN1_SPEED + dev_no - 1);
3888 * Only remember fanspeeds which are real values or
3889 * NOT PRESENT values.
3891 if ((fanspeed <= LOM_FAN_MAX_SPEED) ||
3892 (fanspeed == LOM_FAN_NOT_PRESENT)) {
3893 ssp->fanspeed[dev_no - 1] = fanspeed;
3897 if ((state_chng & EBUS_STATE_PSU) && ((dev_no - 1) < MAX_PSUS)) {
3898 (void) bscv_get8(ssp, chan_general,
3899 EBUS_IDX_PSU1_STAT + dev_no - 1);
3902 if (state_chng & EBUS_STATE_GP) {
3903 (void) bscv_get8(ssp, chan_general, EBUS_IDX_GPIP);
3906 if (state_chng & EBUS_STATE_CB) {
3907 (void) bscv_get8(ssp, chan_general, EBUS_IDX_CBREAK_STATUS);
3910 if ((state_chng & EBUS_STATE_TEMPERATURE) &&
3911 ((dev_no - 1) < MAX_TEMPS)) {
3912 temp = bscv_get8(ssp, chan_general,
3913 EBUS_IDX_TEMP1 + dev_no - 1);
3915 * Only remember temperatures which are real values or
3916 * a NOT PRESENT value.
3918 if ((temp <= LOM_TEMP_MAX_VALUE) ||
3919 (temp == LOM_TEMP_STATE_NOT_PRESENT)) {
3920 ssp->temps.temp[dev_no - 1] = temp;
3924 if (state_chng & EBUS_STATE_RAIL) {
3925 (void) bscv_get8(ssp, chan_general, EBUS_IDX_SUPPLY_LO);
3926 (void) bscv_get8(ssp, chan_general, EBUS_IDX_SUPPLY_HI);
3930 char *
3931 bscv_get_label(char labels[][MAX_LOM2_NAME_STR], int limit, int index)
3934 if (labels == NULL)
3935 return ("");
3937 if (limit < 0 || index < 0 || index > limit)
3938 return ("-");
3940 return (labels[index]);
3943 static void
3944 bscv_generic_sysevent(bscv_soft_state_t *ssp, char *class, char *subclass,
3945 char *fru_id, char *res_id, int32_t fru_state, char *msg)
3947 int rv;
3948 nvlist_t *attr_list;
3950 BSCV_TRACE(ssp, 'E', "bscv_generic_sysevent", "%s/%s:(%s,%s,%d) %s",
3951 class, subclass, fru_id, res_id, fru_state, msg);
3954 if (nvlist_alloc(&attr_list, NV_UNIQUE_NAME_TYPE, KM_SLEEP)) {
3955 BSCV_TRACE(ssp, 'E', "bscv_generic_sysevent",
3956 "nvlist alloc failure");
3957 return;
3959 if (nvlist_add_uint32(attr_list, ENV_VERSION, 1)) {
3960 BSCV_TRACE(ssp, 'E', "bscv_generic_sysevent",
3961 "nvlist ENV_VERSION failure");
3962 nvlist_free(attr_list);
3963 return;
3965 if (nvlist_add_string(attr_list, ENV_FRU_ID, fru_id)) {
3966 BSCV_TRACE(ssp, 'E', "bscv_generic_sysevent",
3967 "nvlist ENV_FRU_ID failure");
3968 nvlist_free(attr_list);
3969 return;
3971 if (nvlist_add_string(attr_list, ENV_FRU_RESOURCE_ID, res_id)) {
3972 BSCV_TRACE(ssp, 'E', "bscv_generic_sysevent",
3973 "nvlist ENV_FRU_RESOURCE_ID failure");
3974 nvlist_free(attr_list);
3975 return;
3977 if (nvlist_add_string(attr_list, ENV_FRU_DEVICE, ENV_RESERVED_ATTR)) {
3978 BSCV_TRACE(ssp, 'E', "bscv_generic_sysevent",
3979 "nvlist ENV_FRU_DEVICE failure");
3980 nvlist_free(attr_list);
3981 return;
3983 if (nvlist_add_int32(attr_list, ENV_FRU_STATE, fru_state)) {
3984 BSCV_TRACE(ssp, 'E', "bscv_generic_sysevent",
3985 "nvlist ENV_FRU_STATE failure");
3986 nvlist_free(attr_list);
3987 return;
3989 if (nvlist_add_string(attr_list, ENV_MSG, msg)) {
3990 BSCV_TRACE(ssp, 'E', "bscv_generic_sysevent",
3991 "nvlist ENV_MSG failure");
3992 nvlist_free(attr_list);
3993 return;
3996 rv = ddi_log_sysevent(ssp->dip, DDI_VENDOR_SUNW, class,
3997 subclass, attr_list, NULL, DDI_SLEEP);
3999 if (rv == DDI_SUCCESS) {
4000 BSCV_TRACE(ssp, 'E', "bscv_generic_sysevent", "sent sysevent");
4001 } else {
4002 cmn_err(CE_WARN, "!cannot deliver sysevent");
4005 nvlist_free(attr_list);
4009 * function - bscv_sysevent
4010 * description - send out a sysevent on the given change if needed
4011 * inputs - soft state pointer, event to report
4012 * outputs - none
4015 static void
4016 bscv_sysevent(bscv_soft_state_t *ssp, lom_event_t *event)
4018 char *class = NULL;
4019 char *subclass = NULL;
4020 char *fru_id = "Blade"; /* The blade is only one FRU */
4021 char *res_id;
4022 int32_t fru_state = 0;
4024 BSCV_TRACE(ssp, 'E', "bscv_sysevent", "processing event");
4026 ASSERT(event != NULL);
4028 /* Map ev_subsys to sysevent class/sub-class */
4030 switch (EVENT_DECODE_SUBSYS(event->ev_subsys)) {
4031 case EVENT_SUBSYS_NONE:
4032 break;
4033 case EVENT_SUBSYS_ALARM:
4034 break;
4035 case EVENT_SUBSYS_TEMP:
4036 class = EC_ENV, subclass = ESC_ENV_TEMP;
4037 res_id = bscv_get_label(ssp->temps.name, ssp->temps.num,
4038 event->ev_resource - 1);
4039 switch (event->ev_event) {
4040 case EVENT_SEVERE_OVERHEAT:
4041 fru_state = ENV_FAILED;
4042 break;
4043 case EVENT_OVERHEAT:
4044 fru_state = ENV_WARNING;
4045 break;
4046 case EVENT_NO_OVERHEAT:
4047 fru_state = ENV_OK;
4048 break;
4049 default:
4050 return;
4052 break;
4053 case EVENT_SUBSYS_OVERTEMP:
4054 break;
4055 case EVENT_SUBSYS_FAN:
4056 class = EC_ENV, subclass = ESC_ENV_FAN;
4057 res_id = bscv_get_label(ssp->fan_names, ssp->num_fans,
4058 event->ev_resource - 1);
4059 switch (event->ev_event) {
4060 case EVENT_FAILED:
4061 fru_state = ENV_FAILED;
4062 break;
4063 case EVENT_RECOVERED:
4064 fru_state = ENV_OK;
4065 break;
4066 default:
4067 return;
4069 break;
4070 case EVENT_SUBSYS_SUPPLY:
4071 class = EC_ENV, subclass = ESC_ENV_POWER;
4072 res_id = bscv_get_label(ssp->sflags.name, ssp->sflags.num,
4073 event->ev_resource - 1);
4074 switch (event->ev_event) {
4075 case EVENT_FAILED:
4076 fru_state = ENV_FAILED;
4077 break;
4078 case EVENT_RECOVERED:
4079 fru_state = ENV_OK;
4080 break;
4081 default:
4082 return;
4084 break;
4085 case EVENT_SUBSYS_BREAKER:
4086 break;
4087 case EVENT_SUBSYS_PSU:
4088 break;
4089 case EVENT_SUBSYS_USER:
4090 break;
4091 case EVENT_SUBSYS_PHONEHOME:
4092 break;
4093 case EVENT_SUBSYS_LOM:
4094 break;
4095 case EVENT_SUBSYS_HOST:
4096 break;
4097 case EVENT_SUBSYS_EVENTLOG:
4098 break;
4099 case EVENT_SUBSYS_EXTRA:
4100 break;
4101 case EVENT_SUBSYS_LED:
4102 if (event->ev_event != EVENT_FAULT_LED &&
4103 event->ev_event != EVENT_STATE_CHANGE)
4104 return;
4106 * There are 3 LEDs : Power, Service, Ready-to-Remove on a
4107 * JBOS blade. We'll never report the Power since Solaris
4108 * won't be running when it is _switched_ ON. Ready-to-Remove
4109 * will only be lit when we're powered down which also means
4110 * Solaris won't be running. We don't want to report it
4111 * during system testing / Sun VTS exercising the LEDs.
4113 * Therefore, we only report the Service Required LED.
4115 class = EC_ENV, subclass = ESC_ENV_LED;
4116 res_id = bscv_get_label(ssp->led_names, MAX_LED_ID,
4117 event->ev_resource - 1);
4119 switch (event->ev_detail) {
4120 case LOM_LED_STATE_ON_STEADY:
4121 fru_state = ENV_LED_ON;
4122 break;
4123 case LOM_LED_STATE_ON_FLASHING:
4124 case LOM_LED_STATE_ON_SLOWFLASH:
4125 fru_state = ENV_LED_BLINKING;
4126 break;
4127 case LOM_LED_STATE_OFF:
4128 fru_state = ENV_LED_OFF;
4129 break;
4130 case LOM_LED_STATE_INACCESSIBLE:
4131 fru_state = ENV_LED_INACCESSIBLE;
4132 break;
4133 case LOM_LED_STATE_STANDBY:
4134 fru_state = ENV_LED_STANDBY;
4135 break;
4136 case LOM_LED_STATE_NOT_PRESENT:
4137 fru_state = ENV_LED_NOT_PRESENT;
4138 break;
4139 default:
4140 fru_state = ENV_LED_INACCESSIBLE;
4141 break;
4143 break;
4144 default :
4145 break;
4148 if (class == NULL || subclass == NULL) {
4149 BSCV_TRACE(ssp, 'E', "bscv_sysevent", "class/subclass NULL");
4150 return;
4153 bscv_generic_sysevent(ssp, class, subclass, fru_id, res_id, fru_state,
4154 ENV_RESERVED_ATTR);
4158 * *********************************************************************
4159 * Firmware download (programming)
4160 * *********************************************************************
4164 * function - bscv_prog
4165 * description - LOMlite2 flash programming code.
4167 * bscv_prog_image - download a complete image to the lom.
4168 * bscv_prog_receive_image - receive data to build up a
4169 * complete image.
4170 * bscv_prog_stop_lom - pause the event daemon and prepare
4171 * lom for firmware upgrade.
4172 * bscv_prog_start_lom - reinit the driver/lom after upgrade
4173 * and restart the event daemon
4175 * inputs - soft state pointer, arg ptr, ioctl mode
4176 * outputs - status
4179 static int
4180 bscv_prog(bscv_soft_state_t *ssp, intptr_t arg, int mode)
4182 lom_prog_t *prog;
4183 int res = 0;
4186 * We will get repeatedly called with bits of data first for
4187 * loader, then for main image.
4189 prog = (lom_prog_t *)kmem_alloc(sizeof (lom_prog_t), KM_SLEEP);
4191 if (ddi_copyin((caddr_t)arg, (caddr_t)prog, sizeof (*prog),
4192 mode) < 0) {
4193 kmem_free((void *)prog, sizeof (*prog));
4194 return (EFAULT);
4197 BSCV_TRACE(ssp, 'U', "bscv_prog",
4198 "index 0x%x size 0x%x", prog->index, prog->size);
4200 mutex_enter(&ssp->prog_mu);
4201 if (prog->size == 0) {
4202 if (prog->index == 2) {
4204 * This is the initial request for the chip type so we
4205 * know what we are programming.
4206 * The type will have been read in at init so just
4207 * return it in data[0].
4209 prog->data[0] = bscv_get8_cached(ssp,
4210 EBUS_IDX_CPU_IDENT);
4212 if (ddi_copyout((caddr_t)prog, (caddr_t)arg,
4213 sizeof (lom_prog_t), mode) < 0) {
4214 res = EFAULT;
4216 } else if (prog->index == 0) {
4217 res = bscv_prog_stop_lom(ssp);
4218 } else if (prog->index == 1) {
4219 res = bscv_prog_start_lom(ssp);
4220 } else {
4221 res = EINVAL;
4223 } else {
4224 if (ssp->image == NULL) {
4225 ssp->image = kmem_zalloc(
4226 BSC_IMAGE_MAX_SIZE, KM_SLEEP);
4228 res = bscv_prog_receive_image(ssp, prog,
4229 ssp->image, BSC_IMAGE_MAX_SIZE);
4231 mutex_exit(&ssp->prog_mu);
4232 kmem_free((void *)prog, sizeof (lom_prog_t));
4234 return (res);
4237 static int
4238 bscv_check_loader_config(bscv_soft_state_t *ssp, boolean_t is_image2)
4240 BSCV_TRACE(ssp, 'U', "bscv_check_loader_config",
4241 "loader_running %d, is_image2 %d",
4242 ssp->loader_running, is_image2);
4245 * loader_running TRUE means that we have told the microcontroller to
4246 * JUMP into the loader code which has been downloaded into its RAM.
4247 * At this point its an error to try and download another loader. We
4248 * should be downloading the actual image at this point.
4249 * Conversely, it is an error to download an image when the loader is
4250 * not already downloaded and the microcontroller hasn't JUMPed into it.
4251 * is_image2 TRUE means the image is being downloaded.
4252 * is_image2 FALSE means the loader is being downloaded.
4254 if (ssp->loader_running && !is_image2) {
4255 cmn_err(CE_WARN, "Attempt to download loader image "
4256 "with loader image already active");
4257 cmn_err(CE_CONT, "This maybe an attempt to restart a "
4258 "failed firmware download - ignoring download attempt");
4259 return (B_FALSE);
4260 } else if (!ssp->loader_running && is_image2) {
4261 cmn_err(CE_WARN, "Attempt to download firmware image "
4262 "without loader image active");
4263 return (B_FALSE);
4267 return (B_TRUE);
4270 static uint32_t
4271 bscv_get_pagesize(bscv_soft_state_t *ssp)
4273 uint32_t pagesize;
4275 ASSERT(bscv_held(ssp));
4277 pagesize = bscv_get32(ssp, chan_prog,
4278 BSCVA(EBUS_CMD_SPACE_PROGRAM, EBUS_PROGRAM_PAGE0));
4280 BSCV_TRACE(ssp, 'U', "bscv_get_pagesize", "pagesize 0x%x", pagesize);
4282 return (pagesize);
4286 * Sets the pagesize, returning the old value.
4288 static uint32_t
4289 bscv_set_pagesize(bscv_soft_state_t *ssp, uint32_t pagesize)
4291 uint32_t old_pagesize;
4293 ASSERT(bscv_held(ssp));
4295 old_pagesize = bscv_get_pagesize(ssp);
4298 * The microcontroller remembers this value until until someone
4299 * changes it.
4301 bscv_put32(ssp, chan_prog,
4302 BSCVA(EBUS_CMD_SPACE_PROGRAM, EBUS_PROGRAM_PSIZ0), pagesize);
4304 return (old_pagesize);
4307 static uint8_t
4308 bscv_enter_programming_mode(bscv_soft_state_t *ssp)
4310 uint8_t retval;
4312 ASSERT(bscv_held(ssp));
4314 bscv_put8(ssp, chan_prog,
4315 BSCVA(EBUS_CMD_SPACE_PROGRAM, EBUS_PROGRAM_PCSR),
4316 EBUS_PROGRAM_PCR_PRGMODE_ON);
4318 retval = bscv_get8(ssp, chan_prog, BSCVA(EBUS_CMD_SPACE_PROGRAM,
4319 EBUS_PROGRAM_PCSR));
4321 return (retval);
4324 static void
4325 bscv_leave_programming_mode(bscv_soft_state_t *ssp, boolean_t with_jmp)
4327 uint8_t reg;
4328 ASSERT(bscv_held(ssp));
4330 if (with_jmp) {
4331 reg = EBUS_PROGRAM_PCR_PROGOFF_JUMPTOADDR;
4332 BSCV_TRACE(ssp, 'U', "bscv_leave_programming_mode",
4333 "jumptoaddr");
4334 } else {
4335 reg = EBUS_PROGRAM_PCR_PRGMODE_OFF;
4336 BSCV_TRACE(ssp, 'U', "bscv_leave_programming_mode",
4337 "prgmode_off");
4340 bscv_put8(ssp, chan_prog,
4341 BSCVA(EBUS_CMD_SPACE_PROGRAM, EBUS_PROGRAM_PCSR), reg);
4345 static void
4346 bscv_set_jump_to_addr(bscv_soft_state_t *ssp, uint32_t loadaddr)
4348 ASSERT(bscv_held(ssp));
4350 bscv_put32(ssp, chan_prog,
4351 BSCVA(EBUS_CMD_SPACE_PROGRAM, EBUS_PROGRAM_PADR0), loadaddr);
4353 BSCV_TRACE(ssp, 'U', "bscv_set_jump_to_addr",
4354 "set jump to loadaddr 0x%x", loadaddr);
4357 static uint8_t
4358 bscv_erase_once(bscv_soft_state_t *ssp, uint32_t loadaddr, uint32_t image_size)
4360 uint8_t retval;
4362 ASSERT(bscv_held(ssp));
4365 * write PADR, PSIZ to define area to be erased
4366 * We do not send erase for zero size because the current
4367 * downloader gets this wrong
4371 * start at 0
4373 BSCV_TRACE(ssp, 'U', "bscv_erase_once", "sending erase command");
4375 bscv_put32(ssp, chan_prog,
4376 BSCVA(EBUS_CMD_SPACE_PROGRAM, EBUS_PROGRAM_PADR0),
4377 loadaddr);
4379 /* set PSIZ to full size of image to be programmed */
4380 bscv_put32(ssp, chan_prog,
4381 BSCVA(EBUS_CMD_SPACE_PROGRAM, EBUS_PROGRAM_PSIZ0),
4382 image_size);
4384 /* write ERASE to PCSR */
4385 bscv_put8(ssp, chan_prog,
4386 BSCVA(EBUS_CMD_SPACE_PROGRAM, EBUS_PROGRAM_PCSR),
4387 EBUS_PROGRAM_PCR_ERASE);
4389 /* read PCSR to check status */
4390 retval = bscv_get8(ssp, chan_prog,
4391 BSCVA(EBUS_CMD_SPACE_PROGRAM, EBUS_PROGRAM_PCSR));
4392 return (retval);
4395 static uint8_t
4396 bscv_do_erase(bscv_soft_state_t *ssp, uint32_t loadaddr, uint32_t image_size,
4397 boolean_t is_image2)
4399 int retryable = BSC_ERASE_RETRY_LIMIT;
4400 uint8_t retval;
4402 while (retryable--) {
4403 retval = bscv_erase_once(ssp, loadaddr, image_size);
4404 if (PSR_SUCCESS(retval))
4405 break;
4406 else
4407 cmn_err(CE_WARN, "erase error 0x%x, attempt %d"
4408 ", base 0x%x, size 0x%x, %s image",
4409 retval, BSC_ERASE_RETRY_LIMIT - retryable,
4410 loadaddr, image_size,
4411 is_image2 ? "main" : "loader");
4414 return (retval);
4417 static uint8_t
4418 bscv_set_page(bscv_soft_state_t *ssp, uint32_t addr)
4420 uint32_t retval;
4421 int retryable = BSC_PAGE_RETRY_LIMIT;
4423 ASSERT(bscv_held(ssp));
4425 while (retryable--) {
4428 * Write the page address and read it back for confirmation.
4430 bscv_put32(ssp, chan_prog,
4431 BSCVA(EBUS_CMD_SPACE_PROGRAM, EBUS_PROGRAM_PADR0),
4432 addr);
4433 retval = bscv_get32(ssp, chan_prog,
4434 BSCVA(EBUS_CMD_SPACE_PROGRAM, EBUS_PROGRAM_PADR0));
4436 if (retval == addr)
4437 break;
4438 else {
4439 cmn_err(CE_WARN, "programmming error, attempt %d, "
4440 "set page 0x%x, read back 0x%x",
4441 BSC_PAGE_RETRY_LIMIT - retryable,
4442 addr, retval);
4445 return ((addr == retval) ? EBUS_PROGRAM_PSR_SUCCESS :
4446 EBUS_PROGRAM_PSR_INVALID_OPERATION);
4449 static uint8_t
4450 bscv_do_page_data_once(bscv_soft_state_t *ssp, uint32_t index,
4451 uint32_t image_size, uint32_t pagesize, uint8_t *imagep,
4452 uint16_t *calcd_chksum)
4454 uint32_t size;
4455 uint16_t chksum;
4456 int i;
4457 uint8_t retval;
4459 ASSERT(bscv_held(ssp));
4461 BSCV_TRACE(ssp, 'P', "bscv_do_page_data_once", "index 0x%x", index);
4463 /* write PSIZ bytes to PDAT */
4464 if (index + pagesize < image_size) {
4465 bscv_rep_rw8(ssp, chan_prog, imagep + index,
4466 BSCVA(EBUS_CMD_SPACE_PROGRAM, EBUS_PROGRAM_DATA),
4467 pagesize, DDI_DEV_NO_AUTOINCR, B_TRUE /* write */);
4468 size = pagesize;
4469 } else {
4470 BSCV_TRACE(ssp, 'P', "bscv_do_page_once",
4471 "Sending last block, last 0x%x bytes",
4472 (image_size % pagesize));
4473 size = (image_size - index);
4474 bscv_rep_rw8(ssp, chan_prog, imagep + index,
4475 BSCVA(EBUS_CMD_SPACE_PROGRAM, EBUS_PROGRAM_DATA),
4476 size, DDI_DEV_NO_AUTOINCR, B_TRUE /* write */);
4477 /* Now pad the rest of the page with zeros */
4478 for (i = size; i < pagesize; i++) {
4479 bscv_put8(ssp, chan_prog,
4480 BSCVA(EBUS_CMD_SPACE_PROGRAM,
4481 EBUS_PROGRAM_DATA),
4486 /* write the checksum to PCSM */
4487 chksum = 0;
4488 for (i = 0; i < size; i++) {
4489 chksum = ((chksum << 3) | (chksum >> 13)) ^
4490 *(imagep + index + i);
4492 /* Cope with non-pagesize sized bufers */
4493 for (; i < pagesize; i++) {
4494 chksum = ((chksum << 3) | (chksum >> 13)) ^ 0;
4496 bscv_put16(ssp, chan_prog,
4497 BSCVA(EBUS_CMD_SPACE_PROGRAM, EBUS_PROGRAM_PCSM0), chksum);
4499 bscv_put8(ssp, chan_prog,
4500 BSCVA(EBUS_CMD_SPACE_PROGRAM, EBUS_PROGRAM_PCSR),
4501 EBUS_PROGRAM_PCR_PROGRAM);
4503 retval = bscv_get8(ssp, chan_prog,
4504 BSCVA(EBUS_CMD_SPACE_PROGRAM, EBUS_PROGRAM_PCSR));
4506 *calcd_chksum = chksum;
4507 return (retval);
4510 static uint8_t bscv_do_page(bscv_soft_state_t *ssp, uint32_t loadaddr,
4511 uint32_t index, uint32_t image_size, uint32_t pagesize, uint8_t *imagep,
4512 boolean_t is_image2)
4514 int retryable = BSC_PAGE_RETRY_LIMIT;
4515 uint8_t retval;
4516 uint16_t checksum;
4518 BSCV_TRACE(ssp, 'P', "bscv_do_page", "index 0x%x", index);
4520 while (retryable--) {
4522 * Set the page address (with retries). If this is not
4523 * successful, then there is no point carrying on and sending
4524 * the page's data since that could cause random memory
4525 * corruption in the microcontroller.
4527 retval = bscv_set_page(ssp, loadaddr + index);
4528 if (!PSR_SUCCESS(retval)) {
4529 cmn_err(CE_WARN, "programming error 0x%x, "
4530 "could not setup page address 0x%x, %s image",
4531 retval, loadaddr + index,
4532 is_image2 ? "main" : "loader");
4533 break;
4537 * Send down the data for the page
4540 BSCV_TRACE(ssp, 'P', "bscv_do_page", "sending data for page");
4542 retval = bscv_do_page_data_once(ssp, index, image_size,
4543 pagesize, imagep, &checksum);
4544 if (PSR_SUCCESS(retval))
4545 break;
4546 else
4547 cmn_err(CE_WARN, "programming error 0x%x,"
4548 " attempt %d, index 0x%x, checksum 0x%x, %s image",
4549 retval, BSC_PAGE_RETRY_LIMIT - retryable,
4550 index, checksum, is_image2 ? "main" : "loader");
4553 BSCV_TRACE(ssp, 'U', "bscv_do_page", "Returning 0x%x for index 0x%x,"
4554 " checksum 0x%x, %s image", retval, index, checksum,
4555 is_image2 ? "main" : "loader");
4557 return (retval);
4560 static uint8_t
4561 bscv_do_pages(bscv_soft_state_t *ssp, uint32_t loadaddr, uint32_t image_size,
4562 uint32_t pagesize, uint8_t *imagep, boolean_t is_image2)
4564 uint8_t retval;
4565 uint32_t index;
4567 BSCV_TRACE(ssp, 'P', "bscv_do_pages", "entered");
4569 for (index = 0; index < image_size; index += pagesize) {
4570 retval = bscv_do_page(ssp, loadaddr, index, image_size,
4571 pagesize, imagep, is_image2);
4572 if (bscv_faulty(ssp) || !PSR_SUCCESS(retval)) {
4573 BSCV_TRACE(ssp, 'U', "bscv_do_pages",
4574 "Failed to program lom (status 0x%x)", retval);
4575 break;
4579 return (retval);
4582 static int
4583 bscv_prog_image(bscv_soft_state_t *ssp, boolean_t is_image2,
4584 uint8_t *imagep, int image_size, uint32_t loadaddr)
4586 uint32_t pagesize;
4587 int res = 0;
4588 uint8_t retval;
4590 BSCV_TRACE(ssp, 'U', "bscv_prog_image",
4591 "image 0x%x, imagep %p, size 0x%x",
4592 is_image2 ? 2 : 1, imagep, image_size);
4594 if (!bscv_check_loader_config(ssp, is_image2))
4596 * Return no error to allow userland to continue on with
4597 * downloading the image.
4599 return (0);
4601 bscv_enter(ssp);
4603 pagesize = bscv_get_pagesize(ssp);
4605 retval = bscv_enter_programming_mode(ssp);
4606 if (bscv_faulty(ssp) || !PSR_PROG(retval)) {
4607 cmn_err(CE_WARN, "lom: Failed to enter program mode, error 0x%x"
4608 ", %s image", retval, is_image2 ? "main" : "loader");
4609 res = EIO;
4610 goto BSCV_PROG_IMAGE_END;
4612 BSCV_TRACE(ssp, 'U', "bscv_prog_image", "entered programming mode");
4615 * Only issue an erase if we are downloading the image. The loader
4616 * does not need this step.
4618 if (is_image2 && (image_size != 0)) {
4619 retval = bscv_do_erase(ssp, loadaddr, image_size, is_image2);
4620 if (bscv_faulty(ssp) || !PSR_SUCCESS(retval)) {
4621 cmn_err(CE_WARN,
4622 "lom: Erase failed during programming, status 0x%x",
4623 retval);
4624 res = EIO;
4625 goto BSCV_PROG_IMAGE_END;
4626 } else {
4627 BSCV_TRACE(ssp, 'U', "bscv_prog_image",
4628 "erase complete - programming...");
4633 (void) bscv_set_pagesize(ssp, pagesize);
4635 retval = bscv_do_pages(ssp, loadaddr, image_size, pagesize, imagep,
4636 is_image2);
4637 if (bscv_faulty(ssp) || !PSR_SUCCESS(retval)) {
4638 BSCV_TRACE(ssp, 'U', "bscv_prog_image",
4639 "Failed to program lom (status 0x%x)", retval);
4640 res = EIO;
4641 goto BSCV_PROG_IMAGE_END;
4644 BSCV_PROG_IMAGE_END:
4645 if (res == 0 && !is_image2) {
4647 * We've downloaded the loader successfully. Now make the
4648 * microcontroller jump to it.
4650 bscv_set_jump_to_addr(ssp, loadaddr);
4651 ssp->loader_running = B_TRUE;
4652 bscv_leave_programming_mode(ssp, B_TRUE);
4653 } else {
4655 * We've just downloaded either the loader which failed, or
4656 * the image (which may or may not have been successful).
4658 bscv_set_jump_to_addr(ssp, 0);
4660 if (res != 0) {
4661 BSCV_TRACE(ssp, 'U', "bscv_prog_image",
4662 "got error 0x%x - leaving programming mode",
4663 res);
4664 cmn_err(CE_WARN, "programming error 0x%x, %s image",
4665 res, is_image2 ? "main" : "loader");
4666 } else {
4667 BSCV_TRACE(ssp, 'U', "bscv_prog_image",
4668 "programming complete - leaving programming mode");
4671 bscv_leave_programming_mode(ssp, B_FALSE);
4672 ssp->loader_running = B_FALSE;
4675 bscv_exit(ssp);
4677 return (res);
4681 static int
4682 bscv_prog_receive_image(bscv_soft_state_t *ssp, lom_prog_t *prog,
4683 uint8_t *imagep, int max_size)
4685 int res = 0;
4686 uint_t size;
4687 int32_t loadaddr;
4688 lom_prog_data_t *prog_data;
4690 if ((prog->index & 0x7FFF) != ssp->prog_index) {
4691 BSCV_TRACE(ssp, 'U', "bscv_prog_receive_image",
4692 "Got wrong buffer 0x%x, expected 0x%x",
4693 prog->index & 0x7fff, ssp->prog_index);
4694 return (EINVAL);
4698 * We want to get the whole image and then do the download.
4699 * It is assumed the device is now in programming mode.
4702 if ((prog->index & 0x7fff) == 0) {
4703 /* Starting a new image */
4704 ssp->image_ptr = 0;
4707 if ((ssp->image_ptr + prog->size) > max_size) {
4708 cmn_err(CE_WARN,
4709 "lom image exceeded maximum size: got 0x%x, maximum 0x%x",
4710 (ssp->image_ptr + prog->size), max_size);
4711 return (EFAULT);
4713 bcopy(prog->data, &imagep[ssp->image_ptr], prog->size);
4714 ssp->image_ptr += prog->size;
4716 ssp->prog_index++;
4718 if (prog->index & 0x8000) {
4720 * OK we have the whole image so synch up and start download.
4722 prog_data = (lom_prog_data_t *)imagep;
4723 if (prog_data->header.magic != PROG_MAGIC) {
4724 /* Old style programming data */
4725 /* Take care image may not fill all of structure */
4727 /* sign extend loadaddr from 16 to 32 bits */
4728 loadaddr = (int16_t)((uint16_t)((imagep[2] << 8) +
4729 imagep[3]));
4731 size = (imagep[0] << 8) + imagep[1];
4732 if (size != (ssp->image_ptr - 4)) {
4733 cmn_err(CE_WARN, "Image size mismatch:"
4734 " expected 0x%x, got 0x%x",
4735 size, (ssp->image_ptr - 1));
4738 res = bscv_prog_image(ssp,
4739 ssp->image2_processing,
4740 imagep + 4, ssp->image_ptr - 4, loadaddr);
4743 * Done the loading so set the flag to say we are doing
4744 * the other image.
4746 ssp->image2_processing = !ssp->image2_processing;
4747 } else if ((ssp->image_ptr < sizeof (*prog_data)) ||
4748 (prog_data->platform.bscv.size !=
4749 (ssp->image_ptr - sizeof (*prog_data)))) {
4750 /* Image too small for new style image */
4751 cmn_err(CE_WARN, "image too small");
4752 res = EINVAL;
4753 } else {
4754 /* New style programming image */
4755 switch (prog_data->platmagic) {
4756 case PROG_PLAT_BSCV_IMAGE:
4757 res = bscv_prog_image(ssp, B_TRUE,
4758 imagep + sizeof (*prog_data),
4759 prog_data->platform.bscv.size,
4760 prog_data->platform.bscv.loadaddr);
4761 ssp->image2_processing = B_FALSE;
4762 break;
4763 case PROG_PLAT_BSCV_LOADER:
4764 res = bscv_prog_image(ssp, B_FALSE,
4765 imagep + sizeof (*prog_data),
4766 prog_data->platform.bscv.size,
4767 prog_data->platform.bscv.loadaddr);
4768 ssp->image2_processing = B_TRUE;
4769 break;
4770 default:
4771 cmn_err(CE_WARN, "unknown platmagic 0x%x",
4772 prog_data->platmagic);
4773 res = EINVAL;
4774 break;
4777 ssp->prog_index = 0;
4778 ssp->image_ptr = 0;
4780 return (res);
4783 static int
4784 bscv_prog_stop_lom(bscv_soft_state_t *ssp)
4786 if (ssp->programming) {
4788 * Already programming - this may be a retry of a failed
4789 * programming attempt or just a software error!
4791 goto queue_stopped;
4794 if (bscv_pause_event_daemon(ssp) == BSCV_FAILURE) {
4795 BSCV_TRACE(ssp, 'Q', "bscv_prog_stop_lom",
4796 "failed to pause event daemon thread");
4797 return (EAGAIN);
4800 bscv_enter(ssp);
4802 ssp->programming = B_TRUE;
4804 bscv_exit(ssp);
4806 queue_stopped:
4808 ssp->prog_index = 0;
4809 ssp->image2_processing = B_FALSE;
4811 return (0);
4814 static int
4815 bscv_prog_start_lom(bscv_soft_state_t *ssp)
4817 int res = 0;
4819 if (!ssp->programming) {
4820 /* Not programming so this is not a valid command */
4821 return (EINVAL);
4824 if (ssp->image != NULL) {
4825 kmem_free((void *)ssp->image, BSC_IMAGE_MAX_SIZE);
4826 ssp->image = NULL;
4830 * OK we are out of reset now so:
4831 * Probe the firmware and set everything up.
4834 bscv_enter(ssp);
4836 /* Explicit clear fault because things may have been mended now */
4837 bscv_clear_fault(ssp);
4839 if (ssp->loader_running) {
4840 cmn_err(CE_WARN, "Firmware upgrade failed to exit loader - "
4841 "performing forced exit");
4842 /* Must try to restart the lom here. */
4843 /* Ensure prog mode entry to enable PRGMODE_OFF */
4844 bscv_put8(ssp, chan_prog,
4845 BSCVA(EBUS_CMD_SPACE_PROGRAM, EBUS_PROGRAM_PCSR),
4846 EBUS_PROGRAM_PCR_PRGMODE_ON);
4847 bscv_put8(ssp, chan_prog,
4848 BSCVA(EBUS_CMD_SPACE_PROGRAM, EBUS_PROGRAM_PCSR),
4849 EBUS_PROGRAM_PCR_PRGMODE_OFF);
4850 ssp->loader_running = B_FALSE;
4851 /* give the lom chance to recover */
4852 delay(drv_usectohz(5000000)); /* 5 seconds */
4855 ssp->prog_mode_only = B_FALSE;
4856 ssp->programming = B_FALSE;
4858 if (bscv_attach_common(ssp) == DDI_FAILURE) {
4859 ssp->prog_mode_only = B_TRUE;
4860 res = EIO;
4863 bscv_exit(ssp);
4865 if (!ssp->prog_mode_only) {
4867 * Start the event thread after the queue has started
4869 * Not sure if this is entirely correct because
4870 * the other code at the end of bscv_attach()
4871 * does not get run here.
4873 bscv_start_event_daemon(ssp);
4874 bscv_resume_event_daemon(ssp);
4877 return (res);
4882 * *********************************************************************
4883 * Attach processing
4884 * *********************************************************************
4888 * function - bscv_attach_common
4889 * description - this routine co-ordinates the initialisation of the
4890 * driver both at attach time and after firmware programming.
4891 * sequence - bscv_setup_capability - read LOMlite2 capabilities
4892 * bscv_probe_check - test comms and setup register cache
4893 * bscv_setup_hostname - sync stored name in lom with nodename.
4894 * bscv_setup_static_info - read device names etc.
4895 * bscv_setup_events - start event daemon etc.
4897 * inputs - device information structure, DDI_ATTACH command
4898 * outputs - DDI_SUCCESS or DDI_FAILURE
4901 static int
4902 bscv_attach_common(bscv_soft_state_t *ssp)
4904 ASSERT(bscv_held(ssp));
4906 BSCV_TRACE(ssp, 'A', "bscv_attach_common:", "");
4909 * Set the threshold for reporting messages to the console to
4910 * Warnings or higher.
4912 ssp->reporting_level = 2;
4915 * When the system is not running the Operating System, make
4916 * the microcontroller print event messages straight onto the
4917 * console.
4919 ssp->serial_reporting = LOM_SER_EVENTS_DEF;
4921 /* Setup capabilities */
4922 bscv_setup_capability(ssp);
4924 if (bscv_probe_check(ssp) == DDI_FAILURE) {
4925 cmn_err(CE_WARN, "BSC chip not responding");
4927 * We want lom -G to talk to this driver upon broken firmware
4928 * so we prematurely return success here.
4930 return (DDI_SUCCESS);
4933 bscv_setup_hostname(ssp);
4934 bscv_setup_static_info(ssp);
4935 bscv_setup_events(ssp);
4937 #if defined(__i386) || defined(__amd64)
4938 bscv_inform_bsc(ssp, BSC_INFORM_ONLINE);
4939 #endif /* __i386 || __amd64 */
4941 * Watchdog configuration and CPU signatures are sent asynchronously
4942 * with respect to attach so only inform the BSC if we've already
4943 * sent the data in the past.
4946 if (ssp->progress & BSCV_WDOG_CFG)
4947 bscv_setup_watchdog(ssp);
4950 return (DDI_SUCCESS);
4954 * function - bscv_cleanup
4955 * description - routine that does the necessary tidying up if the attach
4956 * request fails or the driver is to be detached.
4957 * If the event thread has been started we may fail to
4958 * stop it (because it is busy) so we fail the cleanup
4959 * and hence the detach. All other calls to bscv_cleanup
4960 * are done before the event daemon is started.
4961 * inputs - soft state structure address.
4962 * outputs - DDI_SUCCESS or DDI_FAILURE.
4965 static int
4966 bscv_cleanup(bscv_soft_state_t *ssp)
4968 int instance;
4969 uint8_t bits2set;
4970 uint8_t bits2clear;
4972 instance = ssp->instance;
4974 if (ssp->progress & BSCV_LOCKS) {
4975 bscv_enter(ssp);
4978 if (ssp->progress & BSCV_THREAD) {
4979 if (bscv_stop_event_daemon(ssp) == DDI_FAILURE) {
4980 /* Fail the cleanup - may be able to cleanup later */
4981 if (ssp->progress & BSCV_LOCKS) {
4982 bscv_exit(ssp);
4984 return (DDI_FAILURE);
4988 if (ssp->progress & BSCV_NODES) {
4989 ddi_remove_minor_node(ssp->dip, NULL);
4992 if (ssp->progress & BSCV_MAPPED_REGS) {
4994 * switch back on serial event reporting - cover all configs.
4996 bits2set = 0;
4997 bits2clear = 0;
4998 if (ssp->serial_reporting == LOM_SER_EVENTS_ON) {
4999 bits2clear |= EBUS_ALARM_NOEVENTS;
5000 } else if (ssp->serial_reporting == LOM_SER_EVENTS_OFF) {
5001 bits2set |= EBUS_ALARM_NOEVENTS;
5002 } else if (ssp->serial_reporting == LOM_SER_EVENTS_DEF) {
5003 bits2clear |= EBUS_ALARM_NOEVENTS;
5005 bscv_setclear8_volatile(ssp, chan_general, EBUS_IDX_ALARM,
5006 bits2set, bits2clear);
5009 * disable the reset function if we have enabled
5010 * it. We don't want any nasty surprises like system
5011 * rebooting unexpectedly. If we timeout on the busy
5012 * flag we just have to carry on.
5015 BSCV_TRACE(ssp, 'W', "bscv_cleanup",
5016 "bscv_cleanup - disable wdog");
5017 if (bscv_get8_cached(ssp, EBUS_IDX_WDOG_CTRL) &
5018 EBUS_WDOG_ENABLE) {
5019 bscv_setclear8(ssp, chan_general, EBUS_IDX_WDOG_CTRL,
5020 0, EBUS_WDOG_RST | EBUS_WDOG_ENABLE);
5025 * unmap registers
5028 if (ssp->progress & BSCV_MAPPED_REGS) {
5029 bscv_unmap_regs(ssp);
5033 * release any memory allocated for mutexes and condition
5034 * variables before deallocating the structures containing them
5037 if (ssp->progress & BSCV_LOCKS) {
5038 bscv_exit(ssp);
5039 cv_destroy(&ssp->task_cv);
5040 cv_destroy(&ssp->task_evnt_cv);
5041 mutex_destroy(&ssp->task_mu);
5042 mutex_destroy(&ssp->prog_mu);
5043 mutex_destroy(&ssp->cmd_mutex);
5046 if (ssp->image != NULL) {
5047 kmem_free((void *)ssp->image, BSC_IMAGE_MAX_SIZE);
5050 #if defined(__i386) || defined(__amd64)
5051 bscv_watchdog_cyclic_remove(ssp);
5052 #endif /* __i386 || __amd64 */
5053 ddi_soft_state_free(bscv_statep, instance);
5055 return (DDI_SUCCESS);
5059 * function - bscv_setup_capability
5060 * description - probe the lom find what capabilities are present for
5061 * us to use.
5062 * inputs - soft state ptr
5063 * outputs - returns DDI_SUCCESS or DDI_FAILURE
5065 static void bscv_setup_capability(bscv_soft_state_t *ssp)
5067 ASSERT(bscv_held(ssp));
5069 if (ssp->prog_mode_only) {
5070 /* Turn off all capabilities */
5071 ssp->cap0 = 0;
5072 ssp->cap1 = 0;
5073 ssp->cap2 = 0;
5074 return;
5077 ssp->cap0 = bscv_get8(ssp, chan_general, EBUS_IDX_CAP0);
5078 ssp->cap1 = bscv_get8(ssp, chan_general, EBUS_IDX_CAP1);
5079 ssp->cap2 = bscv_get8(ssp, chan_general, EBUS_IDX_CAP2);
5080 if (!bscv_faulty(ssp)) {
5081 BSCV_TRACE(ssp, 'A', "bscv_setup_capability",
5082 "Capability flags cap0=0x%x cap1=0x%x, cap2=0x%x",
5083 ssp->cap0, ssp->cap1, ssp->cap2);
5084 } else {
5085 cmn_err(CE_WARN, "!Could not read capability flags");
5086 ssp->cap0 = 0; ssp->cap1 = 0; ssp->cap2 = 0;
5091 * function - bscv_probe_check
5092 * description - probe the lom to check for correct operation
5093 * has a side effect of setting up the cached registers and
5094 * updates ssp->prog_mode_only.
5095 * inputs - soft state ptr
5096 * outputs - returns DDI_SUCCESS or DDI_FAILURE
5099 static int bscv_probe_check(bscv_soft_state_t *ssp)
5101 int i;
5102 uint8_t probeval;
5104 ASSERT(bscv_held(ssp));
5106 BSCV_TRACE(ssp, 'A', "bscv_probe_check", "");
5108 if (!ssp->prog_mode_only) {
5110 * Make sure probe location is OK so that we are
5111 * in sync.
5112 * We want to make sure that this is not faulty so we
5113 * do a bscv_clear_fault to clear any existing
5114 * fault records down.
5116 bscv_clear_fault(ssp);
5117 probeval = bscv_get8(ssp, chan_general, EBUS_IDX_PROBEAA);
5118 if (bscv_faulty(ssp)) {
5119 ssp->prog_mode_only = B_TRUE;
5120 } else if (probeval != 0xAA) {
5121 BSCV_TRACE(ssp, 'A', "bscv_probe_check",
5122 "LOMlite out of sync");
5125 * It may be that the LOMlite was out of
5126 * sync so lets try the read again.
5128 probeval = bscv_get8(ssp, chan_general,
5129 EBUS_IDX_PROBEAA);
5130 if (bscv_faulty(ssp)) {
5131 BSCV_TRACE(ssp, 'A', "bscv_probe_check",
5132 "Init readAA1 failed");
5133 ssp->prog_mode_only = B_TRUE;
5134 } else if (probeval != 0xAA) {
5136 * OK that is twice we are out so I
5137 * guess the LOMlite is in trouble
5139 BSCV_TRACE(ssp, 'A', "bscv_probe_check",
5140 "Init readAA probe failed - got 0x%x",
5141 probeval);
5142 ssp->prog_mode_only = B_TRUE;
5148 * Read in all page zero lom registers.
5149 * Read state change 1st so we dont miss anything and clear it.
5150 * Note: we discard the values because we rely on bscv_get8 to
5151 * setup the cache of register values.
5154 if (!ssp->prog_mode_only) {
5155 (void) bscv_get8(ssp, chan_general, EBUS_IDX_STATE_CHNG);
5156 if (bscv_faulty(ssp)) {
5157 BSCV_TRACE(ssp, 'A', "bscv_probe_check",
5158 "Read of state change register failed");
5159 ssp->prog_mode_only = B_TRUE;
5163 if (!ssp->prog_mode_only) {
5164 for (i = 1; i < 0x80; i++) {
5165 switch (i) {
5166 case EBUS_IDX_STATE_CHNG:
5167 case EBUS_IDX_CMD_RES:
5168 case EBUS_IDX_HNAME_CHAR:
5170 * Should not read these - they have side
5171 * effects.
5173 break;
5174 default:
5175 (void) bscv_get8(ssp, chan_general, i);
5176 break;
5178 if (bscv_faulty(ssp)) {
5179 BSCV_TRACE(ssp, 'A', "bscv_probe_check",
5180 "Initial read or register %2x failed", i);
5181 ssp->prog_mode_only = B_TRUE;
5182 /* Might as well give up now! */
5183 break;
5189 * Check the probe keys so we know the lom is OK
5192 if (!ssp->prog_mode_only) {
5193 if ((bscv_get8_cached(ssp, EBUS_IDX_PROBE55) != 0x55) ||
5194 (bscv_get8_cached(ssp, EBUS_IDX_PROBEAA) != 0xAA)) {
5196 BSCV_TRACE(ssp, 'A', "bscv_probe_check",
5197 "LOMlite Probe failed");
5198 for (i = 0; i < 0x8; i++) {
5199 BSCV_TRACE(ssp, 'A', "bscv_probe_check",
5200 "%2x %2x %2x %2x %2x %2x %2x %2x %2x "
5201 "%2x %2x %2x %2x %2x %2x %2x %2x %2x",
5202 bscv_get8_cached(ssp, i),
5203 bscv_get8_cached(ssp, i + 1),
5204 bscv_get8_cached(ssp, i + 2),
5205 bscv_get8_cached(ssp, i + 3),
5206 bscv_get8_cached(ssp, i + 4),
5207 bscv_get8_cached(ssp, i + 5),
5208 bscv_get8_cached(ssp, i + 6),
5209 bscv_get8_cached(ssp, i + 7),
5210 bscv_get8_cached(ssp, i + 8),
5211 bscv_get8_cached(ssp, i + 9),
5212 bscv_get8_cached(ssp, i + 10),
5213 bscv_get8_cached(ssp, i + 11),
5214 bscv_get8_cached(ssp, i + 12),
5215 bscv_get8_cached(ssp, i + 13),
5216 bscv_get8_cached(ssp, i + 14),
5217 bscv_get8_cached(ssp, i + 15));
5219 ssp->prog_mode_only = B_TRUE;
5223 return ((ssp->prog_mode_only == B_FALSE) ? DDI_SUCCESS : DDI_FAILURE);
5227 static void
5228 bscv_wdog_do_pat(bscv_soft_state_t *ssp)
5230 uint8_t pat;
5233 * The value of the dog pat is a sequence number which wraps around,
5234 * bounded by BSCV_WDOG_PAT_SEQ_MASK.
5236 pat = ssp->pat_seq++;
5237 pat &= EBUS_WDOG_NB_PAT_SEQ_MASK;
5239 /* Set top nibble to indicate a pat */
5240 pat |= EBUS_WDOG_NB_PAT;
5243 * Now pat the dog. This exercises a special protocol in the
5244 * bus nexus that offers : non-blocking IO, and timely delivery,
5245 * callable from high-level interrupt context. The requirement
5246 * on us is that the channel is not shared for any other use.
5247 * This means for chan_wdogpat, nothing may use channel[chan].regs
5248 * or channel.[chan].handle.
5251 ddi_put8(ssp->channel[chan_wdogpat].handle,
5252 ssp->channel[chan_wdogpat].regs, pat);
5254 BSCV_TRACE(ssp, 'W', "bscv_wdog_pat", "patted the dog with seq %d",
5255 pat);
5259 static void
5260 bscv_write_wdog_cfg(bscv_soft_state_t *ssp,
5261 uint_t wdog_timeout_s,
5262 boolean_t enable_wdog,
5263 uint8_t reset_system_on_timeout)
5265 uint8_t cfg = EBUS_WDOG_NB_CFG;
5268 * Configure the timeout value (1 to 127 seconds).
5269 * Note that a policy is implemented at the bsc/ssp which bounds
5270 * the value further. The bounding here is to fit the timeout value
5271 * into the 7 bits the bsc uses.
5273 if (wdog_timeout_s < 1)
5274 ssp->watchdog_timeout = 1;
5275 else if (wdog_timeout_s > 127)
5276 ssp->watchdog_timeout = 127;
5277 else
5278 ssp->watchdog_timeout = wdog_timeout_s;
5281 * Configure the watchdog on or off.
5283 if (enable_wdog)
5284 cfg |= EBUS_WDOG_NB_CFG_ENB;
5285 else
5286 cfg &= ~EBUS_WDOG_NB_CFG_ENB;
5289 * Configure whether the microcontroller should reset the system when
5290 * the watchdog expires.
5292 ssp->watchdog_reset_on_timeout = reset_system_on_timeout;
5294 ddi_put8(ssp->channel[chan_wdogpat].handle,
5295 ssp->channel[chan_wdogpat].regs, cfg);
5297 /* have the event daemon set the timeout value and whether to reset */
5298 ssp->watchdog_change = B_TRUE;
5300 BSCV_TRACE(ssp, 'W', "bscv_wdog_cfg",
5301 "configured the dog with cfg 0x%x", cfg);
5305 * function - bscv_setup_watchdog
5306 * description - setup the bsc watchdog
5307 * inputs - soft state ptr
5308 * outputs -
5310 static void bscv_setup_watchdog(bscv_soft_state_t *ssp)
5312 uint8_t set = 0;
5313 uint8_t clear = 0;
5315 ASSERT(bscv_held(ssp));
5317 /* Set the timeout */
5318 bscv_put8(ssp, chan_general,
5319 EBUS_IDX_WDOG_TIME, ssp->watchdog_timeout);
5321 /* Set whether to reset the system on timeout */
5322 if (ssp->watchdog_reset_on_timeout) {
5323 set |= EBUS_WDOG_RST;
5324 } else {
5325 clear |= EBUS_WDOG_RST;
5328 if (watchdog_activated) {
5329 set |= EBUS_WDOG_ENABLE;
5330 } else {
5331 clear |= EBUS_WDOG_ENABLE;
5334 /* Set other host defaults */
5335 clear |= (EBUS_WDOG_BREAK_DISABLE | EBUS_WDOG_AL3_FANPSU
5336 | EBUS_WDOG_AL3_WDOG);
5338 bscv_setclear8_volatile(ssp, chan_general, EBUS_IDX_WDOG_CTRL,
5339 set, clear);
5341 #if defined(__i386) || defined(__amd64)
5342 /* start the cyclic based watchdog patter */
5343 bscv_watchdog_cyclic_add(ssp);
5344 #endif /* __i386 || __amd64 */
5345 ssp->progress |= BSCV_WDOG_CFG;
5350 * function - bscv_setup_hostname
5351 * description - setup the lom hostname if different from the nodename
5352 * inputs - soft state ptr
5353 * outputs - none
5356 static void bscv_setup_hostname(bscv_soft_state_t *ssp)
5358 char host_nodename[128];
5359 char lom_nodename[128];
5360 size_t hostlen;
5361 size_t nodelen;
5363 ASSERT(bscv_held(ssp));
5366 * Check machine label is the same as the
5367 * system nodename.
5369 (void) strncpy(host_nodename, utsname.nodename,
5370 sizeof (host_nodename));
5372 /* read in lom hostname */
5373 bscv_read_hostname(ssp, lom_nodename);
5375 /* Enforce null termination */
5376 host_nodename[sizeof (host_nodename) - 1] = '\0';
5377 lom_nodename[sizeof (lom_nodename) - 1] = '\0';
5379 hostlen = (size_t)bscv_get8(ssp, chan_general, EBUS_IDX_HNAME_LENGTH);
5380 nodelen = (size_t)strlen(host_nodename);
5381 if ((nodelen > 0) &&
5382 ((hostlen != nodelen) || (strcmp((const char *)&lom_nodename,
5383 (const char *)&host_nodename)) ||
5384 (hostlen == 0))) {
5385 BSCV_TRACE(ssp, 'A', "bscv_setup_hostname",
5386 "nodename(%s,%d) != bsc label(%s,%d)",
5387 host_nodename, nodelen, lom_nodename, hostlen);
5389 /* Write new label into LOM EEPROM */
5390 bscv_write_hostname(ssp,
5391 host_nodename,
5392 (uint8_t)strlen(host_nodename));
5395 ssp->progress |= BSCV_HOSTNAME_DONE;
5399 * function - bscv_read_hostname
5400 * description - read the current hostname from the lom
5401 * inputs - soft state pointer and buffer to store the hostname in.
5402 * outputs - none
5405 static void
5406 bscv_read_hostname(bscv_soft_state_t *ssp, char *lom_nodename)
5408 int num_failures;
5409 boolean_t needretry;
5410 int length;
5411 int i;
5413 ASSERT(bscv_held(ssp));
5416 * We have a special failure case here because a retry of a read
5417 * causes data to be lost. Thus we handle the retries ourselves
5418 * and are also responsible for detemining if the lom is faulty
5420 for (num_failures = 0;
5421 num_failures < BSC_FAILURE_RETRY_LIMIT;
5422 num_failures++) {
5423 bscv_clear_fault(ssp);
5424 length = bscv_get8(ssp, chan_general, EBUS_IDX_HNAME_LENGTH);
5425 if (bscv_faulty(ssp)) {
5426 needretry = 1;
5427 } else {
5428 needretry = 0;
5429 for (i = 0; i < length; i++) {
5430 lom_nodename[i] = bscv_get8_once(ssp,
5431 chan_general, EBUS_IDX_HNAME_CHAR);
5432 /* Retry on any error */
5433 if (bscv_retcode(ssp) != 0) {
5434 needretry = 1;
5435 break;
5438 /* null terminate for strcmp later */
5439 lom_nodename[length] = '\0';
5441 if (!needretry) {
5442 break;
5444 /* Force the nodename to be empty */
5445 lom_nodename[0] = '\0';
5448 if (needretry) {
5449 /* Failure - we ran out of retries */
5450 cmn_err(CE_WARN,
5451 "bscv_read_hostname: retried %d times, giving up",
5452 num_failures);
5453 ssp->had_fault = B_TRUE;
5454 } else if (num_failures > 0) {
5455 BSCV_TRACE(ssp, 'R', "bscv_read_hostname",
5456 "retried %d times, succeeded", num_failures);
5461 * function - bscv_write_hostname
5462 * description - write a new hostname to the lom
5463 * inputs - soft state pointer, pointer to new name, name length
5464 * outputs - none
5466 static void
5467 bscv_write_hostname(bscv_soft_state_t *ssp,
5468 char *host_nodename, uint8_t length)
5470 int num_failures;
5471 boolean_t needretry;
5472 int i;
5474 ASSERT(bscv_held(ssp));
5477 * We have a special failure case here because a retry of a read
5478 * causes data to be lost. Thus we handle the retries ourselves
5479 * and are also responsible for detemining if the lom is faulty
5481 for (num_failures = 0;
5482 num_failures < BSC_FAILURE_RETRY_LIMIT;
5483 num_failures++) {
5484 bscv_clear_fault(ssp);
5485 bscv_put8(ssp, chan_general, EBUS_IDX_HNAME_LENGTH, length);
5486 if (bscv_faulty(ssp)) {
5487 needretry = 1;
5488 } else {
5489 needretry = 0;
5490 for (i = 0; i < length; i++) {
5491 bscv_put8_once(ssp, chan_general,
5492 EBUS_IDX_HNAME_CHAR, host_nodename[i]);
5493 /* Retry on any error */
5494 if (bscv_retcode(ssp) != 0) {
5495 needretry = 1;
5496 break;
5500 if (!needretry) {
5501 break;
5505 if (needretry) {
5506 /* Failure - we ran out of retries */
5507 cmn_err(CE_WARN,
5508 "bscv_write_hostname: retried %d times, giving up",
5509 num_failures);
5510 ssp->had_fault = B_TRUE;
5511 } else if (num_failures > 0) {
5512 BSCV_TRACE(ssp, 'R', "bscv_write_hostname",
5513 "retried %d times, succeeded", num_failures);
5518 * function - bscv_setup_static_info
5519 * description - read in static information from the lom at attach time.
5520 * inputs - soft state ptr
5521 * outputs - none
5524 static void
5525 bscv_setup_static_info(bscv_soft_state_t *ssp)
5527 uint8_t addr_space_ptr;
5528 uint16_t mask;
5529 uint8_t fanspeed;
5530 int oldtemps[MAX_TEMPS];
5531 int8_t temp;
5532 int i;
5534 ASSERT(bscv_held(ssp));
5537 * Finally read in some static info like device names,
5538 * shutdown enabled, etc before the queue starts.
5542 * To get the volts static info we need address space 2
5544 bzero(&ssp->volts, sizeof (lom_volts_t));
5545 ssp->volts.num = EBUS_CONFIG2_NSUPPLY_DEC(
5546 bscv_get8(ssp, chan_general, EBUS_IDX_CONFIG2));
5547 if (ssp->volts.num > MAX_VOLTS) {
5548 cmn_err(CE_WARN,
5549 "lom: firmware reported too many voltage lines. ");
5550 cmn_err(CE_CONT, "Reported %d, maximum is %d",
5551 ssp->volts.num, MAX_VOLTS);
5552 ssp->volts.num = MAX_VOLTS;
5555 BSCV_TRACE(ssp, 'A', "bscv_setup_static_info",
5556 "num volts %d", ssp->volts.num);
5557 (void) bscv_read_env_name(ssp,
5558 EBUS_CMD_SPACE2,
5559 EBUS_IDX2_SUPPLY_NAME_START,
5560 EBUS_IDX2_SUPPLY_NAME_END,
5561 ssp->volts.name,
5562 ssp->volts.num);
5564 mask = bscv_get8(ssp, chan_general, BSCVA(EBUS_CMD_SPACE2,
5565 EBUS_IDX2_SUPPLY_FATAL_MASK1)) << 8;
5566 mask |= bscv_get8(ssp, chan_general, BSCVA(EBUS_CMD_SPACE2,
5567 EBUS_IDX2_SUPPLY_FATAL_MASK2));
5569 for (i = 0; i < ssp->volts.num; i++) {
5570 ssp->volts.shutdown_enabled[i] =
5571 (((mask >> i) & 1) == 0) ? 0 : 1;
5575 * Get the temperature static info and populate initial temperatures.
5576 * Do not destroy old temperature values if the new value is not
5577 * known i.e. if the device is inaccessible.
5579 bcopy(ssp->temps.temp, oldtemps, sizeof (oldtemps));
5581 bzero(&ssp->temps, sizeof (lom_temp_t));
5582 ssp->temps.num = EBUS_CONFIG2_NTEMP_DEC(
5583 bscv_get8(ssp, chan_general, EBUS_IDX_CONFIG2));
5584 if (ssp->temps.num > MAX_TEMPS) {
5585 cmn_err(CE_WARN,
5586 "lom: firmware reported too many temperatures being "
5587 "monitored.");
5588 cmn_err(CE_CONT, "Reported %d, maximum is %d",
5589 ssp->temps.num, MAX_TEMPS);
5590 ssp->temps.num = MAX_TEMPS;
5592 ssp->temps.num_ov = EBUS_CONFIG3_NOTEMP_DEC(
5593 bscv_get8(ssp, chan_general, EBUS_IDX_CONFIG3));
5594 if (ssp->temps.num_ov > MAX_TEMPS) {
5595 cmn_err(CE_WARN,
5596 "lom: firmware reported too many over temperatures being "
5597 "monitored.");
5598 cmn_err(CE_CONT, "Reported %d, maximum is %d",
5599 ssp->temps.num_ov, MAX_TEMPS);
5600 ssp->temps.num_ov = MAX_TEMPS;
5602 BSCV_TRACE(ssp, 'A', "bscv_setup_static_info",
5603 "num temps %d, over temps %d",
5604 ssp->temps.num, ssp->temps.num_ov);
5606 addr_space_ptr = bscv_read_env_name(ssp,
5607 EBUS_CMD_SPACE4,
5608 EBUS_IDX4_TEMP_NAME_START,
5609 EBUS_IDX4_TEMP_NAME_END,
5610 ssp->temps.name,
5611 ssp->temps.num);
5613 for (i = 0; i < ssp->temps.num; i++) {
5614 ssp->temps.warning[i] = (int8_t)bscv_get8(ssp, chan_general,
5615 BSCVA(EBUS_CMD_SPACE4, EBUS_IDX4_TEMP_WARN1 + i));
5618 * If shutdown is not enabled then set it as zero so
5619 * it is not displayed by the utility.
5621 if ((bscv_get8(ssp, chan_general, BSCVA(EBUS_CMD_SPACE4,
5622 EBUS_IDX4_TEMP_FATAL_MASK)) >> i) & 0x01) {
5623 ssp->temps.shutdown[i] = (int8_t)bscv_get8(ssp,
5624 chan_general,
5625 BSCVA(EBUS_CMD_SPACE4, EBUS_IDX4_TEMP_SDOWN1 + i));
5626 } else {
5627 ssp->temps.shutdown[i] = 0;
5631 for (i = 0; i < ssp->temps.num; i++) {
5632 temp = bscv_get8(ssp, chan_general, EBUS_IDX_TEMP1 + i);
5633 if ((temp <= LOM_TEMP_MAX_VALUE) ||
5634 (temp == LOM_TEMP_STATE_NOT_PRESENT)) {
5635 ssp->temps.temp[i] = temp;
5636 } else {
5637 /* New value is not known - use old value */
5638 ssp->temps.temp[i] = oldtemps[i];
5643 * Check for and skip a single 0xff character between the
5644 * temperature and over temperature names
5646 if (bscv_get8(ssp, chan_general,
5647 BSCVA(EBUS_CMD_SPACE4, addr_space_ptr)) == 0xff) {
5648 addr_space_ptr++;
5651 (void) bscv_read_env_name(ssp,
5652 EBUS_CMD_SPACE4,
5653 addr_space_ptr,
5654 EBUS_IDX4_TEMP_NAME_END,
5655 ssp->temps.name_ov,
5656 ssp->temps.num_ov);
5659 * To get the CB static info we need address space 3
5661 bzero(&ssp->sflags, sizeof (lom_sflags_t));
5662 ssp->sflags.num = EBUS_CONFIG3_NBREAKERS_DEC(bscv_get8(ssp,
5663 chan_general, EBUS_IDX_CONFIG3));
5664 if (ssp->sflags.num > MAX_STATS) {
5665 cmn_err(CE_WARN,
5666 "lom: firmware reported too many status flags.");
5667 cmn_err(CE_CONT,
5668 "Reported %d, maximum is %d",
5669 ssp->sflags.num, MAX_STATS);
5670 ssp->sflags.num = MAX_STATS;
5672 BSCV_TRACE(ssp, 'A', "bscv_setup_static_info",
5673 "num sflags %d", ssp->sflags.num);
5675 (void) bscv_read_env_name(ssp,
5676 EBUS_CMD_SPACE3,
5677 EBUS_IDX3_BREAKER_NAME_START,
5678 EBUS_IDX3_BREAKER_NAME_END,
5679 ssp->sflags.name,
5680 ssp->sflags.num);
5684 * To get the fan static info we need address space 5
5686 ssp->num_fans = EBUS_CONFIG_NFAN_DEC(
5687 bscv_get8(ssp, chan_general, EBUS_IDX_CONFIG));
5688 if (ssp->num_fans > MAX_FANS) {
5689 cmn_err(CE_WARN,
5690 "lom: firmware reported too many fans. ");
5691 cmn_err(CE_CONT,
5692 "Reported %d, maximum is %d",
5693 ssp->num_fans, MAX_FANS);
5694 ssp->num_fans = MAX_FANS;
5697 for (i = 0; i < ssp->num_fans; i++) {
5698 fanspeed = bscv_get8(ssp, chan_general,
5699 EBUS_IDX_FAN1_SPEED + i);
5700 if ((fanspeed <= LOM_FAN_MAX_SPEED) ||
5701 (fanspeed == LOM_FAN_NOT_PRESENT)) {
5703 * Do not destroy previous values unless the
5704 * value is definitive.
5706 ssp->fanspeed[i] = fanspeed;
5710 BSCV_TRACE(ssp, 'A', "bscv_setup_static_info",
5711 "num fans %d", ssp->num_fans);
5713 (void) bscv_read_env_name(ssp,
5714 EBUS_CMD_SPACE5,
5715 EBUS_IDX5_FAN_NAME_START,
5716 EBUS_IDX5_FAN_NAME_END,
5717 ssp->fan_names,
5718 ssp->num_fans);
5720 /* Get led static information from address space 10 */
5722 (void) bscv_read_env_name(ssp,
5723 EBUS_CMD_SPACE_LEDS,
5724 EBUS_IDX10_LED_NAME_START,
5725 EBUS_IDX10_LED_NAME_END,
5726 ssp->led_names,
5727 MAX_LED_ID);
5731 * function - bscv_read_env_name
5732 * description - read in static environment names
5733 * warning changes address space and the caller relies
5734 * on this behaviour.
5735 * inputs - soft state ptr, chosen address space,
5736 * start of name data, end of name data,
5737 * name storage, number of names.
5738 * outputs - next address for reading name data.
5741 static uint8_t
5742 bscv_read_env_name(bscv_soft_state_t *ssp,
5743 uint8_t addr_space,
5744 uint8_t addr_start,
5745 uint8_t addr_end,
5746 char namebuf[][MAX_LOM2_NAME_STR],
5747 int numnames)
5749 int i;
5750 int nameidx;
5751 int namemax;
5752 unsigned int addr_space_ptr;
5753 uint8_t this_char;
5755 ASSERT(bscv_held(ssp));
5757 BSCV_TRACE(ssp, 'A', "bscv_read_env_name",
5758 "bscv_read_env_name, space %d, start 0x%x, end 0x%x, numnames %d",
5759 addr_space, addr_start, addr_end, numnames);
5761 addr_space_ptr = addr_start;
5763 for (i = 0; i < numnames; i++) {
5764 nameidx = 0;
5765 namemax = sizeof (namebuf[i]);
5766 bzero(namebuf[i], namemax);
5768 while (addr_space_ptr <= addr_end) {
5770 * Read the current character.
5772 this_char = bscv_get8(ssp, chan_general,
5773 BSCVA(addr_space, addr_space_ptr));
5775 if (this_char == 0xff) {
5777 * Ran out of names - this must
5778 * be the end of the name.
5779 * This is really an error because
5780 * we have just seen either a non-NUL
5781 * terminated string or the number of
5782 * strings did not match what was
5783 * reported.
5785 break;
5788 * We increment the buffer pointer now so that
5789 * it is ready for the next read
5791 addr_space_ptr++;
5793 if (this_char == '\0') {
5794 /* Found end of string - done */
5795 break;
5797 if (nameidx < (namemax - 1)) {
5799 * Buffer not full - record character
5800 * NOTE we always leave room for the NUL
5801 * terminator.
5803 namebuf[i][nameidx++] = this_char;
5806 /* Ensure null termination */
5807 namebuf[i][nameidx] = '\0';
5809 /* Clamp addr_space_ptr to 0xff because we return uint8_t */
5810 if (addr_space_ptr > 0xff) {
5811 addr_space_ptr = 0xff;
5813 return (addr_space_ptr);
5817 * function - bscv_setup_events
5818 * description - initialise the event reporting code
5819 * inputs - soft state ptr
5820 * outputs - DDI_SUCCESS or DDI_FAILURE
5823 static void
5824 bscv_setup_events(bscv_soft_state_t *ssp)
5826 uint8_t bits2set;
5827 uint8_t bits2clear;
5829 ASSERT(bscv_held(ssp));
5832 * deal with event reporting - cover all cases
5835 bits2set = 0;
5836 bits2clear = 0;
5837 if (ssp->serial_reporting == LOM_SER_EVENTS_ON) {
5838 bits2clear |= EBUS_ALARM_NOEVENTS;
5839 } else if (ssp->serial_reporting == LOM_SER_EVENTS_OFF) {
5840 bits2set |= EBUS_ALARM_NOEVENTS;
5841 } else if (ssp->serial_reporting == LOM_SER_EVENTS_DEF) {
5842 bits2set |= EBUS_ALARM_NOEVENTS;
5844 bscv_setclear8_volatile(ssp, chan_general, EBUS_IDX_ALARM,
5845 bits2set, bits2clear);
5849 #if defined(__i386) || defined(__amd64)
5852 * function - bscv_inform_bsc
5853 * description - inform bsc of driver state for logging purposes
5854 * inputs - driver soft state, state
5855 * outputs - none
5858 static void
5859 bscv_inform_bsc(bscv_soft_state_t *ssp, uint32_t state)
5861 ASSERT(bscv_held(ssp));
5863 BSCV_TRACE(ssp, 'X', "bscv_inform_bsc",
5864 "bscv_inform_bsc: state=%d", state);
5866 bscv_put32(ssp, chan_general,
5867 BSCVA(EBUS_CMD_SPACE_CPUSIG, EBUS_IDX11_CPU_SIG_MSB), state);
5868 bscv_put8(ssp, chan_cpusig,
5869 BSCVA(EBUS_CMD_SPACE_CPUSIG, EBUS_IDX11_CPU_ID), EBUS_ANY_CPU_ID);
5873 * function - bscv_watchdog_pat_request
5874 * description - request a heartbeat pat
5875 * inputs - timeout value in seconds
5876 * outputs - none
5878 static void
5879 bscv_watchdog_pat_request(void *arg)
5881 bscv_soft_state_t *ssp = (bscv_soft_state_t *)arg;
5883 bscv_wdog_do_pat(ssp);
5887 * function - bscv_watchdog_cfg_request
5888 * description - request configuration of the bsc hardware watchdog
5889 * inputs - new state (0=disabled, 1=enabled)
5890 * outputs - one if successful, zero if unsuccesful
5892 static void
5893 bscv_watchdog_cfg_request(bscv_soft_state_t *ssp, uint8_t new_state)
5895 ASSERT(new_state == WDOG_ON || new_state == WDOG_OFF);
5897 watchdog_activated = new_state;
5898 BSCV_TRACE(ssp, 'X', "bscv_watchdog_cfg_request",
5899 "watchdog_activated=%d", watchdog_activated);
5900 bscv_write_wdog_cfg(ssp,
5901 bscv_watchdog_timeout_seconds,
5902 new_state,
5903 wdog_reset_on_timeout);
5907 * function - bscv_set_watchdog_timer
5908 * description - setup the heartbeat timeout value
5909 * inputs - timeout value in seconds
5910 * outputs - zero if the value was not changed
5911 * otherwise the current value
5913 static uint_t
5914 bscv_set_watchdog_timer(bscv_soft_state_t *ssp, uint_t timeoutval)
5916 BSCV_TRACE(ssp, 'X', "bscv_set_watchdog_timer:",
5917 "timeout=%d", timeoutval);
5920 * We get started during bscv_attach only
5921 * if bscv_watchdog_enable is set.
5923 if (bscv_watchdog_available && (!watchdog_activated ||
5924 (watchdog_activated &&
5925 (timeoutval != bscv_watchdog_timeout_seconds)))) {
5926 bscv_watchdog_timeout_seconds = timeoutval;
5927 bscv_watchdog_cfg_request(ssp, WDOG_ON);
5928 return (bscv_watchdog_timeout_seconds);
5930 return (0);
5934 * function - bscv_clear_watchdog_timer
5935 * description - add the watchdog patter cyclic
5936 * inputs - driver soft state
5937 * outputs - value of watchdog timeout in seconds
5939 * This function is a copy of the SPARC implementation
5940 * in the todblade clock driver.
5942 static void
5943 bscv_clear_watchdog_timer(bscv_soft_state_t *ssp)
5945 BSCV_TRACE(ssp, 'X', "bscv_clear_watchdog_timer", "");
5947 if (bscv_watchdog_available && watchdog_activated) {
5948 bscv_watchdog_enable = 0;
5949 bscv_watchdog_cfg_request(ssp, WDOG_OFF);
5954 * function - bscv_panic_callback
5955 * description - called when we panic so we can disabled the watchdog
5956 * inputs - driver soft state pointer
5957 * outputs - DDI_SUCCESS
5959 /*ARGSUSED1*/
5960 static boolean_t
5961 bscv_panic_callback(void *arg, int code)
5963 bscv_soft_state_t *ssp = (bscv_soft_state_t *)arg;
5965 BSCV_TRACE(ssp, 'X', "bscv_panic_callback",
5966 "disabling watchdog");
5968 bscv_clear_watchdog_timer(ssp);
5970 * We dont get interrupts during the panic callback. But bscbus
5971 * takes care of all this
5973 bscv_full_stop(ssp);
5974 return (DDI_SUCCESS);
5978 * function - bscv_watchdog_cyclic_add
5979 * description - add the watchdog patter cyclic
5980 * inputs - driver soft state
5981 * outputs - none
5983 static void
5984 bscv_watchdog_cyclic_add(bscv_soft_state_t *ssp)
5986 if (ssp->periodic_id != NULL) {
5987 return;
5990 ssp->periodic_id = ddi_periodic_add(bscv_watchdog_pat_request, ssp,
5991 WATCHDOG_PAT_INTERVAL, DDI_IPL_10);
5993 BSCV_TRACE(ssp, 'X', "bscv_watchdog_cyclic_add:",
5994 "cyclic added");
5998 * function - bscv_watchdog_cyclic_remove
5999 * description - remove the watchdog patter cyclic
6000 * inputs - soft state ptr
6001 * outputs - none
6003 static void
6004 bscv_watchdog_cyclic_remove(bscv_soft_state_t *ssp)
6006 if (ssp->periodic_id == NULL) {
6007 return;
6009 ddi_periodic_delete(ssp->periodic_id);
6010 ssp->periodic_id = NULL;
6011 BSCV_TRACE(ssp, 'X', "bscv_watchdog_cyclic_remove:",
6012 "cyclic removed");
6014 #endif /* __i386 || __amd64 */
6018 * General utility routines ...
6021 #ifdef DEBUG
6023 static void
6024 bscv_trace(bscv_soft_state_t *ssp, char code, const char *caller,
6025 const char *fmt, ...)
6027 char buf[256];
6028 char *p;
6029 va_list va;
6031 if (ssp->debug & (1 << (code-'@'))) {
6032 p = buf;
6033 (void) snprintf(p, sizeof (buf) - (p - buf),
6034 "%s/%s: ", MYNAME, caller);
6035 p += strlen(p);
6037 va_start(va, fmt);
6038 (void) vsnprintf(p, sizeof (buf) - (p - buf), fmt, va);
6039 va_end(va);
6041 buf[sizeof (buf) - 1] = '\0';
6042 (void) strlog((short)ssp->majornum, (short)ssp->minornum, code,
6043 SL_TRACE, buf);
6047 #else /* DEBUG */
6049 _NOTE(ARGSUSED(0))
6050 static void
6051 bscv_trace(bscv_soft_state_t *ssp, char code, const char *caller,
6052 const char *fmt, ...)
6056 #endif /* DEBUG */