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]
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.
36 #include <sys/types.h>
37 #include <sys/param.h>
41 #include <sys/stream.h>
42 #include <sys/systm.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>
50 #include <sys/consdev.h>
55 #include <sys/sunddi.h>
56 #include <sys/stream.h>
57 #include <sys/strlog.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
*);
98 static int bscv_held(bscv_soft_state_t
*);
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
*,
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;
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 */
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
[] =
240 "temperature sensor ", /* 02 */
241 "overheat sensor ", /* 03 */
243 "supply rail ", /* 05 */
244 "circuit breaker ", /* 06 */
247 "phonehome ", /* 09; unutilized */
250 "event log ", /* 0c */
251 "", /* 0d; EVENT_SUBSYS_EXTRA unutilized */
255 static char *eventTypeStrings
[] =
257 "[null event]", /* 00 */
260 "state change", /* 03 */
262 "power off", /* 05 */
263 "powered off unexpectedly", /* 06 */
264 "reset unexpectedly", /* 07 */
266 "watchdog enabled", /* 09 */
267 "watchdog disabled", /* 0a */
268 "watchdog triggered", /* 0b */
270 "recovered", /* 0d */
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 */
283 "password changed", /* 1a */
284 "login failed", /* 1b */
286 "flash download", /* 1d */
287 "data lost", /* 1e */
288 "device busy", /* 1f */
289 "fault led state", /* 20 */
291 "severe overheat", /* 22 */
292 "no overheat", /* 23 */
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 */
325 bscv_ioctl
, /* ioctl */
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
340 static struct dev_ops bscv_dev_ops
= {
341 DEVO_REV
, /* devo_rev */
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
360 #define BSCV_VERSION_STRING "bscv driver - Debug"
362 #define BSCV_VERSION_STRING "bscv driver"
365 static struct modldrv modldrv
= {
371 static struct modlinkage modlinkage
= {
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
387 * kernel accessible routines. These routines are necessarily global so the
388 * driver can be loaded, and unloaded successfully
393 * description - initializes the driver state structure and installs the
394 * driver module into the kernel
396 * outputs - success or failure of module installation
404 if ((e
= ddi_soft_state_init(&bscv_statep
,
405 sizeof (bscv_soft_state_t
), 1)) != 0) {
409 if ((e
= mod_install(&modlinkage
)) != 0) {
410 ddi_soft_state_fini(&bscv_statep
);
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
));
431 * description - removes a module from the kernel and frees the driver soft
434 * outputs - success or failure of module removal
442 if ((e
= mod_remove(&modlinkage
)) != 0) {
446 ddi_soft_state_fini(&bscv_statep
);
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
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
;
468 instance
= DEVICETOINSTANCE(dev
);
471 case DDI_INFO_DEVT2INSTANCE
:
472 *result
= (void *)(uintptr_t)instance
;
476 case DDI_INFO_DEVT2DEVINFO
:
477 ssp
= ddi_get_soft_state(bscv_statep
, instance
);
479 return (DDI_FAILURE
);
480 *result
= (void *) ssp
->dip
;
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
;
512 instance
= ddi_get_instance(dip
);
514 if (ddi_soft_state_zalloc(bscv_statep
, instance
) !=
516 return (DDI_FAILURE
);
520 ssp
= ddi_get_soft_state(bscv_statep
, instance
);
525 ssp
->instance
= instance
;
526 ssp
->event_waiting
= B_FALSE
;
527 ssp
->status_change
= B_FALSE
;
528 ssp
->nodename_change
= B_FALSE
;
532 ssp
->prog_mode_only
= B_FALSE
;
533 ssp
->programming
= B_FALSE
;
534 ssp
->cssp_prog
= B_FALSE
;
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
);
573 bscv_leave_programming_mode(ssp
, B_FALSE
);
575 if (bscv_attach_common(ssp
) == DDI_FAILURE
) {
577 (void) bscv_cleanup(ssp
);
578 return (DDI_FAILURE
);
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
);
624 bscv_setup_watchdog(ssp
); /* starts cyclic callback */
627 #endif /* __i386 || __amd64 */
629 return (DDI_SUCCESS
);
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
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
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.
662 bscv_quiesce(dev_info_t
*dip
)
664 bscv_soft_state_t
*ssp
;
668 instance
= ddi_get_instance(dip
);
669 ssp
= ddi_get_soft_state(bscv_statep
, instance
);
671 return (DDI_FAILURE
);
674 /* Disable tracing, as we are executing at High-Interrupt level */
677 /* quiesce the device */
680 return (DDI_SUCCESS
);
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
695 * inputs - device number, flag specifying open type, device type,
697 * outputs - success or failure of operation
702 bscv_open(dev_t
*devp
, int flag
, int otype
, cred_t
*cred
)
704 bscv_soft_state_t
*ssp
;
707 instance
= DEVICETOINSTANCE(*devp
);
708 ssp
= ddi_get_soft_state(bscv_statep
, instance
);
710 return (ENXIO
); /* not attached yet */
712 BSCV_TRACE(ssp
, 'O', "bscv_open", "instance 0x%x", instance
);
714 if (otype
!= OTYP_CHR
) {
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
726 * inputs - device number,flag specifying open type, device type,
728 * outputs - success or failure of operation
733 bscv_close(dev_t dev
, int flag
, int otype
, cred_t
*cred
)
735 bscv_soft_state_t
*ssp
;
738 instance
= DEVICETOINSTANCE(dev
);
739 ssp
= ddi_get_soft_state(bscv_statep
, instance
);
743 BSCV_TRACE(ssp
, 'O', "bscv_close", "instance 0x%x", instance
);
749 bscv_map_regs(bscv_soft_state_t
*ssp
)
754 unsigned int nelements
;
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"
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
);
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
);
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",
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 */
807 for (; i
>= 0; i
--) {
808 ddi_regs_map_free(&ssp
->channel
[i
].handle
);
815 return (DDI_SUCCESS
);
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.
825 return (DDI_FAILURE
);
829 bscv_unmap_regs(bscv_soft_state_t
*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.
844 bscv_map_chan_logical_physical(bscv_soft_state_t
*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.
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)
864 if (ssp
->nchannels
> 3)
866 if (ssp
->nchannels
> 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
879 bscv_full_stop(bscv_soft_state_t
*ssp
)
881 uint8_t bits2set
= 0;
882 uint8_t bits2clear
= 0;
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
);
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
;
912 case LOM_SER_EVENTS_OFF
:
913 /* Make sure serial event reporting is on */
914 bits2set
= EBUS_ALARM_NOEVENTS
;
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) {
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.
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().
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
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.
999 * bscv_faulty() - returns B_TRUE if the LOM (communications) have been
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
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
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.
1021 * bscv_probe() - perform a probe (NOP) operation to check out lom comms.
1022 * bscv_resync_comms() - resynchronise communications after a transient fault.
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
;
1034 bscv_tryenter(bscv_soft_state_t
*ssp
)
1038 BSCV_TRACE(ssp
, '@', "bscv_tryenter", "");
1039 if ((rv
= mutex_tryenter(&ssp
->cmd_mutex
)) != 0) {
1040 ssp
->had_session_error
= B_FALSE
;
1046 bscv_exit(bscv_soft_state_t
*ssp
)
1048 mutex_exit(&ssp
->cmd_mutex
);
1049 BSCV_TRACE(ssp
, '@', "bscv_exit", "");
1054 bscv_held(bscv_soft_state_t
*ssp
)
1056 return (mutex_owned(&ssp
->cmd_mutex
));
1061 bscv_put8(bscv_soft_state_t
*ssp
, int chan
, bscv_addr_t addr
, uint8_t val
)
1063 boolean_t needretry
;
1066 ASSERT(bscv_held(ssp
));
1068 if (bscv_faulty(ssp
)) {
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
;
1078 bscv_put8_once(ssp
, chan
, addr
, val
);
1079 needretry
= bscv_should_retry(ssp
);
1084 if (ssp
->command_error
!= 0) {
1085 ssp
->had_session_error
= B_TRUE
;
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
);
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);
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);
1124 bscv_get8(bscv_soft_state_t
*ssp
, int chan
, bscv_addr_t addr
)
1127 boolean_t needretry
;
1130 ASSERT(bscv_held(ssp
));
1132 if (bscv_faulty(ssp
)) {
1136 for (num_failures
= 0;
1137 num_failures
< BSC_FAILURE_RETRY_LIMIT
;
1139 retval
= bscv_get8_once(ssp
, chan
, addr
);
1140 needretry
= bscv_should_retry(ssp
);
1145 if (ssp
->command_error
!= 0) {
1146 ssp
->had_session_error
= B_TRUE
;
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
);
1167 bscv_get16(bscv_soft_state_t
*ssp
, int chan
, bscv_addr_t addr
)
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
);
1182 bscv_get32(bscv_soft_state_t
*ssp
, int chan
, bscv_addr_t addr
)
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
);
1199 bscv_setclear8(bscv_soft_state_t
*ssp
, int chan
,
1200 bscv_addr_t addr
, uint8_t set
, uint8_t clear
)
1204 ASSERT(bscv_held(ssp
));
1205 ASSERT(addr
< BSC_ADDR_CACHE_LIMIT
);
1207 val
= ssp
->lom_regs
[addr
] | set
;
1210 BSCV_TRACE(ssp
, '@', "bscv_setclear8",
1211 "addr 0x%x.%02x, set %02x, clear %02x => %02x",
1212 addr
>> 8, addr
& 0xff,
1215 bscv_put8(ssp
, chan
, addr
, val
);
1219 bscv_setclear8_volatile(bscv_soft_state_t
*ssp
, int chan
,
1220 bscv_addr_t addr
, uint8_t set
, uint8_t clear
)
1223 boolean_t needretry
;
1226 ASSERT(bscv_held(ssp
));
1227 ASSERT(addr
< BSC_ADDR_CACHE_LIMIT
);
1229 if (bscv_faulty(ssp
)) {
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
;
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
);
1249 needretry
= bscv_should_retry(ssp
);
1255 if (ssp
->command_error
!= 0) {
1256 ssp
->had_session_error
= B_TRUE
;
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
);
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
,
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
) {
1287 bscv_put8(ssp
, chan
, dev_addr
, *host_addr
++);
1289 *host_addr
++ = bscv_get8(ssp
, chan
, dev_addr
);
1293 bscv_put8_once(ssp
, chan
,
1294 dev_addr
, *host_addr
++);
1296 *host_addr
++ = bscv_get8_once(ssp
, chan
,
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.
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
]);
1325 bscv_get8_locked(bscv_soft_state_t
*ssp
, int chan
, bscv_addr_t addr
, int *res
)
1329 ASSERT(addr
< BSC_ADDR_CACHE_LIMIT
);
1331 retval
= bscv_get8(ssp
, chan
, addr
);
1332 bscv_locked_result(ssp
, res
);
1334 BSCV_TRACE(ssp
, '@', "bscv_get8_locked",
1335 "addr 0x%x.%02x => %02x", addr
>> 8, addr
& 0xff, retval
);
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
)
1344 bscv_rep_rw8(ssp
, chan
, host_addr
, dev_addr
, repcount
,
1345 flags
, B_FALSE
/* read */);
1346 bscv_locked_result(ssp
, res
);
1351 bscv_faulty(bscv_soft_state_t
*ssp
)
1353 ASSERT(bscv_held(ssp
));
1354 return (ssp
->had_fault
);
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
;
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
;
1375 bscv_session_error(bscv_soft_state_t
*ssp
)
1377 ASSERT(bscv_held(ssp
));
1378 return (ssp
->had_session_error
);
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
);
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 */
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
1409 bscv_locked_result(bscv_soft_state_t
*ssp
, int *res
)
1411 if (bscv_faulty(ssp
) || (bscv_retcode(ssp
) != 0)) {
1417 bscv_put8_once(bscv_soft_state_t
*ssp
, int chan
, bscv_addr_t addr
, uint8_t val
)
1421 ASSERT(bscv_held(ssp
));
1423 ssp
->command_error
= 0;
1425 if (bscv_faulty(ssp
)) {
1426 /* Bail out things are not working */
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");
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
;
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
);
1474 bscv_get8_once(bscv_soft_state_t
*ssp
, int chan
, bscv_addr_t addr
)
1479 ASSERT(bscv_held(ssp
));
1481 ssp
->command_error
= 0;
1483 if (bscv_faulty(ssp
)) {
1484 /* Bail out things are not working */
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");
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
);
1539 bscv_probe(bscv_soft_state_t
*ssp
, int chan
, uint32_t *fault
)
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));
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
));
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
);
1570 bscv_resync_comms(bscv_soft_state_t
*ssp
, int chan
)
1573 uint32_t command_error
= ssp
->command_error
;
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");
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",
1593 for (try = 1; try <= 8; try++) {
1595 fault
= ddi_get32(ssp
->channel
[chan
].handle
,
1596 (uint32_t *)BSC_NEXUS_ADDR(ssp
, chan
, 0,
1602 cmn_err(CE_WARN
, "!bscv_resync_comms: "
1603 "comms resync (probing) - try 0x%x "
1604 "had fault 0x%x", try, fault
);
1608 cmn_err(CE_WARN
, "!bscv_resync_comms: "
1609 "Failed to resync comms - giving up");
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.
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
);
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
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 */
1667 "!bscv_window_setup: read invalid eeprom parameters");
1668 ssp
->eeinfo_valid
= B_FALSE
;
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.
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
;
1696 while (remaining
> 0) {
1697 page_idx
= blk_addr
& 0xff;
1698 if ((page_idx
+ remaining
) > 0x100) {
1699 blk_size
= 0x100 - page_idx
;
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
)) {
1722 remaining
-= blk_size
;
1723 blk_addr
+= blk_size
;
1731 bscv_is_null_event(bscv_soft_state_t
*ssp
, lom_event_t
*e
)
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");
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");
1755 BSCV_TRACE(ssp
, 'E', "bscv_is_null_event", "returning False");
1761 * *********************************************************************
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)
1780 * LOMIOCDOGCTL, TSIOCDOGCTL
1781 * LOMIOCDOGPAT, TSIOCDOGPAT
1782 * LOMIOCDOGTIME, TSIOCDOGTIME
1787 * LOMIOCNBMON, TSIOCNBMON
1789 * LOMIOCUNLOCK, TSIOCUNLOCK
1790 * LOMIOCWTMON, TSIOCWTMON
1793 * LOMIOCDOGSTATE, TSIOCDOGSTATE
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.
1817 bscv_ioctl(dev_t dev
, int cmd
, intptr_t arg
, int mode
, cred_t
*cred
, int *rvalp
)
1819 bscv_soft_state_t
*ssp
;
1823 instance
= DEVICETOINSTANCE(dev
);
1824 ssp
= ddi_get_soft_state(bscv_statep
, instance
);
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
1839 case LOMIOCCLEARLOG
:
1847 case LOMIOCEVENTLOG
:
1859 * set the default result.
1864 if (ssp
->cssp_prog
) {
1866 } else if ((ssp
->prog_mode_only
|| ssp
->programming
) &&
1867 cmd
!= LOMIOCPROG
) {
1872 * Check that the caller has appropriate access permissions
1873 * (FWRITE set in mode) for those ioctls which change lom
1876 if (!(mode
& FWRITE
)) {
1885 /* Does not require write access */
1892 case LOMIOCDOGSTATE
:
1893 res
= bscv_ioc_dogstate(ssp
, arg
, mode
);
1897 res
= bscv_prog(ssp
, arg
, mode
);
1900 case LOMIOCPSUSTATE
:
1901 res
= bscv_ioc_psustate(ssp
, arg
, mode
);
1904 case LOMIOCFANSTATE
:
1905 res
= bscv_ioc_fanstate(ssp
, arg
, mode
);
1908 case LOMIOCFLEDSTATE
:
1909 res
= bscv_ioc_fledstate(ssp
, arg
, mode
);
1912 case LOMIOCLEDSTATE
:
1913 res
= bscv_ioc_ledstate(ssp
, arg
, mode
);
1917 res
= bscv_ioc_info(ssp
, arg
, mode
);
1921 res
= bscv_ioc_mread(ssp
, arg
, mode
);
1925 res
= bscv_ioc_volts(ssp
, arg
, mode
);
1929 res
= bscv_ioc_stats(ssp
, arg
, mode
);
1933 res
= bscv_ioc_temp(ssp
, arg
, mode
);
1937 res
= bscv_ioc_cons(ssp
, arg
, mode
);
1940 case LOMIOCEVENTLOG2
:
1941 res
= bscv_ioc_eventlog2(ssp
, arg
, mode
);
1945 res
= bscv_ioc_info2(ssp
, arg
, mode
);
1949 res
= bscv_ioc_test(ssp
, arg
, mode
);
1953 res
= bscv_ioc_mprog2(ssp
, arg
, mode
);
1957 res
= bscv_ioc_mread2(ssp
, arg
, mode
);
1961 BSCV_TRACE(ssp
, 'I', "bscv_ioctl", "Invalid IOCTL 0x%x", cmd
);
1969 * TSIOCDOGSTATE - indicate whether the alarm watchdog and reset
1970 * circuitry is enabled or not.
1973 bscv_ioc_dogstate(bscv_soft_state_t
*ssp
, intptr_t arg
, int mode
)
1975 lom_dogstate_t dogstate
;
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
);
1986 (ddi_copyout((caddr_t
)&dogstate
,
1987 (caddr_t
)arg
, sizeof (dogstate
), mode
) < 0)) {
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.
2000 bscv_ioc_psustate(bscv_soft_state_t
*ssp
, intptr_t arg
, int mode
)
2002 lom_psudata_t psudata
;
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
),
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.
2032 bscv_ioc_fanstate(bscv_soft_state_t
*ssp
, intptr_t arg
, int mode
)
2034 lom_fandata_t fandata
;
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
);
2052 (ddi_copyout((caddr_t
)&fandata
, (caddr_t
)arg
, sizeof (fandata
),
2060 * LOMIOCFLEDSTATE - returns the state of the fault LED
2063 bscv_ioc_fledstate(bscv_soft_state_t
*ssp
, intptr_t arg
, int mode
)
2065 lom_fled_info_t fled_info
;
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) {
2075 /* has +1 here - not 2 as in the info ioctl */
2076 fled_info
.on
= EBUS_ALARM_LED_DEC(fledstate
) + 1;
2079 (ddi_copyout((caddr_t
)&fled_info
, (caddr_t
)arg
,
2080 sizeof (fled_info
), mode
) < 0)) {
2087 * LOMIOCLEDSTATE - returns the state of the requested LED
2090 bscv_ioc_ledstate(bscv_soft_state_t
*ssp
, intptr_t arg
, int mode
)
2092 lom_led_state_t led_state
;
2096 /* copy in arguments supplied */
2097 if (ddi_copyin((caddr_t
)arg
, (caddr_t
)&led_state
,
2098 sizeof (lom_led_state_t
), mode
) < 0) {
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
;
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
;
2124 case LOM_LED_STATE_ON_STEADY
:
2125 led_state
.state
= LOM_LED_ON
;
2126 led_state
.colour
= LOM_LED_COLOUR_ANY
;
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
;
2133 case LOM_LED_STATE_NOT_PRESENT
:
2134 led_state
.state
= LOM_LED_NOT_IMPLEMENTED
;
2135 led_state
.colour
= LOM_LED_COLOUR_NONE
;
2137 case LOM_LED_STATE_INACCESSIBLE
:
2138 case LOM_LED_STATE_STANDBY
:
2140 led_state
.state
= LOM_LED_ACCESS_ERROR
;
2141 led_state
.colour
= LOM_LED_COLOUR_NONE
;
2145 /* set the label info */
2146 (void) strcpy(led_state
.label
,
2147 ssp
->led_names
[led_state
.index
]);
2150 /* copy out lom_state */
2152 (ddi_copyout((caddr_t
)&led_state
, (caddr_t
)arg
,
2153 sizeof (lom_led_state_t
), mode
) < 0)) {
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.
2167 bscv_ioc_info(bscv_soft_state_t
*ssp
, intptr_t arg
, int mode
)
2174 info
.ser_char
= bscv_get8_locked(ssp
, chan_general
, EBUS_IDX_ESCAPE
,
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
)
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
,
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
) {
2196 (ddi_copyout((caddr_t
)&info
, (caddr_t
)arg
, sizeof (info
),
2204 * LOMIOCMREAD - used to query the LOMlite configuration parameters
2207 bscv_ioc_mread(bscv_soft_state_t
*ssp
, intptr_t arg
, int mode
)
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
,
2220 mprog
.config
= bscv_get8_locked(ssp
, chan_general
, EBUS_IDX_CONFIG
,
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
);
2233 (ddi_copyout((caddr_t
)&mprog
, (caddr_t
)arg
, sizeof (mprog
),
2244 bscv_ioc_volts(bscv_soft_state_t
*ssp
, intptr_t arg
, int mode
)
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
,
2254 for (i
= 0; i
< ssp
->volts
.num
; i
++) {
2255 ssp
->volts
.status
[i
] = (supply
>> i
) & 1;
2259 (ddi_copyout((caddr_t
)&ssp
->volts
, (caddr_t
)arg
,
2260 sizeof (ssp
->volts
), mode
) < 0)) {
2270 bscv_ioc_stats(bscv_soft_state_t
*ssp
, intptr_t arg
, int mode
)
2276 status
= bscv_get8_locked(ssp
, chan_general
, EBUS_IDX_CBREAK_STATUS
,
2278 for (i
= 0; i
< ssp
->sflags
.num
; i
++) {
2279 ssp
->sflags
.status
[i
] = (int)((status
>> i
) & 1);
2283 (ddi_copyout((caddr_t
)&ssp
->sflags
, (caddr_t
)arg
,
2284 sizeof (ssp
->sflags
), mode
) < 0)) {
2294 bscv_ioc_temp(bscv_soft_state_t
*ssp
, intptr_t arg
, int mode
)
2302 bzero(&temps
, sizeof (temps
));
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
];
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
,
2320 for (i
= 0; i
< ssp
->temps
.num_ov
; i
++) {
2321 ssp
->temps
.status_ov
[i
] = (status_ov
>> i
) & 1;
2325 (ddi_copyout((caddr_t
)&temps
, (caddr_t
)arg
, sizeof (temps
),
2336 bscv_ioc_cons(bscv_soft_state_t
*ssp
, intptr_t arg
, int mode
)
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';
2355 (ddi_copyout((caddr_t
)&cbuf
, (caddr_t
)arg
, sizeof (cbuf
),
2366 bscv_ioc_eventlog2(bscv_soft_state_t
*ssp
, intptr_t arg
, int mode
)
2368 lom_eventlog2_t
*eventlog2
;
2369 int events_recorded
;
2371 uint16_t next_offset
;
2375 eventlog2
= (lom_eventlog2_t
*)kmem_zalloc(sizeof (*eventlog2
),
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
));
2391 * OK we have full private access to the LOM now so loop
2392 * over the eventlog addr spaces until we get the required
2396 if (!bscv_window_setup(ssp
)) {
2399 kmem_free((void *)eventlog2
, sizeof (*eventlog2
));
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",
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
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",
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
);
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
);
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
]));
2476 eventlog2
->num
= events_recorded
;
2481 (ddi_copyout((caddr_t
)eventlog2
, (caddr_t
)arg
,
2482 sizeof (lom_eventlog2_t
), mode
) < 0)) {
2486 kmem_free((void *)eventlog2
, sizeof (lom_eventlog2_t
));
2494 bscv_ioc_info2(bscv_soft_state_t
*ssp
, intptr_t arg
, int mode
)
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
)
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
]);
2555 (ddi_copyout((caddr_t
)&info2
, (caddr_t
)arg
, sizeof (info2
),
2566 bscv_ioc_test(bscv_soft_state_t
*ssp
, intptr_t arg
, int mode
)
2573 if (ddi_copyin((caddr_t
)arg
, (caddr_t
)&test
, sizeof (test
),
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
) {
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 */
2605 /* Stop other things and then run the test */
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
)) {
2617 /* Get hold of the SunVTS error code */
2618 test
= bscv_retcode(ssp
);
2625 BSCV_TRACE(ssp
, 'F', "bscv_ioc_test",
2626 "LOMIOCTEST status 0x%x, res 0x%x", test
, res
);
2628 (ddi_copyout((caddr_t
)&test
, (caddr_t
)arg
, sizeof (test
),
2639 bscv_ioc_mprog2(bscv_soft_state_t
*ssp
, intptr_t arg
, int mode
)
2641 lom2_mprog_t mprog2
;
2644 uint32_t eeprom_size
;
2647 if (ddi_copyin((caddr_t
)arg
, (caddr_t
)&mprog2
, sizeof (mprog2
),
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)) {
2662 /* Calculate required data location */
2664 base_addr
= (mprog2
.addr_space
- 240) * data_size
;
2666 eeprom_size
= bscv_get8(ssp
, chan_general
, EBUS_IDX_EEPROM_SIZE_KB
) *
2669 if (bscv_faulty(ssp
)) {
2672 } else if ((base_addr
+ data_size
) > eeprom_size
) {
2673 BSCV_TRACE(ssp
, 'M', "bscv_ioc_mprog2",
2674 "Request extends past end of eeprom");
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");
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");
2693 if (bscv_eerw(ssp
, base_addr
, &mprog2
.data
[0],
2694 data_size
, B_TRUE
/* write */) != 0) {
2698 /* Read a probe key to release the lock. */
2699 (void) bscv_get8(ssp
, chan_general
, EBUS_IDX_PROBEAA
);
2701 if (bscv_faulty(ssp
)) {
2713 bscv_ioc_mread2(bscv_soft_state_t
*ssp
, intptr_t arg
, int mode
)
2715 lom2_mprog_t mprog2
;
2718 uint32_t eeprom_size
;
2721 if (ddi_copyin((caddr_t
)arg
, (caddr_t
)&mprog2
, sizeof (mprog2
),
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)) {
2738 /* Calculate required data location */
2740 base_addr
= (mprog2
.addr_space
- 240) * data_size
;
2741 eeprom_size
= bscv_get8(ssp
, chan_general
, EBUS_IDX_EEPROM_SIZE_KB
) *
2744 if (bscv_faulty(ssp
)) {
2747 } else if ((base_addr
+ data_size
) > eeprom_size
) {
2748 BSCV_TRACE(ssp
, 'M', "bscv_ioc_mread2",
2749 "Request extends past end of eeprom");
2754 if (bscv_eerw(ssp
, base_addr
, &mprog2
.data
[0],
2755 data_size
, B_FALSE
/* read */) != 0) {
2759 if (bscv_faulty(ssp
)) {
2765 (ddi_copyout((caddr_t
)&mprog2
, (caddr_t
)arg
, sizeof (mprog2
),
2773 bscv_get_state_changes(bscv_soft_state_t
*ssp
)
2775 int i
= STATUS_READ_LIMIT
;
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
;
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 * *********************************************************************
2801 * *********************************************************************
2805 * function - bscv_event_daemon
2806 * description - Perform periodic lom tasks in a separate thread.
2807 * inputs - LOM soft state structure pointer
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
;
2820 clock_t poll_period
= BSC_EVENT_POLL_NORMAL
;
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
;
2832 if ((ssp
->task_flags
& TASK_STOP_FLG
) != 0) {
2833 /* Stop request seen - terminate */
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 */
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",
2847 /* Treat non-fault conditions */
2849 if (ssp
->cssp_prog
|| ssp
->prog_mode_only
) {
2851 * The BSC has become available again.
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
);
2862 "!bscv_event_daemon previous fault "
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
;
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.
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
;
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
2908 /* Getting ready to explode */
2911 "!bscv_event_daemon had fault 0x%x",
2914 ssp
->event_sleep
= B_TRUE
;
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",
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] =
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
2968 bscv_event_process(ssp
, do_events
);
2971 BSCV_TRACE(ssp
, 'D', "bscv_event_daemon",
2972 "do_nodename task");
2973 bscv_setup_hostname(ssp
);
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.
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
;
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
);
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
));
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",
3053 * function - bscv_start_event_daemon
3054 * description - Create the event daemon thread.
3055 * inputs - LOM soft state structure pointer
3059 bscv_start_event_daemon(bscv_soft_state_t
*ssp
)
3061 if (ssp
->progress
& BSCV_THREAD
)
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
3078 bscv_stop_event_daemon(bscv_soft_state_t
*ssp
)
3081 int res
= DDI_SUCCESS
;
3083 mutex_enter(&ssp
->task_mu
);
3085 /* Wait for task daemon to stop running. */
3087 ((ssp
->task_flags
& TASK_ALIVE_FLG
) && try < 10);
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.
3101 mutex_enter(&ssp
->task_mu
);
3104 if (ssp
->task_flags
& TASK_ALIVE_FLG
) {
3107 mutex_exit(&ssp
->task_mu
);
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
3119 bscv_pause_event_daemon(bscv_soft_state_t
*ssp
)
3123 if (!(ssp
->progress
& BSCV_THREAD
)) {
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. */
3137 (!(ssp
->task_flags
& TASK_SLEEPING_FLG
) &&
3138 (ssp
->task_flags
& TASK_ALIVE_FLG
) &&
3142 ssp
->task_flags
|= TASK_PAUSE_FLG
;
3143 cv_signal(&ssp
->task_cv
);
3144 /* Release task daemon lock. */
3145 mutex_exit(&ssp
->task_mu
);
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
3169 bscv_resume_event_daemon(bscv_soft_state_t
*ssp
)
3171 if (!(ssp
->progress
& BSCV_THREAD
)) {
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
3193 bscv_event_process(bscv_soft_state_t
*ssp
, boolean_t do_events
)
3198 /* Raw values read from the lom */
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
);
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
;
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",
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 */
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.
3274 ASSERT(logptr
== currptr
);
3275 } else if (count
> evcount
) {
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
;
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.
3303 bscv_event_validate(bscv_soft_state_t
*ssp
, uint32_t newptr
, uint8_t unread
)
3308 if (!bscv_window_setup(ssp
)) {
3309 /* Problem with lom eeprom setup we cannot do anything */
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
;
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
3331 newptr
+= ssp
->eventlog_size
;
3333 if (!ssp
->oldeeptr_valid
) {
3334 /* We have just started up - we have to trust lom */
3336 } else if ((unread
== 0) && (newptr
== oldptr
)) {
3337 /* Nothing to do - we were just polling */
3339 } else if (oldptr
+ (unread
* sizeof (lom_event_t
)) == newptr
) {
3340 /* Ok - got as many events as we expected */
3342 } else if (oldptr
+ (unread
* sizeof (lom_event_t
)) > newptr
) {
3344 * Errrm more messages than there should have been.
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
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).",
3358 cmn_err(CE_CONT
, "only processing %d events", count
);
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",
3367 /* Whatever happens only read a maximum of 255 entries */
3368 if ((count
>= 0xff)) {
3370 "bscv_event_process: too many events (%d) to "
3371 "process - some may have been lost", count
);
3378 * function - bscv_event_process_one
3379 * description - reports on state changes to the host.
3381 * inputs - LOM soft state structure pointer.
3387 bscv_event_process_one(bscv_soft_state_t
*ssp
, lom_event_t
*event
)
3393 if (bscv_is_null_event(ssp
, event
)) {
3394 /* Cleared entry - do not report it */
3398 level
= bscv_level_of_event(event
);
3405 case EVENT_LEVEL_FATAL
:
3406 case EVENT_LEVEL_FAULT
:
3411 bscv_build_eventstring(ssp
, event
, eventstr
, 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
);
3422 * The message goes only to the log.
3424 cmn_err(msg_type
, "!%s", eventstr
);
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
3449 bscv_event_snprintgmttime(char *buf
, size_t bufsz
, todinfo_t t
)
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.
3471 bscv_build_eventstring(bscv_soft_state_t
*ssp
, lom_event_t
*event
,
3472 char *buf
, char *bufend
)
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
3490 subsystem
= EVENT_DECODE_SUBSYS(event
->ev_subsys
);
3491 eventtype
= event
->ev_event
;
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
) {
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));
3505 mutex_enter(&tod_lock
);
3506 buf
+= bscv_event_snprintgmttime(buf
, bufend
-buf
,
3508 mutex_exit(&tod_lock
);
3510 buf
+= snprintf(buf
, bufend
-buf
, " ");
3514 (sizeof (eventSubsysStrings
)/sizeof (*eventSubsysStrings
))) {
3515 buf
+= snprintf(buf
, bufend
- buf
, "%s",
3516 eventSubsysStrings
[subsystem
]);
3518 buf
+= snprintf(buf
, bufend
- buf
,
3519 "unknown subsystem %d ", subsystem
);
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
);
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));
3542 if (event
->ev_subsys
& EVENT_MASK_FAULT
) {
3543 if (event
->ev_subsys
& EVENT_MASK_FATAL
) {
3544 buf
+= snprintf(buf
, bufend
- buf
, "FATAL FAULT: ");
3546 buf
+= snprintf(buf
, bufend
- buf
, "FAULT: ");
3552 (sizeof (eventTypeStrings
)/sizeof (*eventTypeStrings
))) {
3553 buf
+= snprintf(buf
, bufend
- buf
, "%s",
3554 eventTypeStrings
[eventtype
]);
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
);
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
);
3571 case EVENT_SUBSYS_FAN
:
3572 if (eventtype
== EVENT_FAILED
) {
3573 buf
+= snprintf(buf
, bufend
- buf
,
3574 " %d%%", event
->ev_detail
);
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));
3587 case EVENT_WATCHDOG_TRIGGER
:
3588 buf
+= snprintf(buf
, bufend
- buf
,
3589 event
->ev_detail
? "- soft" : " - hard");
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",
3597 ~LOM_UNEXPECTEDRESET_MASK_BADTRAP
);
3601 switch (event
->ev_detail
) {
3602 case LOM_RESET_DETAIL_BYUSER
:
3603 buf
+= snprintf(buf
, bufend
- buf
, " by user");
3605 case LOM_RESET_DETAIL_REPROGRAMMING
:
3606 buf
+= snprintf(buf
, bufend
- buf
,
3607 " after flash download");
3610 buf
+= snprintf(buf
, bufend
- buf
,
3611 " - unknown reason");
3619 case EVENT_SUBSYS_LED
:
3620 switch (event
->ev_detail
) {
3621 case LOM_LED_STATE_OFF
:
3622 buf
+= snprintf(buf
, bufend
- buf
, ": OFF");
3624 case LOM_LED_STATE_ON_STEADY
:
3625 buf
+= snprintf(buf
, bufend
- buf
, ": ON");
3627 case LOM_LED_STATE_ON_FLASHING
:
3628 case LOM_LED_STATE_ON_SLOWFLASH
:
3629 buf
+= snprintf(buf
, bufend
- buf
, ": BLINKING");
3631 case LOM_LED_STATE_INACCESSIBLE
:
3632 buf
+= snprintf(buf
, bufend
- buf
, ": inaccessible");
3634 case LOM_LED_STATE_STANDBY
:
3635 buf
+= snprintf(buf
, bufend
- buf
, ": standby");
3637 case LOM_LED_STATE_NOT_PRESENT
:
3638 buf
+= snprintf(buf
, bufend
- buf
, ": not present");
3641 buf
+= snprintf(buf
, bufend
- buf
, ": 0x%x",
3642 event
->ev_resource
);
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
);
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");
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");
3677 /* At least one input is ok */
3678 if (!(event
->ev_detail
& LOM_PSU_INPUT_A_OK
)) {
3679 buf
+= snprintf(buf
, bufend
- buf
,
3682 if (!(event
->ev_detail
& LOM_PSU_INPUT_B_OK
)) {
3683 buf
+= snprintf(buf
, bufend
- buf
,
3687 * Only flag an output error if an input is
3690 if (!(event
->ev_detail
& LOM_PSU_OUTPUT_OK
)) {
3691 buf
+= snprintf(buf
, bufend
- buf
,
3695 buf
+= snprintf(buf
, bufend
- buf
, " failed");
3698 case EVENT_SUBSYS_NONE
:
3699 if (eventtype
== EVENT_FAULT_LED
) {
3700 switch (event
->ev_detail
) {
3702 buf
+= snprintf(buf
, bufend
- buf
, " - ON");
3705 buf
+= snprintf(buf
, bufend
- buf
, " - OFF");
3708 buf
+= snprintf(buf
, bufend
- buf
,
3709 " - %dHz", event
->ev_detail
);
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
,
3722 case EBUS_BOOTMODE_RESET_DEFAULT
:
3723 buf
+= snprintf(buf
, bufend
- buf
,
3724 " - reset defaults");
3726 case EBUS_BOOTMODE_FULLDIAG
:
3727 buf
+= snprintf(buf
, bufend
- buf
,
3730 case EBUS_BOOTMODE_SKIPDIAG
:
3731 buf
+= snprintf(buf
, bufend
- buf
,
3738 if (eventtype
== EVENT_SCC_STATUS
) {
3739 switch (event
->ev_detail
) {
3741 buf
+= snprintf(buf
, bufend
- buf
,
3745 buf
+= snprintf(buf
, bufend
- buf
,
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 */
3770 cmn_err(CE_WARN
, "!bscv_build_eventstring: buffer too small!");
3776 * function - bscv_level_of_event
3777 * description - This routine determines which level an event should be
3779 * inputs - lom event structure pointer
3780 * outputs - event level.
3783 bscv_level_of_event(lom_event_t
*event
)
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
;
3821 level
= EVENT_LEVEL_FATAL
;
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
3837 bscv_status(bscv_soft_state_t
*ssp
, uint8_t state_chng
, uint8_t dev_no
)
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
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",
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",
3871 } else if (dev_no
== EBUS_DETAIL_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
);
3931 bscv_get_label(char labels
[][MAX_LOM2_NAME_STR
], int limit
, int index
)
3937 if (limit
< 0 || index
< 0 || index
> limit
)
3940 return (labels
[index
]);
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
)
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");
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
);
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
);
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
);
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
);
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
);
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
);
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");
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
4016 bscv_sysevent(bscv_soft_state_t
*ssp
, lom_event_t
*event
)
4019 char *subclass
= NULL
;
4020 char *fru_id
= "Blade"; /* The blade is only one FRU */
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
:
4033 case EVENT_SUBSYS_ALARM
:
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
;
4043 case EVENT_OVERHEAT
:
4044 fru_state
= ENV_WARNING
;
4046 case EVENT_NO_OVERHEAT
:
4053 case EVENT_SUBSYS_OVERTEMP
:
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
) {
4061 fru_state
= ENV_FAILED
;
4063 case EVENT_RECOVERED
:
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
) {
4076 fru_state
= ENV_FAILED
;
4078 case EVENT_RECOVERED
:
4085 case EVENT_SUBSYS_BREAKER
:
4087 case EVENT_SUBSYS_PSU
:
4089 case EVENT_SUBSYS_USER
:
4091 case EVENT_SUBSYS_PHONEHOME
:
4093 case EVENT_SUBSYS_LOM
:
4095 case EVENT_SUBSYS_HOST
:
4097 case EVENT_SUBSYS_EVENTLOG
:
4099 case EVENT_SUBSYS_EXTRA
:
4101 case EVENT_SUBSYS_LED
:
4102 if (event
->ev_event
!= EVENT_FAULT_LED
&&
4103 event
->ev_event
!= EVENT_STATE_CHANGE
)
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
;
4123 case LOM_LED_STATE_ON_FLASHING
:
4124 case LOM_LED_STATE_ON_SLOWFLASH
:
4125 fru_state
= ENV_LED_BLINKING
;
4127 case LOM_LED_STATE_OFF
:
4128 fru_state
= ENV_LED_OFF
;
4130 case LOM_LED_STATE_INACCESSIBLE
:
4131 fru_state
= ENV_LED_INACCESSIBLE
;
4133 case LOM_LED_STATE_STANDBY
:
4134 fru_state
= ENV_LED_STANDBY
;
4136 case LOM_LED_STATE_NOT_PRESENT
:
4137 fru_state
= ENV_LED_NOT_PRESENT
;
4140 fru_state
= ENV_LED_INACCESSIBLE
;
4148 if (class == NULL
|| subclass
== NULL
) {
4149 BSCV_TRACE(ssp
, 'E', "bscv_sysevent", "class/subclass NULL");
4153 bscv_generic_sysevent(ssp
, class, subclass
, fru_id
, res_id
, fru_state
,
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
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
4180 bscv_prog(bscv_soft_state_t
*ssp
, intptr_t arg
, int mode
)
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
),
4193 kmem_free((void *)prog
, sizeof (*prog
));
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) {
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
);
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
));
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");
4260 } else if (!ssp
->loader_running
&& is_image2
) {
4261 cmn_err(CE_WARN
, "Attempt to download firmware image "
4262 "without loader image active");
4271 bscv_get_pagesize(bscv_soft_state_t
*ssp
)
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
);
4286 * Sets the pagesize, returning the old value.
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
4301 bscv_put32(ssp
, chan_prog
,
4302 BSCVA(EBUS_CMD_SPACE_PROGRAM
, EBUS_PROGRAM_PSIZ0
), pagesize
);
4304 return (old_pagesize
);
4308 bscv_enter_programming_mode(bscv_soft_state_t
*ssp
)
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
));
4325 bscv_leave_programming_mode(bscv_soft_state_t
*ssp
, boolean_t with_jmp
)
4328 ASSERT(bscv_held(ssp
));
4331 reg
= EBUS_PROGRAM_PCR_PROGOFF_JUMPTOADDR
;
4332 BSCV_TRACE(ssp
, 'U', "bscv_leave_programming_mode",
4335 reg
= EBUS_PROGRAM_PCR_PRGMODE_OFF
;
4336 BSCV_TRACE(ssp
, 'U', "bscv_leave_programming_mode",
4340 bscv_put8(ssp
, chan_prog
,
4341 BSCVA(EBUS_CMD_SPACE_PROGRAM
, EBUS_PROGRAM_PCSR
), reg
);
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
);
4358 bscv_erase_once(bscv_soft_state_t
*ssp
, uint32_t loadaddr
, uint32_t image_size
)
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
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
),
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
),
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
));
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
;
4402 while (retryable
--) {
4403 retval
= bscv_erase_once(ssp
, loadaddr
, image_size
);
4404 if (PSR_SUCCESS(retval
))
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");
4418 bscv_set_page(bscv_soft_state_t
*ssp
, uint32_t addr
)
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
),
4433 retval
= bscv_get32(ssp
, chan_prog
,
4434 BSCVA(EBUS_CMD_SPACE_PROGRAM
, EBUS_PROGRAM_PADR0
));
4439 cmn_err(CE_WARN
, "programmming error, attempt %d, "
4440 "set page 0x%x, read back 0x%x",
4441 BSC_PAGE_RETRY_LIMIT
- retryable
,
4445 return ((addr
== retval
) ? EBUS_PROGRAM_PSR_SUCCESS
:
4446 EBUS_PROGRAM_PSR_INVALID_OPERATION
);
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
)
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 */);
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
,
4486 /* write the checksum to PCSM */
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
;
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
;
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");
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
))
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");
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
)
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
);
4583 bscv_prog_image(bscv_soft_state_t
*ssp
, boolean_t is_image2
,
4584 uint8_t *imagep
, int image_size
, uint32_t loadaddr
)
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.
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");
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
)) {
4622 "lom: Erase failed during programming, status 0x%x",
4625 goto BSCV_PROG_IMAGE_END
;
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
,
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
);
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
);
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);
4661 BSCV_TRACE(ssp
, 'U', "bscv_prog_image",
4662 "got error 0x%x - leaving programming mode",
4664 cmn_err(CE_WARN
, "programming error 0x%x, %s image",
4665 res
, is_image2
? "main" : "loader");
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
;
4682 bscv_prog_receive_image(bscv_soft_state_t
*ssp
, lom_prog_t
*prog
,
4683 uint8_t *imagep
, int max_size
)
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
);
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 */
4707 if ((ssp
->image_ptr
+ prog
->size
) > max_size
) {
4709 "lom image exceeded maximum size: got 0x%x, maximum 0x%x",
4710 (ssp
->image_ptr
+ prog
->size
), max_size
);
4713 bcopy(prog
->data
, &imagep
[ssp
->image_ptr
], prog
->size
);
4714 ssp
->image_ptr
+= prog
->size
;
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) +
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
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");
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
;
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
;
4771 cmn_err(CE_WARN
, "unknown platmagic 0x%x",
4772 prog_data
->platmagic
);
4777 ssp
->prog_index
= 0;
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!
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");
4802 ssp
->programming
= B_TRUE
;
4808 ssp
->prog_index
= 0;
4809 ssp
->image2_processing
= B_FALSE
;
4815 bscv_prog_start_lom(bscv_soft_state_t
*ssp
)
4819 if (!ssp
->programming
) {
4820 /* Not programming so this is not a valid command */
4824 if (ssp
->image
!= NULL
) {
4825 kmem_free((void *)ssp
->image
, BSC_IMAGE_MAX_SIZE
);
4830 * OK we are out of reset now so:
4831 * Probe the firmware and set everything up.
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
;
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
);
4882 * *********************************************************************
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
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
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.
4966 bscv_cleanup(bscv_soft_state_t
*ssp
)
4972 instance
= ssp
->instance
;
4974 if (ssp
->progress
& BSCV_LOCKS
) {
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
) {
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.
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
) &
5019 bscv_setclear8(ssp
, chan_general
, EBUS_IDX_WDOG_CTRL
,
5020 0, EBUS_WDOG_RST
| EBUS_WDOG_ENABLE
);
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
) {
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
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 */
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
);
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
)
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
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
,
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",
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
++) {
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
5175 (void) bscv_get8(ssp
, chan_general
, i
);
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! */
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
);
5228 bscv_wdog_do_pat(bscv_soft_state_t
*ssp
)
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",
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;
5278 ssp
->watchdog_timeout
= wdog_timeout_s
;
5281 * Configure the watchdog on or off.
5284 cfg
|= EBUS_WDOG_NB_CFG_ENB
;
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
5310 static void bscv_setup_watchdog(bscv_soft_state_t
*ssp
)
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
;
5325 clear
|= EBUS_WDOG_RST
;
5328 if (watchdog_activated
) {
5329 set
|= EBUS_WDOG_ENABLE
;
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
,
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
5356 static void bscv_setup_hostname(bscv_soft_state_t
*ssp
)
5358 char host_nodename
[128];
5359 char lom_nodename
[128];
5363 ASSERT(bscv_held(ssp
));
5366 * Check machine label is the same as the
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
)) ||
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
,
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.
5406 bscv_read_hostname(bscv_soft_state_t
*ssp
, char *lom_nodename
)
5409 boolean_t needretry
;
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
;
5423 bscv_clear_fault(ssp
);
5424 length
= bscv_get8(ssp
, chan_general
, EBUS_IDX_HNAME_LENGTH
);
5425 if (bscv_faulty(ssp
)) {
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) {
5438 /* null terminate for strcmp later */
5439 lom_nodename
[length
] = '\0';
5444 /* Force the nodename to be empty */
5445 lom_nodename
[0] = '\0';
5449 /* Failure - we ran out of retries */
5451 "bscv_read_hostname: retried %d times, giving up",
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
5467 bscv_write_hostname(bscv_soft_state_t
*ssp
,
5468 char *host_nodename
, uint8_t length
)
5471 boolean_t needretry
;
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
;
5484 bscv_clear_fault(ssp
);
5485 bscv_put8(ssp
, chan_general
, EBUS_IDX_HNAME_LENGTH
, length
);
5486 if (bscv_faulty(ssp
)) {
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) {
5506 /* Failure - we ran out of retries */
5508 "bscv_write_hostname: retried %d times, giving up",
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
5525 bscv_setup_static_info(bscv_soft_state_t
*ssp
)
5527 uint8_t addr_space_ptr
;
5530 int oldtemps
[MAX_TEMPS
];
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
) {
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
,
5559 EBUS_IDX2_SUPPLY_NAME_START
,
5560 EBUS_IDX2_SUPPLY_NAME_END
,
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
) {
5586 "lom: firmware reported too many temperatures being "
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
) {
5596 "lom: firmware reported too many over temperatures being "
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
,
5608 EBUS_IDX4_TEMP_NAME_START
,
5609 EBUS_IDX4_TEMP_NAME_END
,
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
,
5625 BSCVA(EBUS_CMD_SPACE4
, EBUS_IDX4_TEMP_SDOWN1
+ i
));
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
;
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) {
5651 (void) bscv_read_env_name(ssp
,
5654 EBUS_IDX4_TEMP_NAME_END
,
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
) {
5666 "lom: firmware reported too many status flags.");
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
,
5677 EBUS_IDX3_BREAKER_NAME_START
,
5678 EBUS_IDX3_BREAKER_NAME_END
,
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
) {
5690 "lom: firmware reported too many fans. ");
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
,
5715 EBUS_IDX5_FAN_NAME_START
,
5716 EBUS_IDX5_FAN_NAME_END
,
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
,
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.
5742 bscv_read_env_name(bscv_soft_state_t
*ssp
,
5746 char namebuf
[][MAX_LOM2_NAME_STR
],
5752 unsigned int addr_space_ptr
;
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
++) {
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
5788 * We increment the buffer pointer now so that
5789 * it is ready for the next read
5793 if (this_char
== '\0') {
5794 /* Found end of string - done */
5797 if (nameidx
< (namemax
- 1)) {
5799 * Buffer not full - record character
5800 * NOTE we always leave room for the NUL
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
5824 bscv_setup_events(bscv_soft_state_t
*ssp
)
5829 ASSERT(bscv_held(ssp
));
5832 * deal with event reporting - cover all cases
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
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
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
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
,
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
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
);
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.
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
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
5984 bscv_watchdog_cyclic_add(bscv_soft_state_t
*ssp
)
5986 if (ssp
->periodic_id
!= NULL
) {
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:",
5998 * function - bscv_watchdog_cyclic_remove
5999 * description - remove the watchdog patter cyclic
6000 * inputs - soft state ptr
6004 bscv_watchdog_cyclic_remove(bscv_soft_state_t
*ssp
)
6006 if (ssp
->periodic_id
== NULL
) {
6009 ddi_periodic_delete(ssp
->periodic_id
);
6010 ssp
->periodic_id
= NULL
;
6011 BSCV_TRACE(ssp
, 'X', "bscv_watchdog_cyclic_remove:",
6014 #endif /* __i386 || __amd64 */
6018 * General utility routines ...
6024 bscv_trace(bscv_soft_state_t
*ssp
, char code
, const char *caller
,
6025 const char *fmt
, ...)
6031 if (ssp
->debug
& (1 << (code
-'@'))) {
6033 (void) snprintf(p
, sizeof (buf
) - (p
- buf
),
6034 "%s/%s: ", MYNAME
, caller
);
6038 (void) vsnprintf(p
, sizeof (buf
) - (p
- buf
), fmt
, va
);
6041 buf
[sizeof (buf
) - 1] = '\0';
6042 (void) strlog((short)ssp
->majornum
, (short)ssp
->minornum
, code
,
6051 bscv_trace(bscv_soft_state_t
*ssp
, char code
, const char *caller
,
6052 const char *fmt
, ...)