Print this page
10886 smatch debug macro cleanup in usr/src/uts
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/uts/common/io/bscv.c
+++ new/usr/src/uts/common/io/bscv.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
↓ open down ↓ |
15 lines elided |
↑ open up ↑ |
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21 /*
22 22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 23 * Use is subject to license terms.
24 24 */
25 25
26 +/*
27 + * Copyright 2019 Joyent, Inc.
28 + */
26 29
27 30 /*
28 31 * bscv.c - multi-threaded lom driver for the Stiletto platform.
29 32 */
30 33
31 34 /*
32 35 * Included files.
33 36 */
34 37
35 38 #include <sys/note.h>
36 39 #include <sys/types.h>
37 40 #include <sys/param.h>
38 41 #include <sys/uio.h>
39 42 #include <sys/open.h>
40 43 #include <sys/cred.h>
41 44 #include <sys/stream.h>
42 45 #include <sys/systm.h>
43 46 #include <sys/conf.h>
44 47 #include <sys/reboot.h>
45 48 #include <sys/modctl.h>
46 49 #include <sys/mkdev.h>
47 50 #include <sys/errno.h>
48 51 #include <sys/debug.h>
49 52 #include <sys/kmem.h>
50 53 #include <sys/consdev.h>
51 54 #include <sys/file.h>
52 55 #include <sys/stat.h>
53 56 #include <sys/disp.h>
54 57 #include <sys/ddi.h>
55 58 #include <sys/sunddi.h>
56 59 #include <sys/stream.h>
57 60 #include <sys/strlog.h>
58 61 #include <sys/log.h>
59 62 #include <sys/utsname.h>
60 63 #include <sys/callb.h>
61 64 #include <sys/sysevent.h>
62 65 #include <sys/nvpair.h>
63 66 #include <sys/sysevent/eventdefs.h>
64 67 #include <sys/sysevent/domain.h>
65 68 #include <sys/sysevent/env.h>
66 69 #include <sys/sysevent/dr.h>
67 70
68 71 #include <sys/lom_io.h>
69 72 #include <sys/bscbus.h>
70 73 #include <sys/bscv_impl.h>
71 74
72 75 /*
73 76 * Variables defined here and visible internally only
74 77 */
75 78
76 79 static void *bscv_statep = NULL;
77 80
78 81 /*
79 82 * Forward declarations
80 83 */
81 84
82 85 static int bscv_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
83 86 static int bscv_attach(dev_info_t *, ddi_attach_cmd_t);
84 87 static int bscv_detach(dev_info_t *, ddi_detach_cmd_t);
85 88 static int bscv_quiesce(dev_info_t *);
86 89 static int bscv_map_regs(bscv_soft_state_t *);
87 90 static void bscv_unmap_regs(bscv_soft_state_t *);
88 91 static void bscv_map_chan_logical_physical(bscv_soft_state_t *);
89 92
90 93 static int bscv_open(dev_t *, int, int, cred_t *);
91 94 static int bscv_close(dev_t, int, int, cred_t *);
92 95 static void bscv_full_stop(bscv_soft_state_t *);
93 96
94 97 static void bscv_enter(bscv_soft_state_t *);
95 98 static int bscv_tryenter(bscv_soft_state_t *ssp);
96 99 static void bscv_exit(bscv_soft_state_t *);
97 100 #ifdef DEBUG
98 101 static int bscv_held(bscv_soft_state_t *);
99 102 #endif /* DEBUG */
100 103
101 104 static void bscv_put8(bscv_soft_state_t *, int, bscv_addr_t, uint8_t);
102 105 static void bscv_put16(bscv_soft_state_t *, int, bscv_addr_t, uint16_t);
103 106 static void bscv_put32(bscv_soft_state_t *, int, bscv_addr_t, uint32_t);
104 107 static uint8_t bscv_get8(bscv_soft_state_t *, int, bscv_addr_t);
105 108 static uint16_t bscv_get16(bscv_soft_state_t *, int, bscv_addr_t);
106 109 static uint32_t bscv_get32(bscv_soft_state_t *, int, bscv_addr_t);
107 110 static void bscv_setclear8(bscv_soft_state_t *, int,
108 111 bscv_addr_t, uint8_t, uint8_t);
109 112 static void bscv_setclear8_volatile(bscv_soft_state_t *, int,
110 113 bscv_addr_t, uint8_t, uint8_t);
111 114 static void bscv_rep_rw8(bscv_soft_state_t *, int,
112 115 uint8_t *, bscv_addr_t, size_t, uint_t, boolean_t);
113 116 static uint8_t bscv_get8_cached(bscv_soft_state_t *, bscv_addr_t);
114 117
115 118 static uint8_t bscv_get8_locked(bscv_soft_state_t *, int, bscv_addr_t, int *);
116 119 static void bscv_rep_get8_locked(bscv_soft_state_t *, int,
117 120 uint8_t *, bscv_addr_t, size_t, uint_t, int *);
118 121
119 122 static boolean_t bscv_faulty(bscv_soft_state_t *);
120 123 static void bscv_clear_fault(bscv_soft_state_t *);
121 124 static void bscv_set_fault(bscv_soft_state_t *);
122 125 static boolean_t bscv_session_error(bscv_soft_state_t *);
123 126 static int bscv_retcode(bscv_soft_state_t *);
124 127 static int bscv_should_retry(bscv_soft_state_t *);
125 128 static void bscv_locked_result(bscv_soft_state_t *, int *);
126 129
127 130 static void bscv_put8_once(bscv_soft_state_t *, int, bscv_addr_t, uint8_t);
128 131 static uint8_t bscv_get8_once(bscv_soft_state_t *, int, bscv_addr_t);
129 132 static uint32_t bscv_probe(bscv_soft_state_t *, int, uint32_t *);
130 133 static void bscv_resync_comms(bscv_soft_state_t *, int);
131 134
132 135 static boolean_t bscv_window_setup(bscv_soft_state_t *);
133 136 static int bscv_eerw(bscv_soft_state_t *, uint32_t, uint8_t *,
134 137 unsigned, boolean_t);
135 138
136 139 static int bscv_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
137 140 static int bscv_ioc_dogstate(bscv_soft_state_t *, intptr_t, int);
138 141 static int bscv_ioc_psustate(bscv_soft_state_t *, intptr_t, int);
139 142 static int bscv_ioc_fanstate(bscv_soft_state_t *, intptr_t, int);
140 143 static int bscv_ioc_fledstate(bscv_soft_state_t *, intptr_t, int);
141 144 static int bscv_ioc_ledstate(bscv_soft_state_t *, intptr_t, int);
142 145 static int bscv_ioc_info(bscv_soft_state_t *, intptr_t, int);
143 146 static int bscv_ioc_mread(bscv_soft_state_t *, intptr_t, int);
144 147 static int bscv_ioc_volts(bscv_soft_state_t *, intptr_t, int);
145 148 static int bscv_ioc_stats(bscv_soft_state_t *, intptr_t, int);
146 149 static int bscv_ioc_temp(bscv_soft_state_t *, intptr_t, int);
147 150 static int bscv_ioc_cons(bscv_soft_state_t *, intptr_t, int);
148 151 static int bscv_ioc_eventlog2(bscv_soft_state_t *, intptr_t, int);
149 152 static int bscv_ioc_info2(bscv_soft_state_t *, intptr_t, int);
150 153 static int bscv_ioc_test(bscv_soft_state_t *, intptr_t, int);
151 154 static int bscv_ioc_mprog2(bscv_soft_state_t *, intptr_t, int);
152 155 static int bscv_ioc_mread2(bscv_soft_state_t *, intptr_t, int);
153 156
154 157 static void bscv_event_daemon(void *);
155 158 static void bscv_start_event_daemon(bscv_soft_state_t *);
156 159 static int bscv_stop_event_daemon(bscv_soft_state_t *);
157 160 static int bscv_pause_event_daemon(bscv_soft_state_t *);
158 161 static void bscv_resume_event_daemon(bscv_soft_state_t *);
159 162 static void bscv_event_process(bscv_soft_state_t *ssp, boolean_t);
160 163 static int bscv_event_validate(bscv_soft_state_t *, uint32_t, uint8_t);
161 164 static void bscv_event_process_one(bscv_soft_state_t *, lom_event_t *);
162 165 static void bscv_build_eventstring(bscv_soft_state_t *,
163 166 lom_event_t *, char *, char *);
164 167 static int bscv_level_of_event(lom_event_t *);
165 168 static void bscv_status(bscv_soft_state_t *, uint8_t, uint8_t);
166 169 char *bscv_get_label(char [][MAX_LOM2_NAME_STR], int, int);
167 170 static void bscv_generic_sysevent(bscv_soft_state_t *, char *, char *, char *,
168 171 char *, int32_t, char *);
169 172 static void bscv_sysevent(bscv_soft_state_t *, lom_event_t *);
170 173
171 174 static int bscv_prog(bscv_soft_state_t *, intptr_t, int);
172 175 static int bscv_prog_image(bscv_soft_state_t *, boolean_t,
173 176 uint8_t *, int, uint32_t);
174 177 static int bscv_prog_receive_image(bscv_soft_state_t *, lom_prog_t *,
175 178 uint8_t *, int);
176 179 static void bscv_leave_programming_mode(bscv_soft_state_t *, boolean_t);
177 180 static int bscv_prog_stop_lom(bscv_soft_state_t *);
178 181 static int bscv_prog_start_lom(bscv_soft_state_t *);
179 182
180 183 static int bscv_attach_common(bscv_soft_state_t *);
181 184 static int bscv_cleanup(bscv_soft_state_t *);
182 185 static void bscv_setup_capability(bscv_soft_state_t *);
183 186 static int bscv_probe_check(bscv_soft_state_t *);
184 187 static void bscv_setup_hostname(bscv_soft_state_t *);
185 188 static void bscv_read_hostname(bscv_soft_state_t *, char *);
186 189 static void bscv_write_hostname(bscv_soft_state_t *, char *, uint8_t);
187 190 static void bscv_setup_static_info(bscv_soft_state_t *);
188 191 static uint8_t bscv_read_env_name(bscv_soft_state_t *, uint8_t,
189 192 uint8_t, uint8_t, char [][MAX_LOM2_NAME_STR], int);
190 193 static void bscv_setup_events(bscv_soft_state_t *);
191 194
192 195 static void bscv_trace(bscv_soft_state_t *, char, const char *,
193 196 const char *, ...);
194 197
195 198 #ifdef __sparc
196 199 static void bscv_idi_init();
197 200 static void bscv_idi_fini();
198 201 static void bscv_idi_new_instance(dev_info_t *dip);
199 202 static void bscv_idi_clear_err();
200 203 void bscv_idi_set(struct bscv_idi_info info);
201 204 static boolean_t bscv_idi_err();
202 205 static boolean_t bscv_nodename_set(struct bscv_idi_info info);
203 206 static boolean_t bscv_sig_set(struct bscv_idi_info info);
204 207 static boolean_t bscv_wdog_pat(struct bscv_idi_info info);
205 208 static boolean_t bscv_wdog_cfg(struct bscv_idi_info info);
206 209 static void bscv_write_sig(bscv_soft_state_t *ssp, bscv_sig_t s);
207 210 #endif /* __sparc */
208 211
209 212 static void bscv_setup_watchdog(bscv_soft_state_t *ssp);
210 213 static void bscv_write_wdog_cfg(bscv_soft_state_t *,
211 214 uint_t, boolean_t, uint8_t);
212 215
213 216 #if defined(__i386) || defined(__amd64)
214 217 static void bscv_inform_bsc(bscv_soft_state_t *, uint32_t);
215 218 static void bscv_watchdog_pat_request(void *);
216 219 static void bscv_watchdog_cfg_request(bscv_soft_state_t *, uint8_t);
217 220 static uint_t bscv_set_watchdog_timer(bscv_soft_state_t *, uint_t);
218 221 static void bscv_clear_watchdog_timer(bscv_soft_state_t *);
219 222
220 223 static boolean_t bscv_panic_callback(void *, int);
221 224 static void bscv_watchdog_cyclic_add(bscv_soft_state_t *);
222 225 static void bscv_watchdog_cyclic_remove(bscv_soft_state_t *);
223 226
224 227 static uint8_t wdog_reset_on_timeout = 1;
225 228
226 229 #define WDOG_ON 1
227 230 #define WDOG_OFF 0
228 231 #define CLK_WATCHDOG_DEFAULT 10 /* 10 seconds */
229 232 #define WATCHDOG_PAT_INTERVAL 1000000000 /* 1 second */
230 233
231 234 static int bscv_watchdog_enable;
232 235 static int bscv_watchdog_available;
233 236 static int watchdog_activated;
234 237 static uint_t bscv_watchdog_timeout_seconds;
235 238 #endif /* __i386 || __amd64 */
236 239
237 240 #ifdef __sparc
238 241 struct bscv_idi_callout bscv_idi_callout_table[] = {
239 242 {BSCV_IDI_NODENAME, &bscv_nodename_set },
240 243 {BSCV_IDI_SIG, &bscv_sig_set },
241 244 {BSCV_IDI_WDOG_PAT, &bscv_wdog_pat },
242 245 {BSCV_IDI_WDOG_CFG, &bscv_wdog_cfg },
243 246 {BSCV_IDI_NULL, NULL }
244 247 };
245 248
246 249 static struct bscv_idi_callout_mgr bscv_idi_mgr;
247 250 #endif /* __sparc */
248 251
249 252 /*
250 253 * Local Definitions
251 254 */
252 255 #define STATUS_READ_LIMIT 8 /* Read up to 8 status changes at a time */
253 256 #define MYNAME "bscv"
254 257 #define BSCV_INST_TO_MINOR(i) (i)
255 258 #define BSCV_MINOR_TO_INST(m) (m)
256 259
257 260 /*
258 261 * Strings for daemon event reporting
259 262 */
260 263
261 264 static char *eventSubsysStrings[] =
262 265 { "", /* 00 */
263 266 "Alarm ", /* 01 */
264 267 "temperature sensor ", /* 02 */
265 268 "overheat sensor ", /* 03 */
266 269 "Fan ", /* 04 */
267 270 "supply rail ", /* 05 */
268 271 "circuit breaker ", /* 06 */
269 272 "PSU ", /* 07 */
270 273 "user ", /* 08 */
271 274 "phonehome ", /* 09; unutilized */
272 275 "LOM ", /* 0a */
273 276 "host ", /* 0b */
274 277 "event log ", /* 0c */
275 278 "", /* 0d; EVENT_SUBSYS_EXTRA unutilized */
276 279 "LED ", /* 0e */
277 280 };
278 281
279 282 static char *eventTypeStrings[] =
280 283 {
281 284 "[null event]", /* 00 */
282 285 "ON", /* 01 */
283 286 "OFF", /* 02 */
284 287 "state change", /* 03 */
285 288 "power on", /* 04 */
286 289 "power off", /* 05 */
287 290 "powered off unexpectedly", /* 06 */
288 291 "reset unexpectedly", /* 07 */
289 292 "booted", /* 08 */
290 293 "watchdog enabled", /* 09 */
291 294 "watchdog disabled", /* 0a */
292 295 "watchdog triggered", /* 0b */
293 296 "failed", /* 0c */
294 297 "recovered", /* 0d */
295 298 "reset", /* 0e */
296 299 "XIR reset", /* 0f */
297 300 "console selected", /* 10 */
298 301 "time reference", /* 11 */
299 302 "script failure", /* 12 */
300 303 "modem access failure", /* 13 */
301 304 "modem dialing failure", /* 14 */
302 305 "bad checksum", /* 15 */
303 306 "added", /* 16 */
304 307 "removed", /* 17 */
305 308 "changed", /* 18 */
306 309 "login", /* 19 */
307 310 "password changed", /* 1a */
308 311 "login failed", /* 1b */
309 312 "logout", /* 1c */
310 313 "flash download", /* 1d */
311 314 "data lost", /* 1e */
312 315 "device busy", /* 1f */
313 316 "fault led state", /* 20 */
314 317 "overheat", /* 21 */
315 318 "severe overheat", /* 22 */
316 319 "no overheat", /* 23 */
317 320 "SCC", /* 24 */
318 321 "device inaccessible", /* 25 */
319 322 "Hostname change", /* 26 */
320 323 "CPU signature timeout", /* 27 */
321 324 "Bootmode change", /* 28 */
322 325 "Watchdog change policy", /* 29 */
323 326 "Watchdog change timeout", /* 2a */
324 327 };
325 328
326 329 /*
327 330 * These store to mapping between the logical service, e.g. chan_prog for
328 331 * programming, and the actual Xbus channel which carries that traffic.
329 332 * Any services can be shared on the same channel apart from chan_wdogpat.
330 333 */
331 334 static int chan_general; /* General Traffic */
332 335 static int chan_wdogpat; /* Watchdog Patting */
333 336 static int chan_cpusig; /* CPU signatures */
334 337 static int chan_eeprom; /* EEPROM I/O */
335 338 static int chan_prog; /* Programming */
336 339
337 340 /*
338 341 * cb_ops structure defining the driver entry points
339 342 */
340 343
341 344 static struct cb_ops bscv_cb_ops = {
342 345 bscv_open, /* open */
343 346 bscv_close, /* close */
344 347 nodev, /* strategy */
345 348 nodev, /* print */
346 349 nodev, /* dump */
347 350 nodev, /* read */
348 351 nodev, /* write */
349 352 bscv_ioctl, /* ioctl */
350 353 nodev, /* devmap */
351 354 nodev, /* mmap */
352 355 nodev, /* segmap */
353 356 nochpoll, /* poll */
354 357 ddi_prop_op, /* prop op */
355 358 NULL, /* ! STREAMS */
356 359 D_NEW | D_MP /* MT/MP Safe */
357 360 };
358 361
359 362 /*
360 363 * dev_ops structure defining autoconfiguration driver autoconfiguration
361 364 * routines
362 365 */
363 366
364 367 static struct dev_ops bscv_dev_ops = {
365 368 DEVO_REV, /* devo_rev */
366 369 0, /* devo_refcnt */
367 370 bscv_getinfo, /* devo_getinfo */
368 371 nulldev, /* devo_identify */
369 372 nulldev, /* devo_probe */
370 373 bscv_attach, /* devo_attach */
371 374 bscv_detach, /* devo_detach */
372 375 nodev, /* devo_reset */
373 376 &bscv_cb_ops, /* devo_cb_ops */
374 377 (struct bus_ops *)0, /* devo_bus_ops */
375 378 NULL, /* devo_power */
376 379 bscv_quiesce, /* devo_quiesce */
377 380 };
378 381
379 382 /*
380 383 * module configuration section
381 384 */
382 385
383 386 #ifdef DEBUG
384 387 #define BSCV_VERSION_STRING "bscv driver - Debug"
385 388 #else /* DEBUG */
386 389 #define BSCV_VERSION_STRING "bscv driver"
387 390 #endif /* DEBUG */
388 391
389 392 static struct modldrv modldrv = {
390 393 &mod_driverops,
391 394 BSCV_VERSION_STRING,
392 395 &bscv_dev_ops,
393 396 };
394 397
395 398 static struct modlinkage modlinkage = {
396 399 MODREV_1,
↓ open down ↓ |
361 lines elided |
↑ open up ↑ |
397 400 &modldrv,
398 401 NULL
399 402 };
400 403
401 404 #ifdef DEBUG
402 405 /* Tracing is enabled if value is non-zero. */
403 406 static int bscv_trace_flag = 1;
404 407
405 408 #define BSCV_TRACE if (bscv_trace_flag != 0) bscv_trace
406 409 #else
407 -#define BSCV_TRACE
410 +#define BSCV_TRACE(...) (void)(0)
408 411 #endif
409 412
410 413 /*
411 414 * kernel accessible routines. These routines are necessarily global so the
412 415 * driver can be loaded, and unloaded successfully
413 416 */
414 417
415 418 /*
416 419 * function - _init
417 420 * description - initializes the driver state structure and installs the
418 421 * driver module into the kernel
419 422 * inputs - none
420 423 * outputs - success or failure of module installation
421 424 */
422 425
423 426 int
424 427 _init(void)
425 428 {
426 429 register int e;
427 430
428 431 if ((e = ddi_soft_state_init(&bscv_statep,
429 432 sizeof (bscv_soft_state_t), 1)) != 0) {
430 433 return (e);
431 434 }
432 435
433 436 if ((e = mod_install(&modlinkage)) != 0) {
434 437 ddi_soft_state_fini(&bscv_statep);
435 438 }
436 439
437 440 #ifdef __sparc
438 441 if (e == 0) bscv_idi_init();
439 442 #endif /* __sparc */
440 443 return (e);
441 444 }
442 445
443 446 /*
444 447 * function - _info
445 448 * description - provide information about a kernel loaded module
446 449 * inputs - module infomation
447 450 * outputs - success or failure of information request
448 451 */
449 452
450 453 int
451 454 _info(struct modinfo *modinfop)
452 455 {
453 456 return (mod_info(&modlinkage, modinfop));
454 457 }
455 458
456 459 /*
457 460 * function - _fini
458 461 * description - removes a module from the kernel and frees the driver soft
459 462 * state memory
460 463 * inputs - none
461 464 * outputs - success or failure of module removal
462 465 */
463 466
464 467 int
465 468 _fini(void)
466 469 {
467 470 register int e;
468 471
469 472 if ((e = mod_remove(&modlinkage)) != 0) {
470 473 return (e);
471 474 }
472 475
473 476 #ifdef __sparc
474 477 bscv_idi_fini();
475 478 #endif /* __sparc */
476 479 ddi_soft_state_fini(&bscv_statep);
477 480
478 481 return (e);
479 482 }
480 483
481 484 /*
482 485 * function - bscv_getinfo
483 486 * description - routine used to provide information on the driver
484 487 * inputs - device information structure, command, command arg, storage
485 488 * area for the result
486 489 * outputs - DDI_SUCCESS or DDI_FAILURE
487 490 */
488 491
489 492 /*ARGSUSED*/
490 493 static int
491 494 bscv_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result)
492 495 {
493 496 bscv_soft_state_t *ssp;
494 497 dev_t dev = (dev_t)arg;
495 498 int instance;
496 499 int error;
497 500
498 501 instance = DEVICETOINSTANCE(dev);
499 502
500 503 switch (cmd) {
501 504 case DDI_INFO_DEVT2INSTANCE:
502 505 *result = (void *)(uintptr_t)instance;
503 506 error = DDI_SUCCESS;
504 507 break;
505 508
506 509 case DDI_INFO_DEVT2DEVINFO:
507 510 ssp = ddi_get_soft_state(bscv_statep, instance);
508 511 if (ssp == NULL)
509 512 return (DDI_FAILURE);
510 513 *result = (void *) ssp->dip;
511 514 error = DDI_SUCCESS;
512 515 break;
513 516
514 517 default:
515 518 error = DDI_FAILURE;
516 519 break;
517 520 }
518 521
519 522 return (error);
520 523 }
521 524
522 525 #ifdef __sparc
523 526 void
524 527 bscv_idi_init()
525 528 {
526 529 bscv_idi_mgr.valid_inst = (uint32_t)~0; /* No valid instances */
527 530 bscv_idi_mgr.tbl = bscv_idi_callout_table;
528 531 bscv_idi_mgr.errs = 0;
529 532
530 533 /*
531 534 * Now that all fields are initialized, set the magic flag. This is
532 535 * a kind of integrity check for the data structure.
533 536 */
534 537 bscv_idi_mgr.magic = BSCV_IDI_CALLOUT_MAGIC;
535 538 }
536 539
537 540 static void
538 541 bscv_idi_clear_err()
539 542 {
540 543 ASSERT(bscv_idi_mgr.magic == BSCV_IDI_CALLOUT_MAGIC);
541 544
542 545 bscv_idi_mgr.errs = 0;
543 546 }
544 547
545 548 /*
546 549 * function - bscv_idi_err
547 550 * description - error messaging service which throttles the number of error
548 551 * messages to avoid overflowing storage
549 552 * inputs - none
550 553 * returns - boolean to indicate whether a message should be reported
551 554 * side-effects - updates the error number counter
552 555 */
553 556 static boolean_t
554 557 bscv_idi_err()
555 558 {
556 559 ASSERT(bscv_idi_mgr.magic == BSCV_IDI_CALLOUT_MAGIC);
557 560
558 561 bscv_idi_mgr.errs++;
559 562
560 563 if (bscv_idi_mgr.errs++ < BSCV_IDI_ERR_MSG_THRESHOLD)
561 564 return (B_TRUE);
562 565
563 566 return (B_FALSE);
564 567 }
565 568
566 569 void
567 570 bscv_idi_new_instance(dev_info_t *dip)
568 571 {
569 572 ASSERT(bscv_idi_mgr.magic == BSCV_IDI_CALLOUT_MAGIC);
570 573
571 574 /*
572 575 * We don't care how many instances we have, or their value, so long
573 576 * as we have at least one valid value. This is so service routines
574 577 * can get any required locks via a soft state pointer.
575 578 */
576 579 if (bscv_idi_mgr.valid_inst == (uint32_t)~0) {
577 580 bscv_idi_mgr.valid_inst = ddi_get_instance(dip);
578 581 }
579 582 }
580 583
581 584 void
582 585 bscv_idi_fini()
583 586 {
584 587 bscv_idi_mgr.valid_inst = (uint32_t)~0; /* No valid instances */
585 588 bscv_idi_mgr.tbl = NULL;
586 589 }
587 590 #endif /* __sparc */
588 591
589 592 /*
590 593 * function - bscv_attach
591 594 * description - this routine is responsible for setting aside memory for the
592 595 * driver data structures, initialising the mutexes and creating
593 596 * the device minor nodes. Additionally, this routine calls the
594 597 * the callback routine.
595 598 * inputs - device information structure, DDI_ATTACH command
596 599 * outputs - DDI_SUCCESS or DDI_FAILURE
597 600 */
598 601
599 602 int
600 603 bscv_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
601 604 {
602 605 bscv_soft_state_t *ssp;
603 606 int instance;
604 607
605 608 switch (cmd) {
606 609 case DDI_ATTACH:
607 610
608 611 instance = ddi_get_instance(dip);
609 612
610 613 if (ddi_soft_state_zalloc(bscv_statep, instance) !=
611 614 DDI_SUCCESS) {
612 615 return (DDI_FAILURE);
613 616 }
614 617
615 618
616 619 ssp = ddi_get_soft_state(bscv_statep, instance);
617 620
618 621 ssp->progress = 0;
619 622
620 623 ssp->dip = dip;
621 624 ssp->instance = instance;
622 625 ssp->event_waiting = B_FALSE;
623 626 ssp->status_change = B_FALSE;
624 627 ssp->nodename_change = B_FALSE;
625 628 ssp->cap0 = 0;
626 629 ssp->cap1 = 0;
627 630 ssp->cap2 = 0;
628 631 ssp->prog_mode_only = B_FALSE;
629 632 ssp->programming = B_FALSE;
630 633 ssp->cssp_prog = B_FALSE;
631 634 ssp->task_flags = 0;
632 635 ssp->debug = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
633 636 DDI_PROP_DONTPASS, "debug", 0);
634 637 ssp->majornum = ddi_driver_major(dip);
635 638 ssp->minornum = BSCV_INST_TO_MINOR(instance);
636 639 #if defined(__i386) || defined(__amd64)
637 640 ssp->last_nodename[0] = '\0';
638 641 #endif /* __i386 || __amd64 */
639 642
640 643 /*
641 644 * initialise the mutexes
642 645 */
643 646
644 647 mutex_init(&ssp->cmd_mutex, NULL, MUTEX_DRIVER, NULL);
645 648
646 649 mutex_init(&ssp->task_mu, NULL, MUTEX_DRIVER, NULL);
647 650 cv_init(&ssp->task_cv, NULL, CV_DRIVER, NULL);
648 651 cv_init(&ssp->task_evnt_cv, NULL, CV_DRIVER, NULL);
649 652 mutex_init(&ssp->prog_mu, NULL, MUTEX_DRIVER, NULL);
650 653 ssp->progress |= BSCV_LOCKS;
651 654
652 655 BSCV_TRACE(ssp, 'A', "bscv_attach",
653 656 "bscv_attach: mutexes and condition vars initialised");
654 657
655 658 /* Map in physical communication channels */
656 659
657 660 if (bscv_map_regs(ssp) != DDI_SUCCESS) {
658 661 (void) bscv_cleanup(ssp);
659 662 return (DDI_FAILURE);
660 663 }
661 664 ssp->progress |= BSCV_MAPPED_REGS;
662 665
663 666 /* Associate logical channels to physical channels */
664 667
665 668 bscv_map_chan_logical_physical(ssp);
666 669
667 670 bscv_enter(ssp);
668 671
669 672 bscv_leave_programming_mode(ssp, B_FALSE);
670 673
671 674 if (bscv_attach_common(ssp) == DDI_FAILURE) {
672 675 bscv_exit(ssp);
673 676 (void) bscv_cleanup(ssp);
674 677 return (DDI_FAILURE);
675 678 }
676 679
677 680 #ifdef __sparc
678 681 /*
679 682 * At this point the inter-driver-interface is made available.
680 683 * The IDI uses the event thread service which
681 684 * bscv_attach_common() sets up.
682 685 */
683 686 bscv_idi_new_instance(dip);
684 687 #endif /* __sparc */
685 688
686 689 bscv_exit(ssp);
687 690
688 691 /*
689 692 * now create the minor nodes
690 693 */
691 694 if (ddi_create_minor_node(ssp->dip, "lom", S_IFCHR,
692 695 BSCV_INST_TO_MINOR(instance),
693 696 DDI_PSEUDO, 0) != DDI_SUCCESS) {
694 697 (void) bscv_cleanup(ssp);
695 698 return (DDI_FAILURE);
696 699 }
697 700 BSCV_TRACE(ssp, 'A', "bscv_attach",
698 701 "bscv_attach: device minor nodes created");
699 702 ssp->progress |= BSCV_NODES;
700 703
701 704 if (!ssp->prog_mode_only)
702 705 bscv_start_event_daemon(ssp);
703 706
704 707 #if defined(__i386) || defined(__amd64)
705 708 bscv_watchdog_enable = 1;
706 709 bscv_watchdog_available = 1;
707 710 watchdog_activated = 0;
708 711 bscv_watchdog_timeout_seconds = CLK_WATCHDOG_DEFAULT;
709 712
710 713 if (bscv_watchdog_enable && (boothowto & RB_DEBUG)) {
711 714 bscv_watchdog_available = 0;
712 715 cmn_err(CE_WARN, "bscv: kernel debugger "
713 716 "detected: hardware watchdog disabled");
714 717 }
715 718
716 719 /*
717 720 * Before we enable the watchdog - register the panic
718 721 * callback so that we get called to stop the watchdog
719 722 * in the case of a panic.
720 723 */
721 724 ssp->callb_id = callb_add(bscv_panic_callback,
722 725 (void *)ssp, CB_CL_PANIC, "");
723 726
724 727 if (bscv_watchdog_available) {
725 728 (void) bscv_set_watchdog_timer(ssp,
726 729 CLK_WATCHDOG_DEFAULT);
727 730 bscv_enter(ssp);
728 731 bscv_setup_watchdog(ssp); /* starts cyclic callback */
729 732 bscv_exit(ssp);
730 733 }
731 734 #endif /* __i386 || __amd64 */
732 735 ddi_report_dev(dip);
733 736 return (DDI_SUCCESS);
734 737 default:
735 738 return (DDI_FAILURE);
736 739 }
737 740 }
738 741
739 742 /*
740 743 * function - bscv_detach
741 744 * description - routine that prepares a module to be unloaded. It undoes all
742 745 * the work done by the bscv_attach)() routine. This is
743 746 * facilitated by the use of the progress indicator
744 747 * inputs - device information structure, DDI_DETACH command
745 748 * outputs - DDI_SUCCESS or DDI_FAILURE
746 749 */
747 750
748 751 /*ARGSUSED*/
749 752 static int
750 753 bscv_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
751 754 {
752 755 return (DDI_FAILURE);
753 756 }
754 757
755 758 /*
756 759 * quiesce(9E) entry point.
757 760 *
758 761 * This function is called when the system is single-threaded at high
759 762 * PIL with preemption disabled. Therefore, this function must not be
760 763 * blocked.
761 764 *
762 765 * This function returns DDI_SUCCESS on success, or DDI_FAILURE on failure.
763 766 * DDI_FAILURE indicates an error condition and should almost never happen.
764 767 */
765 768 static int
766 769 bscv_quiesce(dev_info_t *dip)
767 770 {
768 771 bscv_soft_state_t *ssp;
769 772 int instance;
770 773
771 774
772 775 instance = ddi_get_instance(dip);
773 776 ssp = ddi_get_soft_state(bscv_statep, instance);
774 777 if (ssp == NULL) {
775 778 return (DDI_FAILURE);
776 779 }
777 780 #ifdef DEBUG
778 781 /* Disable tracing, as we are executing at High-Interrupt level */
779 782 bscv_trace_flag = 0;
780 783 #endif
781 784 /* quiesce the device */
782 785 bscv_full_stop(ssp);
783 786
784 787 return (DDI_SUCCESS);
785 788 }
786 789
787 790 /*
788 791 * cb_ops routines
789 792 */
790 793
791 794 /*
792 795 * function - bscv_open
793 796 * description - routine to provide association between user fd and device
794 797 * minor number. This routine is necessarily simple since a
795 798 * read/write interface is not provided. Additionally, the
796 799 * driver does not enforce exclusive access (FEXCL) or
797 800 * non-blocking during an open (FNDELAY). Deferred attach is
798 801 * supported.
799 802 * inputs - device number, flag specifying open type, device type,
800 803 * permissions
801 804 * outputs - success or failure of operation
802 805 */
803 806
804 807 /*ARGSUSED*/
805 808 static int
806 809 bscv_open(dev_t *devp, int flag, int otype, cred_t *cred)
807 810 {
808 811 bscv_soft_state_t *ssp;
809 812 int instance;
810 813
811 814 instance = DEVICETOINSTANCE(*devp);
812 815 ssp = ddi_get_soft_state(bscv_statep, instance);
813 816 if (ssp == NULL) {
814 817 return (ENXIO); /* not attached yet */
815 818 }
816 819 BSCV_TRACE(ssp, 'O', "bscv_open", "instance 0x%x", instance);
817 820
818 821 if (otype != OTYP_CHR) {
819 822 return (EINVAL);
820 823 }
821 824
822 825 return (0);
823 826 }
824 827
825 828 /*
826 829 * function - bscv_close
827 830 * description - routine to perform the final close on the device. As per the
828 831 * open routine, neither FEXCL or FNDELAY accesses are enforced
829 832 * by the driver.
830 833 * inputs - device number,flag specifying open type, device type,
831 834 * permissions
832 835 * outputs - success or failure of operation
833 836 */
834 837
835 838 /*ARGSUSED1*/
836 839 static int
837 840 bscv_close(dev_t dev, int flag, int otype, cred_t *cred)
838 841 {
839 842 bscv_soft_state_t *ssp;
840 843 int instance;
841 844
842 845 instance = DEVICETOINSTANCE(dev);
843 846 ssp = ddi_get_soft_state(bscv_statep, instance);
844 847 if (ssp == NULL) {
845 848 return (ENXIO);
846 849 }
847 850 BSCV_TRACE(ssp, 'O', "bscv_close", "instance 0x%x", instance);
848 851
849 852 return (0);
850 853 }
851 854
852 855 static int
853 856 bscv_map_regs(bscv_soft_state_t *ssp)
854 857 {
855 858 int i;
856 859 int retval;
857 860 int *props;
858 861 unsigned int nelements;
859 862
860 863 ASSERT(ssp);
861 864
862 865 ssp->nchannels = 0;
863 866
864 867 /*
865 868 * Work out how many channels are available by looking at the number
866 869 * of elements of the regs property array.
867 870 */
868 871 retval = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, ssp->dip,
869 872 DDI_PROP_DONTPASS, "reg", &props, &nelements);
870 873
871 874 /* We don't need props anymore. Free memory if it was allocated */
872 875 if (retval == DDI_PROP_SUCCESS)
873 876 ddi_prop_free(props);
874 877
875 878 /* Check for sanity of nelements */
876 879 if (retval != DDI_PROP_SUCCESS) {
877 880 BSCV_TRACE(ssp, 'A', "bscv_map_regs", "lookup reg returned"
878 881 " 0x%x", retval);
879 882 goto cleanup_exit;
880 883 } else if (nelements % LOMBUS_REGSPEC_SIZE != 0) {
881 884 BSCV_TRACE(ssp, 'A', "bscv_map_regs", "nelements %d not"
882 885 " a multiple of %d", nelements, LOMBUS_REGSPEC_SIZE);
883 886 goto cleanup_exit;
884 887 } else if (nelements > BSCV_MAXCHANNELS * LOMBUS_REGSPEC_SIZE) {
885 888 BSCV_TRACE(ssp, 'A', "bscv_map_regs", "nelements %d too large"
886 889 ", probably a misconfiguration", nelements);
887 890 goto cleanup_exit;
888 891 } else if (nelements < BSCV_MINCHANNELS * LOMBUS_REGSPEC_SIZE) {
889 892 BSCV_TRACE(ssp, 'A', "bscv_map_regs", "nelements %d too small"
890 893 ", need to have at least a general and a wdog channel",
891 894 nelements);
892 895 goto cleanup_exit;
893 896 }
894 897
895 898 ssp->nchannels = nelements / LOMBUS_REGSPEC_SIZE;
896 899
897 900 ssp->attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
898 901 ssp->attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC;
899 902 ssp->attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
900 903
901 904 for (i = 0; i < ssp->nchannels; i++) {
902 905 retval = ddi_regs_map_setup(ssp->dip, i,
903 906 (caddr_t *)&ssp->channel[i].regs,
904 907 0, 0, &ssp->attr, &ssp->channel[i].handle);
905 908 if (retval != DDI_SUCCESS) {
906 909 BSCV_TRACE(ssp, 'A', "bscv_map_regs", "map failure"
907 910 " 0x%x on space %d", retval, i);
908 911
909 912 /* Rewind all current mappings - avoiding failed one */
910 913 i--;
911 914 for (; i >= 0; i--) {
912 915 ddi_regs_map_free(&ssp->channel[i].handle);
913 916 }
914 917
915 918 goto cleanup_exit;
916 919 }
917 920 }
918 921
919 922 return (DDI_SUCCESS);
920 923
921 924 cleanup_exit:
922 925 /*
923 926 * It is important to set nchannels to 0 even if, say, only one of
924 927 * the two required handles was mapped. If we cannot achieve our
925 928 * minimum config its not safe to do any IO; this keeps our failure
926 929 * mode handling simpler.
927 930 */
928 931 ssp->nchannels = 0;
929 932 return (DDI_FAILURE);
930 933 }
931 934
932 935 static void
933 936 bscv_unmap_regs(bscv_soft_state_t *ssp)
934 937 {
935 938 int i;
936 939
937 940 ASSERT(ssp);
938 941
939 942 for (i = 0; i < ssp->nchannels; i++) {
940 943 ddi_regs_map_free(&ssp->channel[i].handle);
941 944 }
942 945 }
943 946
944 947 /*
945 948 * Map logical services onto physical XBus channels.
946 949 */
947 950 static void
948 951 bscv_map_chan_logical_physical(bscv_soft_state_t *ssp)
949 952 {
950 953 ASSERT(ssp);
951 954
952 955 /*
953 956 * We can assert that there will always be at least two channels,
954 957 * to allow watchdog pats to be segregated from all other traffic.
955 958 */
956 959 chan_general = 0;
957 960 chan_wdogpat = 1;
958 961
959 962 /*
960 963 * By default move all other services onto the generic channel unless
961 964 * the hardware supports additional channels.
962 965 */
963 966
964 967 chan_cpusig = chan_eeprom = chan_prog = chan_general;
965 968
966 969 if (ssp->nchannels > 2)
967 970 chan_cpusig = 2;
968 971 if (ssp->nchannels > 3)
969 972 chan_eeprom = 3;
970 973 if (ssp->nchannels > 4)
971 974 chan_prog = 4;
972 975 }
973 976
974 977
975 978 /*
976 979 * function - bscv_full_stop
977 980 * description - gracefully shut the lom down during panic or reboot.
978 981 * Disables the watchdog and sets up serial event reporting.
979 982 * inputs - soft state pointer
980 983 * outputs - none
981 984 */
982 985 void
983 986 bscv_full_stop(bscv_soft_state_t *ssp)
984 987 {
985 988 uint8_t bits2set = 0;
986 989 uint8_t bits2clear = 0;
987 990 int obtained_lock;
988 991
989 992 BSCV_TRACE(ssp, 'W', "bscv_full_stop",
990 993 "turning off watchdog");
991 994
992 995 /*
993 996 * Obtain the softstate lock only if it is not already owned,
994 997 * as this function can be called from a High-level interrupt
995 998 * context. As a result, our thread cannot sleep.
996 999 * At end of function, our thread releases the lock only if
997 1000 * it acquired the lock.
998 1001 */
999 1002 obtained_lock = (bscv_tryenter(ssp) != 0);
1000 1003
1001 1004 #if defined(__i386) || defined(__amd64)
1002 1005 if (ddi_in_panic()) {
1003 1006 bscv_inform_bsc(ssp, BSC_INFORM_PANIC);
1004 1007 } else {
1005 1008 bscv_inform_bsc(ssp, BSC_INFORM_OFFLINE);
1006 1009 }
1007 1010 #endif /* __i386 || __amd64 */
1008 1011
1009 1012 /* set serial event reporting */
1010 1013 switch (ssp->serial_reporting) {
1011 1014 case LOM_SER_EVENTS_ON:
1012 1015 case LOM_SER_EVENTS_DEF:
1013 1016 /* Make sure serial event reporting is on */
1014 1017 bits2clear = EBUS_ALARM_NOEVENTS;
1015 1018 break;
1016 1019 case LOM_SER_EVENTS_OFF:
1017 1020 /* Make sure serial event reporting is on */
1018 1021 bits2set = EBUS_ALARM_NOEVENTS;
1019 1022 break;
1020 1023 default:
1021 1024 break;
1022 1025 }
1023 1026 bscv_setclear8_volatile(ssp, chan_general,
1024 1027 EBUS_IDX_ALARM, bits2set, bits2clear);
1025 1028
1026 1029 /* Do not free the lock if our thread did not obtain it. */
1027 1030 if (obtained_lock != 0) {
1028 1031 bscv_exit(ssp);
1029 1032 }
1030 1033 }
1031 1034
1032 1035 /*
1033 1036 * LOM I/O routines.
1034 1037 *
1035 1038 * locking
1036 1039 *
1037 1040 * Two sets of routines are provided:
1038 1041 * normal - must be called after acquiring an appropriate lock.
1039 1042 * locked - perform all the locking required and return any error
1040 1043 * code in the supplied 'res' argument. If there is no
1041 1044 * error 'res' is not changed.
1042 1045 * The locked routines are designed for use in ioctl commands where
1043 1046 * only a single operation needs to be performed and the overhead of
1044 1047 * locking and result checking adds significantly to code complexity.
1045 1048 *
1046 1049 * locking primitives
1047 1050 *
1048 1051 * bscv_enter() - acquires an I/O lock for the calling thread.
1049 1052 * bscv_tryenter() - conditionally acquires an I/O lock for calling thread.
1050 1053 * bscv_exit() - releases an I/O lock acquired by bscv_enter().
1051 1054 * bscv_held() - used to assert ownership of an I/O lock.
1052 1055 *
1053 1056 * normal I/O routines
1054 1057 *
1055 1058 * Note bscv_{put|get}{16|32} routines are big-endian. This assumes that
1056 1059 * the firmware works that way too.
1057 1060 *
1058 1061 * bscv_put8(), bscv_put16, bscv_put32 - write values to the LOM
1059 1062 * and handle any retries if necessary.
1060 1063 * 16 and 32 bit values are big-endian.
1061 1064 * bscv_get8(), bscv_get16, bscv_get32 - read values from the LOM
1062 1065 * and handle any retries if necessary.
1063 1066 * 16 and 32 bit values are big-endian.
1064 1067 * bscv_setclear8() - set or clear the specified bits in the register
1065 1068 * at the supplied address.
1066 1069 * bscv_setclear8_volatile() - set or clear the specified bits in the
1067 1070 * register at the supplied address. If the lom reports
1068 1071 * that the registers has changed since the last read
1069 1072 * re-read and apply the set or clear to the new bits.
1070 1073 * bscv_get8_cached() - Return a cached register value (addr < 0x80).
1071 1074 * Does not access the hardware. A read of the hardware
1072 1075 * automatically updates this cache.
1073 1076 *
1074 1077 * locked I/O routines
1075 1078 *
1076 1079 * bscv_get8_locked(), bscv_rep_get8_locked().
1077 1080 *
1078 1081 * Call the indicated function from above, but wrapping it with
1079 1082 * bscv_enter()/bscv_exit().
1080 1083 *
1081 1084 *
1082 1085 * Fault management
1083 1086 *
1084 1087 * LOM communications fault are grouped into three categories:
1085 1088 * 1) Faulty - the LOM is not responding and no attempt to communicate
1086 1089 * with it should be made.
1087 1090 * 2) Transient fault - something which might recover after a retry
1088 1091 * but which doesn't affect our ability to perform other
1089 1092 * commands.
1090 1093 * 3) Command error - an inappropriate command was executed. A retry
1091 1094 * will not fix it but the command failed.
1092 1095 *
1093 1096 * The current implementation of the bscv driver is not very good at
1094 1097 * noticing command errors due to the structure of the original code
1095 1098 * that it is based on. It is possible to extend the driver to do this
1096 1099 * and would probably involve having a concept of a "session error"
1097 1100 * which is less severe than a fault but means that a sequence of
1098 1101 * commands had some fault which cannot be recovered.
1099 1102 *
1100 1103 *
1101 1104 * faults
1102 1105 *
1103 1106 * bscv_faulty() - returns B_TRUE if the LOM (communications) have been
1104 1107 * declared faulty.
1105 1108 * bscv_clear_fault() - marks the LOM as not faulty.
1106 1109 * bscv_set_fault() - marks the LOM as being faulty.
1107 1110 *
1108 1111 * bscv_clear_fault and bscv_set_fault should generally not be called
1109 1112 * directly.
1110 1113 *
1111 1114 * command errors/transient faults
1112 1115 *
1113 1116 * bscv_retcode() - returns the actual error code of the last operation.
1114 1117 * bscv_should_retry() - determines if last operation may suceed if
1115 1118 * retried.
1116 1119 * bscv_locked_result() - Set the result of a locked register access.
1117 1120 *
1118 1121 * low level I/O primitives
1119 1122 *
1120 1123 * These are generally not called directly. These perform a single
1121 1124 * access to the LOM device. They do not handle retries.
1122 1125 *
1123 1126 * bscv_put8_once()
1124 1127 * bscv_get8_once()
1125 1128 * bscv_probe() - perform a probe (NOP) operation to check out lom comms.
1126 1129 * bscv_resync_comms() - resynchronise communications after a transient fault.
1127 1130 */
1128 1131
1129 1132 static void
1130 1133 bscv_enter(bscv_soft_state_t *ssp)
1131 1134 {
1132 1135 BSCV_TRACE(ssp, '@', "bscv_enter", "");
1133 1136 mutex_enter(&ssp->cmd_mutex);
1134 1137 ssp->had_session_error = B_FALSE;
1135 1138 }
1136 1139
1137 1140 static int
1138 1141 bscv_tryenter(bscv_soft_state_t *ssp)
1139 1142 {
1140 1143 int rv;
1141 1144
1142 1145 BSCV_TRACE(ssp, '@', "bscv_tryenter", "");
1143 1146 if ((rv = mutex_tryenter(&ssp->cmd_mutex)) != 0) {
1144 1147 ssp->had_session_error = B_FALSE;
1145 1148 }
1146 1149 return (rv);
1147 1150 }
1148 1151
1149 1152 static void
1150 1153 bscv_exit(bscv_soft_state_t *ssp)
1151 1154 {
1152 1155 mutex_exit(&ssp->cmd_mutex);
1153 1156 BSCV_TRACE(ssp, '@', "bscv_exit", "");
1154 1157 }
1155 1158
1156 1159 #ifdef DEBUG
1157 1160 static int
1158 1161 bscv_held(bscv_soft_state_t *ssp)
1159 1162 {
1160 1163 return (mutex_owned(&ssp->cmd_mutex));
1161 1164 }
1162 1165 #endif /* DEBUG */
1163 1166
1164 1167 static void
1165 1168 bscv_put8(bscv_soft_state_t *ssp, int chan, bscv_addr_t addr, uint8_t val)
1166 1169 {
1167 1170 boolean_t needretry;
1168 1171 int num_failures;
1169 1172
1170 1173 ASSERT(bscv_held(ssp));
1171 1174
1172 1175 if (bscv_faulty(ssp)) {
1173 1176 return;
1174 1177 }
1175 1178
1176 1179 BSCV_TRACE(ssp, '@', "bscv_put8",
1177 1180 "addr 0x%x.%02x <= 0x%02x", addr >> 8, addr & 0xff, val);
1178 1181
1179 1182 for (num_failures = 0;
1180 1183 num_failures < BSC_FAILURE_RETRY_LIMIT;
1181 1184 num_failures++) {
1182 1185 bscv_put8_once(ssp, chan, addr, val);
1183 1186 needretry = bscv_should_retry(ssp);
1184 1187 if (!needretry) {
1185 1188 break;
1186 1189 }
1187 1190 }
1188 1191 if (ssp->command_error != 0) {
1189 1192 ssp->had_session_error = B_TRUE;
1190 1193 }
1191 1194
1192 1195 if (needretry) {
1193 1196 /* Failure - we ran out of retries */
1194 1197 cmn_err(CE_WARN, "bscv_put8: addr 0x%x.%02x retried "
1195 1198 "write %d times, giving up",
1196 1199 addr >> 8, addr & 0xff, num_failures);
1197 1200 bscv_set_fault(ssp);
1198 1201 } else if (num_failures > 0) {
1199 1202 BSCV_TRACE(ssp, 'R', "bscv_put8",
1200 1203 "addr 0x%x.%02x retried write %d times, succeeded",
1201 1204 addr >> 8, addr & 0xff, num_failures);
1202 1205 }
1203 1206 }
1204 1207
1205 1208 static void
1206 1209 bscv_put16(bscv_soft_state_t *ssp, int chan, bscv_addr_t addr, uint16_t val)
1207 1210 {
1208 1211 ASSERT(bscv_held(ssp));
1209 1212 BSCV_TRACE(ssp, '@', "bscv_put16",
1210 1213 "addr 0x%x.%02x <= %04x", addr >> 8, addr & 0xff, val);
1211 1214 bscv_put8(ssp, chan, addr, val >> 8);
1212 1215 bscv_put8(ssp, chan, addr + 1, val & 0xff);
1213 1216 }
1214 1217
1215 1218 static void
1216 1219 bscv_put32(bscv_soft_state_t *ssp, int chan, bscv_addr_t addr, uint32_t val)
1217 1220 {
1218 1221 ASSERT(bscv_held(ssp));
1219 1222 BSCV_TRACE(ssp, '@', "bscv_put32",
1220 1223 "addr 0x%x.%02x <= %08x", addr >> 8, addr & 0xff, val);
1221 1224 bscv_put8(ssp, chan, addr, (val >> 24) & 0xff);
1222 1225 bscv_put8(ssp, chan, addr + 1, (val >> 16) & 0xff);
1223 1226 bscv_put8(ssp, chan, addr + 2, (val >> 8) & 0xff);
1224 1227 bscv_put8(ssp, chan, addr + 3, val & 0xff);
1225 1228 }
1226 1229
1227 1230 static uint8_t
1228 1231 bscv_get8(bscv_soft_state_t *ssp, int chan, bscv_addr_t addr)
1229 1232 {
1230 1233 uint8_t retval;
1231 1234 boolean_t needretry;
1232 1235 int num_failures;
1233 1236
1234 1237 ASSERT(bscv_held(ssp));
1235 1238
1236 1239 if (bscv_faulty(ssp)) {
1237 1240 return (0);
1238 1241 }
1239 1242
1240 1243 for (num_failures = 0;
1241 1244 num_failures < BSC_FAILURE_RETRY_LIMIT;
1242 1245 num_failures++) {
1243 1246 retval = bscv_get8_once(ssp, chan, addr);
1244 1247 needretry = bscv_should_retry(ssp);
1245 1248 if (!needretry) {
1246 1249 break;
1247 1250 }
1248 1251 }
1249 1252 if (ssp->command_error != 0) {
1250 1253 ssp->had_session_error = B_TRUE;
1251 1254 }
1252 1255
1253 1256 if (needretry) {
1254 1257 /* Failure */
1255 1258 cmn_err(CE_WARN, "bscv_get8: addr 0x%x.%02x retried "
1256 1259 "read %d times, giving up",
1257 1260 addr >> 8, addr & 0xff, num_failures);
1258 1261 bscv_set_fault(ssp);
1259 1262 } else if (num_failures > 0) {
1260 1263 BSCV_TRACE(ssp, 'R', "bscv_get8",
1261 1264 "addr 0x%x.%02x retried read %d times, succeeded",
1262 1265 addr >> 8, addr & 0xff, num_failures);
1263 1266 }
1264 1267
1265 1268 BSCV_TRACE(ssp, '@', "bscv_get8",
1266 1269 "addr 0x%x.%02x => %02x", addr >> 8, addr & 0xff, retval);
1267 1270 return (retval);
1268 1271 }
1269 1272
1270 1273 static uint16_t
1271 1274 bscv_get16(bscv_soft_state_t *ssp, int chan, bscv_addr_t addr)
1272 1275 {
1273 1276 uint16_t retval;
1274 1277
1275 1278 ASSERT(bscv_held(ssp));
1276 1279
1277 1280 retval = bscv_get8(ssp, chan, addr) << 8;
1278 1281 retval |= bscv_get8(ssp, chan, addr + 1);
1279 1282
1280 1283 BSCV_TRACE(ssp, '@', "bscv_get16",
1281 1284 "addr 0x%x.%02x => %04x", addr >> 8, addr & 0xff, retval);
1282 1285 return (retval);
1283 1286 }
1284 1287
1285 1288 static uint32_t
1286 1289 bscv_get32(bscv_soft_state_t *ssp, int chan, bscv_addr_t addr)
1287 1290 {
1288 1291 uint32_t retval;
1289 1292
1290 1293 ASSERT(bscv_held(ssp));
1291 1294
1292 1295 retval = bscv_get8(ssp, chan, addr) << 24;
1293 1296 retval |= bscv_get8(ssp, chan, addr + 1) << 16;
1294 1297 retval |= bscv_get8(ssp, chan, addr + 2) << 8;
1295 1298 retval |= bscv_get8(ssp, chan, addr + 3);
1296 1299
1297 1300 BSCV_TRACE(ssp, '@', "bscv_get32",
1298 1301 "addr 0x%x.%02x => %08x", addr >> 8, addr & 0xff, retval);
1299 1302 return (retval);
1300 1303 }
1301 1304
1302 1305 static void
1303 1306 bscv_setclear8(bscv_soft_state_t *ssp, int chan,
1304 1307 bscv_addr_t addr, uint8_t set, uint8_t clear)
1305 1308 {
1306 1309 uint8_t val;
1307 1310
1308 1311 ASSERT(bscv_held(ssp));
1309 1312 ASSERT(addr < BSC_ADDR_CACHE_LIMIT);
1310 1313
1311 1314 val = ssp->lom_regs[addr] | set;
1312 1315 val &= ~clear;
1313 1316
1314 1317 BSCV_TRACE(ssp, '@', "bscv_setclear8",
1315 1318 "addr 0x%x.%02x, set %02x, clear %02x => %02x",
1316 1319 addr >> 8, addr & 0xff,
1317 1320 set, clear, val);
1318 1321
1319 1322 bscv_put8(ssp, chan, addr, val);
1320 1323 }
1321 1324
1322 1325 static void
1323 1326 bscv_setclear8_volatile(bscv_soft_state_t *ssp, int chan,
1324 1327 bscv_addr_t addr, uint8_t set, uint8_t clear)
1325 1328 {
1326 1329 uint8_t val;
1327 1330 boolean_t needretry;
1328 1331 int num_failures;
1329 1332
1330 1333 ASSERT(bscv_held(ssp));
1331 1334 ASSERT(addr < BSC_ADDR_CACHE_LIMIT);
1332 1335
1333 1336 if (bscv_faulty(ssp)) {
1334 1337 return;
1335 1338 }
1336 1339
1337 1340 BSCV_TRACE(ssp, '@', "bscv_setclear8_volatile",
1338 1341 "addr 0x%x.%02x => set %02x clear %02x",
1339 1342 addr >> 8, addr & 0xff, set, clear);
1340 1343
1341 1344 val = bscv_get8_cached(ssp, addr);
1342 1345 for (num_failures = 0;
1343 1346 num_failures < BSC_FAILURE_RETRY_LIMIT;
1344 1347 num_failures++) {
1345 1348 val |= set;
1346 1349 val &= ~clear;
1347 1350 bscv_put8_once(ssp, chan, addr, val);
1348 1351 if (ssp->command_error == EBUS_ERROR_STALEDATA) {
1349 1352 /* Re-read the stale register from the lom */
1350 1353 val = bscv_get8_once(ssp, chan, addr);
1351 1354 needretry = 1;
1352 1355 } else {
1353 1356 needretry = bscv_should_retry(ssp);
1354 1357 if (!needretry) {
1355 1358 break;
1356 1359 }
1357 1360 }
1358 1361 }
1359 1362 if (ssp->command_error != 0) {
1360 1363 ssp->had_session_error = B_TRUE;
1361 1364 }
1362 1365
1363 1366 if (needretry) {
1364 1367 /* Failure */
1365 1368 cmn_err(CE_WARN, "bscv_setclear8_volatile: addr 0x%x.%02x "
1366 1369 "retried write %d times, giving up",
1367 1370 addr >> 8, addr & 0xff, num_failures);
1368 1371 if (ssp->command_error != EBUS_ERROR_STALEDATA) {
1369 1372 bscv_set_fault(ssp);
1370 1373 }
1371 1374 } else if (num_failures > 0) {
1372 1375 BSCV_TRACE(ssp, 'R', "bscv_setclear8_volatile",
1373 1376 "addr 0x%x.%02x retried write %d times, succeeded",
1374 1377 addr >> 8, addr & 0xff, num_failures);
1375 1378 }
1376 1379 }
1377 1380
1378 1381 static void
1379 1382 bscv_rep_rw8(bscv_soft_state_t *ssp, int chan, uint8_t *host_addr,
1380 1383 bscv_addr_t dev_addr, size_t repcount, uint_t flags,
1381 1384 boolean_t is_write)
1382 1385 {
1383 1386 size_t inc;
1384 1387
1385 1388 ASSERT(bscv_held(ssp));
1386 1389
1387 1390 inc = (flags & DDI_DEV_AUTOINCR) ? 1 : 0;
1388 1391 for (; repcount--; dev_addr += inc) {
1389 1392 if (flags & DDI_DEV_AUTOINCR) {
1390 1393 if (is_write) {
1391 1394 bscv_put8(ssp, chan, dev_addr, *host_addr++);
1392 1395 } else {
1393 1396 *host_addr++ = bscv_get8(ssp, chan, dev_addr);
1394 1397 }
1395 1398 } else {
1396 1399 if (is_write) {
1397 1400 bscv_put8_once(ssp, chan,
1398 1401 dev_addr, *host_addr++);
1399 1402 } else {
1400 1403 *host_addr++ = bscv_get8_once(ssp, chan,
1401 1404 dev_addr);
1402 1405 }
1403 1406 /* We need this because _once routines don't do it */
1404 1407 if (ssp->command_error != 0) {
1405 1408 ssp->had_session_error = B_TRUE;
1406 1409 }
1407 1410 }
1408 1411 if (bscv_faulty(ssp) || bscv_session_error(ssp)) {
1409 1412 /*
1410 1413 * No retry here. If we were AUTOINCR then get/put
1411 1414 * will have retried. For NO_AUTOINCR we cannot retry
1412 1415 * because the data would be corrupted.
1413 1416 */
1414 1417 break;
1415 1418 }
1416 1419 }
1417 1420 }
1418 1421
1419 1422 static uint8_t
1420 1423 bscv_get8_cached(bscv_soft_state_t *ssp, bscv_addr_t addr)
1421 1424 {
1422 1425 ASSERT(addr < BSC_ADDR_CACHE_LIMIT);
1423 1426 /* Can be called with or without the lock held */
1424 1427
1425 1428 return (ssp->lom_regs[addr]);
1426 1429 }
1427 1430
1428 1431 static uint8_t
1429 1432 bscv_get8_locked(bscv_soft_state_t *ssp, int chan, bscv_addr_t addr, int *res)
1430 1433 {
1431 1434 uint8_t retval;
1432 1435
1433 1436 ASSERT(addr < BSC_ADDR_CACHE_LIMIT);
1434 1437 bscv_enter(ssp);
1435 1438 retval = bscv_get8(ssp, chan, addr);
1436 1439 bscv_locked_result(ssp, res);
1437 1440 bscv_exit(ssp);
1438 1441 BSCV_TRACE(ssp, '@', "bscv_get8_locked",
1439 1442 "addr 0x%x.%02x => %02x", addr >> 8, addr & 0xff, retval);
1440 1443 return (retval);
1441 1444 }
1442 1445
1443 1446 static void
1444 1447 bscv_rep_get8_locked(bscv_soft_state_t *ssp, int chan, uint8_t *host_addr,
1445 1448 bscv_addr_t dev_addr, size_t repcount, uint_t flags, int *res)
1446 1449 {
1447 1450 bscv_enter(ssp);
1448 1451 bscv_rep_rw8(ssp, chan, host_addr, dev_addr, repcount,
1449 1452 flags, B_FALSE /* read */);
1450 1453 bscv_locked_result(ssp, res);
1451 1454 bscv_exit(ssp);
1452 1455 }
1453 1456
1454 1457 static boolean_t
1455 1458 bscv_faulty(bscv_soft_state_t *ssp)
1456 1459 {
1457 1460 ASSERT(bscv_held(ssp));
1458 1461 return (ssp->had_fault);
1459 1462 }
1460 1463
1461 1464 static void
1462 1465 bscv_clear_fault(bscv_soft_state_t *ssp)
1463 1466 {
1464 1467 ASSERT(bscv_held(ssp));
1465 1468 BSCV_TRACE(ssp, 'J', "bscv_clear_fault", "clearing fault flag");
1466 1469 ssp->had_fault = B_FALSE;
1467 1470 ssp->had_session_error = B_FALSE;
1468 1471 }
1469 1472
1470 1473 static void
1471 1474 bscv_set_fault(bscv_soft_state_t *ssp)
1472 1475 {
1473 1476 ASSERT(bscv_held(ssp));
1474 1477 BSCV_TRACE(ssp, 'J', "bscv_set_fault", "setting fault flag");
1475 1478 ssp->had_fault = B_TRUE;
1476 1479 }
1477 1480
1478 1481 static boolean_t
1479 1482 bscv_session_error(bscv_soft_state_t *ssp)
1480 1483 {
1481 1484 ASSERT(bscv_held(ssp));
1482 1485 return (ssp->had_session_error);
1483 1486 }
1484 1487
1485 1488 static int
1486 1489 bscv_retcode(bscv_soft_state_t *ssp)
1487 1490 {
1488 1491 BSCV_TRACE(ssp, '@', "bscv_retcode",
1489 1492 "code 0x%x", ssp->command_error);
1490 1493 return (ssp->command_error);
1491 1494 }
1492 1495
1493 1496 static int
1494 1497 bscv_should_retry(bscv_soft_state_t *ssp)
1495 1498 {
1496 1499 if ((ssp->command_error == EBUS_ERROR_DEVICEFAIL) ||
1497 1500 (ssp->command_error >= LOMBUS_ERR_BASE)) {
1498 1501 /* This command is due to an I/O fault - retry might fix */
1499 1502 return (1);
1500 1503 } else {
1501 1504 /*
1502 1505 * The command itself was bad - there is no point in fixing
1503 1506 * Note. Whatever happens we should know that if we were
1504 1507 * doing EBUS_IDX_SELFTEST0..EBUS_IDX_SELFTEST7 and we
1505 1508 * had 0x80 set then this is a test error not a retry
1506 1509 * error.
1507 1510 */
1508 1511 return (0);
1509 1512 }
1510 1513 }
1511 1514
1512 1515 static void
1513 1516 bscv_locked_result(bscv_soft_state_t *ssp, int *res)
1514 1517 {
1515 1518 if (bscv_faulty(ssp) || (bscv_retcode(ssp) != 0)) {
1516 1519 *res = EIO;
1517 1520 }
1518 1521 }
1519 1522
1520 1523 static void
1521 1524 bscv_put8_once(bscv_soft_state_t *ssp, int chan, bscv_addr_t addr, uint8_t val)
1522 1525 {
1523 1526 uint32_t fault;
1524 1527
1525 1528 ASSERT(bscv_held(ssp));
1526 1529
1527 1530 ssp->command_error = 0;
1528 1531
1529 1532 if (bscv_faulty(ssp)) {
1530 1533 /* Bail out things are not working */
1531 1534 return;
1532 1535 } else if (ssp->nchannels == 0) {
1533 1536 /* Didn't manage to map handles so ddi_{get,put}* broken */
1534 1537 BSCV_TRACE(ssp, '@', "bscv_put8_once",
1535 1538 "nchannels is 0x0 so cannot do IO");
1536 1539 return;
1537 1540 }
1538 1541
1539 1542 /* Clear any pending fault */
1540 1543 ddi_put32(ssp->channel[chan].handle,
1541 1544 (uint32_t *)BSC_NEXUS_ADDR(ssp, chan, 0, LOMBUS_FAULT_REG), 0);
1542 1545
1543 1546 /* Do the access and get fault code - may take a long time */
1544 1547 ddi_put8(ssp->channel[chan].handle,
1545 1548 &ssp->channel[chan].regs[addr], val);
1546 1549 fault = ddi_get32(ssp->channel[chan].handle,
1547 1550 (uint32_t *)BSC_NEXUS_ADDR(ssp, chan, 0, LOMBUS_FAULT_REG));
1548 1551
1549 1552 ssp->command_error = fault;
1550 1553
1551 1554 if (fault == 0) {
1552 1555 /* Things were ok - update cache entry */
1553 1556 if (addr < BSC_ADDR_CACHE_LIMIT) {
1554 1557 /* Store cacheable entries */
1555 1558 ssp->lom_regs[addr] = val;
1556 1559 }
1557 1560 } else if (fault >= LOMBUS_ERR_BASE) {
1558 1561 /* lombus problem - do a resync session */
1559 1562 cmn_err(CE_WARN, "!bscv_put8_once: Had comms fault "
1560 1563 "for address 0x%x.%02x - data 0x%x, fault 0x%x",
1561 1564 addr >> 8, addr & 0xff, val, fault);
1562 1565 /* Attempt to resync with the lom */
1563 1566 bscv_resync_comms(ssp, chan);
1564 1567 /*
1565 1568 * Note: we do not set fault status here. That
1566 1569 * is done if our caller decides to give up talking to
1567 1570 * the lom. The observant might notice that this means
1568 1571 * that if we mend things on the last attempt we still
1569 1572 * get the fault set - we just live with that!
1570 1573 */
1571 1574 }
1572 1575
1573 1576 BSCV_TRACE(ssp, '@', "bscv_put8_once",
1574 1577 "addr 0x%x.%02x <= 0x%02x", addr >> 8, addr & 0xff, val);
1575 1578 }
1576 1579
1577 1580 static uint8_t
1578 1581 bscv_get8_once(bscv_soft_state_t *ssp, int chan, bscv_addr_t addr)
1579 1582 {
1580 1583 uint8_t val;
1581 1584 uint32_t fault;
1582 1585
1583 1586 ASSERT(bscv_held(ssp));
1584 1587
1585 1588 ssp->command_error = 0;
1586 1589
1587 1590 if (bscv_faulty(ssp)) {
1588 1591 /* Bail out things are not working */
1589 1592 return (0xff);
1590 1593 } else if (ssp->nchannels == 0) {
1591 1594 /* Didn't manage to map handles so ddi_{get,put}* broken */
1592 1595 BSCV_TRACE(ssp, '@', "bscv_get8_once",
1593 1596 "nchannels is 0x0 so cannot do IO");
1594 1597 return (0xff);
1595 1598 }
1596 1599
1597 1600 /* Clear any pending fault */
1598 1601 ddi_put32(ssp->channel[chan].handle,
1599 1602 (uint32_t *)BSC_NEXUS_ADDR(ssp, chan, 0, LOMBUS_FAULT_REG), 0);
1600 1603
1601 1604 /* Do the access and get fault code - may take a long time */
1602 1605 val = ddi_get8(ssp->channel[chan].handle,
1603 1606 &ssp->channel[chan].regs[addr]);
1604 1607 fault = ddi_get32(ssp->channel[chan].handle,
1605 1608 (uint32_t *)BSC_NEXUS_ADDR(ssp, chan, 0, LOMBUS_FAULT_REG));
1606 1609 ssp->command_error = fault;
1607 1610
1608 1611 if (fault >= LOMBUS_ERR_BASE) {
1609 1612 /* lombus problem - do a resync session */
1610 1613 cmn_err(CE_WARN, "!bscv_get8_once: Had comms fault "
1611 1614 "for address 0x%x.%02x - data 0x%x, fault 0x%x",
1612 1615 addr >> 8, addr & 0xff, val, fault);
1613 1616 /* Attempt to resync with the lom */
1614 1617 bscv_resync_comms(ssp, chan);
1615 1618 /*
1616 1619 * Note: we do not set fault status here. That
1617 1620 * is done if our caller decides to give up talking to
1618 1621 * the lom. The observant might notice that this means
1619 1622 * that if we mend things on the last attempt we still
1620 1623 * get the fault set - we just live with that!
1621 1624 */
1622 1625 }
1623 1626 /*
1624 1627 * FIXME - should report error if you get
1625 1628 * EBUS_ERROR_DEVICEFAIL reported from the BSC. That gets
1626 1629 * logged as a failure in bscv_should_retry and may contribute
1627 1630 * to a permanent failure. Reference issues seen by Mitac.
1628 1631 */
1629 1632
1630 1633 if (!bscv_faulty(ssp)) {
1631 1634 if (addr < BSC_ADDR_CACHE_LIMIT) {
1632 1635 /* Store cacheable entries */
1633 1636 ssp->lom_regs[addr] = val;
1634 1637 }
1635 1638 }
1636 1639
1637 1640 BSCV_TRACE(ssp, '@', "bscv_get8_once",
1638 1641 "addr 0x%x.%02x => 0x%02x", addr >> 8, addr & 0xff, val);
1639 1642 return (val);
1640 1643 }
1641 1644
1642 1645 static uint32_t
1643 1646 bscv_probe(bscv_soft_state_t *ssp, int chan, uint32_t *fault)
1644 1647 {
1645 1648 uint32_t async_reg;
1646 1649
1647 1650 if (ssp->nchannels == 0) {
1648 1651 /*
1649 1652 * Failed to map handles, so cannot do any IO. Set the
1650 1653 * fault indicator and return a dummy value.
1651 1654 */
1652 1655 BSCV_TRACE(ssp, '@', "bscv_probe",
1653 1656 "nchannels is 0x0 so cannot do any IO");
1654 1657 *fault = LOMBUS_ERR_REG_NUM;
1655 1658 return ((~(int8_t)0));
1656 1659 }
1657 1660
1658 1661 /* Clear faults */
1659 1662 ddi_put32(ssp->channel[chan].handle,
1660 1663 (uint32_t *)BSC_NEXUS_ADDR(ssp, chan, 0, LOMBUS_FAULT_REG), 0);
1661 1664 /* Probe and Check faults */
1662 1665 *fault = ddi_get32(ssp->channel[chan].handle,
1663 1666 (uint32_t *)BSC_NEXUS_ADDR(ssp, chan, 0, LOMBUS_PROBE_REG));
1664 1667 /* Read status */
1665 1668 async_reg = ddi_get32(ssp->channel[chan].handle,
1666 1669 (uint32_t *)BSC_NEXUS_ADDR(ssp, chan, 0, LOMBUS_ASYNC_REG));
1667 1670
1668 1671 BSCV_TRACE(ssp, '@', "bscv_probe",
1669 1672 "async status 0x%x, fault 0x%x", async_reg, *fault);
1670 1673 return (async_reg);
1671 1674 }
1672 1675
1673 1676 static void
1674 1677 bscv_resync_comms(bscv_soft_state_t *ssp, int chan)
1675 1678 {
1676 1679 int try;
1677 1680 uint32_t command_error = ssp->command_error;
1678 1681 uint32_t fault = 0;
1679 1682
1680 1683 if (ssp->nchannels == 0) {
1681 1684 /*
1682 1685 * Didn't manage to map handles so ddi_{get,put}* broken.
1683 1686 * Therefore, there is no way to resync comms.
1684 1687 */
1685 1688 BSCV_TRACE(ssp, '@', "bscv_resync_comms",
1686 1689 "nchannels is 0x0 so not possible to resync comms");
1687 1690 return;
1688 1691 }
1689 1692 if (command_error >= LOMBUS_ERR_BASE &&
1690 1693 command_error != LOMBUS_ERR_REG_NUM &&
1691 1694 command_error != LOMBUS_ERR_REG_SIZE &&
1692 1695 command_error != LOMBUS_ERR_TIMEOUT) {
1693 1696 /* Resync here to make sure that the lom is talking */
1694 1697 cmn_err(CE_WARN, "!bscv_resync_comms: "
1695 1698 "Attempting comms resync after comms fault 0x%x",
1696 1699 command_error);
1697 1700 for (try = 1; try <= 8; try++) {
1698 1701 /* Probe */
1699 1702 fault = ddi_get32(ssp->channel[chan].handle,
1700 1703 (uint32_t *)BSC_NEXUS_ADDR(ssp, chan, 0,
1701 1704 LOMBUS_PROBE_REG));
1702 1705
1703 1706 if (fault == 0) {
1704 1707 break;
1705 1708 } else {
1706 1709 cmn_err(CE_WARN, "!bscv_resync_comms: "
1707 1710 "comms resync (probing) - try 0x%x "
1708 1711 "had fault 0x%x", try, fault);
1709 1712 }
1710 1713 }
1711 1714 if (fault != 0) {
1712 1715 cmn_err(CE_WARN, "!bscv_resync_comms: "
1713 1716 "Failed to resync comms - giving up");
1714 1717 ssp->bad_resync++;
1715 1718 } else {
1716 1719 cmn_err(CE_WARN, "!bscv_resync_comms: "
1717 1720 "resync comms after 0x%x tries", try);
1718 1721 ssp->bad_resync = 0;
1719 1722 }
1720 1723 }
1721 1724
1722 1725 }
1723 1726
1724 1727
1725 1728 /*
1726 1729 * LOMLite configuration/event eeprom access routines
1727 1730 *
1728 1731 * bscv_window_setup() - Read/Sanity check the eeprom parameters.
1729 1732 * This must be called prior to calling bscv_eerw().
1730 1733 * bscv_eerw() - Read/write data from/to the eeprom.
1731 1734 */
1732 1735
1733 1736 /*
1734 1737 * function - bscv_window_setup
1735 1738 * description - this routine reads the eeprom parameters and sanity
1736 1739 * checks them to ensure that the lom is talking sense.
1737 1740 * inputs - soft state ptr
1738 1741 * outputs - B_TRUE if the eeprom is ok, B_FALSE if the eeprom is not OK.
1739 1742 */
1740 1743 static boolean_t
1741 1744 bscv_window_setup(bscv_soft_state_t *ssp)
1742 1745 {
1743 1746 ASSERT(bscv_held(ssp));
1744 1747
1745 1748 if (ssp->eeinfo_valid) {
1746 1749 /* Already have good cached values */
1747 1750 return (ssp->eeinfo_valid);
1748 1751 }
1749 1752 ssp->eeprom_size =
1750 1753 bscv_get8(ssp, chan_general, EBUS_IDX_EEPROM_SIZE_KB) * 1024;
1751 1754 ssp->eventlog_start = bscv_get16(ssp, chan_general,
1752 1755 EBUS_IDX_LOG_START_HI);
1753 1756
1754 1757 /*
1755 1758 * The log does not run to the end of the EEPROM because it is a
1756 1759 * logical partition. The last 8K partition is reserved for FRUID
1757 1760 * usage.
1758 1761 */
1759 1762 ssp->eventlog_size = EBUS_LOG_END - ssp->eventlog_start;
1760 1763
1761 1764 BSCV_TRACE(ssp, 'I', "bscv_window_setup", "eeprom size 0x%x log_start"
1762 1765 " 0x%x log_size 0x%x", ssp->eeprom_size, ssp->eventlog_start,
1763 1766 ssp->eventlog_size);
1764 1767
1765 1768 if (bscv_faulty(ssp) || bscv_session_error(ssp)) {
1766 1769 ssp->eeinfo_valid = B_FALSE;
1767 1770 } else if ((ssp->eeprom_size == 0) ||
1768 1771 (ssp->eventlog_start >= ssp->eeprom_size)) {
1769 1772 /* Sanity check values */
1770 1773 cmn_err(CE_WARN,
1771 1774 "!bscv_window_setup: read invalid eeprom parameters");
1772 1775 ssp->eeinfo_valid = B_FALSE;
1773 1776 } else {
1774 1777 ssp->eeinfo_valid = B_TRUE;
1775 1778 }
1776 1779
1777 1780 BSCV_TRACE(ssp, 'I', "bscv_window_setup", "returning eeinfo_valid %s",
1778 1781 ssp->eeinfo_valid ? "true" : "false");
1779 1782 return (ssp->eeinfo_valid);
1780 1783 }
1781 1784
1782 1785 /*
1783 1786 * function - bscv_eerw
1784 1787 * description - this routine reads/write data from/to the eeprom.
1785 1788 * It takes care of setting the window on the eeprom correctly.
1786 1789 * inputs - soft state ptr, eeprom offset, data buffer, size, read/write
1787 1790 * outputs - B_TRUE if the eeprom is ok, B_FALSE if the eeprom is not OK.
1788 1791 */
1789 1792 static int
1790 1793 bscv_eerw(bscv_soft_state_t *ssp, uint32_t eeoffset, uint8_t *buf,
1791 1794 unsigned size, boolean_t is_write)
1792 1795 {
1793 1796 uint32_t blk_addr = eeoffset;
1794 1797 unsigned remaining = size;
1795 1798 uint8_t page_idx;
1796 1799 uint8_t this_page;
1797 1800 uint8_t blk_size;
1798 1801 int res = 0;
1799 1802
1800 1803 while (remaining > 0) {
1801 1804 page_idx = blk_addr & 0xff;
1802 1805 if ((page_idx + remaining) > 0x100) {
1803 1806 blk_size = 0x100 - page_idx;
1804 1807 } else {
1805 1808 blk_size = remaining;
1806 1809 }
1807 1810
1808 1811 /* Select correct eeprom page */
1809 1812 this_page = blk_addr >> 8;
1810 1813 bscv_put8(ssp, chan_eeprom, EBUS_IDX_EEPROM_PAGESEL, this_page);
1811 1814
1812 1815 BSCV_TRACE(ssp, 'M', "lom_eerw",
1813 1816 "%s data @0x%x.%02x, size 0x%x, 0x%x bytes remaining",
1814 1817 is_write ? "writing" : "reading",
1815 1818 this_page, page_idx, blk_size, remaining - blk_size);
1816 1819
1817 1820 bscv_rep_rw8(ssp, chan_eeprom,
1818 1821 buf, BSCVA(EBUS_CMD_SPACE_EEPROM, page_idx),
1819 1822 blk_size, DDI_DEV_AUTOINCR, is_write);
1820 1823
1821 1824 if (bscv_faulty(ssp) || bscv_session_error(ssp)) {
1822 1825 res = EIO;
1823 1826 break;
1824 1827 }
1825 1828
1826 1829 remaining -= blk_size;
1827 1830 blk_addr += blk_size;
1828 1831 buf += blk_size;
1829 1832 }
1830 1833
1831 1834 return (res);
1832 1835 }
1833 1836
1834 1837 static boolean_t
1835 1838 bscv_is_null_event(bscv_soft_state_t *ssp, lom_event_t *e)
1836 1839 {
1837 1840 ASSERT(e != NULL);
1838 1841
1839 1842 if (EVENT_DECODE_SUBSYS(e->ev_subsys) == EVENT_SUBSYS_NONE &&
1840 1843 e->ev_event == EVENT_NONE) {
1841 1844 /*
1842 1845 * This marks a NULL event.
1843 1846 */
1844 1847 BSCV_TRACE(ssp, 'E', "bscv_is_null_event",
1845 1848 "EVENT_SUBSYS_NONE/EVENT_NONE null event");
1846 1849 return (B_TRUE);
1847 1850 } else if (e->ev_subsys == 0xff && e->ev_event == 0xff) {
1848 1851 /*
1849 1852 * Under some circumstances, we've seen all 1s to represent
1850 1853 * a manually cleared event log at the BSC prompt. Only
1851 1854 * a test/diagnosis environment is likely to show this.
1852 1855 */
1853 1856 BSCV_TRACE(ssp, 'E', "bscv_is_null_event", "0xffff null event");
1854 1857 return (B_TRUE);
1855 1858 } else {
1856 1859 /*
1857 1860 * Not a NULL event.
1858 1861 */
1859 1862 BSCV_TRACE(ssp, 'E', "bscv_is_null_event", "returning False");
1860 1863 return (B_FALSE);
1861 1864 }
1862 1865 }
1863 1866
1864 1867 /*
1865 1868 * *********************************************************************
1866 1869 * IOCTL Processing
1867 1870 * *********************************************************************
1868 1871 */
1869 1872
1870 1873 /*
1871 1874 * function - bscv_ioctl
1872 1875 * description - routine that acts as a high level manager for ioctls. It
1873 1876 * calls the appropriate handler for ioctls on the alarm:mon and
1874 1877 * alarm:ctl minor nodes respectively
1875 1878 *
1876 1879 * Unsupported ioctls (now deprecated)
1877 1880 * LOMIOCALCTL
1878 1881 * LOMIOCALSTATE
1879 1882 * LOMIOCCLEARLOG
1880 1883 * LOMIOCCTL
1881 1884 * LOMIOCCTL2
1882 1885 * LOMIOCDAEMON
1883 1886 * LOMIOCDMON
1884 1887 * LOMIOCDOGCTL, TSIOCDOGCTL
1885 1888 * LOMIOCDOGPAT, TSIOCDOGPAT
1886 1889 * LOMIOCDOGTIME, TSIOCDOGTIME
1887 1890 * LOMIOCEVENTLOG
1888 1891 * LOMIOCEVNT
1889 1892 * LOMIOCGETMASK
1890 1893 * LOMIOCMPROG
1891 1894 * LOMIOCNBMON, TSIOCNBMON
1892 1895 * LOMIOCSLEEP
1893 1896 * LOMIOCUNLOCK, TSIOCUNLOCK
1894 1897 * LOMIOCWTMON, TSIOCWTMON
1895 1898 *
1896 1899 * Supported ioctls
1897 1900 * LOMIOCDOGSTATE, TSIOCDOGSTATE
1898 1901 * LOMIOCPROG
1899 1902 * LOMIOCPSUSTATE
1900 1903 * LOMIOCFANSTATE
1901 1904 * LOMIOCFLEDSTATE
1902 1905 * LOMIOCINFO
1903 1906 * LOMIOCMREAD
1904 1907 * LOMIOCVOLTS
1905 1908 * LOMIOCSTATS
1906 1909 * LOMIOCTEMP
1907 1910 * LOMIOCCONS
1908 1911 * LOMIOCEVENTLOG2
1909 1912 * LOMIOCINFO2
1910 1913 * LOMIOCTEST
1911 1914 * LOMIOCMPROG2
1912 1915 * LOMIOCMREAD2
1913 1916 *
1914 1917 * inputs - device number, command, user space arg, filemode, user
1915 1918 * credentials, return value
1916 1919 * outputs - the return value propagated back by the lower level routines.
1917 1920 */
1918 1921
1919 1922 /*ARGSUSED*/
1920 1923 static int
1921 1924 bscv_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *cred, int *rvalp)
1922 1925 {
1923 1926 bscv_soft_state_t *ssp;
1924 1927 int instance;
1925 1928 int res = 0;
1926 1929
1927 1930 instance = DEVICETOINSTANCE(dev);
1928 1931 ssp = ddi_get_soft_state(bscv_statep, instance);
1929 1932 if (ssp == NULL) {
1930 1933 return (ENXIO);
1931 1934 }
1932 1935
1933 1936 /*
1934 1937 * The Combined Switch and Service Processor takes care of configuration
1935 1938 * and control. The CSSP tells the BSC chip about it; therefore the
1936 1939 * bscv driver doesn't send such configuration and control to the BSC.
1937 1940 * Additionally Watchdog configuration is no longer done from userland
1938 1941 * lom.
1939 1942 */
1940 1943 switch (cmd) {
1941 1944 case LOMIOCALCTL:
1942 1945 case LOMIOCALSTATE:
1943 1946 case LOMIOCCLEARLOG:
1944 1947 case LOMIOCCTL:
1945 1948 case LOMIOCCTL2:
1946 1949 case LOMIOCDAEMON:
1947 1950 case LOMIOCDMON:
1948 1951 case LOMIOCDOGCTL:
1949 1952 case LOMIOCDOGPAT:
1950 1953 case LOMIOCDOGTIME:
1951 1954 case LOMIOCEVENTLOG:
1952 1955 case LOMIOCEVNT:
1953 1956 case LOMIOCGETMASK:
1954 1957 case LOMIOCMPROG:
1955 1958 case LOMIOCNBMON:
1956 1959 case LOMIOCSLEEP:
1957 1960 case LOMIOCUNLOCK:
1958 1961 case LOMIOCWTMON:
1959 1962 return (ENOTSUP);
1960 1963 }
1961 1964
1962 1965 /*
1963 1966 * set the default result.
1964 1967 */
1965 1968
1966 1969 *rvalp = 0;
1967 1970
1968 1971 if (ssp->cssp_prog) {
1969 1972 return (ENXIO);
1970 1973 } else if ((ssp->prog_mode_only || ssp->programming) &&
1971 1974 cmd != LOMIOCPROG) {
1972 1975 return (ENXIO);
1973 1976 }
1974 1977
1975 1978 /*
1976 1979 * Check that the caller has appropriate access permissions
1977 1980 * (FWRITE set in mode) for those ioctls which change lom
1978 1981 * state
1979 1982 */
1980 1983 if (!(mode & FWRITE)) {
1981 1984 switch (cmd) {
1982 1985 case LOMIOCMPROG2:
1983 1986 case LOMIOCMREAD2:
1984 1987 case LOMIOCPROG:
1985 1988 case LOMIOCTEST:
1986 1989 return (EACCES);
1987 1990 /* NOTREACHED */
1988 1991 default:
1989 1992 /* Does not require write access */
1990 1993 break;
1991 1994 }
1992 1995 }
1993 1996
1994 1997 switch (cmd) {
1995 1998
1996 1999 case LOMIOCDOGSTATE:
1997 2000 res = bscv_ioc_dogstate(ssp, arg, mode);
1998 2001 break;
1999 2002
2000 2003 case LOMIOCPROG:
2001 2004 res = bscv_prog(ssp, arg, mode);
2002 2005 break;
2003 2006
2004 2007 case LOMIOCPSUSTATE:
2005 2008 res = bscv_ioc_psustate(ssp, arg, mode);
2006 2009 break;
2007 2010
2008 2011 case LOMIOCFANSTATE:
2009 2012 res = bscv_ioc_fanstate(ssp, arg, mode);
2010 2013 break;
2011 2014
2012 2015 case LOMIOCFLEDSTATE:
2013 2016 res = bscv_ioc_fledstate(ssp, arg, mode);
2014 2017 break;
2015 2018
2016 2019 case LOMIOCLEDSTATE:
2017 2020 res = bscv_ioc_ledstate(ssp, arg, mode);
2018 2021 break;
2019 2022
2020 2023 case LOMIOCINFO:
2021 2024 res = bscv_ioc_info(ssp, arg, mode);
2022 2025 break;
2023 2026
2024 2027 case LOMIOCMREAD:
2025 2028 res = bscv_ioc_mread(ssp, arg, mode);
2026 2029 break;
2027 2030
2028 2031 case LOMIOCVOLTS:
2029 2032 res = bscv_ioc_volts(ssp, arg, mode);
2030 2033 break;
2031 2034
2032 2035 case LOMIOCSTATS:
2033 2036 res = bscv_ioc_stats(ssp, arg, mode);
2034 2037 break;
2035 2038
2036 2039 case LOMIOCTEMP:
2037 2040 res = bscv_ioc_temp(ssp, arg, mode);
2038 2041 break;
2039 2042
2040 2043 case LOMIOCCONS:
2041 2044 res = bscv_ioc_cons(ssp, arg, mode);
2042 2045 break;
2043 2046
2044 2047 case LOMIOCEVENTLOG2:
2045 2048 res = bscv_ioc_eventlog2(ssp, arg, mode);
2046 2049 break;
2047 2050
2048 2051 case LOMIOCINFO2:
2049 2052 res = bscv_ioc_info2(ssp, arg, mode);
2050 2053 break;
2051 2054
2052 2055 case LOMIOCTEST:
2053 2056 res = bscv_ioc_test(ssp, arg, mode);
2054 2057 break;
2055 2058
2056 2059 case LOMIOCMPROG2:
2057 2060 res = bscv_ioc_mprog2(ssp, arg, mode);
2058 2061 break;
2059 2062
2060 2063 case LOMIOCMREAD2:
2061 2064 res = bscv_ioc_mread2(ssp, arg, mode);
2062 2065 break;
2063 2066
2064 2067 default:
2065 2068 BSCV_TRACE(ssp, 'I', "bscv_ioctl", "Invalid IOCTL 0x%x", cmd);
2066 2069 res = EINVAL;
2067 2070 }
2068 2071 return (res);
2069 2072 }
2070 2073
2071 2074 /*
2072 2075 * LOMIOCDOGSTATE
2073 2076 * TSIOCDOGSTATE - indicate whether the alarm watchdog and reset
2074 2077 * circuitry is enabled or not.
2075 2078 */
2076 2079 static int
2077 2080 bscv_ioc_dogstate(bscv_soft_state_t *ssp, intptr_t arg, int mode)
2078 2081 {
2079 2082 lom_dogstate_t dogstate;
2080 2083 uint8_t dogval;
2081 2084 int res = 0;
2082 2085
2083 2086 dogval = bscv_get8_locked(ssp, chan_general, EBUS_IDX_WDOG_CTRL, &res);
2084 2087 dogstate.dog_enable = (dogval & EBUS_WDOG_ENABLE) ? 1 : 0;
2085 2088 dogstate.reset_enable = (dogval & EBUS_WDOG_RST) ? 1 : 0;
2086 2089 dogstate.dog_timeout = bscv_get8_locked(ssp, chan_general,
2087 2090 EBUS_IDX_WDOG_TIME, &res);
2088 2091
2089 2092 if ((res == 0) &&
2090 2093 (ddi_copyout((caddr_t)&dogstate,
2091 2094 (caddr_t)arg, sizeof (dogstate), mode) < 0)) {
2092 2095 res = EFAULT;
2093 2096 }
2094 2097 return (res);
2095 2098 }
2096 2099
2097 2100 /*
2098 2101 * LOMIOCPSUSTATE - returns full information for 4 PSUs. All this
2099 2102 * information is available from two bytes of LOMlite RAM, but if
2100 2103 * on the first read it is noticed that two or more of the PSUs are
2101 2104 * not present only 1 byte will be read subsequently.
2102 2105 */
2103 2106 static int
2104 2107 bscv_ioc_psustate(bscv_soft_state_t *ssp, intptr_t arg, int mode)
2105 2108 {
2106 2109 lom_psudata_t psudata;
2107 2110 uint8_t psustat;
2108 2111 int i;
2109 2112 int res = 0;
2110 2113
2111 2114 for (i = 0; i < MAX_PSUS; i++) {
2112 2115 psustat = bscv_get8_locked(ssp, chan_general,
2113 2116 EBUS_IDX_PSU1_STAT + i, &res);
2114 2117 psudata.fitted[i] = psustat & EBUS_PSU_PRESENT;
2115 2118 psudata.output[i] = psustat & EBUS_PSU_OUTPUT;
2116 2119 psudata.supplyb[i] = psustat & EBUS_PSU_INPUTB;
2117 2120 psudata.supplya[i] = psustat & EBUS_PSU_INPUTA;
2118 2121 psudata.standby[i] = psustat & EBUS_PSU_STANDBY;
2119 2122 }
2120 2123
2121 2124 if (ddi_copyout((caddr_t)&psudata, (caddr_t)arg, sizeof (psudata),
2122 2125 mode) < 0) {
2123 2126 res = EFAULT;
2124 2127 }
2125 2128 return (res);
2126 2129 }
2127 2130
2128 2131 /*
2129 2132 * LOMIOCFANSTATE - returns full information including speed for 4
2130 2133 * fans and the minimum and maximum operating speeds for each fan as
2131 2134 * stored in the READ ONLY EEPROM data. As this EEPROM data is set
2132 2135 * at manufacture time, this data should only be read by the driver
2133 2136 * once and stored locally.
2134 2137 */
2135 2138 static int
2136 2139 bscv_ioc_fanstate(bscv_soft_state_t *ssp, intptr_t arg, int mode)
2137 2140 {
2138 2141 lom_fandata_t fandata;
2139 2142 int numfans;
2140 2143 int i;
2141 2144 int res = 0;
2142 2145
2143 2146 bzero(&fandata, sizeof (lom_fandata_t));
2144 2147 numfans = EBUS_CONFIG_NFAN_DEC(bscv_get8_locked(ssp,
2145 2148 chan_general, EBUS_IDX_CONFIG, &res));
2146 2149 for (i = 0; (i < numfans) && (res == 0); i++) {
2147 2150 if (ssp->fanspeed[i] != LOM_FAN_NOT_PRESENT) {
2148 2151 fandata.fitted[i] = 1;
2149 2152 fandata.speed[i] = ssp->fanspeed[i];
2150 2153 fandata.minspeed[i] = bscv_get8_cached(ssp,
2151 2154 EBUS_IDX_FAN1_LOW + i);
2152 2155 }
2153 2156 }
2154 2157
2155 2158 if ((res == 0) &&
2156 2159 (ddi_copyout((caddr_t)&fandata, (caddr_t)arg, sizeof (fandata),
2157 2160 mode) < 0)) {
2158 2161 res = EFAULT;
2159 2162 }
2160 2163 return (res);
2161 2164 }
2162 2165
2163 2166 /*
2164 2167 * LOMIOCFLEDSTATE - returns the state of the fault LED
2165 2168 */
2166 2169 static int
2167 2170 bscv_ioc_fledstate(bscv_soft_state_t *ssp, intptr_t arg, int mode)
2168 2171 {
2169 2172 lom_fled_info_t fled_info;
2170 2173 uint8_t fledstate;
2171 2174 int res = 0;
2172 2175
2173 2176 fledstate = bscv_get8_locked(ssp, chan_general, EBUS_IDX_ALARM, &res);
2174 2177
2175 2178 /* Decode of 0x0F is off and 0x00-0x07 is on. */
2176 2179 if (EBUS_ALARM_LED_DEC(fledstate) == 0x0F) {
2177 2180 fled_info.on = 0;
2178 2181 } else {
2179 2182 /* has +1 here - not 2 as in the info ioctl */
2180 2183 fled_info.on = EBUS_ALARM_LED_DEC(fledstate) + 1;
2181 2184 }
2182 2185 if ((res == 0) &&
2183 2186 (ddi_copyout((caddr_t)&fled_info, (caddr_t)arg,
2184 2187 sizeof (fled_info), mode) < 0)) {
2185 2188 res = EFAULT;
2186 2189 }
2187 2190 return (res);
2188 2191 }
2189 2192
2190 2193 /*
2191 2194 * LOMIOCLEDSTATE - returns the state of the requested LED
2192 2195 */
2193 2196 static int
2194 2197 bscv_ioc_ledstate(bscv_soft_state_t *ssp, intptr_t arg, int mode)
2195 2198 {
2196 2199 lom_led_state_t led_state;
2197 2200 int fw_led_state;
2198 2201 int res = 0;
2199 2202
2200 2203 /* copy in arguments supplied */
2201 2204 if (ddi_copyin((caddr_t)arg, (caddr_t)&led_state,
2202 2205 sizeof (lom_led_state_t), mode) < 0) {
2203 2206 return (EFAULT);
2204 2207 }
2205 2208
2206 2209 /*
2207 2210 * check if led index is -1, if so set it to max value for
2208 2211 * this implementation.
2209 2212 */
2210 2213 if (led_state.index == -1) {
2211 2214 led_state.index = MAX_LED_ID;
2212 2215 }
2213 2216
2214 2217 /* is the index in a valid range */
2215 2218 if ((led_state.index > MAX_LED_ID) || (led_state.index < 0)) {
2216 2219 led_state.state = LOM_LED_OUTOFRANGE;
2217 2220 } else {
2218 2221 /* read the relevant led info */
2219 2222 fw_led_state = bscv_get8_locked(ssp, chan_general,
2220 2223 EBUS_IDX_LED1_STATUS + led_state.index, &res);
2221 2224
2222 2225 /* set the state values accordingly */
2223 2226 switch (fw_led_state) {
2224 2227 case LOM_LED_STATE_OFF:
2225 2228 led_state.state = LOM_LED_OFF;
2226 2229 led_state.colour = LOM_LED_COLOUR_ANY;
2227 2230 break;
2228 2231 case LOM_LED_STATE_ON_STEADY:
2229 2232 led_state.state = LOM_LED_ON;
2230 2233 led_state.colour = LOM_LED_COLOUR_ANY;
2231 2234 break;
2232 2235 case LOM_LED_STATE_ON_FLASHING:
2233 2236 case LOM_LED_STATE_ON_SLOWFLASH:
2234 2237 led_state.state = LOM_LED_BLINKING;
2235 2238 led_state.colour = LOM_LED_COLOUR_ANY;
2236 2239 break;
2237 2240 case LOM_LED_STATE_NOT_PRESENT:
2238 2241 led_state.state = LOM_LED_NOT_IMPLEMENTED;
2239 2242 led_state.colour = LOM_LED_COLOUR_NONE;
2240 2243 break;
2241 2244 case LOM_LED_STATE_INACCESSIBLE:
2242 2245 case LOM_LED_STATE_STANDBY:
2243 2246 default:
2244 2247 led_state.state = LOM_LED_ACCESS_ERROR;
2245 2248 led_state.colour = LOM_LED_COLOUR_NONE;
2246 2249 break;
2247 2250 }
2248 2251
2249 2252 /* set the label info */
2250 2253 (void) strcpy(led_state.label,
2251 2254 ssp->led_names[led_state.index]);
2252 2255 }
2253 2256
2254 2257 /* copy out lom_state */
2255 2258 if ((res == 0) &&
2256 2259 (ddi_copyout((caddr_t)&led_state, (caddr_t)arg,
2257 2260 sizeof (lom_led_state_t), mode) < 0)) {
2258 2261 res = EFAULT;
2259 2262 }
2260 2263 return (res);
2261 2264 }
2262 2265
2263 2266 /*
2264 2267 * LOMIOCINFO - returns with a structure containing any information
2265 2268 * stored on the LOMlite which a user should not need to access but
2266 2269 * may be useful for diagnostic problems. The structure contains: the
2267 2270 * serial escape character, alarm3 mode, version and checksum read from
2268 2271 * RAM and the Product revision and ID read from EEPROM.
2269 2272 */
2270 2273 static int
2271 2274 bscv_ioc_info(bscv_soft_state_t *ssp, intptr_t arg, int mode)
2272 2275 {
2273 2276 lom_info_t info;
2274 2277 int i;
2275 2278 uint16_t csum;
2276 2279 int res = 0;
2277 2280
2278 2281 info.ser_char = bscv_get8_locked(ssp, chan_general, EBUS_IDX_ESCAPE,
2279 2282 &res);
2280 2283 info.a3mode = WATCHDOG;
2281 2284 info.fver = bscv_get8_locked(ssp, chan_general, EBUS_IDX_FW_REV, &res);
2282 2285 csum = bscv_get8_locked(ssp, chan_general, EBUS_IDX_CHECK_HI, &res)
2283 2286 << 8;
2284 2287 csum |= bscv_get8_locked(ssp, chan_general, EBUS_IDX_CHECK_LO, &res);
2285 2288 info.fchksum = csum;
2286 2289 info.prod_rev = bscv_get8_locked(ssp, chan_general, EBUS_IDX_MODEL_REV,
2287 2290 &res);
2288 2291 for (i = 0; i < sizeof (info.prod_id); i++) {
2289 2292 info.prod_id[i] = bscv_get8_locked(ssp,
2290 2293 chan_general, EBUS_IDX_MODEL_ID1 + i, &res);
2291 2294 }
2292 2295 if (bscv_get8_locked(ssp, chan_general, EBUS_IDX_ALARM, &res) &
2293 2296 EBUS_ALARM_NOEVENTS) {
2294 2297 info.events = OFF;
2295 2298 } else {
2296 2299 info.events = ON;
2297 2300 }
2298 2301
2299 2302 if ((res == 0) &&
2300 2303 (ddi_copyout((caddr_t)&info, (caddr_t)arg, sizeof (info),
2301 2304 mode) < 0)) {
2302 2305 res = EFAULT;
2303 2306 }
2304 2307 return (res);
2305 2308 }
2306 2309
2307 2310 /*
2308 2311 * LOMIOCMREAD - used to query the LOMlite configuration parameters
2309 2312 */
2310 2313 static int
2311 2314 bscv_ioc_mread(bscv_soft_state_t *ssp, intptr_t arg, int mode)
2312 2315 {
2313 2316 lom_mprog_t mprog;
2314 2317 int i;
2315 2318 int fanz;
2316 2319 int res = 0;
2317 2320
2318 2321 for (i = 0; i < sizeof (mprog.mod_id); i++) {
2319 2322 mprog.mod_id[i] = bscv_get8_locked(ssp, chan_general,
2320 2323 EBUS_IDX_MODEL_ID1 + i, &res);
2321 2324 }
2322 2325 mprog.mod_rev = bscv_get8_locked(ssp, chan_general, EBUS_IDX_MODEL_REV,
2323 2326 &res);
2324 2327 mprog.config = bscv_get8_locked(ssp, chan_general, EBUS_IDX_CONFIG,
2325 2328 &res);
2326 2329
2327 2330 /* Read the fan calibration values */
2328 2331 fanz = sizeof (mprog.fanhz) / sizeof (mprog.fanhz[0]);
2329 2332 for (i = 0; i < fanz; i++) {
2330 2333 mprog.fanhz[i] = bscv_get8_cached(ssp,
2331 2334 EBUS_IDX_FAN1_CAL + i);
2332 2335 mprog.fanmin[i] = bscv_get8_cached(ssp,
2333 2336 EBUS_IDX_FAN1_LOW + i);
2334 2337 }
2335 2338
2336 2339 if ((res == 0) &&
2337 2340 (ddi_copyout((caddr_t)&mprog, (caddr_t)arg, sizeof (mprog),
2338 2341 mode) < 0)) {
2339 2342 res = EFAULT;
2340 2343 }
2341 2344 return (res);
2342 2345 }
2343 2346
2344 2347 /*
2345 2348 * LOMIOCVOLTS
2346 2349 */
2347 2350 static int
2348 2351 bscv_ioc_volts(bscv_soft_state_t *ssp, intptr_t arg, int mode)
2349 2352 {
2350 2353 int i;
2351 2354 uint16_t supply;
2352 2355 int res = 0;
2353 2356
2354 2357 supply = (bscv_get8_locked(ssp, chan_general, EBUS_IDX_SUPPLY_HI, &res)
2355 2358 << 8) | bscv_get8_locked(ssp, chan_general, EBUS_IDX_SUPPLY_LO,
2356 2359 &res);
2357 2360
2358 2361 for (i = 0; i < ssp->volts.num; i++) {
2359 2362 ssp->volts.status[i] = (supply >> i) & 1;
2360 2363 }
2361 2364
2362 2365 if ((res == 0) &&
2363 2366 (ddi_copyout((caddr_t)&ssp->volts, (caddr_t)arg,
2364 2367 sizeof (ssp->volts), mode) < 0)) {
2365 2368 res = EFAULT;
2366 2369 }
2367 2370 return (res);
2368 2371 }
2369 2372
2370 2373 /*
2371 2374 * LOMIOCSTATS
2372 2375 */
2373 2376 static int
2374 2377 bscv_ioc_stats(bscv_soft_state_t *ssp, intptr_t arg, int mode)
2375 2378 {
2376 2379 int i;
2377 2380 uint8_t status;
2378 2381 int res = 0;
2379 2382
2380 2383 status = bscv_get8_locked(ssp, chan_general, EBUS_IDX_CBREAK_STATUS,
2381 2384 &res);
2382 2385 for (i = 0; i < ssp->sflags.num; i++) {
2383 2386 ssp->sflags.status[i] = (int)((status >> i) & 1);
2384 2387 }
2385 2388
2386 2389 if ((res == 0) &&
2387 2390 (ddi_copyout((caddr_t)&ssp->sflags, (caddr_t)arg,
2388 2391 sizeof (ssp->sflags), mode) < 0)) {
2389 2392 res = EFAULT;
2390 2393 }
2391 2394 return (res);
2392 2395 }
2393 2396
2394 2397 /*
2395 2398 * LOMIOCTEMP
2396 2399 */
2397 2400 static int
2398 2401 bscv_ioc_temp(bscv_soft_state_t *ssp, intptr_t arg, int mode)
2399 2402 {
2400 2403 int i;
2401 2404 int idx;
2402 2405 uint8_t status_ov;
2403 2406 lom_temp_t temps;
2404 2407 int res = 0;
2405 2408
2406 2409 bzero(&temps, sizeof (temps));
2407 2410 idx = 0;
2408 2411 for (i = 0; i < ssp->temps.num; i++) {
2409 2412 if (ssp->temps.temp[i] != LOM_TEMP_STATE_NOT_PRESENT) {
2410 2413 temps.temp[idx] = ssp->temps.temp[i];
2411 2414 bcopy(ssp->temps.name[i], temps.name[idx],
2412 2415 sizeof (temps.name[idx]));
2413 2416 temps.warning[idx] = ssp->temps.warning[i];
2414 2417 temps.shutdown[idx] = ssp->temps.shutdown[i];
2415 2418 idx++;
2416 2419 }
2417 2420 }
2418 2421 temps.num = idx;
2419 2422
2420 2423 bcopy(ssp->temps.name_ov, temps.name_ov, sizeof (temps.name_ov));
2421 2424 temps.num_ov = ssp->temps.num_ov;
2422 2425 status_ov = bscv_get8_locked(ssp, chan_general, EBUS_IDX_OTEMP_STATUS,
2423 2426 &res);
2424 2427 for (i = 0; i < ssp->temps.num_ov; i++) {
2425 2428 ssp->temps.status_ov[i] = (status_ov >> i) & 1;
2426 2429 }
2427 2430
2428 2431 if ((res == 0) &&
2429 2432 (ddi_copyout((caddr_t)&temps, (caddr_t)arg, sizeof (temps),
2430 2433 mode) < 0)) {
2431 2434 res = EFAULT;
2432 2435 }
2433 2436 return (res);
2434 2437 }
2435 2438
2436 2439 /*
2437 2440 * LOMIOCCONS
2438 2441 */
2439 2442 static int
2440 2443 bscv_ioc_cons(bscv_soft_state_t *ssp, intptr_t arg, int mode)
2441 2444 {
2442 2445 lom_cbuf_t cbuf;
2443 2446 int datasize;
2444 2447 int res = 0;
2445 2448
2446 2449 bzero(&cbuf, sizeof (cbuf));
2447 2450 datasize = EBUS_IDX1_CONS_BUF_END - EBUS_IDX1_CONS_BUF_START + 1;
2448 2451 /* Ensure that we do not overfill cbuf and that it is NUL terminated */
2449 2452 if (datasize > (sizeof (cbuf) - 1)) {
2450 2453 datasize = sizeof (cbuf) - 1;
2451 2454 }
2452 2455 bscv_rep_get8_locked(ssp, chan_general, (uint8_t *)cbuf.lrbuf,
2453 2456 BSCVA(EBUS_CMD_SPACE1, (EBUS_IDX1_CONS_BUF_END - datasize + 1)),
2454 2457 datasize, DDI_DEV_AUTOINCR, &res);
2455 2458 /* This is always within the array due to the checks above */
2456 2459 cbuf.lrbuf[datasize] = '\0';
2457 2460
2458 2461 if ((res == 0) &&
2459 2462 (ddi_copyout((caddr_t)&cbuf, (caddr_t)arg, sizeof (cbuf),
2460 2463 mode) < 0)) {
2461 2464 res = EFAULT;
2462 2465 }
2463 2466 return (res);
2464 2467 }
2465 2468
2466 2469 /*
2467 2470 * LOMIOCEVENTLOG2
2468 2471 */
2469 2472 static int
2470 2473 bscv_ioc_eventlog2(bscv_soft_state_t *ssp, intptr_t arg, int mode)
2471 2474 {
2472 2475 lom_eventlog2_t *eventlog2;
2473 2476 int events_recorded;
2474 2477 int level;
2475 2478 uint16_t next_offset;
2476 2479 lom_event_t event;
2477 2480 int res = 0;
2478 2481
2479 2482 eventlog2 = (lom_eventlog2_t *)kmem_zalloc(sizeof (*eventlog2),
2480 2483 KM_SLEEP);
2481 2484
2482 2485 /*
2483 2486 * First get number of events and level requested.
2484 2487 */
2485 2488
2486 2489 if (ddi_copyin((caddr_t)arg, (caddr_t)eventlog2,
2487 2490 sizeof (lom_eventlog2_t), mode) < 0) {
2488 2491 kmem_free((void *)eventlog2, sizeof (*eventlog2));
2489 2492 return (EFAULT);
2490 2493 }
2491 2494
2492 2495 bscv_enter(ssp);
2493 2496
2494 2497 /*
2495 2498 * OK we have full private access to the LOM now so loop
2496 2499 * over the eventlog addr spaces until we get the required
2497 2500 * number of events.
2498 2501 */
2499 2502
2500 2503 if (!bscv_window_setup(ssp)) {
2501 2504 res = EIO;
2502 2505 bscv_exit(ssp);
2503 2506 kmem_free((void *)eventlog2, sizeof (*eventlog2));
2504 2507 return (res);
2505 2508 }
2506 2509
2507 2510 /*
2508 2511 * Read count, next event ptr MSB,LSB. Note a read of count
2509 2512 * is necessary to latch values for the next event ptr
2510 2513 */
2511 2514 (void) bscv_get8(ssp, chan_general, EBUS_IDX_UNREAD_EVENTS);
2512 2515 next_offset = bscv_get16(ssp, chan_general, EBUS_IDX_LOG_PTR_HI);
2513 2516 BSCV_TRACE(ssp, 'I', "bscv_ioc_eventlog2", "log_ptr_hi 0x%x",
2514 2517 next_offset);
2515 2518
2516 2519 events_recorded = 0;
2517 2520
2518 2521 while (events_recorded < eventlog2->num) {
2519 2522 /*
2520 2523 * Working backwards - read an event at a time.
2521 2524 * next_offset is one event on from where we want to be!
2522 2525 * Decrement next_offset and maybe wrap to the end of the
2523 2526 * buffer.
2524 2527 * Note the unsigned arithmetic, so check values first!
2525 2528 */
2526 2529 if (next_offset <= ssp->eventlog_start) {
2527 2530 /* Wrap to the end of the buffer */
2528 2531 next_offset = ssp->eventlog_start + ssp->eventlog_size;
2529 2532 BSCV_TRACE(ssp, 'I', "bscv_ioc_eventlog2", "wrapping"
2530 2533 " around to end of buffer; next_offset 0x%x",
2531 2534 next_offset);
2532 2535 }
2533 2536 next_offset -= sizeof (event);
2534 2537
2535 2538 if (bscv_eerw(ssp, next_offset, (uint8_t *)&event,
2536 2539 sizeof (event), B_FALSE /* read */) != 0) {
2537 2540 /* Fault reading data - stop */
2538 2541 BSCV_TRACE(ssp, 'I', "bscv_ioc_eventlog2", "read"
2539 2542 " failure for offset 0x%x", next_offset);
2540 2543 res = EIO;
2541 2544 break;
2542 2545 }
2543 2546
2544 2547 if (bscv_is_null_event(ssp, &event)) {
2545 2548 /*
2546 2549 * No more events in this log so give up.
2547 2550 */
2548 2551 BSCV_TRACE(ssp, 'I', "bscv_ioc_eventlog2", "no more"
2549 2552 " events left at offset 0x%x", next_offset);
2550 2553 break;
2551 2554 }
2552 2555
2553 2556 /*
2554 2557 * Are we interested in this event
2555 2558 */
2556 2559
2557 2560 level = bscv_level_of_event(&event);
2558 2561 if (level <= eventlog2->level) {
2559 2562 /* Arggh why the funny byte ordering 3, 2, 0, 1 */
2560 2563 eventlog2->code[events_recorded] =
2561 2564 ((unsigned)event.ev_event |
2562 2565 ((unsigned)event.ev_subsys << 8) |
2563 2566 ((unsigned)event.ev_resource << 16) |
2564 2567 ((unsigned)event.ev_detail << 24));
2565 2568
2566 2569 eventlog2->time[events_recorded] =
2567 2570 ((unsigned)event.ev_data[0] |
2568 2571 ((unsigned)event.ev_data[1] << 8) |
2569 2572 ((unsigned)event.ev_data[3] << 16) |
2570 2573 ((unsigned)event.ev_data[2] << 24));
2571 2574
2572 2575 bscv_build_eventstring(ssp,
2573 2576 &event, eventlog2->string[events_recorded],
2574 2577 eventlog2->string[events_recorded] +
2575 2578 sizeof (eventlog2->string[events_recorded]));
2576 2579 events_recorded++;
2577 2580 }
2578 2581 }
2579 2582
2580 2583 eventlog2->num = events_recorded;
2581 2584
2582 2585 bscv_exit(ssp);
2583 2586
2584 2587 if ((res == 0) &&
2585 2588 (ddi_copyout((caddr_t)eventlog2, (caddr_t)arg,
2586 2589 sizeof (lom_eventlog2_t), mode) < 0)) {
2587 2590 res = EFAULT;
2588 2591 }
2589 2592
2590 2593 kmem_free((void *)eventlog2, sizeof (lom_eventlog2_t));
2591 2594 return (res);
2592 2595 }
2593 2596
2594 2597 /*
2595 2598 * LOMIOCINFO2
2596 2599 */
2597 2600 static int
2598 2601 bscv_ioc_info2(bscv_soft_state_t *ssp, intptr_t arg, int mode)
2599 2602 {
2600 2603 lom2_info_t info2;
2601 2604 int i;
2602 2605 uint16_t csum;
2603 2606 int res = 0;
2604 2607
2605 2608 bzero(&info2, sizeof (info2));
2606 2609
2607 2610 (void) strncpy(info2.escape_chars, ssp->escape_chars,
2608 2611 sizeof (info2.escape_chars));
2609 2612 info2.serial_events = ssp->reporting_level | ssp->serial_reporting;
2610 2613 info2.a3mode = WATCHDOG;
2611 2614
2612 2615 info2.fver = bscv_get8_locked(ssp, chan_general, EBUS_IDX_FW_REV, &res);
2613 2616 csum = bscv_get8_locked(ssp, chan_general, EBUS_IDX_CHECK_HI, &res)
2614 2617 << 8;
2615 2618 csum |= bscv_get8_locked(ssp, chan_general, EBUS_IDX_CHECK_LO, &res);
2616 2619 info2.fchksum = csum;
2617 2620 info2.prod_rev = bscv_get8_locked(ssp, chan_general,
2618 2621 EBUS_IDX_MODEL_REV, &res);
2619 2622 for (i = 0; i < sizeof (info2.prod_id); i++) {
2620 2623 info2.prod_id[i] = bscv_get8_locked(ssp, chan_general,
2621 2624 EBUS_IDX_MODEL_ID1 + i, &res);
2622 2625 }
2623 2626 info2.serial_config = bscv_get8_locked(ssp, chan_general,
2624 2627 EBUS_IDX_SER_TIMEOUT, &res);
2625 2628 if (bscv_get8_locked(ssp, chan_general, EBUS_IDX_CONFIG_MISC, &res) &
2626 2629 EBUS_CONFIG_MISC_SECURITY_ENABLED) {
2627 2630 info2.serial_config |= LOM_SER_SECURITY;
2628 2631 }
2629 2632 if (bscv_get8_locked(ssp, chan_general, EBUS_IDX_CONFIG_MISC, &res) &
2630 2633 EBUS_CONFIG_MISC_AUTO_CONSOLE) {
2631 2634 info2.serial_config |= LOM_SER_RETURN;
2632 2635 }
2633 2636 if (bscv_get8_locked(ssp, chan_general, EBUS_IDX_WDOG_CTRL, &res) &
2634 2637 EBUS_WDOG_BREAK_DISABLE) {
2635 2638 info2.serial_config |= LOM_DISABLE_WDOG_BREAK;
2636 2639 }
2637 2640 info2.baud_rate = bscv_get8_locked(ssp, chan_general,
2638 2641 EBUS_IDX_SER_BAUD, &res);
2639 2642 info2.serial_hw_config =
2640 2643 ((int)bscv_get8_locked(ssp, chan_general,
2641 2644 EBUS_IDX_SER_CHARMODE, &res) |
2642 2645 ((int)bscv_get8_locked(ssp, chan_general,
2643 2646 EBUS_IDX_SER_FLOWCTL, &res) << 8) |
2644 2647 ((int)bscv_get8_locked(ssp, chan_general,
2645 2648 EBUS_IDX_SER_MODEMTYPE, &res) << 16));
2646 2649
2647 2650 /*
2648 2651 * There is no phone home support on the blade platform. We hardcode
2649 2652 * FALSE and NUL for config and script respectively.
2650 2653 */
2651 2654 info2.phone_home_config = B_FALSE;
2652 2655 info2.phone_home_script[0] = '\0';
2653 2656
2654 2657 for (i = 0; i < ssp->num_fans; i++) {
2655 2658 (void) strcpy(info2.fan_names[i], ssp->fan_names[i]);
2656 2659 }
2657 2660
2658 2661 if ((res == 0) &&
2659 2662 (ddi_copyout((caddr_t)&info2, (caddr_t)arg, sizeof (info2),
2660 2663 mode) < 0)) {
2661 2664 res = EFAULT;
2662 2665 }
2663 2666 return (res);
2664 2667 }
2665 2668
2666 2669 /*
2667 2670 * LOMIOCTEST
2668 2671 */
2669 2672 static int
2670 2673 bscv_ioc_test(bscv_soft_state_t *ssp, intptr_t arg, int mode)
2671 2674 {
2672 2675 uint32_t test;
2673 2676 uint8_t testnum;
2674 2677 uint8_t testarg;
2675 2678 int res = 0;
2676 2679
2677 2680 if (ddi_copyin((caddr_t)arg, (caddr_t)&test, sizeof (test),
2678 2681 mode) < 0) {
2679 2682 return (EFAULT);
2680 2683 }
2681 2684
2682 2685 /*
2683 2686 * Extract num iterations.
2684 2687 */
2685 2688
2686 2689 testarg = (test & 0xff00) >> 8;
2687 2690 testnum = test & 0xff;
2688 2691
2689 2692 BSCV_TRACE(ssp, 'F', "bscv_ioc_test",
2690 2693 "LOMIOCTEST data 0x%x (test 0x%x, arg 0x%x)",
2691 2694 test, (EBUS_IDX_SELFTEST0 + testnum), testarg);
2692 2695
2693 2696 switch (testnum + EBUS_IDX_SELFTEST0) {
2694 2697 default:
2695 2698 /* Invalid test */
2696 2699 res = EINVAL;
2697 2700 break;
2698 2701
2699 2702 case EBUS_IDX_SELFTEST0: /* power on self-test result */
2700 2703 case EBUS_IDX_SELFTEST1: /* not used currently */
2701 2704 case EBUS_IDX_SELFTEST2: /* not used currently */
2702 2705 case EBUS_IDX_SELFTEST3: /* not used currently */
2703 2706 case EBUS_IDX_SELFTEST4: /* not used currently */
2704 2707 case EBUS_IDX_SELFTEST5: /* not used currently */
2705 2708 case EBUS_IDX_SELFTEST6: /* LED self-test */
2706 2709 case EBUS_IDX_SELFTEST7: /* platform-specific tests */
2707 2710 /* Run the test */
2708 2711
2709 2712 /* Stop other things and then run the test */
2710 2713 bscv_enter(ssp);
2711 2714
2712 2715 /*
2713 2716 * Then we simply write the argument to the relevant register
2714 2717 * and wait for the return code.
2715 2718 */
2716 2719 bscv_put8(ssp, chan_general,
2717 2720 EBUS_IDX_SELFTEST0 + testnum, testarg);
2718 2721 if (bscv_faulty(ssp)) {
2719 2722 res = EIO;
2720 2723 } else {
2721 2724 /* Get hold of the SunVTS error code */
2722 2725 test = bscv_retcode(ssp);
2723 2726 }
2724 2727
2725 2728 bscv_exit(ssp);
2726 2729 break;
2727 2730 }
2728 2731
2729 2732 BSCV_TRACE(ssp, 'F', "bscv_ioc_test",
2730 2733 "LOMIOCTEST status 0x%x, res 0x%x", test, res);
2731 2734 if ((res == 0) &&
2732 2735 (ddi_copyout((caddr_t)&test, (caddr_t)arg, sizeof (test),
2733 2736 mode) < 0)) {
2734 2737 res = EFAULT;
2735 2738 }
2736 2739 return (res);
2737 2740 }
2738 2741
2739 2742 /*
2740 2743 * LOMIOCMPROG2
2741 2744 */
2742 2745 static int
2743 2746 bscv_ioc_mprog2(bscv_soft_state_t *ssp, intptr_t arg, int mode)
2744 2747 {
2745 2748 lom2_mprog_t mprog2;
2746 2749 uint32_t base_addr;
2747 2750 uint32_t data_size;
2748 2751 uint32_t eeprom_size;
2749 2752 int res = 0;
2750 2753
2751 2754 if (ddi_copyin((caddr_t)arg, (caddr_t)&mprog2, sizeof (mprog2),
2752 2755 mode) < 0) {
2753 2756 return (EFAULT);
2754 2757 }
2755 2758
2756 2759 /*
2757 2760 * Note that originally this was accessed as 255 byte pages
2758 2761 * in address spaces 240-255. We have to emulate this behaviour.
2759 2762 */
2760 2763 if ((mprog2.addr_space < 240) || (mprog2.addr_space > 255)) {
2761 2764 return (EINVAL);
2762 2765 }
2763 2766
2764 2767 bscv_enter(ssp);
2765 2768
2766 2769 /* Calculate required data location */
2767 2770 data_size = 255;
2768 2771 base_addr = (mprog2.addr_space - 240) * data_size;
2769 2772
2770 2773 eeprom_size = bscv_get8(ssp, chan_general, EBUS_IDX_EEPROM_SIZE_KB) *
2771 2774 1024;
2772 2775
2773 2776 if (bscv_faulty(ssp)) {
2774 2777 bscv_exit(ssp);
2775 2778 return (EIO);
2776 2779 } else if ((base_addr + data_size) > eeprom_size) {
2777 2780 BSCV_TRACE(ssp, 'M', "bscv_ioc_mprog2",
2778 2781 "Request extends past end of eeprom");
2779 2782 bscv_exit(ssp);
2780 2783 return (ENXIO);
2781 2784 }
2782 2785
2783 2786 bscv_put8(ssp, chan_general, EBUS_IDX_CMD_RES, EBUS_CMD_UNLOCK1);
2784 2787 if (bscv_faulty(ssp)) {
2785 2788 BSCV_TRACE(ssp, 'M', "bscv_ioc_mprog2", "ML1 Write failed");
2786 2789 bscv_exit(ssp);
2787 2790 return (EIO);
2788 2791 }
2789 2792
2790 2793 bscv_put8(ssp, chan_general, EBUS_IDX_CMD_RES, EBUS_CMD_UNLOCK2);
2791 2794 if (bscv_faulty(ssp)) {
2792 2795 BSCV_TRACE(ssp, 'M', "bscv_ioc_mprog2", "ML2 Write failed");
2793 2796 bscv_exit(ssp);
2794 2797 return (EIO);
2795 2798 }
2796 2799
2797 2800 if (bscv_eerw(ssp, base_addr, &mprog2.data[0],
2798 2801 data_size, B_TRUE /* write */) != 0) {
2799 2802 res = EIO;
2800 2803 }
2801 2804
2802 2805 /* Read a probe key to release the lock. */
2803 2806 (void) bscv_get8(ssp, chan_general, EBUS_IDX_PROBEAA);
2804 2807
2805 2808 if (bscv_faulty(ssp)) {
2806 2809 res = EIO;
2807 2810 }
2808 2811 bscv_exit(ssp);
2809 2812
2810 2813 return (res);
2811 2814 }
2812 2815
2813 2816 /*
2814 2817 * LOMIOCMREAD2
2815 2818 */
2816 2819 static int
2817 2820 bscv_ioc_mread2(bscv_soft_state_t *ssp, intptr_t arg, int mode)
2818 2821 {
2819 2822 lom2_mprog_t mprog2;
2820 2823 uint32_t base_addr;
2821 2824 uint32_t data_size;
2822 2825 uint32_t eeprom_size;
2823 2826 int res = 0;
2824 2827
2825 2828 if (ddi_copyin((caddr_t)arg, (caddr_t)&mprog2, sizeof (mprog2),
2826 2829 mode) < 0) {
2827 2830 return (EFAULT);
2828 2831 }
2829 2832
2830 2833 /*
2831 2834 * Need to stop the queue and then just read
2832 2835 * the bytes blind to the relevant addresses.
2833 2836 * Note that originally this was accessed as 255 byte pages
2834 2837 * in address spaces 240-255. We have to emulate this behaviour.
2835 2838 */
2836 2839 if ((mprog2.addr_space < 240) || (mprog2.addr_space > 255)) {
2837 2840 return (EINVAL);
2838 2841 }
2839 2842
2840 2843 bscv_enter(ssp);
2841 2844
2842 2845 /* Calculate required data location */
2843 2846 data_size = 255;
2844 2847 base_addr = (mprog2.addr_space - 240) * data_size;
2845 2848 eeprom_size = bscv_get8(ssp, chan_general, EBUS_IDX_EEPROM_SIZE_KB) *
2846 2849 1024;
2847 2850
2848 2851 if (bscv_faulty(ssp)) {
2849 2852 bscv_exit(ssp);
2850 2853 return (EIO);
2851 2854 } else if ((base_addr + data_size) > eeprom_size) {
2852 2855 BSCV_TRACE(ssp, 'M', "bscv_ioc_mread2",
2853 2856 "Request extends past end of eeprom");
2854 2857 bscv_exit(ssp);
2855 2858 return (ENXIO);
2856 2859 }
2857 2860
2858 2861 if (bscv_eerw(ssp, base_addr, &mprog2.data[0],
2859 2862 data_size, B_FALSE /* read */) != 0) {
2860 2863 res = EIO;
2861 2864 }
2862 2865
2863 2866 if (bscv_faulty(ssp)) {
2864 2867 res = EIO;
2865 2868 }
2866 2869 bscv_exit(ssp);
2867 2870
2868 2871 if ((res == 0) &&
2869 2872 (ddi_copyout((caddr_t)&mprog2, (caddr_t)arg, sizeof (mprog2),
2870 2873 mode) < 0)) {
2871 2874 res = EFAULT;
2872 2875 }
2873 2876 return (res);
2874 2877 }
2875 2878
2876 2879 static void
2877 2880 bscv_get_state_changes(bscv_soft_state_t *ssp)
2878 2881 {
2879 2882 int i = STATUS_READ_LIMIT;
2880 2883 uint8_t change;
2881 2884 uint8_t detail;
2882 2885
2883 2886 ASSERT(bscv_held(ssp));
2884 2887
2885 2888 while (i-- && !ssp->cssp_prog) {
2886 2889 /* Are there any changes to process? */
2887 2890 change = bscv_get8(ssp, chan_general, EBUS_IDX_STATE_CHNG);
2888 2891 change &= EBUS_STATE_MASK;
2889 2892 if (!change)
2890 2893 break;
2891 2894
2892 2895 /* Clarify the pending change */
2893 2896 detail = bscv_get8(ssp, chan_general, EBUS_IDX_EVENT_DETAIL);
2894 2897
2895 2898 bscv_status(ssp, change, detail);
2896 2899 }
2897 2900
2898 2901 BSCV_TRACE(ssp, 'D', "bscv_get_state_changes",
2899 2902 "loop index %d ssp->cssp_prog 0x%x", i, ssp->cssp_prog);
2900 2903 }
2901 2904
2902 2905 /*
2903 2906 * *********************************************************************
2904 2907 * Event Processing
2905 2908 * *********************************************************************
2906 2909 */
2907 2910
2908 2911 /*
2909 2912 * function - bscv_event_daemon
2910 2913 * description - Perform periodic lom tasks in a separate thread.
2911 2914 * inputs - LOM soft state structure pointer
2912 2915 * outputs - none.
2913 2916 */
2914 2917 static void
2915 2918 bscv_event_daemon(void *arg)
2916 2919 {
2917 2920 bscv_soft_state_t *ssp = (void *)arg;
2918 2921 boolean_t do_events;
2919 2922 boolean_t do_status;
2920 2923 boolean_t do_nodename;
2921 2924 boolean_t do_watchdog;
2922 2925 uint32_t async_reg;
2923 2926 uint32_t fault;
2924 2927 clock_t poll_period = BSC_EVENT_POLL_NORMAL;
2925 2928 int fault_cnt = 0;
2926 2929
2927 2930 BSCV_TRACE(ssp, 'D', "bscv_event_daemon",
2928 2931 "bscv_event_daemon: started");
2929 2932
2930 2933 /* Acquire task daemon lock. */
2931 2934 mutex_enter(&ssp->task_mu);
2932 2935
2933 2936 ssp->task_flags |= TASK_ALIVE_FLG;
2934 2937
2935 2938 for (;;) {
2936 2939 if ((ssp->task_flags & TASK_STOP_FLG) != 0) {
2937 2940 /* Stop request seen - terminate */
2938 2941 break;
2939 2942 }
2940 2943 if ((ssp->task_flags & TASK_PAUSE_FLG) == 0) {
2941 2944 /* Poll for events reported to the nexus */
2942 2945 mutex_exit(&ssp->task_mu);
2943 2946 /* Probe and Check faults */
2944 2947 bscv_enter(ssp);
2945 2948 async_reg = bscv_probe(ssp, chan_general, &fault);
2946 2949 BSCV_TRACE(ssp, 'D', "bscv_event_daemon",
2947 2950 "process event: async_reg 0x%x, fault 0x%x",
2948 2951 async_reg, fault);
2949 2952
2950 2953 if (!fault) {
2951 2954 /* Treat non-fault conditions */
2952 2955
2953 2956 if (ssp->cssp_prog || ssp->prog_mode_only) {
2954 2957 /*
2955 2958 * The BSC has become available again.
2956 2959 */
2957 2960 fault_cnt = 0;
2958 2961 ssp->cssp_prog = B_FALSE;
2959 2962 ssp->prog_mode_only = B_FALSE;
2960 2963 (void) bscv_attach_common(ssp);
2961 2964 } else if (fault_cnt > 0) {
2962 2965 /* Previous fault has cleared */
2963 2966 bscv_clear_fault(ssp);
2964 2967 fault_cnt = 0;
2965 2968 cmn_err(CE_WARN,
2966 2969 "!bscv_event_daemon previous fault "
2967 2970 "cleared.");
2968 2971 } else if (bscv_faulty(ssp)) {
2969 2972 /* Previous fault has cleared */
2970 2973 bscv_clear_fault(ssp);
2971 2974 /* Sleep to avoid busy waiting */
2972 2975 ssp->event_sleep = B_TRUE;
2973 2976 }
2974 2977 poll_period = BSC_EVENT_POLL_NORMAL;
2975 2978
2976 2979 if (async_reg) {
2977 2980 ssp->status_change = B_TRUE;
2978 2981 ssp->event_waiting = B_TRUE;
2979 2982 }
2980 2983 } else if (ssp->cssp_prog) {
2981 2984 /*
2982 2985 * Expect radio silence or error values
2983 2986 * when the CSSP is upgrading the BSC firmware
2984 2987 * so throw away any fault indication.
2985 2988 */
2986 2989 fault = B_FALSE;
2987 2990 } else if (fault_cnt == BSC_PROBE_FAULT_LIMIT) {
2988 2991 /* Count previous faults and maybe fail */
2989 2992 /* Declare the lom broken */
2990 2993 bscv_set_fault(ssp);
2991 2994 poll_period = BSC_EVENT_POLL_FAULTY;
2992 2995 cmn_err(CE_WARN,
2993 2996 "!bscv_event_daemon had faults probing "
2994 2997 "lom - marking it as faulty.");
2995 2998 /*
2996 2999 * Increment fault_cnt to ensure that
2997 3000 * next time we do not report a message
2998 3001 * i.e. we drop out of the bottom
2999 3002 */
3000 3003 fault_cnt = BSC_PROBE_FAULT_LIMIT + 1;
3001 3004 ssp->event_sleep = B_TRUE;
3002 3005 } else if (fault_cnt < BSC_PROBE_FAULT_LIMIT) {
3003 3006 if (bscv_faulty(ssp)) {
3004 3007 poll_period = BSC_EVENT_POLL_FAULTY;
3005 3008 /*
3006 3009 * No recovery messages in this case
3007 3010 * because there was never a fault
3008 3011 * message here.
3009 3012 */
3010 3013 fault_cnt = 0;
3011 3014 } else {
3012 3015 /* Getting ready to explode */
3013 3016 fault_cnt++;
3014 3017 cmn_err(CE_WARN,
3015 3018 "!bscv_event_daemon had fault 0x%x",
3016 3019 fault);
3017 3020 }
3018 3021 ssp->event_sleep = B_TRUE;
3019 3022 }
3020 3023 bscv_exit(ssp);
3021 3024 mutex_enter(&ssp->task_mu);
3022 3025 }
3023 3026
3024 3027 #if defined(__i386) || defined(__amd64)
3025 3028 /*
3026 3029 * we have no platmod hook on Solaris x86 to report
3027 3030 * a change to the nodename so we keep a copy so
3028 3031 * we can detect a change and request that the bsc
3029 3032 * be updated when appropriate.
3030 3033 */
3031 3034 if (strcmp(ssp->last_nodename, utsname.nodename) != 0) {
3032 3035
3033 3036 BSCV_TRACE(ssp, 'X', "bscv_event_daemon",
3034 3037 "utsname.nodename='%s' possible change detected",
3035 3038 utsname.nodename);
3036 3039 ssp->nodename_change = B_TRUE;
3037 3040 (void) strncpy(ssp->last_nodename, utsname.nodename,
3038 3041 sizeof (ssp->last_nodename));
3039 3042 /* enforce null termination */
3040 3043 ssp->last_nodename[sizeof (ssp->last_nodename) - 1] =
3041 3044 '\0';
3042 3045 }
3043 3046 #endif /* __i386 || __amd64 */
3044 3047
3045 3048 if (((ssp->task_flags & TASK_PAUSE_FLG) == 0) &&
3046 3049 fault_cnt == 0 && ssp->cssp_prog == B_FALSE &&
3047 3050 (ssp->event_waiting || ssp->status_change ||
3048 3051 ssp->nodename_change || ssp->watchdog_change)) {
3049 3052
3050 3053 do_events = ssp->event_waiting;
3051 3054 ssp->event_waiting = B_FALSE;
3052 3055 ssp->task_flags |= do_events ?
3053 3056 TASK_EVENT_PENDING_FLG : 0;
3054 3057 do_status = ssp->status_change;
3055 3058 ssp->status_change = B_FALSE;
3056 3059 do_nodename = ssp->nodename_change;
3057 3060 ssp->nodename_change = B_FALSE;
3058 3061 do_watchdog = ssp->watchdog_change;
3059 3062 if (ssp->watchdog_change) {
3060 3063 ssp->watchdog_change = B_FALSE;
3061 3064 }
3062 3065
3063 3066 mutex_exit(&ssp->task_mu);
3064 3067 /*
3065 3068 * We must not hold task_mu whilst processing
3066 3069 * events because this can lead to priority
3067 3070 * inversion and hence our interrupts getting
3068 3071 * locked out.
3069 3072 */
3070 3073 bscv_enter(ssp);
3071 3074 if (do_events) {
3072 3075 bscv_event_process(ssp, do_events);
3073 3076 }
3074 3077 if (do_nodename) {
3075 3078 BSCV_TRACE(ssp, 'D', "bscv_event_daemon",
3076 3079 "do_nodename task");
3077 3080 bscv_setup_hostname(ssp);
3078 3081 }
3079 3082 if (do_watchdog) {
3080 3083 BSCV_TRACE(ssp, 'D', "bscv_event_daemon",
3081 3084 "do_watchdog task");
3082 3085 bscv_setup_watchdog(ssp);
3083 3086 }
3084 3087 /*
3085 3088 * Pending status changes are dealt with last because
3086 3089 * if we see that the BSC is about to be programmed,
3087 3090 * then it will expect us to to quiescent in the
3088 3091 * first second so it can cleanly tear down its comms
3089 3092 * protocols; this takes ~100 ms.
3090 3093 */
3091 3094 if (do_status) {
3092 3095 bscv_get_state_changes(ssp);
3093 3096 }
3094 3097 if (bscv_session_error(ssp)) {
3095 3098 /*
3096 3099 * Had fault during event session. We always
3097 3100 * sleep after one of these because there
3098 3101 * may be a problem with the lom which stops
3099 3102 * us doing useful work in the event daemon.
3100 3103 * If we don't sleep then we may livelock.
3101 3104 */
3102 3105 BSCV_TRACE(ssp, 'D', "bscv_event_daemon",
3103 3106 "had session error - sleeping");
3104 3107 ssp->event_sleep = B_TRUE;
3105 3108 }
3106 3109 bscv_exit(ssp);
3107 3110
3108 3111 mutex_enter(&ssp->task_mu);
3109 3112
3110 3113 if (ssp->task_flags & TASK_EVENT_PENDING_FLG) {
3111 3114 /*
3112 3115 * We have read any events which were
3113 3116 * pending. Let the consumer continue.
3114 3117 * Ignore the race condition with new events
3115 3118 * arriving - just let the consumer have
3116 3119 * whatever was pending when they asked.
3117 3120 */
3118 3121 ssp->event_active_count++;
3119 3122 ssp->task_flags &= ~(TASK_EVENT_PENDING_FLG |
3120 3123 TASK_EVENT_CONSUMER_FLG);
3121 3124 cv_broadcast(&ssp->task_evnt_cv);
3122 3125 }
3123 3126 } else {
3124 3127 /* There was nothing to do - sleep */
3125 3128 ssp->event_sleep = B_TRUE;
3126 3129 }
3127 3130
3128 3131 if (ssp->event_sleep) {
3129 3132 ssp->task_flags |= TASK_SLEEPING_FLG;
3130 3133 /* Sleep until there is something to do */
3131 3134 (void) cv_reltimedwait(&ssp->task_cv,
3132 3135 &ssp->task_mu, poll_period, TR_CLOCK_TICK);
3133 3136 ssp->task_flags &= ~TASK_SLEEPING_FLG;
3134 3137 ssp->event_sleep = B_FALSE;
3135 3138 }
3136 3139 }
3137 3140
3138 3141 if (ssp->task_flags & TASK_EVENT_CONSUMER_FLG) {
3139 3142 /*
3140 3143 * We are going away so wake up any event consumer.
3141 3144 * Pretend that any pending events have been processed.
3142 3145 */
3143 3146 ssp->event_active_count += 2;
3144 3147 cv_broadcast(&ssp->task_evnt_cv);
3145 3148 }
3146 3149
3147 3150 ASSERT(!(ssp->task_flags & TASK_EVENT_PENDING_FLG));
3148 3151 ssp->task_flags &=
3149 3152 ~(TASK_STOP_FLG | TASK_ALIVE_FLG | TASK_EVENT_CONSUMER_FLG);
3150 3153 mutex_exit(&ssp->task_mu);
3151 3154
3152 3155 BSCV_TRACE(ssp, 'D', "bscv_event_daemon",
3153 3156 "exiting.");
3154 3157 }
3155 3158
3156 3159 /*
3157 3160 * function - bscv_start_event_daemon
3158 3161 * description - Create the event daemon thread.
3159 3162 * inputs - LOM soft state structure pointer
3160 3163 * outputs - none
3161 3164 */
3162 3165 static void
3163 3166 bscv_start_event_daemon(bscv_soft_state_t *ssp)
3164 3167 {
3165 3168 if (ssp->progress & BSCV_THREAD)
3166 3169 return;
3167 3170
3168 3171 /* Start the event thread after the queue has started */
3169 3172 (void) thread_create(NULL, 0, (void (*)())bscv_event_daemon, ssp,
3170 3173 0, &p0, TS_RUN, minclsyspri);
3171 3174
3172 3175 ssp->progress |= BSCV_THREAD;
3173 3176 }
3174 3177
3175 3178 /*
3176 3179 * function - bscv_stop_event_daemon
3177 3180 * description - Attempt to stop the event daemon thread.
3178 3181 * inputs - LOM soft state structure pointer
3179 3182 * outputs - DDI_SUCCESS OR DDI_FAILURE
3180 3183 */
3181 3184 static int
3182 3185 bscv_stop_event_daemon(bscv_soft_state_t *ssp)
3183 3186 {
3184 3187 int try;
3185 3188 int res = DDI_SUCCESS;
3186 3189
3187 3190 mutex_enter(&ssp->task_mu);
3188 3191
3189 3192 /* Wait for task daemon to stop running. */
3190 3193 for (try = 0;
3191 3194 ((ssp->task_flags & TASK_ALIVE_FLG) && try < 10);
3192 3195 try++) {
3193 3196 /* Signal that the task daemon should stop */
3194 3197 ssp->task_flags |= TASK_STOP_FLG;
3195 3198 cv_signal(&ssp->task_cv);
3196 3199 /* Release task daemon lock. */
3197 3200 mutex_exit(&ssp->task_mu);
3198 3201 /*
3199 3202 * TODO - when the driver is modified to support
3200 3203 * system suspend or if this routine gets called
3201 3204 * during panic we should use drv_usecwait() rather
3202 3205 * than delay in those circumstances.
3203 3206 */
3204 3207 delay(drv_usectohz(1000000));
3205 3208 mutex_enter(&ssp->task_mu);
3206 3209 }
3207 3210
3208 3211 if (ssp->task_flags & TASK_ALIVE_FLG) {
3209 3212 res = DDI_FAILURE;
3210 3213 }
3211 3214 mutex_exit(&ssp->task_mu);
3212 3215
3213 3216 return (res);
3214 3217 }
3215 3218
3216 3219 /*
3217 3220 * function - bscv_pause_event_daemon
3218 3221 * description - Attempt to pause the event daemon thread.
3219 3222 * inputs - LOM soft state structure pointer
3220 3223 * outputs - DDI_SUCCESS OR DDI_FAILURE
3221 3224 */
3222 3225 static int
3223 3226 bscv_pause_event_daemon(bscv_soft_state_t *ssp)
3224 3227 {
3225 3228 int try;
3226 3229
3227 3230 if (!(ssp->progress & BSCV_THREAD)) {
3228 3231 /* Nothing to do */
3229 3232 return (BSCV_SUCCESS);
3230 3233 }
3231 3234
3232 3235 BSCV_TRACE(ssp, 'D', "bscv_pause_event_daemon",
3233 3236 "Attempting to pause event daemon");
3234 3237
3235 3238 mutex_enter(&ssp->task_mu);
3236 3239 /* Signal that the task daemon should pause */
3237 3240 ssp->task_flags |= TASK_PAUSE_FLG;
3238 3241
3239 3242 /* Wait for task daemon to pause. */
3240 3243 for (try = 0;
3241 3244 (!(ssp->task_flags & TASK_SLEEPING_FLG) &&
3242 3245 (ssp->task_flags & TASK_ALIVE_FLG) &&
3243 3246 try < 10);
3244 3247 try++) {
3245 3248 /* Paranoia */
3246 3249 ssp->task_flags |= TASK_PAUSE_FLG;
3247 3250 cv_signal(&ssp->task_cv);
3248 3251 /* Release task daemon lock. */
3249 3252 mutex_exit(&ssp->task_mu);
3250 3253 delay(drv_usectohz(1000000));
3251 3254 mutex_enter(&ssp->task_mu);
3252 3255 }
3253 3256 if ((ssp->task_flags & TASK_SLEEPING_FLG) ||
3254 3257 !(ssp->task_flags & TASK_ALIVE_FLG)) {
3255 3258 mutex_exit(&ssp->task_mu);
3256 3259 BSCV_TRACE(ssp, 'D', "bscv_pause_event_daemon",
3257 3260 "Pause event daemon - success");
3258 3261 return (BSCV_SUCCESS);
3259 3262 }
3260 3263 mutex_exit(&ssp->task_mu);
3261 3264 BSCV_TRACE(ssp, 'D', "bscv_pause_event_daemon",
3262 3265 "Pause event daemon - failed");
3263 3266 return (BSCV_FAILURE);
3264 3267 }
3265 3268
3266 3269 /*
3267 3270 * function - bscv_resume_event_daemon
3268 3271 * description - Resumethe event daemon thread.
3269 3272 * inputs - LOM soft state structure pointer
3270 3273 * outputs - None.
3271 3274 */
3272 3275 static void
3273 3276 bscv_resume_event_daemon(bscv_soft_state_t *ssp)
3274 3277 {
3275 3278 if (!(ssp->progress & BSCV_THREAD)) {
3276 3279 /* Nothing to do */
3277 3280 return;
3278 3281 }
3279 3282
3280 3283 mutex_enter(&ssp->task_mu);
3281 3284 /* Allow the task daemon to resume event processing */
3282 3285 ssp->task_flags &= ~TASK_PAUSE_FLG;
3283 3286 cv_signal(&ssp->task_cv);
3284 3287 mutex_exit(&ssp->task_mu);
3285 3288
3286 3289 BSCV_TRACE(ssp, 'D', "bscv_pause_event_daemon",
3287 3290 "Event daemon resumed");
3288 3291 }
3289 3292
3290 3293 /*
3291 3294 * function - bscv_event_process
3292 3295 * description - process (report) events
3293 3296 * inputs - Soft state ptr, process event request
3294 3297 * outputs - none
3295 3298 */
3296 3299 static void
3297 3300 bscv_event_process(bscv_soft_state_t *ssp, boolean_t do_events)
3298 3301 {
3299 3302 uint32_t currptr;
3300 3303 unsigned int count;
3301 3304
3302 3305 /* Raw values read from the lom */
3303 3306 uint8_t evcount;
3304 3307 uint16_t logptr;
3305 3308
3306 3309 lom_event_t event;
3307 3310
3308 3311 if (do_events) {
3309 3312 /*
3310 3313 * Read count, next event ptr MSB,LSB. Note a read of count
3311 3314 * latches values for the next event ptr
3312 3315 */
3313 3316 evcount = bscv_get8(ssp, chan_general, EBUS_IDX_UNREAD_EVENTS);
3314 3317 logptr = bscv_get16(ssp, chan_general, EBUS_IDX_LOG_PTR_HI);
3315 3318
3316 3319 /* Sanity check the values from the lom */
3317 3320 count = bscv_event_validate(ssp, logptr, evcount);
3318 3321
3319 3322 if (count == -1) {
3320 3323 /*
3321 3324 * Nothing to do - or badly configured event log.
3322 3325 * We really do not want to touch the lom in this
3323 3326 * case because any data that we access may be bad!
3324 3327 * This differs from zero because if we have zero
3325 3328 * to read the lom probably things that unread is
3326 3329 * non-zero and we want that to be set to zero!
3327 3330 * Signal event fault to make the thread wait
3328 3331 * before attempting to re-read the log.
3329 3332 */
3330 3333 ssp->event_sleep = B_TRUE;
3331 3334
3332 3335 goto logdone;
3333 3336 }
3334 3337 if (ssp->event_fault_reported) {
3335 3338 /* Clear down any old status - things are fixed */
3336 3339 cmn_err(CE_NOTE, "Event pointer fault recovered.");
3337 3340 ssp->event_fault_reported = B_FALSE;
3338 3341 }
3339 3342
3340 3343 /* Compute the first entry that we need to read. */
3341 3344 currptr = logptr - ssp->eventlog_start;
3342 3345 currptr += ssp->eventlog_size;
3343 3346 currptr -= (count * sizeof (event));
3344 3347 currptr %= ssp->eventlog_size;
3345 3348 currptr += ssp->eventlog_start;
3346 3349
3347 3350 BSCV_TRACE(ssp, 'E', "bscv_event_process",
3348 3351 "processing %d events from 0x%x in 0x%x:0x%x",
3349 3352 count, currptr,
3350 3353 ssp->eventlog_start,
3351 3354 ssp->eventlog_start + ssp->eventlog_size);
3352 3355
3353 3356 for (; count > 0; count--) {
3354 3357 /* Ensure window is positioned correctly */
3355 3358 if (bscv_eerw(ssp, currptr, (uint8_t *)&event,
3356 3359 sizeof (event), B_FALSE /* read */) != 0) {
3357 3360 /* Fault reading data - stop */
3358 3361 break;
3359 3362 }
3360 3363
3361 3364 bscv_event_process_one(ssp, &event);
3362 3365 bscv_sysevent(ssp, &event);
3363 3366
3364 3367 currptr += sizeof (event);
3365 3368 if (currptr >= ssp->eventlog_start +
3366 3369 ssp->eventlog_size) {
3367 3370 currptr = ssp->eventlog_start;
3368 3371 }
3369 3372 }
3370 3373 /*
3371 3374 * Clear event count - write the evcount value to remove that
3372 3375 * many from the unread total.
3373 3376 * Adjust the value to reflect how many we have left to
3374 3377 * read just in case we had a failure reading events.
3375 3378 */
3376 3379 if (count == 0) {
3377 3380 /*EMPTY*/
3378 3381 ASSERT(logptr == currptr);
3379 3382 } else if (count > evcount) {
3380 3383 evcount = 0;
3381 3384 } else {
3382 3385 evcount -= count;
3383 3386 }
3384 3387 bscv_put8(ssp, chan_general, EBUS_IDX_UNREAD_EVENTS, evcount);
3385 3388 /* Remember where we were for next time */
3386 3389 ssp->oldeeptr = currptr;
3387 3390 ssp->oldeeptr_valid = B_TRUE;
3388 3391 logdone:
3389 3392 ;
3390 3393 }
3391 3394 }
3392 3395
3393 3396 /*
3394 3397 * function - bscv_event_validate
3395 3398 * description - validate the event data supplied by the lom and determine
3396 3399 * how many (if any) events to read.
3397 3400 * This function performs complex checks to ensure that
3398 3401 * events are not lost due to lom resets or host resets.
3399 3402 * A combination of lom reset and host reset (i.e. power fail)
3400 3403 * may cause some events to not be reported.
3401 3404 * inputs - Soft state ptr, next event pointer, number of unread events.
3402 3405 * outputs - the number of events to read. -1 on error.
3403 3406 * zero is a valid value because it forces the loms unread
3404 3407 * count to be cleared.
3405 3408 */
3406 3409 static int
3407 3410 bscv_event_validate(bscv_soft_state_t *ssp, uint32_t newptr, uint8_t unread)
3408 3411 {
3409 3412 uint32_t oldptr;
3410 3413 unsigned int count;
3411 3414
3412 3415 if (!bscv_window_setup(ssp)) {
3413 3416 /* Problem with lom eeprom setup we cannot do anything */
3414 3417 return (-1);
3415 3418 }
3416 3419
3417 3420 /* Sanity check the event pointers */
3418 3421 if ((newptr < ssp->eventlog_start) ||
3419 3422 (newptr >= (ssp->eventlog_start + ssp->eventlog_size))) {
3420 3423 if (!ssp->event_fault_reported) {
3421 3424 cmn_err(CE_WARN, "Event pointer out of range. "
3422 3425 "Cannot read events.");
3423 3426 ssp->event_fault_reported = B_TRUE;
3424 3427 }
3425 3428 return (-1);
3426 3429 }
3427 3430 oldptr = ssp->oldeeptr;
3428 3431 /* Now sanity check log pointer against count */
3429 3432 if (newptr < oldptr) {
3430 3433 /*
3431 3434 * Must have wrapped add eventlog_size to get the
3432 3435 * correct relative values - this makes the checks
3433 3436 * below work!
3434 3437 */
3435 3438 newptr += ssp->eventlog_size;
3436 3439 }
3437 3440 if (!ssp->oldeeptr_valid) {
3438 3441 /* We have just started up - we have to trust lom */
3439 3442 count = unread;
3440 3443 } else if ((unread == 0) && (newptr == oldptr)) {
3441 3444 /* Nothing to do - we were just polling */
3442 3445 return (-1);
3443 3446 } else if (oldptr + (unread * sizeof (lom_event_t)) == newptr) {
3444 3447 /* Ok - got as many events as we expected */
3445 3448 count = unread;
3446 3449 } else if (oldptr + (unread * sizeof (lom_event_t)) > newptr) {
3447 3450 /*
3448 3451 * Errrm more messages than there should have been.
3449 3452 * Possible causes:
3450 3453 * 1. the event log has filled - we have been
3451 3454 * away for a long time
3452 3455 * 2. software bug in lom or driver.
3453 3456 * 3. something that I haven't thought of!
3454 3457 * Always warn about this we should really never
3455 3458 * see it!
3456 3459 */
3457 3460 count = (newptr - oldptr) / sizeof (lom_event_t);
3458 3461 BSCV_TRACE(ssp, 'E', "bscv_event_process",
3459 3462 "bscv_event_process: lom reported "
3460 3463 "more events (%d) than expected (%d).",
3461 3464 unread, count);
3462 3465 cmn_err(CE_CONT, "only processing %d events", count);
3463 3466 } else {
3464 3467 /* Less messages - perhaps the lom has been reset */
3465 3468 count = (newptr - oldptr) / sizeof (lom_event_t);
3466 3469 BSCV_TRACE(ssp, 'E', "bscv_event_process",
3467 3470 "lom reported less events (%d) than expected (%d)"
3468 3471 " - the lom may have been reset",
3469 3472 unread, count);
3470 3473 }
3471 3474 /* Whatever happens only read a maximum of 255 entries */
3472 3475 if ((count >= 0xff)) {
3473 3476 cmn_err(CE_WARN,
3474 3477 "bscv_event_process: too many events (%d) to "
3475 3478 "process - some may have been lost", count);
3476 3479 count = 0xff;
3477 3480 }
3478 3481 return (count);
3479 3482 }
3480 3483
3481 3484 /*
3482 3485 * function - bscv_event_process_one
3483 3486 * description - reports on state changes to the host.
3484 3487 *
3485 3488 * inputs - LOM soft state structure pointer.
3486 3489 *
3487 3490 * outputs - none.
3488 3491 */
3489 3492
3490 3493 static void
3491 3494 bscv_event_process_one(bscv_soft_state_t *ssp, lom_event_t *event)
3492 3495 {
3493 3496 int level;
3494 3497 char eventstr[100];
3495 3498 int msg_type = 0;
3496 3499
3497 3500 if (bscv_is_null_event(ssp, event)) {
3498 3501 /* Cleared entry - do not report it */
3499 3502 return;
3500 3503 }
3501 3504
3502 3505 level = bscv_level_of_event(event);
3503 3506
3504 3507 switch (level) {
3505 3508 default:
3506 3509 msg_type = CE_NOTE;
3507 3510 break;
3508 3511
3509 3512 case EVENT_LEVEL_FATAL:
3510 3513 case EVENT_LEVEL_FAULT:
3511 3514 msg_type = CE_WARN;
3512 3515 break;
3513 3516 }
3514 3517
3515 3518 bscv_build_eventstring(ssp, event, eventstr, eventstr +
3516 3519 sizeof (eventstr));
3517 3520
3518 3521 if (level <= ssp->reporting_level) {
3519 3522 /*
3520 3523 * The message is important enough to be shown on the console
3521 3524 * as well as the log.
3522 3525 */
3523 3526 cmn_err(msg_type, "%s", eventstr);
3524 3527 } else {
3525 3528 /*
3526 3529 * The message goes only to the log.
3527 3530 */
3528 3531 cmn_err(msg_type, "!%s", eventstr);
3529 3532 }
3530 3533 }
3531 3534
3532 3535 /*
3533 3536 * time formats
3534 3537 *
3535 3538 * The BSC represents times as seconds since epoch 1970. Currently it gives
3536 3539 * us 32 bits, unsigned. In the future this might change to a 64-bit count,
3537 3540 * to allow a greater range.
3538 3541 *
3539 3542 * Timestamp values below BSC_TIME_SANITY do not represent an absolute time,
3540 3543 * but instead represent an offset from the last reset. This must be
3541 3544 * borne in mind by output routines.
3542 3545 */
3543 3546
3544 3547 typedef uint32_t bsctime_t;
3545 3548
3546 3549 #define BSC_TIME_SANITY 1000000000
3547 3550
3548 3551 /*
3549 3552 * render a formatted time for display
3550 3553 */
3551 3554
3552 3555 static size_t
3553 3556 bscv_event_snprintgmttime(char *buf, size_t bufsz, todinfo_t t)
3554 3557 {
3555 3558 int year;
3556 3559
3557 3560 /* tod_year is base 1900 so this code needs to adjust */
3558 3561 year = 1900 + t.tod_year;
3559 3562
3560 3563 return (snprintf(buf, bufsz, "%04d-%02d-%02d %02d:%02d:%02dZ",
3561 3564 year, t.tod_month, t.tod_day, t.tod_hour,
3562 3565 t.tod_min, t.tod_sec));
3563 3566 }
3564 3567
3565 3568 /*
3566 3569 * function - bscv_build_eventstring
3567 3570 * description - reports on state changes to the host.
3568 3571 *
3569 3572 * inputs - LOM soft state structure pointer.
3570 3573 *
3571 3574 * outputs - none.
3572 3575 */
3573 3576
3574 3577 static void
3575 3578 bscv_build_eventstring(bscv_soft_state_t *ssp, lom_event_t *event,
3576 3579 char *buf, char *bufend)
3577 3580 {
3578 3581 uint8_t subsystem;
3579 3582 uint8_t eventtype;
3580 3583 bsctime_t bsctm;
3581 3584
3582 3585 BSCV_TRACE(ssp, 'S', "bscv_build_eventstring", "event %2x%2x%2x%2x",
3583 3586 event->ev_subsys, event->ev_event,
3584 3587 event->ev_resource, event->ev_detail);
3585 3588 BSCV_TRACE(ssp, 'S', "bscv_build_eventstring", "time %2x%2x%2x%2x",
3586 3589 event->ev_data[0], event->ev_data[1],
3587 3590 event->ev_data[2], event->ev_data[3]);
3588 3591
3589 3592 /*
3590 3593 * We accept bad subsystems and event type codes here.
3591 3594 * The code decodes as much as possible and then produces
3592 3595 * suitable output.
3593 3596 */
3594 3597 subsystem = EVENT_DECODE_SUBSYS(event->ev_subsys);
3595 3598 eventtype = event->ev_event;
3596 3599
3597 3600 /* time */
3598 3601 bsctm = (((uint32_t)event->ev_data[0]) << 24) |
3599 3602 (((uint32_t)event->ev_data[1]) << 16) |
3600 3603 (((uint32_t)event->ev_data[2]) << 8) |
3601 3604 ((uint32_t)event->ev_data[3]);
3602 3605 if (bsctm < BSC_TIME_SANITY) {
3603 3606 /* offset */
3604 3607 buf += snprintf(buf, bufend-buf, "+P%dd%02dh%02dm%02ds",
3605 3608 (int)(bsctm/86400), (int)(bsctm/3600%24),
3606 3609 (int)(bsctm/60%60), (int)(bsctm%60));
3607 3610 } else {
3608 3611 /* absolute time */
3609 3612 mutex_enter(&tod_lock);
3610 3613 buf += bscv_event_snprintgmttime(buf, bufend-buf,
3611 3614 utc_to_tod(bsctm));
3612 3615 mutex_exit(&tod_lock);
3613 3616 }
3614 3617 buf += snprintf(buf, bufend-buf, " ");
3615 3618
3616 3619 /* subsysp */
3617 3620 if (subsystem <
3618 3621 (sizeof (eventSubsysStrings)/sizeof (*eventSubsysStrings))) {
3619 3622 buf += snprintf(buf, bufend - buf, "%s",
3620 3623 eventSubsysStrings[subsystem]);
3621 3624 } else {
3622 3625 buf += snprintf(buf, bufend - buf,
3623 3626 "unknown subsystem %d ", subsystem);
3624 3627 }
3625 3628
3626 3629 /* resource */
3627 3630 switch (subsystem) {
3628 3631 case EVENT_SUBSYS_ALARM:
3629 3632 case EVENT_SUBSYS_TEMP:
3630 3633 case EVENT_SUBSYS_OVERTEMP:
3631 3634 case EVENT_SUBSYS_FAN:
3632 3635 case EVENT_SUBSYS_SUPPLY:
3633 3636 case EVENT_SUBSYS_BREAKER:
3634 3637 case EVENT_SUBSYS_PSU:
3635 3638 buf += snprintf(buf, bufend - buf, "%d ", event->ev_resource);
3636 3639 break;
3637 3640 case EVENT_SUBSYS_LED:
3638 3641 buf += snprintf(buf, bufend - buf, "%s ", bscv_get_label(
3639 3642 ssp->led_names, MAX_LED_ID, event->ev_resource - 1));
3640 3643 break;
3641 3644 default:
3642 3645 break;
3643 3646 }
3644 3647
3645 3648 /* fatal */
3646 3649 if (event->ev_subsys & EVENT_MASK_FAULT) {
3647 3650 if (event->ev_subsys & EVENT_MASK_FATAL) {
3648 3651 buf += snprintf(buf, bufend - buf, "FATAL FAULT: ");
3649 3652 } else {
3650 3653 buf += snprintf(buf, bufend - buf, "FAULT: ");
3651 3654 }
3652 3655 }
3653 3656
3654 3657 /* eventp */
3655 3658 if (eventtype <
3656 3659 (sizeof (eventTypeStrings)/sizeof (*eventTypeStrings))) {
3657 3660 buf += snprintf(buf, bufend - buf, "%s",
3658 3661 eventTypeStrings[eventtype]);
3659 3662 } else {
3660 3663 buf += snprintf(buf, bufend - buf,
3661 3664 "unknown event 0x%02x%02x%02x%02x",
3662 3665 event->ev_subsys, event->ev_event,
3663 3666 event->ev_resource, event->ev_detail);
3664 3667 }
3665 3668
3666 3669 /* detail */
3667 3670 switch (subsystem) {
3668 3671 case EVENT_SUBSYS_TEMP:
3669 3672 if ((eventtype != EVENT_RECOVERED) &&
3670 3673 eventtype != EVENT_DEVICE_INACCESSIBLE) {
3671 3674 buf += snprintf(buf, bufend - buf, " - %d degC",
3672 3675 (int8_t)event->ev_detail);
3673 3676 }
3674 3677 break;
3675 3678 case EVENT_SUBSYS_FAN:
3676 3679 if (eventtype == EVENT_FAILED) {
3677 3680 buf += snprintf(buf, bufend - buf,
3678 3681 " %d%%", event->ev_detail);
3679 3682 }
3680 3683 break;
3681 3684 case EVENT_SUBSYS_LOM:
3682 3685 switch (eventtype) {
3683 3686 case EVENT_FLASH_DOWNLOAD:
3684 3687 buf += snprintf(buf, bufend - buf,
3685 3688 ": v%d.%d to v%d.%d",
3686 3689 (event->ev_resource >> 4),
3687 3690 (event->ev_resource & 0x0f),
3688 3691 (event->ev_detail >> 4),
3689 3692 (event->ev_detail & 0x0f));
3690 3693 break;
3691 3694 case EVENT_WATCHDOG_TRIGGER:
3692 3695 buf += snprintf(buf, bufend - buf,
3693 3696 event->ev_detail ? "- soft" : " - hard");
3694 3697 break;
3695 3698 case EVENT_UNEXPECTED_RESET:
3696 3699 if (event->ev_detail &
3697 3700 LOM_UNEXPECTEDRESET_MASK_BADTRAP) {
3698 3701 buf += snprintf(buf, bufend - buf,
3699 3702 " - unclaimed exception 0x%x",
3700 3703 event->ev_detail &
3701 3704 ~LOM_UNEXPECTEDRESET_MASK_BADTRAP);
3702 3705 }
3703 3706 break;
3704 3707 case EVENT_RESET:
3705 3708 switch (event->ev_detail) {
3706 3709 case LOM_RESET_DETAIL_BYUSER:
3707 3710 buf += snprintf(buf, bufend - buf, " by user");
3708 3711 break;
3709 3712 case LOM_RESET_DETAIL_REPROGRAMMING:
3710 3713 buf += snprintf(buf, bufend - buf,
3711 3714 " after flash download");
3712 3715 break;
3713 3716 default:
3714 3717 buf += snprintf(buf, bufend - buf,
3715 3718 " - unknown reason");
3716 3719 break;
3717 3720 }
3718 3721 break;
3719 3722 default:
3720 3723 break;
3721 3724 }
3722 3725 break;
3723 3726 case EVENT_SUBSYS_LED:
3724 3727 switch (event->ev_detail) {
3725 3728 case LOM_LED_STATE_OFF:
3726 3729 buf += snprintf(buf, bufend - buf, ": OFF");
3727 3730 break;
3728 3731 case LOM_LED_STATE_ON_STEADY:
3729 3732 buf += snprintf(buf, bufend - buf, ": ON");
3730 3733 break;
3731 3734 case LOM_LED_STATE_ON_FLASHING:
3732 3735 case LOM_LED_STATE_ON_SLOWFLASH:
3733 3736 buf += snprintf(buf, bufend - buf, ": BLINKING");
3734 3737 break;
3735 3738 case LOM_LED_STATE_INACCESSIBLE:
3736 3739 buf += snprintf(buf, bufend - buf, ": inaccessible");
3737 3740 break;
3738 3741 case LOM_LED_STATE_STANDBY:
3739 3742 buf += snprintf(buf, bufend - buf, ": standby");
3740 3743 break;
3741 3744 case LOM_LED_STATE_NOT_PRESENT:
3742 3745 buf += snprintf(buf, bufend - buf, ": not present");
3743 3746 break;
3744 3747 default:
3745 3748 buf += snprintf(buf, bufend - buf, ": 0x%x",
3746 3749 event->ev_resource);
3747 3750 break;
3748 3751 }
3749 3752 break;
3750 3753 case EVENT_SUBSYS_USER:
3751 3754 switch (eventtype) {
3752 3755 case EVENT_USER_ADDED:
3753 3756 case EVENT_USER_REMOVED:
3754 3757 case EVENT_USER_PERMSCHANGED:
3755 3758 case EVENT_USER_LOGIN:
3756 3759 case EVENT_USER_PASSWORD_CHANGE:
3757 3760 case EVENT_USER_LOGINFAIL:
3758 3761 case EVENT_USER_LOGOUT:
3759 3762 buf += snprintf(buf, bufend - buf, " %d",
3760 3763 event->ev_resource);
3761 3764 default:
3762 3765 break;
3763 3766 }
3764 3767 break;
3765 3768 case EVENT_SUBSYS_PSU:
3766 3769 if (event->ev_detail & LOM_PSU_NOACCESS) {
3767 3770 buf += snprintf(buf, bufend - buf, " - inaccessible");
3768 3771 } else if ((event->ev_detail & LOM_PSU_STATUS_MASK)
3769 3772 == LOM_PSU_STATUS_MASK) {
3770 3773 buf += snprintf(buf, bufend - buf, " - OK");
3771 3774 } else {
3772 3775 buf += snprintf(buf, bufend - buf, " -");
3773 3776 /*
3774 3777 * If both inputs are seen to have failed then simply
3775 3778 * indicate that the PSU input has failed
3776 3779 */
3777 3780 if (!(event->ev_detail &
3778 3781 (LOM_PSU_INPUT_A_OK | LOM_PSU_INPUT_B_OK))) {
3779 3782 buf += snprintf(buf, bufend - buf, " Input");
3780 3783 } else {
3781 3784 /* At least one input is ok */
3782 3785 if (!(event->ev_detail & LOM_PSU_INPUT_A_OK)) {
3783 3786 buf += snprintf(buf, bufend - buf,
3784 3787 " InA");
3785 3788 }
3786 3789 if (!(event->ev_detail & LOM_PSU_INPUT_B_OK)) {
3787 3790 buf += snprintf(buf, bufend - buf,
3788 3791 " InB");
3789 3792 }
3790 3793 /*
3791 3794 * Only flag an output error if an input is
3792 3795 * still present
3793 3796 */
3794 3797 if (!(event->ev_detail & LOM_PSU_OUTPUT_OK)) {
3795 3798 buf += snprintf(buf, bufend - buf,
3796 3799 " Output");
3797 3800 }
3798 3801 }
3799 3802 buf += snprintf(buf, bufend - buf, " failed");
3800 3803 }
3801 3804 break;
3802 3805 case EVENT_SUBSYS_NONE:
3803 3806 if (eventtype == EVENT_FAULT_LED) {
3804 3807 switch (event->ev_detail) {
3805 3808 case 0:
3806 3809 buf += snprintf(buf, bufend - buf, " - ON");
3807 3810 break;
3808 3811 case 255:
3809 3812 buf += snprintf(buf, bufend - buf, " - OFF");
3810 3813 break;
3811 3814 default:
3812 3815 buf += snprintf(buf, bufend - buf,
3813 3816 " - %dHz", event->ev_detail);
3814 3817 break;
3815 3818 }
3816 3819 }
3817 3820 break;
3818 3821 case EVENT_SUBSYS_HOST:
3819 3822 if (eventtype == EVENT_BOOTMODE_CHANGE) {
3820 3823 switch (event->ev_detail &
3821 3824 ~EBUS_BOOTMODE_FORCE_CONSOLE) {
3822 3825 case EBUS_BOOTMODE_FORCE_NOBOOT:
3823 3826 buf += snprintf(buf, bufend - buf,
3824 3827 " - no boot");
3825 3828 break;
3826 3829 case EBUS_BOOTMODE_RESET_DEFAULT:
3827 3830 buf += snprintf(buf, bufend - buf,
3828 3831 " - reset defaults");
3829 3832 break;
3830 3833 case EBUS_BOOTMODE_FULLDIAG:
3831 3834 buf += snprintf(buf, bufend - buf,
3832 3835 " - full diag");
3833 3836 break;
3834 3837 case EBUS_BOOTMODE_SKIPDIAG:
3835 3838 buf += snprintf(buf, bufend - buf,
3836 3839 " - skip diag");
3837 3840 break;
3838 3841 default:
3839 3842 break;
3840 3843 }
3841 3844 }
3842 3845 if (eventtype == EVENT_SCC_STATUS) {
3843 3846 switch (event->ev_detail) {
3844 3847 case 0:
3845 3848 buf += snprintf(buf, bufend - buf,
3846 3849 " - inserted");
3847 3850 break;
3848 3851 case 1:
3849 3852 buf += snprintf(buf, bufend - buf,
3850 3853 " - removed");
3851 3854 break;
3852 3855 default:
3853 3856 break;
3854 3857 }
3855 3858 }
3856 3859 break;
3857 3860
3858 3861 default:
3859 3862 break;
3860 3863 }
3861 3864
3862 3865 /* shutd */
3863 3866 if (event->ev_subsys & EVENT_MASK_SHUTDOWN_REQD) {
3864 3867 buf += snprintf(buf, bufend - buf, " - shutdown req'd");
3865 3868 }
3866 3869
3867 3870 buf += snprintf(buf, bufend - buf, "\n");
3868 3871
3869 3872 if (buf >= bufend) {
3870 3873 /* Ensure newline at end of string */
3871 3874 bufend[-2] = '\n';
3872 3875 bufend[-1] = '\0';
3873 3876 #ifdef DEBUG
3874 3877 cmn_err(CE_WARN, "!bscv_build_eventstring: buffer too small!");
3875 3878 #endif /* DEBUG */
3876 3879 }
3877 3880 }
3878 3881
3879 3882 /*
3880 3883 * function - bscv_level_of_event
3881 3884 * description - This routine determines which level an event should be
3882 3885 * reported at.
3883 3886 * inputs - lom event structure pointer
3884 3887 * outputs - event level.
3885 3888 */
3886 3889 static int
3887 3890 bscv_level_of_event(lom_event_t *event)
3888 3891 {
3889 3892 int level;
3890 3893 /*
3891 3894 * This is the same criteria that the firmware uses except we
3892 3895 * log the fault led on as being EVENT_LEVEL_FAULT
3893 3896 */
3894 3897 if (EVENT_DECODE_SUBSYS(event->ev_subsys) == EVENT_SUBSYS_USER) {
3895 3898 level = EVENT_LEVEL_USER;
3896 3899 } else if ((EVENT_DECODE_SUBSYS(event->ev_subsys) ==
3897 3900 EVENT_SUBSYS_ALARM) && (event->ev_event == EVENT_STATE_ON)) {
3898 3901 level = EVENT_LEVEL_FAULT;
3899 3902 } else if ((EVENT_DECODE_SUBSYS(event->ev_subsys) ==
3900 3903 EVENT_SUBSYS_NONE) &&
3901 3904 (event->ev_event == EVENT_FAULT_LED) &&
3902 3905 (event->ev_detail != 0xff)) {
3903 3906 level = EVENT_LEVEL_FAULT;
3904 3907 } else if ((EVENT_DECODE_SUBSYS(event->ev_subsys) ==
3905 3908 EVENT_SUBSYS_LOM) && event->ev_event == EVENT_TIME_REFERENCE) {
3906 3909 level = EVENT_LEVEL_NOTICE;
3907 3910 } else if (event->ev_event == EVENT_RECOVERED) {
3908 3911 /*
3909 3912 * All recovery messages need to be reported to the console
3910 3913 * because during boot, the faults which occurred whilst
3911 3914 * Solaris was not running are relayed to the console. There
3912 3915 * is a case whereby a fatal fault (eg. over temp) could
3913 3916 * have occurred and then recovered. The recovery condition
3914 3917 * needs to be reported so the user doesn't think that the
3915 3918 * failure (over temp) is still present.
3916 3919 */
3917 3920 level = EVENT_LEVEL_FAULT;
3918 3921 } else if (EVENT_DECODE_FAULT(event->ev_subsys) == 0) {
3919 3922 /* None of FAULT, FATAL or SHUTDOWN REQD are set */
3920 3923 level = EVENT_LEVEL_NOTICE;
3921 3924 } else if (EVENT_DECODE_FAULT(event->ev_subsys) == EVENT_MASK_FAULT) {
3922 3925 /* Only FAULT set i.e not FATAL or SHUTDOWN REQD */
3923 3926 level = EVENT_LEVEL_FAULT;
3924 3927 } else {
3925 3928 level = EVENT_LEVEL_FATAL;
3926 3929 }
3927 3930
3928 3931 return (level);
3929 3932 }
3930 3933
3931 3934 /*
3932 3935 * function - bscv_status
3933 3936 * description - This routine is called when any change in the LOMlite2 status
3934 3937 * is indicated by the status registers.
3935 3938 *
3936 3939 * inputs - LOM soft state structure pointer
3937 3940 *
3938 3941 * outputs - none.
3939 3942 */
3940 3943 static void
3941 3944 bscv_status(bscv_soft_state_t *ssp, uint8_t state_chng, uint8_t dev_no)
3942 3945 {
3943 3946 int8_t temp;
3944 3947 uint8_t fanspeed;
3945 3948
3946 3949 ASSERT(bscv_held(ssp));
3947 3950
3948 3951 BSCV_TRACE(ssp, 'D', "bscv_status", "state_chng 0x%x dev_no 0x%x",
3949 3952 state_chng, dev_no);
3950 3953
3951 3954 /*
3952 3955 * The device that has changed is given by the state change
3953 3956 * register and the event detail register so react
3954 3957 * accordingly.
3955 3958 */
3956 3959
3957 3960 if (state_chng == EBUS_STATE_NOTIFY) {
3958 3961 /*
3959 3962 * The BSC is indicating a self state change
3960 3963 */
3961 3964 if (dev_no == EBUS_DETAIL_FLASH) {
3962 3965 ssp->cssp_prog = B_TRUE;
3963 3966 BSCV_TRACE(ssp, 'D', "bscv_status",
3964 3967 "ssp->cssp_prog changed to 0x%x",
3965 3968 ssp->cssp_prog);
3966 3969 /*
3967 3970 * It takes the BSC at least 100 ms to
3968 3971 * clear down the comms protocol.
3969 3972 * We back-off from talking to the
3970 3973 * BSC during this period.
3971 3974 */
3972 3975 delay(BSC_EVENT_POLL_NORMAL);
3973 3976 BSCV_TRACE(ssp, 'D', "bscv_status",
3974 3977 "completed delay");
3975 3978 } else if (dev_no == EBUS_DETAIL_RESET) {
3976 3979 /*
3977 3980 * The bsc has reset
3978 3981 */
3979 3982 BSCV_TRACE(ssp, 'D', "bscv_status",
3980 3983 "BSC reset occured, re-synching");
3981 3984 (void) bscv_attach_common(ssp);
3982 3985 BSCV_TRACE(ssp, 'D', "bscv_status",
3983 3986 "completed attach_common");
3984 3987 }
3985 3988
3986 3989 }
3987 3990
3988 3991 if ((state_chng & EBUS_STATE_FAN) && ((dev_no - 1) < MAX_FANS)) {
3989 3992 fanspeed = bscv_get8(ssp, chan_general,
3990 3993 EBUS_IDX_FAN1_SPEED + dev_no - 1);
3991 3994 /*
3992 3995 * Only remember fanspeeds which are real values or
3993 3996 * NOT PRESENT values.
3994 3997 */
3995 3998 if ((fanspeed <= LOM_FAN_MAX_SPEED) ||
3996 3999 (fanspeed == LOM_FAN_NOT_PRESENT)) {
3997 4000 ssp->fanspeed[dev_no - 1] = fanspeed;
3998 4001 }
3999 4002 }
4000 4003
4001 4004 if ((state_chng & EBUS_STATE_PSU) && ((dev_no - 1) < MAX_PSUS)) {
4002 4005 (void) bscv_get8(ssp, chan_general,
4003 4006 EBUS_IDX_PSU1_STAT + dev_no - 1);
4004 4007 }
4005 4008
4006 4009 if (state_chng & EBUS_STATE_GP) {
4007 4010 (void) bscv_get8(ssp, chan_general, EBUS_IDX_GPIP);
4008 4011 }
4009 4012
4010 4013 if (state_chng & EBUS_STATE_CB) {
4011 4014 (void) bscv_get8(ssp, chan_general, EBUS_IDX_CBREAK_STATUS);
4012 4015 }
4013 4016
4014 4017 if ((state_chng & EBUS_STATE_TEMPERATURE) &&
4015 4018 ((dev_no - 1) < MAX_TEMPS)) {
4016 4019 temp = bscv_get8(ssp, chan_general,
4017 4020 EBUS_IDX_TEMP1 + dev_no - 1);
4018 4021 /*
4019 4022 * Only remember temperatures which are real values or
4020 4023 * a NOT PRESENT value.
4021 4024 */
4022 4025 if ((temp <= LOM_TEMP_MAX_VALUE) ||
4023 4026 (temp == LOM_TEMP_STATE_NOT_PRESENT)) {
4024 4027 ssp->temps.temp[dev_no - 1] = temp;
4025 4028 }
4026 4029 }
4027 4030
4028 4031 if (state_chng & EBUS_STATE_RAIL) {
4029 4032 (void) bscv_get8(ssp, chan_general, EBUS_IDX_SUPPLY_LO);
4030 4033 (void) bscv_get8(ssp, chan_general, EBUS_IDX_SUPPLY_HI);
4031 4034 }
4032 4035 }
4033 4036
4034 4037 char *
4035 4038 bscv_get_label(char labels[][MAX_LOM2_NAME_STR], int limit, int index)
4036 4039 {
4037 4040
4038 4041 if (labels == NULL)
4039 4042 return ("");
4040 4043
4041 4044 if (limit < 0 || index < 0 || index > limit)
4042 4045 return ("-");
4043 4046
4044 4047 return (labels[index]);
4045 4048 }
4046 4049
4047 4050 static void
4048 4051 bscv_generic_sysevent(bscv_soft_state_t *ssp, char *class, char *subclass,
4049 4052 char *fru_id, char *res_id, int32_t fru_state, char *msg)
4050 4053 {
4051 4054 int rv;
4052 4055 nvlist_t *attr_list;
4053 4056
4054 4057 BSCV_TRACE(ssp, 'E', "bscv_generic_sysevent", "%s/%s:(%s,%s,%d) %s",
4055 4058 class, subclass, fru_id, res_id, fru_state, msg);
4056 4059
4057 4060
4058 4061 if (nvlist_alloc(&attr_list, NV_UNIQUE_NAME_TYPE, KM_SLEEP)) {
4059 4062 BSCV_TRACE(ssp, 'E', "bscv_generic_sysevent",
4060 4063 "nvlist alloc failure");
4061 4064 return;
4062 4065 }
4063 4066 if (nvlist_add_uint32(attr_list, ENV_VERSION, 1)) {
4064 4067 BSCV_TRACE(ssp, 'E', "bscv_generic_sysevent",
4065 4068 "nvlist ENV_VERSION failure");
4066 4069 nvlist_free(attr_list);
4067 4070 return;
4068 4071 }
4069 4072 if (nvlist_add_string(attr_list, ENV_FRU_ID, fru_id)) {
4070 4073 BSCV_TRACE(ssp, 'E', "bscv_generic_sysevent",
4071 4074 "nvlist ENV_FRU_ID failure");
4072 4075 nvlist_free(attr_list);
4073 4076 return;
4074 4077 }
4075 4078 if (nvlist_add_string(attr_list, ENV_FRU_RESOURCE_ID, res_id)) {
4076 4079 BSCV_TRACE(ssp, 'E', "bscv_generic_sysevent",
4077 4080 "nvlist ENV_FRU_RESOURCE_ID failure");
4078 4081 nvlist_free(attr_list);
4079 4082 return;
4080 4083 }
4081 4084 if (nvlist_add_string(attr_list, ENV_FRU_DEVICE, ENV_RESERVED_ATTR)) {
4082 4085 BSCV_TRACE(ssp, 'E', "bscv_generic_sysevent",
4083 4086 "nvlist ENV_FRU_DEVICE failure");
4084 4087 nvlist_free(attr_list);
4085 4088 return;
4086 4089 }
4087 4090 if (nvlist_add_int32(attr_list, ENV_FRU_STATE, fru_state)) {
4088 4091 BSCV_TRACE(ssp, 'E', "bscv_generic_sysevent",
4089 4092 "nvlist ENV_FRU_STATE failure");
4090 4093 nvlist_free(attr_list);
4091 4094 return;
4092 4095 }
4093 4096 if (nvlist_add_string(attr_list, ENV_MSG, msg)) {
4094 4097 BSCV_TRACE(ssp, 'E', "bscv_generic_sysevent",
4095 4098 "nvlist ENV_MSG failure");
4096 4099 nvlist_free(attr_list);
4097 4100 return;
4098 4101 }
4099 4102
4100 4103 rv = ddi_log_sysevent(ssp->dip, DDI_VENDOR_SUNW, class,
4101 4104 subclass, attr_list, NULL, DDI_SLEEP);
4102 4105
4103 4106 if (rv == DDI_SUCCESS) {
4104 4107 BSCV_TRACE(ssp, 'E', "bscv_generic_sysevent", "sent sysevent");
4105 4108 } else {
4106 4109 cmn_err(CE_WARN, "!cannot deliver sysevent");
4107 4110 }
4108 4111
4109 4112 nvlist_free(attr_list);
4110 4113 }
4111 4114
4112 4115 /*
4113 4116 * function - bscv_sysevent
4114 4117 * description - send out a sysevent on the given change if needed
4115 4118 * inputs - soft state pointer, event to report
4116 4119 * outputs - none
4117 4120 */
4118 4121
4119 4122 static void
4120 4123 bscv_sysevent(bscv_soft_state_t *ssp, lom_event_t *event)
4121 4124 {
4122 4125 char *class = NULL;
4123 4126 char *subclass = NULL;
4124 4127 char *fru_id = "Blade"; /* The blade is only one FRU */
4125 4128 char *res_id;
4126 4129 int32_t fru_state = 0;
4127 4130
4128 4131 BSCV_TRACE(ssp, 'E', "bscv_sysevent", "processing event");
4129 4132
4130 4133 ASSERT(event != NULL);
4131 4134
4132 4135 /* Map ev_subsys to sysevent class/sub-class */
4133 4136
4134 4137 switch (EVENT_DECODE_SUBSYS(event->ev_subsys)) {
4135 4138 case EVENT_SUBSYS_NONE:
4136 4139 break;
4137 4140 case EVENT_SUBSYS_ALARM:
4138 4141 break;
4139 4142 case EVENT_SUBSYS_TEMP:
4140 4143 class = EC_ENV, subclass = ESC_ENV_TEMP;
4141 4144 res_id = bscv_get_label(ssp->temps.name, ssp->temps.num,
4142 4145 event->ev_resource - 1);
4143 4146 switch (event->ev_event) {
4144 4147 case EVENT_SEVERE_OVERHEAT:
4145 4148 fru_state = ENV_FAILED;
4146 4149 break;
4147 4150 case EVENT_OVERHEAT:
4148 4151 fru_state = ENV_WARNING;
4149 4152 break;
4150 4153 case EVENT_NO_OVERHEAT:
4151 4154 fru_state = ENV_OK;
4152 4155 break;
4153 4156 default:
4154 4157 return;
4155 4158 }
4156 4159 break;
4157 4160 case EVENT_SUBSYS_OVERTEMP:
4158 4161 break;
4159 4162 case EVENT_SUBSYS_FAN:
4160 4163 class = EC_ENV, subclass = ESC_ENV_FAN;
4161 4164 res_id = bscv_get_label(ssp->fan_names, ssp->num_fans,
4162 4165 event->ev_resource - 1);
4163 4166 switch (event->ev_event) {
4164 4167 case EVENT_FAILED:
4165 4168 fru_state = ENV_FAILED;
4166 4169 break;
4167 4170 case EVENT_RECOVERED:
4168 4171 fru_state = ENV_OK;
4169 4172 break;
4170 4173 default:
4171 4174 return;
4172 4175 }
4173 4176 break;
4174 4177 case EVENT_SUBSYS_SUPPLY:
4175 4178 class = EC_ENV, subclass = ESC_ENV_POWER;
4176 4179 res_id = bscv_get_label(ssp->sflags.name, ssp->sflags.num,
4177 4180 event->ev_resource - 1);
4178 4181 switch (event->ev_event) {
4179 4182 case EVENT_FAILED:
4180 4183 fru_state = ENV_FAILED;
4181 4184 break;
4182 4185 case EVENT_RECOVERED:
4183 4186 fru_state = ENV_OK;
4184 4187 break;
4185 4188 default:
4186 4189 return;
4187 4190 }
4188 4191 break;
4189 4192 case EVENT_SUBSYS_BREAKER:
4190 4193 break;
4191 4194 case EVENT_SUBSYS_PSU:
4192 4195 break;
4193 4196 case EVENT_SUBSYS_USER:
4194 4197 break;
4195 4198 case EVENT_SUBSYS_PHONEHOME:
4196 4199 break;
4197 4200 case EVENT_SUBSYS_LOM:
4198 4201 break;
4199 4202 case EVENT_SUBSYS_HOST:
4200 4203 break;
4201 4204 case EVENT_SUBSYS_EVENTLOG:
4202 4205 break;
4203 4206 case EVENT_SUBSYS_EXTRA:
4204 4207 break;
4205 4208 case EVENT_SUBSYS_LED:
4206 4209 if (event->ev_event != EVENT_FAULT_LED &&
4207 4210 event->ev_event != EVENT_STATE_CHANGE)
4208 4211 return;
4209 4212 /*
4210 4213 * There are 3 LEDs : Power, Service, Ready-to-Remove on a
4211 4214 * JBOS blade. We'll never report the Power since Solaris
4212 4215 * won't be running when it is _switched_ ON. Ready-to-Remove
4213 4216 * will only be lit when we're powered down which also means
4214 4217 * Solaris won't be running. We don't want to report it
4215 4218 * during system testing / Sun VTS exercising the LEDs.
4216 4219 *
4217 4220 * Therefore, we only report the Service Required LED.
4218 4221 */
4219 4222 class = EC_ENV, subclass = ESC_ENV_LED;
4220 4223 res_id = bscv_get_label(ssp->led_names, MAX_LED_ID,
4221 4224 event->ev_resource - 1);
4222 4225
4223 4226 switch (event->ev_detail) {
4224 4227 case LOM_LED_STATE_ON_STEADY:
4225 4228 fru_state = ENV_LED_ON;
4226 4229 break;
4227 4230 case LOM_LED_STATE_ON_FLASHING:
4228 4231 case LOM_LED_STATE_ON_SLOWFLASH:
4229 4232 fru_state = ENV_LED_BLINKING;
4230 4233 break;
4231 4234 case LOM_LED_STATE_OFF:
4232 4235 fru_state = ENV_LED_OFF;
4233 4236 break;
4234 4237 case LOM_LED_STATE_INACCESSIBLE:
4235 4238 fru_state = ENV_LED_INACCESSIBLE;
4236 4239 break;
4237 4240 case LOM_LED_STATE_STANDBY:
4238 4241 fru_state = ENV_LED_STANDBY;
4239 4242 break;
4240 4243 case LOM_LED_STATE_NOT_PRESENT:
4241 4244 fru_state = ENV_LED_NOT_PRESENT;
4242 4245 break;
4243 4246 default:
4244 4247 fru_state = ENV_LED_INACCESSIBLE;
4245 4248 break;
4246 4249 }
4247 4250 break;
4248 4251 default :
4249 4252 break;
4250 4253 }
4251 4254
4252 4255 if (class == NULL || subclass == NULL) {
4253 4256 BSCV_TRACE(ssp, 'E', "bscv_sysevent", "class/subclass NULL");
4254 4257 return;
4255 4258 }
4256 4259
4257 4260 bscv_generic_sysevent(ssp, class, subclass, fru_id, res_id, fru_state,
4258 4261 ENV_RESERVED_ATTR);
4259 4262 }
4260 4263
4261 4264 /*
4262 4265 * *********************************************************************
4263 4266 * Firmware download (programming)
4264 4267 * *********************************************************************
4265 4268 */
4266 4269
4267 4270 /*
4268 4271 * function - bscv_prog
4269 4272 * description - LOMlite2 flash programming code.
4270 4273 *
4271 4274 * bscv_prog_image - download a complete image to the lom.
4272 4275 * bscv_prog_receive_image - receive data to build up a
4273 4276 * complete image.
4274 4277 * bscv_prog_stop_lom - pause the event daemon and prepare
4275 4278 * lom for firmware upgrade.
4276 4279 * bscv_prog_start_lom - reinit the driver/lom after upgrade
4277 4280 * and restart the event daemon
4278 4281 *
4279 4282 * inputs - soft state pointer, arg ptr, ioctl mode
4280 4283 * outputs - status
4281 4284 */
4282 4285
4283 4286 static int
4284 4287 bscv_prog(bscv_soft_state_t *ssp, intptr_t arg, int mode)
4285 4288 {
4286 4289 lom_prog_t *prog;
4287 4290 int res = 0;
4288 4291
4289 4292 /*
4290 4293 * We will get repeatedly called with bits of data first for
4291 4294 * loader, then for main image.
4292 4295 */
4293 4296 prog = (lom_prog_t *)kmem_alloc(sizeof (lom_prog_t), KM_SLEEP);
4294 4297
4295 4298 if (ddi_copyin((caddr_t)arg, (caddr_t)prog, sizeof (*prog),
4296 4299 mode) < 0) {
4297 4300 kmem_free((void *)prog, sizeof (*prog));
4298 4301 return (EFAULT);
4299 4302 }
4300 4303
4301 4304 BSCV_TRACE(ssp, 'U', "bscv_prog",
4302 4305 "index 0x%x size 0x%x", prog->index, prog->size);
4303 4306
4304 4307 mutex_enter(&ssp->prog_mu);
4305 4308 if (prog->size == 0) {
4306 4309 if (prog->index == 2) {
4307 4310 /*
4308 4311 * This is the initial request for the chip type so we
4309 4312 * know what we are programming.
4310 4313 * The type will have been read in at init so just
4311 4314 * return it in data[0].
4312 4315 */
4313 4316 prog->data[0] = bscv_get8_cached(ssp,
4314 4317 EBUS_IDX_CPU_IDENT);
4315 4318
4316 4319 if (ddi_copyout((caddr_t)prog, (caddr_t)arg,
4317 4320 sizeof (lom_prog_t), mode) < 0) {
4318 4321 res = EFAULT;
4319 4322 }
4320 4323 } else if (prog->index == 0) {
4321 4324 res = bscv_prog_stop_lom(ssp);
4322 4325 } else if (prog->index == 1) {
4323 4326 res = bscv_prog_start_lom(ssp);
4324 4327 } else {
4325 4328 res = EINVAL;
4326 4329 }
4327 4330 } else {
4328 4331 if (ssp->image == NULL) {
4329 4332 ssp->image = (uint8_t *)kmem_zalloc(
4330 4333 BSC_IMAGE_MAX_SIZE, KM_SLEEP);
4331 4334 }
4332 4335 res = bscv_prog_receive_image(ssp, prog,
4333 4336 ssp->image, BSC_IMAGE_MAX_SIZE);
4334 4337 }
4335 4338 mutex_exit(&ssp->prog_mu);
4336 4339 kmem_free((void *)prog, sizeof (lom_prog_t));
4337 4340
4338 4341 return (res);
4339 4342 }
4340 4343
4341 4344 static int
4342 4345 bscv_check_loader_config(bscv_soft_state_t *ssp, boolean_t is_image2)
4343 4346 {
4344 4347 BSCV_TRACE(ssp, 'U', "bscv_check_loader_config",
4345 4348 "loader_running %d, is_image2 %d",
4346 4349 ssp->loader_running, is_image2);
4347 4350
4348 4351 /*
4349 4352 * loader_running TRUE means that we have told the microcontroller to
4350 4353 * JUMP into the loader code which has been downloaded into its RAM.
4351 4354 * At this point its an error to try and download another loader. We
4352 4355 * should be downloading the actual image at this point.
4353 4356 * Conversely, it is an error to download an image when the loader is
4354 4357 * not already downloaded and the microcontroller hasn't JUMPed into it.
4355 4358 * is_image2 TRUE means the image is being downloaded.
4356 4359 * is_image2 FALSE means the loader is being downloaded.
4357 4360 */
4358 4361 if (ssp->loader_running && !is_image2) {
4359 4362 cmn_err(CE_WARN, "Attempt to download loader image "
4360 4363 "with loader image already active");
4361 4364 cmn_err(CE_CONT, "This maybe an attempt to restart a "
4362 4365 "failed firmware download - ignoring download attempt");
4363 4366 return (B_FALSE);
4364 4367 } else if (!ssp->loader_running && is_image2) {
4365 4368 cmn_err(CE_WARN, "Attempt to download firmware image "
4366 4369 "without loader image active");
4367 4370 return (B_FALSE);
4368 4371
4369 4372 }
4370 4373
4371 4374 return (B_TRUE);
4372 4375 }
4373 4376
4374 4377 static uint32_t
4375 4378 bscv_get_pagesize(bscv_soft_state_t *ssp)
4376 4379 {
4377 4380 uint32_t pagesize;
4378 4381
4379 4382 ASSERT(bscv_held(ssp));
4380 4383
4381 4384 pagesize = bscv_get32(ssp, chan_prog,
4382 4385 BSCVA(EBUS_CMD_SPACE_PROGRAM, EBUS_PROGRAM_PAGE0));
4383 4386
4384 4387 BSCV_TRACE(ssp, 'U', "bscv_get_pagesize", "pagesize 0x%x", pagesize);
4385 4388
4386 4389 return (pagesize);
4387 4390 }
4388 4391
4389 4392 /*
4390 4393 * Sets the pagesize, returning the old value.
4391 4394 */
4392 4395 static uint32_t
4393 4396 bscv_set_pagesize(bscv_soft_state_t *ssp, uint32_t pagesize)
4394 4397 {
4395 4398 uint32_t old_pagesize;
4396 4399
4397 4400 ASSERT(bscv_held(ssp));
4398 4401
4399 4402 old_pagesize = bscv_get_pagesize(ssp);
4400 4403
4401 4404 /*
4402 4405 * The microcontroller remembers this value until until someone
4403 4406 * changes it.
4404 4407 */
4405 4408 bscv_put32(ssp, chan_prog,
4406 4409 BSCVA(EBUS_CMD_SPACE_PROGRAM, EBUS_PROGRAM_PSIZ0), pagesize);
4407 4410
4408 4411 return (old_pagesize);
4409 4412 }
4410 4413
4411 4414 static uint8_t
4412 4415 bscv_enter_programming_mode(bscv_soft_state_t *ssp)
4413 4416 {
4414 4417 uint8_t retval;
4415 4418
4416 4419 ASSERT(bscv_held(ssp));
4417 4420
4418 4421 bscv_put8(ssp, chan_prog,
4419 4422 BSCVA(EBUS_CMD_SPACE_PROGRAM, EBUS_PROGRAM_PCSR),
4420 4423 EBUS_PROGRAM_PCR_PRGMODE_ON);
4421 4424
4422 4425 retval = bscv_get8(ssp, chan_prog, BSCVA(EBUS_CMD_SPACE_PROGRAM,
4423 4426 EBUS_PROGRAM_PCSR));
4424 4427
4425 4428 return (retval);
4426 4429 }
4427 4430
4428 4431 static void
4429 4432 bscv_leave_programming_mode(bscv_soft_state_t *ssp, boolean_t with_jmp)
4430 4433 {
4431 4434 uint8_t reg;
4432 4435 ASSERT(bscv_held(ssp));
4433 4436
4434 4437 if (with_jmp) {
4435 4438 reg = EBUS_PROGRAM_PCR_PROGOFF_JUMPTOADDR;
4436 4439 BSCV_TRACE(ssp, 'U', "bscv_leave_programming_mode",
4437 4440 "jumptoaddr");
4438 4441 } else {
4439 4442 reg = EBUS_PROGRAM_PCR_PRGMODE_OFF;
4440 4443 BSCV_TRACE(ssp, 'U', "bscv_leave_programming_mode",
4441 4444 "prgmode_off");
4442 4445 }
4443 4446
4444 4447 bscv_put8(ssp, chan_prog,
4445 4448 BSCVA(EBUS_CMD_SPACE_PROGRAM, EBUS_PROGRAM_PCSR), reg);
4446 4449 }
4447 4450
4448 4451
4449 4452 static void
4450 4453 bscv_set_jump_to_addr(bscv_soft_state_t *ssp, uint32_t loadaddr)
4451 4454 {
4452 4455 ASSERT(bscv_held(ssp));
4453 4456
4454 4457 bscv_put32(ssp, chan_prog,
4455 4458 BSCVA(EBUS_CMD_SPACE_PROGRAM, EBUS_PROGRAM_PADR0), loadaddr);
4456 4459
4457 4460 BSCV_TRACE(ssp, 'U', "bscv_set_jump_to_addr",
4458 4461 "set jump to loadaddr 0x%x", loadaddr);
4459 4462 }
4460 4463
4461 4464 static uint8_t
4462 4465 bscv_erase_once(bscv_soft_state_t *ssp, uint32_t loadaddr, uint32_t image_size)
4463 4466 {
4464 4467 uint8_t retval;
4465 4468
4466 4469 ASSERT(bscv_held(ssp));
4467 4470
4468 4471 /*
4469 4472 * write PADR, PSIZ to define area to be erased
4470 4473 * We do not send erase for zero size because the current
4471 4474 * downloader gets this wrong
4472 4475 */
4473 4476
4474 4477 /*
4475 4478 * start at 0
4476 4479 */
4477 4480 BSCV_TRACE(ssp, 'U', "bscv_erase_once", "sending erase command");
4478 4481
4479 4482 bscv_put32(ssp, chan_prog,
4480 4483 BSCVA(EBUS_CMD_SPACE_PROGRAM, EBUS_PROGRAM_PADR0),
4481 4484 loadaddr);
4482 4485
4483 4486 /* set PSIZ to full size of image to be programmed */
4484 4487 bscv_put32(ssp, chan_prog,
4485 4488 BSCVA(EBUS_CMD_SPACE_PROGRAM, EBUS_PROGRAM_PSIZ0),
4486 4489 image_size);
4487 4490
4488 4491 /* write ERASE to PCSR */
4489 4492 bscv_put8(ssp, chan_prog,
4490 4493 BSCVA(EBUS_CMD_SPACE_PROGRAM, EBUS_PROGRAM_PCSR),
4491 4494 EBUS_PROGRAM_PCR_ERASE);
4492 4495
4493 4496 /* read PCSR to check status */
4494 4497 retval = bscv_get8(ssp, chan_prog,
4495 4498 BSCVA(EBUS_CMD_SPACE_PROGRAM, EBUS_PROGRAM_PCSR));
4496 4499 return (retval);
4497 4500 }
4498 4501
4499 4502 static uint8_t
4500 4503 bscv_do_erase(bscv_soft_state_t *ssp, uint32_t loadaddr, uint32_t image_size,
4501 4504 boolean_t is_image2)
4502 4505 {
4503 4506 int retryable = BSC_ERASE_RETRY_LIMIT;
4504 4507 uint8_t retval;
4505 4508
4506 4509 while (retryable--) {
4507 4510 retval = bscv_erase_once(ssp, loadaddr, image_size);
4508 4511 if (PSR_SUCCESS(retval))
4509 4512 break;
4510 4513 else
4511 4514 cmn_err(CE_WARN, "erase error 0x%x, attempt %d"
4512 4515 ", base 0x%x, size 0x%x, %s image",
4513 4516 retval, BSC_ERASE_RETRY_LIMIT - retryable,
4514 4517 loadaddr, image_size,
4515 4518 is_image2 ? "main" : "loader");
4516 4519 }
4517 4520
4518 4521 return (retval);
4519 4522 }
4520 4523
4521 4524 static uint8_t
4522 4525 bscv_set_page(bscv_soft_state_t *ssp, uint32_t addr)
4523 4526 {
4524 4527 uint32_t retval;
4525 4528 int retryable = BSC_PAGE_RETRY_LIMIT;
4526 4529
4527 4530 ASSERT(bscv_held(ssp));
4528 4531
4529 4532 while (retryable--) {
4530 4533
4531 4534 /*
4532 4535 * Write the page address and read it back for confirmation.
4533 4536 */
4534 4537 bscv_put32(ssp, chan_prog,
4535 4538 BSCVA(EBUS_CMD_SPACE_PROGRAM, EBUS_PROGRAM_PADR0),
4536 4539 addr);
4537 4540 retval = bscv_get32(ssp, chan_prog,
4538 4541 BSCVA(EBUS_CMD_SPACE_PROGRAM, EBUS_PROGRAM_PADR0));
4539 4542
4540 4543 if (retval == addr)
4541 4544 break;
4542 4545 else {
4543 4546 cmn_err(CE_WARN, "programmming error, attempt %d, "
4544 4547 "set page 0x%x, read back 0x%x",
4545 4548 BSC_PAGE_RETRY_LIMIT - retryable,
4546 4549 addr, retval);
4547 4550 }
4548 4551 }
4549 4552 return ((addr == retval) ? EBUS_PROGRAM_PSR_SUCCESS :
4550 4553 EBUS_PROGRAM_PSR_INVALID_OPERATION);
4551 4554 }
4552 4555
4553 4556 static uint8_t
4554 4557 bscv_do_page_data_once(bscv_soft_state_t *ssp, uint32_t index,
4555 4558 uint32_t image_size, uint32_t pagesize, uint8_t *imagep,
4556 4559 uint16_t *calcd_chksum)
4557 4560 {
4558 4561 uint32_t size;
4559 4562 uint16_t chksum;
4560 4563 int i;
4561 4564 uint8_t retval;
4562 4565
4563 4566 ASSERT(bscv_held(ssp));
4564 4567
4565 4568 BSCV_TRACE(ssp, 'P', "bscv_do_page_data_once", "index 0x%x", index);
4566 4569
4567 4570 /* write PSIZ bytes to PDAT */
4568 4571 if (index + pagesize < image_size) {
4569 4572 bscv_rep_rw8(ssp, chan_prog, imagep + index,
4570 4573 BSCVA(EBUS_CMD_SPACE_PROGRAM, EBUS_PROGRAM_DATA),
4571 4574 pagesize, DDI_DEV_NO_AUTOINCR, B_TRUE /* write */);
4572 4575 size = pagesize;
4573 4576 } else {
4574 4577 BSCV_TRACE(ssp, 'P', "bscv_do_page_once",
4575 4578 "Sending last block, last 0x%x bytes",
4576 4579 (image_size % pagesize));
4577 4580 size = (image_size - index);
4578 4581 bscv_rep_rw8(ssp, chan_prog, imagep + index,
4579 4582 BSCVA(EBUS_CMD_SPACE_PROGRAM, EBUS_PROGRAM_DATA),
4580 4583 size, DDI_DEV_NO_AUTOINCR, B_TRUE /* write */);
4581 4584 /* Now pad the rest of the page with zeros */
4582 4585 for (i = size; i < pagesize; i++) {
4583 4586 bscv_put8(ssp, chan_prog,
4584 4587 BSCVA(EBUS_CMD_SPACE_PROGRAM,
4585 4588 EBUS_PROGRAM_DATA),
4586 4589 0);
4587 4590 }
4588 4591 }
4589 4592
4590 4593 /* write the checksum to PCSM */
4591 4594 chksum = 0;
4592 4595 for (i = 0; i < size; i++) {
4593 4596 chksum = ((chksum << 3) | (chksum >> 13)) ^
4594 4597 *(imagep + index + i);
4595 4598 }
4596 4599 /* Cope with non-pagesize sized bufers */
4597 4600 for (; i < pagesize; i++) {
4598 4601 chksum = ((chksum << 3) | (chksum >> 13)) ^ 0;
4599 4602 }
4600 4603 bscv_put16(ssp, chan_prog,
4601 4604 BSCVA(EBUS_CMD_SPACE_PROGRAM, EBUS_PROGRAM_PCSM0), chksum);
4602 4605
4603 4606 bscv_put8(ssp, chan_prog,
4604 4607 BSCVA(EBUS_CMD_SPACE_PROGRAM, EBUS_PROGRAM_PCSR),
4605 4608 EBUS_PROGRAM_PCR_PROGRAM);
4606 4609
4607 4610 retval = bscv_get8(ssp, chan_prog,
4608 4611 BSCVA(EBUS_CMD_SPACE_PROGRAM, EBUS_PROGRAM_PCSR));
4609 4612
4610 4613 *calcd_chksum = chksum;
4611 4614 return (retval);
4612 4615 }
4613 4616
4614 4617 static uint8_t bscv_do_page(bscv_soft_state_t *ssp, uint32_t loadaddr,
4615 4618 uint32_t index, uint32_t image_size, uint32_t pagesize, uint8_t *imagep,
4616 4619 boolean_t is_image2)
4617 4620 {
4618 4621 int retryable = BSC_PAGE_RETRY_LIMIT;
4619 4622 uint8_t retval;
4620 4623 uint16_t checksum;
4621 4624
4622 4625 BSCV_TRACE(ssp, 'P', "bscv_do_page", "index 0x%x", index);
4623 4626
4624 4627 while (retryable--) {
4625 4628 /*
4626 4629 * Set the page address (with retries). If this is not
4627 4630 * successful, then there is no point carrying on and sending
4628 4631 * the page's data since that could cause random memory
4629 4632 * corruption in the microcontroller.
4630 4633 */
4631 4634 retval = bscv_set_page(ssp, loadaddr + index);
4632 4635 if (!PSR_SUCCESS(retval)) {
4633 4636 cmn_err(CE_WARN, "programming error 0x%x, "
4634 4637 "could not setup page address 0x%x, %s image",
4635 4638 retval, loadaddr + index,
4636 4639 is_image2 ? "main" : "loader");
4637 4640 break;
4638 4641 }
4639 4642
4640 4643 /*
4641 4644 * Send down the data for the page
4642 4645 */
4643 4646
4644 4647 BSCV_TRACE(ssp, 'P', "bscv_do_page", "sending data for page");
4645 4648
4646 4649 retval = bscv_do_page_data_once(ssp, index, image_size,
4647 4650 pagesize, imagep, &checksum);
4648 4651 if (PSR_SUCCESS(retval))
4649 4652 break;
4650 4653 else
4651 4654 cmn_err(CE_WARN, "programming error 0x%x,"
4652 4655 " attempt %d, index 0x%x, checksum 0x%x, %s image",
4653 4656 retval, BSC_PAGE_RETRY_LIMIT - retryable,
4654 4657 index, checksum, is_image2 ? "main" : "loader");
4655 4658 }
4656 4659
4657 4660 BSCV_TRACE(ssp, 'U', "bscv_do_page", "Returning 0x%x for index 0x%x,"
4658 4661 " checksum 0x%x, %s image", retval, index, checksum,
4659 4662 is_image2 ? "main" : "loader");
4660 4663
4661 4664 return (retval);
4662 4665 }
4663 4666
4664 4667 static uint8_t
4665 4668 bscv_do_pages(bscv_soft_state_t *ssp, uint32_t loadaddr, uint32_t image_size,
4666 4669 uint32_t pagesize, uint8_t *imagep, boolean_t is_image2)
4667 4670 {
4668 4671 uint8_t retval;
4669 4672 uint32_t index;
4670 4673
4671 4674 BSCV_TRACE(ssp, 'P', "bscv_do_pages", "entered");
4672 4675
4673 4676 for (index = 0; index < image_size; index += pagesize) {
4674 4677 retval = bscv_do_page(ssp, loadaddr, index, image_size,
4675 4678 pagesize, imagep, is_image2);
4676 4679 if (bscv_faulty(ssp) || !PSR_SUCCESS(retval)) {
4677 4680 BSCV_TRACE(ssp, 'U', "bscv_do_pages",
4678 4681 "Failed to program lom (status 0x%x)", retval);
4679 4682 break;
4680 4683 }
4681 4684 }
4682 4685
4683 4686 return (retval);
4684 4687 }
4685 4688
4686 4689 static int
4687 4690 bscv_prog_image(bscv_soft_state_t *ssp, boolean_t is_image2,
4688 4691 uint8_t *imagep, int image_size, uint32_t loadaddr)
4689 4692 {
4690 4693 uint32_t pagesize;
4691 4694 int res = 0;
4692 4695 uint8_t retval;
4693 4696
4694 4697 BSCV_TRACE(ssp, 'U', "bscv_prog_image",
4695 4698 "image 0x%x, imagep %p, size 0x%x",
4696 4699 is_image2 ? 2 : 1, imagep, image_size);
4697 4700
4698 4701 if (!bscv_check_loader_config(ssp, is_image2))
4699 4702 /*
4700 4703 * Return no error to allow userland to continue on with
4701 4704 * downloading the image.
4702 4705 */
4703 4706 return (0);
4704 4707
4705 4708 bscv_enter(ssp);
4706 4709
4707 4710 pagesize = bscv_get_pagesize(ssp);
4708 4711
4709 4712 retval = bscv_enter_programming_mode(ssp);
4710 4713 if (bscv_faulty(ssp) || !PSR_PROG(retval)) {
4711 4714 cmn_err(CE_WARN, "lom: Failed to enter program mode, error 0x%x"
4712 4715 ", %s image", retval, is_image2 ? "main" : "loader");
4713 4716 res = EIO;
4714 4717 goto BSCV_PROG_IMAGE_END;
4715 4718 }
4716 4719 BSCV_TRACE(ssp, 'U', "bscv_prog_image", "entered programming mode");
4717 4720
4718 4721 /*
4719 4722 * Only issue an erase if we are downloading the image. The loader
4720 4723 * does not need this step.
4721 4724 */
4722 4725 if (is_image2 && (image_size != 0)) {
4723 4726 retval = bscv_do_erase(ssp, loadaddr, image_size, is_image2);
4724 4727 if (bscv_faulty(ssp) || !PSR_SUCCESS(retval)) {
4725 4728 cmn_err(CE_WARN,
4726 4729 "lom: Erase failed during programming, status 0x%x",
4727 4730 retval);
4728 4731 res = EIO;
4729 4732 goto BSCV_PROG_IMAGE_END;
4730 4733 } else {
4731 4734 BSCV_TRACE(ssp, 'U', "bscv_prog_image",
4732 4735 "erase complete - programming...");
4733 4736
4734 4737 }
4735 4738 }
4736 4739
4737 4740 (void) bscv_set_pagesize(ssp, pagesize);
4738 4741
4739 4742 retval = bscv_do_pages(ssp, loadaddr, image_size, pagesize, imagep,
4740 4743 is_image2);
4741 4744 if (bscv_faulty(ssp) || !PSR_SUCCESS(retval)) {
4742 4745 BSCV_TRACE(ssp, 'U', "bscv_prog_image",
4743 4746 "Failed to program lom (status 0x%x)", retval);
4744 4747 res = EIO;
4745 4748 goto BSCV_PROG_IMAGE_END;
4746 4749 }
4747 4750
4748 4751 BSCV_PROG_IMAGE_END:
4749 4752 if (res == 0 && !is_image2) {
4750 4753 /*
4751 4754 * We've downloaded the loader successfully. Now make the
4752 4755 * microcontroller jump to it.
4753 4756 */
4754 4757 bscv_set_jump_to_addr(ssp, loadaddr);
4755 4758 ssp->loader_running = B_TRUE;
4756 4759 bscv_leave_programming_mode(ssp, B_TRUE);
4757 4760 } else {
4758 4761 /*
4759 4762 * We've just downloaded either the loader which failed, or
4760 4763 * the image (which may or may not have been successful).
4761 4764 */
4762 4765 bscv_set_jump_to_addr(ssp, 0);
4763 4766
4764 4767 if (res != 0) {
4765 4768 BSCV_TRACE(ssp, 'U', "bscv_prog_image",
4766 4769 "got error 0x%x - leaving programming mode",
4767 4770 res);
4768 4771 cmn_err(CE_WARN, "programming error 0x%x, %s image",
4769 4772 res, is_image2 ? "main" : "loader");
4770 4773 } else {
4771 4774 BSCV_TRACE(ssp, 'U', "bscv_prog_image",
4772 4775 "programming complete - leaving programming mode");
4773 4776 }
4774 4777
4775 4778 bscv_leave_programming_mode(ssp, B_FALSE);
4776 4779 ssp->loader_running = B_FALSE;
4777 4780 }
4778 4781
4779 4782 bscv_exit(ssp);
4780 4783
4781 4784 return (res);
4782 4785 }
4783 4786
4784 4787
4785 4788 static int
4786 4789 bscv_prog_receive_image(bscv_soft_state_t *ssp, lom_prog_t *prog,
4787 4790 uint8_t *imagep, int max_size)
4788 4791 {
4789 4792 int res = 0;
4790 4793 uint_t size;
4791 4794 int32_t loadaddr;
4792 4795 lom_prog_data_t *prog_data;
4793 4796
4794 4797 if ((prog->index & 0x7FFF) != ssp->prog_index) {
4795 4798 BSCV_TRACE(ssp, 'U', "bscv_prog_receive_image",
4796 4799 "Got wrong buffer 0x%x, expected 0x%x",
4797 4800 prog->index & 0x7fff, ssp->prog_index);
4798 4801 return (EINVAL);
4799 4802 }
4800 4803
4801 4804 /*
4802 4805 * We want to get the whole image and then do the download.
4803 4806 * It is assumed the device is now in programming mode.
4804 4807 */
4805 4808
4806 4809 if ((prog->index & 0x7fff) == 0) {
4807 4810 /* Starting a new image */
4808 4811 ssp->image_ptr = 0;
4809 4812 }
4810 4813
4811 4814 if ((ssp->image_ptr + prog->size) > max_size) {
4812 4815 cmn_err(CE_WARN,
4813 4816 "lom image exceeded maximum size: got 0x%x, maximum 0x%x",
4814 4817 (ssp->image_ptr + prog->size), max_size);
4815 4818 return (EFAULT);
4816 4819 }
4817 4820 bcopy(prog->data, &imagep[ssp->image_ptr], prog->size);
4818 4821 ssp->image_ptr += prog->size;
4819 4822
4820 4823 ssp->prog_index++;
4821 4824
4822 4825 if (prog->index & 0x8000) {
4823 4826 /*
4824 4827 * OK we have the whole image so synch up and start download.
4825 4828 */
4826 4829 prog_data = (lom_prog_data_t *)imagep;
4827 4830 if (prog_data->header.magic != PROG_MAGIC) {
4828 4831 /* Old style programming data */
4829 4832 /* Take care image may not fill all of structure */
4830 4833
4831 4834 /* sign extend loadaddr from 16 to 32 bits */
4832 4835 loadaddr = (int16_t)((uint16_t)((imagep[2] << 8) +
4833 4836 imagep[3]));
4834 4837
4835 4838 size = (imagep[0] << 8) + imagep[1];
4836 4839 if (size != (ssp->image_ptr - 4)) {
4837 4840 cmn_err(CE_WARN, "Image size mismatch:"
4838 4841 " expected 0x%x, got 0x%x",
4839 4842 size, (ssp->image_ptr - 1));
4840 4843 }
4841 4844
4842 4845 res = bscv_prog_image(ssp,
4843 4846 ssp->image2_processing,
4844 4847 imagep + 4, ssp->image_ptr - 4, loadaddr);
4845 4848
4846 4849 /*
4847 4850 * Done the loading so set the flag to say we are doing
4848 4851 * the other image.
4849 4852 */
4850 4853 ssp->image2_processing = !ssp->image2_processing;
4851 4854 } else if ((ssp->image_ptr < sizeof (*prog_data)) ||
4852 4855 (prog_data->platform.bscv.size !=
4853 4856 (ssp->image_ptr - sizeof (*prog_data)))) {
4854 4857 /* Image too small for new style image */
4855 4858 cmn_err(CE_WARN, "image too small");
4856 4859 res = EINVAL;
4857 4860 } else {
4858 4861 /* New style programming image */
4859 4862 switch (prog_data->platmagic) {
4860 4863 case PROG_PLAT_BSCV_IMAGE:
4861 4864 res = bscv_prog_image(ssp, B_TRUE,
4862 4865 imagep + sizeof (*prog_data),
4863 4866 prog_data->platform.bscv.size,
4864 4867 prog_data->platform.bscv.loadaddr);
4865 4868 ssp->image2_processing = B_FALSE;
4866 4869 break;
4867 4870 case PROG_PLAT_BSCV_LOADER:
4868 4871 res = bscv_prog_image(ssp, B_FALSE,
4869 4872 imagep + sizeof (*prog_data),
4870 4873 prog_data->platform.bscv.size,
4871 4874 prog_data->platform.bscv.loadaddr);
4872 4875 ssp->image2_processing = B_TRUE;
4873 4876 break;
4874 4877 default:
4875 4878 cmn_err(CE_WARN, "unknown platmagic 0x%x",
4876 4879 prog_data->platmagic);
4877 4880 res = EINVAL;
4878 4881 break;
4879 4882 }
4880 4883 }
4881 4884 ssp->prog_index = 0;
4882 4885 ssp->image_ptr = 0;
4883 4886 }
4884 4887 return (res);
4885 4888 }
4886 4889
4887 4890 static int
4888 4891 bscv_prog_stop_lom(bscv_soft_state_t *ssp)
4889 4892 {
4890 4893 if (ssp->programming) {
4891 4894 /*
4892 4895 * Already programming - this may be a retry of a failed
4893 4896 * programming attempt or just a software error!
4894 4897 */
4895 4898 goto queue_stopped;
4896 4899 }
4897 4900
4898 4901 if (bscv_pause_event_daemon(ssp) == BSCV_FAILURE) {
4899 4902 BSCV_TRACE(ssp, 'Q', "bscv_prog_stop_lom",
4900 4903 "failed to pause event daemon thread");
4901 4904 return (EAGAIN);
4902 4905 }
4903 4906
4904 4907 bscv_enter(ssp);
4905 4908
4906 4909 ssp->programming = B_TRUE;
4907 4910
4908 4911 bscv_exit(ssp);
4909 4912
4910 4913 queue_stopped:
4911 4914
4912 4915 ssp->prog_index = 0;
4913 4916 ssp->image2_processing = B_FALSE;
4914 4917
4915 4918 return (0);
4916 4919 }
4917 4920
4918 4921 static int
4919 4922 bscv_prog_start_lom(bscv_soft_state_t *ssp)
4920 4923 {
4921 4924 int res = 0;
4922 4925
4923 4926 if (!ssp->programming) {
4924 4927 /* Not programming so this is not a valid command */
4925 4928 return (EINVAL);
4926 4929 }
4927 4930
4928 4931 if (ssp->image != NULL) {
4929 4932 kmem_free((void *)ssp->image, BSC_IMAGE_MAX_SIZE);
4930 4933 ssp->image = NULL;
4931 4934 }
4932 4935
4933 4936 /*
4934 4937 * OK we are out of reset now so:
4935 4938 * Probe the firmware and set everything up.
4936 4939 */
4937 4940
4938 4941 bscv_enter(ssp);
4939 4942
4940 4943 /* Explicit clear fault because things may have been mended now */
4941 4944 bscv_clear_fault(ssp);
4942 4945
4943 4946 if (ssp->loader_running) {
4944 4947 cmn_err(CE_WARN, "Firmware upgrade failed to exit loader - "
4945 4948 "performing forced exit");
4946 4949 /* Must try to restart the lom here. */
4947 4950 /* Ensure prog mode entry to enable PRGMODE_OFF */
4948 4951 bscv_put8(ssp, chan_prog,
4949 4952 BSCVA(EBUS_CMD_SPACE_PROGRAM, EBUS_PROGRAM_PCSR),
4950 4953 EBUS_PROGRAM_PCR_PRGMODE_ON);
4951 4954 bscv_put8(ssp, chan_prog,
4952 4955 BSCVA(EBUS_CMD_SPACE_PROGRAM, EBUS_PROGRAM_PCSR),
4953 4956 EBUS_PROGRAM_PCR_PRGMODE_OFF);
4954 4957 ssp->loader_running = B_FALSE;
4955 4958 /* give the lom chance to recover */
4956 4959 delay(drv_usectohz(5000000)); /* 5 seconds */
4957 4960 }
4958 4961
4959 4962 ssp->prog_mode_only = B_FALSE;
4960 4963 ssp->programming = B_FALSE;
4961 4964
4962 4965 if (bscv_attach_common(ssp) == DDI_FAILURE) {
4963 4966 ssp->prog_mode_only = B_TRUE;
4964 4967 res = EIO;
4965 4968 }
4966 4969
4967 4970 bscv_exit(ssp);
4968 4971
4969 4972 if (!ssp->prog_mode_only) {
4970 4973 /*
4971 4974 * Start the event thread after the queue has started
4972 4975 *
4973 4976 * Not sure if this is entirely correct because
4974 4977 * the other code at the end of bscv_attach()
4975 4978 * does not get run here.
4976 4979 */
4977 4980 bscv_start_event_daemon(ssp);
4978 4981 bscv_resume_event_daemon(ssp);
4979 4982 }
4980 4983
4981 4984 return (res);
4982 4985 }
4983 4986
4984 4987
4985 4988 /*
4986 4989 * *********************************************************************
4987 4990 * Attach processing
4988 4991 * *********************************************************************
4989 4992 */
4990 4993
4991 4994 /*
4992 4995 * function - bscv_attach_common
4993 4996 * description - this routine co-ordinates the initialisation of the
4994 4997 * driver both at attach time and after firmware programming.
4995 4998 * sequence - bscv_setup_capability - read LOMlite2 capabilities
4996 4999 * bscv_probe_check - test comms and setup register cache
4997 5000 * bscv_setup_hostname - sync stored name in lom with nodename.
4998 5001 * bscv_setup_static_info - read device names etc.
4999 5002 * bscv_setup_events - start event daemon etc.
5000 5003 *
5001 5004 * inputs - device information structure, DDI_ATTACH command
5002 5005 * outputs - DDI_SUCCESS or DDI_FAILURE
5003 5006 */
5004 5007
5005 5008 static int
5006 5009 bscv_attach_common(bscv_soft_state_t *ssp)
5007 5010 {
5008 5011 ASSERT(bscv_held(ssp));
5009 5012
5010 5013 BSCV_TRACE(ssp, 'A', "bscv_attach_common:", "");
5011 5014
5012 5015 /*
5013 5016 * Set the threshold for reporting messages to the console to
5014 5017 * Warnings or higher.
5015 5018 */
5016 5019 ssp->reporting_level = 2;
5017 5020
5018 5021 /*
5019 5022 * When the system is not running the Operating System, make
5020 5023 * the microcontroller print event messages straight onto the
5021 5024 * console.
5022 5025 */
5023 5026 ssp->serial_reporting = LOM_SER_EVENTS_DEF;
5024 5027
5025 5028 /* Setup capabilities */
5026 5029 bscv_setup_capability(ssp);
5027 5030
5028 5031 if (bscv_probe_check(ssp) == DDI_FAILURE) {
5029 5032 cmn_err(CE_WARN, "BSC chip not responding");
5030 5033 /*
5031 5034 * We want lom -G to talk to this driver upon broken firmware
5032 5035 * so we prematurely return success here.
5033 5036 */
5034 5037 return (DDI_SUCCESS);
5035 5038 }
5036 5039
5037 5040 bscv_setup_hostname(ssp);
5038 5041 bscv_setup_static_info(ssp);
5039 5042 bscv_setup_events(ssp);
5040 5043
5041 5044 #if defined(__i386) || defined(__amd64)
5042 5045 bscv_inform_bsc(ssp, BSC_INFORM_ONLINE);
5043 5046 #endif /* __i386 || __amd64 */
5044 5047 /*
5045 5048 * Watchdog configuration and CPU signatures are sent asynchronously
5046 5049 * with respect to attach so only inform the BSC if we've already
5047 5050 * sent the data in the past.
5048 5051 */
5049 5052
5050 5053 if (ssp->progress & BSCV_WDOG_CFG)
5051 5054 bscv_setup_watchdog(ssp);
5052 5055
5053 5056 #ifdef __sparc
5054 5057 if (ssp->progress & BSCV_SIG_SENT)
5055 5058 bscv_write_sig(ssp, ssp->last_sig);
5056 5059 #endif /* __sparc */
5057 5060
5058 5061 return (DDI_SUCCESS);
5059 5062 }
5060 5063
5061 5064 /*
5062 5065 * function - bscv_cleanup
5063 5066 * description - routine that does the necessary tidying up if the attach
5064 5067 * request fails or the driver is to be detached.
5065 5068 * If the event thread has been started we may fail to
5066 5069 * stop it (because it is busy) so we fail the cleanup
5067 5070 * and hence the detach. All other calls to bscv_cleanup
5068 5071 * are done before the event daemon is started.
5069 5072 * inputs - soft state structure address.
5070 5073 * outputs - DDI_SUCCESS or DDI_FAILURE.
5071 5074 */
5072 5075
5073 5076 static int
5074 5077 bscv_cleanup(bscv_soft_state_t *ssp)
5075 5078 {
5076 5079 int instance;
5077 5080 uint8_t bits2set;
5078 5081 uint8_t bits2clear;
5079 5082
5080 5083 instance = ssp->instance;
5081 5084
5082 5085 if (ssp->progress & BSCV_LOCKS) {
5083 5086 bscv_enter(ssp);
5084 5087 }
5085 5088
5086 5089 if (ssp->progress & BSCV_THREAD) {
5087 5090 if (bscv_stop_event_daemon(ssp) == DDI_FAILURE) {
5088 5091 /* Fail the cleanup - may be able to cleanup later */
5089 5092 if (ssp->progress & BSCV_LOCKS) {
5090 5093 bscv_exit(ssp);
5091 5094 }
5092 5095 return (DDI_FAILURE);
5093 5096 }
5094 5097 }
5095 5098
5096 5099 if (ssp->progress & BSCV_NODES) {
5097 5100 ddi_remove_minor_node(ssp->dip, NULL);
5098 5101 }
5099 5102
5100 5103 if (ssp->progress & BSCV_MAPPED_REGS) {
5101 5104 /*
5102 5105 * switch back on serial event reporting - cover all configs.
5103 5106 */
5104 5107 bits2set = 0;
5105 5108 bits2clear = 0;
5106 5109 if (ssp->serial_reporting == LOM_SER_EVENTS_ON) {
5107 5110 bits2clear |= EBUS_ALARM_NOEVENTS;
5108 5111 } else if (ssp->serial_reporting == LOM_SER_EVENTS_OFF) {
5109 5112 bits2set |= EBUS_ALARM_NOEVENTS;
5110 5113 } else if (ssp->serial_reporting == LOM_SER_EVENTS_DEF) {
5111 5114 bits2clear |= EBUS_ALARM_NOEVENTS;
5112 5115 }
5113 5116 bscv_setclear8_volatile(ssp, chan_general, EBUS_IDX_ALARM,
5114 5117 bits2set, bits2clear);
5115 5118
5116 5119 /*
5117 5120 * disable the reset function if we have enabled
5118 5121 * it. We don't want any nasty surprises like system
5119 5122 * rebooting unexpectedly. If we timeout on the busy
5120 5123 * flag we just have to carry on.
5121 5124 */
5122 5125
5123 5126 BSCV_TRACE(ssp, 'W', "bscv_cleanup",
5124 5127 "bscv_cleanup - disable wdog");
5125 5128 if (bscv_get8_cached(ssp, EBUS_IDX_WDOG_CTRL) &
5126 5129 EBUS_WDOG_ENABLE) {
5127 5130 bscv_setclear8(ssp, chan_general, EBUS_IDX_WDOG_CTRL,
5128 5131 0, EBUS_WDOG_RST | EBUS_WDOG_ENABLE);
5129 5132 }
5130 5133 }
5131 5134
5132 5135 /*
5133 5136 * unmap registers
5134 5137 */
5135 5138
5136 5139 if (ssp->progress & BSCV_MAPPED_REGS) {
5137 5140 bscv_unmap_regs(ssp);
5138 5141 }
5139 5142
5140 5143 /*
5141 5144 * release any memory allocated for mutexes and condition
5142 5145 * variables before deallocating the structures containing them
5143 5146 */
5144 5147
5145 5148 if (ssp->progress & BSCV_LOCKS) {
5146 5149 bscv_exit(ssp);
5147 5150 cv_destroy(&ssp->task_cv);
5148 5151 cv_destroy(&ssp->task_evnt_cv);
5149 5152 mutex_destroy(&ssp->task_mu);
5150 5153 mutex_destroy(&ssp->prog_mu);
5151 5154 mutex_destroy(&ssp->cmd_mutex);
5152 5155 }
5153 5156
5154 5157 if (ssp->image != NULL) {
5155 5158 kmem_free((void *)ssp->image, BSC_IMAGE_MAX_SIZE);
5156 5159 }
5157 5160
5158 5161 #if defined(__i386) || defined(__amd64)
5159 5162 bscv_watchdog_cyclic_remove(ssp);
5160 5163 #endif /* __i386 || __amd64 */
5161 5164 ddi_soft_state_free(bscv_statep, instance);
5162 5165
5163 5166 return (DDI_SUCCESS);
5164 5167 }
5165 5168
5166 5169 /*
5167 5170 * function - bscv_setup_capability
5168 5171 * description - probe the lom find what capabilities are present for
5169 5172 * us to use.
5170 5173 * inputs - soft state ptr
5171 5174 * outputs - returns DDI_SUCCESS or DDI_FAILURE
5172 5175 */
5173 5176 static void bscv_setup_capability(bscv_soft_state_t *ssp)
5174 5177 {
5175 5178 ASSERT(bscv_held(ssp));
5176 5179
5177 5180 if (ssp->prog_mode_only) {
5178 5181 /* Turn off all capabilities */
5179 5182 ssp->cap0 = 0;
5180 5183 ssp->cap1 = 0;
5181 5184 ssp->cap2 = 0;
5182 5185 return;
5183 5186 }
5184 5187
5185 5188 ssp->cap0 = bscv_get8(ssp, chan_general, EBUS_IDX_CAP0);
5186 5189 ssp->cap1 = bscv_get8(ssp, chan_general, EBUS_IDX_CAP1);
5187 5190 ssp->cap2 = bscv_get8(ssp, chan_general, EBUS_IDX_CAP2);
5188 5191 if (!bscv_faulty(ssp)) {
5189 5192 BSCV_TRACE(ssp, 'A', "bscv_setup_capability",
5190 5193 "Capability flags cap0=0x%x cap1=0x%x, cap2=0x%x",
5191 5194 ssp->cap0, ssp->cap1, ssp->cap2);
5192 5195 } else {
5193 5196 cmn_err(CE_WARN, "!Could not read capability flags");
5194 5197 ssp->cap0 = 0; ssp->cap1 = 0; ssp->cap2 = 0;
5195 5198 }
5196 5199 }
5197 5200
5198 5201 /*
5199 5202 * function - bscv_probe_check
5200 5203 * description - probe the lom to check for correct operation
5201 5204 * has a side effect of setting up the cached registers and
5202 5205 * updates ssp->prog_mode_only.
5203 5206 * inputs - soft state ptr
5204 5207 * outputs - returns DDI_SUCCESS or DDI_FAILURE
5205 5208 */
5206 5209
5207 5210 static int bscv_probe_check(bscv_soft_state_t *ssp)
5208 5211 {
5209 5212 int i;
5210 5213 uint8_t probeval;
5211 5214
5212 5215 ASSERT(bscv_held(ssp));
5213 5216
5214 5217 BSCV_TRACE(ssp, 'A', "bscv_probe_check", "");
5215 5218
5216 5219 if (!ssp->prog_mode_only) {
5217 5220 /*
5218 5221 * Make sure probe location is OK so that we are
5219 5222 * in sync.
5220 5223 * We want to make sure that this is not faulty so we
5221 5224 * do a bscv_clear_fault to clear any existing
5222 5225 * fault records down.
5223 5226 */
5224 5227 bscv_clear_fault(ssp);
5225 5228 probeval = bscv_get8(ssp, chan_general, EBUS_IDX_PROBEAA);
5226 5229 if (bscv_faulty(ssp)) {
5227 5230 ssp->prog_mode_only = B_TRUE;
5228 5231 } else if (probeval != 0xAA) {
5229 5232 BSCV_TRACE(ssp, 'A', "bscv_probe_check",
5230 5233 "LOMlite out of sync");
5231 5234
5232 5235 /*
5233 5236 * It may be that the LOMlite was out of
5234 5237 * sync so lets try the read again.
5235 5238 */
5236 5239 probeval = bscv_get8(ssp, chan_general,
5237 5240 EBUS_IDX_PROBEAA);
5238 5241 if (bscv_faulty(ssp)) {
5239 5242 BSCV_TRACE(ssp, 'A', "bscv_probe_check",
5240 5243 "Init readAA1 failed");
5241 5244 ssp->prog_mode_only = B_TRUE;
5242 5245 } else if (probeval != 0xAA) {
5243 5246 /*
5244 5247 * OK that is twice we are out so I
5245 5248 * guess the LOMlite is in trouble
5246 5249 */
5247 5250 BSCV_TRACE(ssp, 'A', "bscv_probe_check",
5248 5251 "Init readAA probe failed - got 0x%x",
5249 5252 probeval);
5250 5253 ssp->prog_mode_only = B_TRUE;
5251 5254 }
5252 5255 }
5253 5256 }
5254 5257
5255 5258 /*
5256 5259 * Read in all page zero lom registers.
5257 5260 * Read state change 1st so we dont miss anything and clear it.
5258 5261 * Note: we discard the values because we rely on bscv_get8 to
5259 5262 * setup the cache of register values.
5260 5263 */
5261 5264
5262 5265 if (!ssp->prog_mode_only) {
5263 5266 (void) bscv_get8(ssp, chan_general, EBUS_IDX_STATE_CHNG);
5264 5267 if (bscv_faulty(ssp)) {
5265 5268 BSCV_TRACE(ssp, 'A', "bscv_probe_check",
5266 5269 "Read of state change register failed");
5267 5270 ssp->prog_mode_only = B_TRUE;
5268 5271 }
5269 5272 }
5270 5273
5271 5274 if (!ssp->prog_mode_only) {
5272 5275 for (i = 1; i < 0x80; i++) {
5273 5276 switch (i) {
5274 5277 case EBUS_IDX_STATE_CHNG:
5275 5278 case EBUS_IDX_CMD_RES:
5276 5279 case EBUS_IDX_HNAME_CHAR:
5277 5280 /*
5278 5281 * Should not read these - they have side
5279 5282 * effects.
5280 5283 */
5281 5284 break;
5282 5285 default:
5283 5286 (void) bscv_get8(ssp, chan_general, i);
5284 5287 break;
5285 5288 }
5286 5289 if (bscv_faulty(ssp)) {
5287 5290 BSCV_TRACE(ssp, 'A', "bscv_probe_check",
5288 5291 "Initial read or register %2x failed", i);
5289 5292 ssp->prog_mode_only = B_TRUE;
5290 5293 /* Might as well give up now! */
5291 5294 break;
5292 5295 }
5293 5296 }
5294 5297 }
5295 5298
5296 5299 /*
5297 5300 * Check the probe keys so we know the lom is OK
5298 5301 */
5299 5302
5300 5303 if (!ssp->prog_mode_only) {
5301 5304 if ((bscv_get8_cached(ssp, EBUS_IDX_PROBE55) != 0x55) ||
5302 5305 (bscv_get8_cached(ssp, EBUS_IDX_PROBEAA) != 0xAA)) {
5303 5306
5304 5307 BSCV_TRACE(ssp, 'A', "bscv_probe_check",
5305 5308 "LOMlite Probe failed");
5306 5309 for (i = 0; i < 0x8; i++) {
5307 5310 BSCV_TRACE(ssp, 'A', "bscv_probe_check",
5308 5311 "%2x %2x %2x %2x %2x %2x %2x %2x %2x "
5309 5312 "%2x %2x %2x %2x %2x %2x %2x %2x %2x",
5310 5313 bscv_get8_cached(ssp, i),
5311 5314 bscv_get8_cached(ssp, i + 1),
5312 5315 bscv_get8_cached(ssp, i + 2),
5313 5316 bscv_get8_cached(ssp, i + 3),
5314 5317 bscv_get8_cached(ssp, i + 4),
5315 5318 bscv_get8_cached(ssp, i + 5),
5316 5319 bscv_get8_cached(ssp, i + 6),
5317 5320 bscv_get8_cached(ssp, i + 7),
5318 5321 bscv_get8_cached(ssp, i + 8),
5319 5322 bscv_get8_cached(ssp, i + 9),
5320 5323 bscv_get8_cached(ssp, i + 10),
5321 5324 bscv_get8_cached(ssp, i + 11),
5322 5325 bscv_get8_cached(ssp, i + 12),
5323 5326 bscv_get8_cached(ssp, i + 13),
5324 5327 bscv_get8_cached(ssp, i + 14),
5325 5328 bscv_get8_cached(ssp, i + 15));
5326 5329 }
5327 5330 ssp->prog_mode_only = B_TRUE;
5328 5331 }
5329 5332 }
5330 5333
5331 5334 return ((ssp->prog_mode_only == B_FALSE) ? DDI_SUCCESS : DDI_FAILURE);
5332 5335 }
5333 5336
5334 5337 #ifdef __sparc
5335 5338 /*
5336 5339 * function - bscv_idi_set
5337 5340 * description - bscv inter driver interface set function
5338 5341 * inputs - structure which defines type of service required and data
5339 5342 * ouputs - none
5340 5343 *
5341 5344 * This is the Entry Point function for the platmod driver. It works out which
5342 5345 * X Bus channel ought to deliver the service requested.
5343 5346 */
5344 5347 void
5345 5348 bscv_idi_set(struct bscv_idi_info info)
5346 5349 {
5347 5350 struct bscv_idi_callout *tbl;
5348 5351 boolean_t retval;
5349 5352
5350 5353 ASSERT(bscv_idi_mgr.magic == BSCV_IDI_CALLOUT_MAGIC);
5351 5354
5352 5355 if (bscv_idi_mgr.tbl == NULL) {
5353 5356 if (bscv_idi_err())
5354 5357 cmn_err(CE_WARN, "!bscv_idi_set : cannot find "
5355 5358 "bscv_callout_table");
5356 5359 return;
5357 5360 } else if (bscv_idi_mgr.valid_inst == (uint32_t)~0) {
5358 5361 if (bscv_idi_err())
5359 5362 /*
5360 5363 * This error message can appear in the context of
5361 5364 * another driver, say platmod or todblade. We want
5362 5365 * to clearly indicate the culprit driver so put in
5363 5366 * the driver name.
5364 5367 */
5365 5368 cmn_err(CE_WARN, "!bscv_idi_set : no valid "
5366 5369 "driver instance of "
5367 5370 MYNAME);
5368 5371 return;
5369 5372 }
5370 5373
5371 5374 tbl = bscv_idi_mgr.tbl;
5372 5375
5373 5376 while (tbl->type != BSCV_IDI_NULL) {
5374 5377 if (tbl->type == info.type) {
5375 5378 /*
5376 5379 * We service the request with a valid instance number
5377 5380 * for the driver.
5378 5381 */
5379 5382 retval = ((tbl->fn) (info));
5380 5383
5381 5384 /*
5382 5385 * If the request was serviced, clear any accumulated
5383 5386 * error counters so future warnings will be reported if
5384 5387 * seen.
5385 5388 */
5386 5389 if (retval == B_TRUE)
5387 5390 bscv_idi_clear_err();
5388 5391 return;
5389 5392 } else {
5390 5393 tbl++;
5391 5394 }
5392 5395 }
5393 5396
5394 5397 if (bscv_idi_err())
5395 5398 cmn_err(CE_WARN, "!bscv_idi_set : cannot match info.type %d",
5396 5399 info.type);
5397 5400 }
5398 5401
5399 5402 /*
5400 5403 * function - bscv_nodename_set
5401 5404 * description - notify the event thread that a nodename change has occurred.
5402 5405 * inputs - data from client driver
5403 5406 * outputs - none.
5404 5407 * side-effects - the event thread will schedule an update to the lom firmware.
5405 5408 */
5406 5409 /*ARGSUSED*/
5407 5410 static boolean_t
5408 5411 bscv_nodename_set(struct bscv_idi_info info)
5409 5412 {
5410 5413 bscv_soft_state_t *ssp;
5411 5414
5412 5415 ssp = ddi_get_soft_state(bscv_statep, bscv_idi_mgr.valid_inst);
5413 5416
5414 5417 if (ssp == NULL) {
5415 5418 if (bscv_idi_err())
5416 5419 cmn_err(CE_WARN, "!blade_nodename_set: cannot get ssp");
5417 5420 return (B_FALSE);
5418 5421 }
5419 5422
5420 5423 /* Get a lock on the SSP, notify our change, then exit */
5421 5424 mutex_enter(&ssp->task_mu);
5422 5425 ssp->nodename_change = B_TRUE;
5423 5426 cv_signal(&ssp->task_cv);
5424 5427 mutex_exit(&ssp->task_mu);
5425 5428
5426 5429 return (B_TRUE);
5427 5430 }
5428 5431
5429 5432 /*
5430 5433 * function - bscv_sig_set
5431 5434 * description - write a signature
5432 5435 * inputs - data from client driver
5433 5436 * outputs - none.
5434 5437 */
5435 5438 static boolean_t
5436 5439 bscv_sig_set(struct bscv_idi_info info)
5437 5440 {
5438 5441 bscv_soft_state_t *ssp;
5439 5442 bscv_sig_t sig;
5440 5443
5441 5444 ssp = ddi_get_soft_state(bscv_statep, bscv_idi_mgr.valid_inst);
5442 5445
5443 5446 if (ssp == NULL) {
5444 5447 if (bscv_idi_err())
5445 5448 cmn_err(CE_WARN, "!blade_nodename_set: cannot get ssp");
5446 5449 return (B_FALSE);
5447 5450 }
5448 5451
5449 5452 /* Service the request */
5450 5453 bcopy(info.data, &sig, sizeof (sig));
5451 5454 bscv_enter(ssp);
5452 5455 bscv_write_sig(ssp, sig);
5453 5456 bscv_exit(ssp);
5454 5457
5455 5458 return (B_TRUE);
5456 5459 }
5457 5460 #endif /* __sparc */
5458 5461
5459 5462 static void
5460 5463 bscv_wdog_do_pat(bscv_soft_state_t *ssp)
5461 5464 {
5462 5465 uint8_t pat;
5463 5466
5464 5467 /*
5465 5468 * The value of the dog pat is a sequence number which wraps around,
5466 5469 * bounded by BSCV_WDOG_PAT_SEQ_MASK.
5467 5470 */
5468 5471 pat = ssp->pat_seq++;
5469 5472 pat &= EBUS_WDOG_NB_PAT_SEQ_MASK;
5470 5473
5471 5474 /* Set top nibble to indicate a pat */
5472 5475 pat |= EBUS_WDOG_NB_PAT;
5473 5476
5474 5477 /*
5475 5478 * Now pat the dog. This exercises a special protocol in the
5476 5479 * bus nexus that offers : non-blocking IO, and timely delivery,
5477 5480 * callable from high-level interrupt context. The requirement
5478 5481 * on us is that the channel is not shared for any other use.
5479 5482 * This means for chan_wdogpat, nothing may use channel[chan].regs
5480 5483 * or channel.[chan].handle.
5481 5484 */
5482 5485
5483 5486 ddi_put8(ssp->channel[chan_wdogpat].handle,
5484 5487 ssp->channel[chan_wdogpat].regs, pat);
5485 5488
5486 5489 BSCV_TRACE(ssp, 'W', "bscv_wdog_pat", "patted the dog with seq %d",
5487 5490 pat);
5488 5491 }
5489 5492
5490 5493 #ifdef __sparc
5491 5494 /*
5492 5495 * function - bscv_wdog_pat
5493 5496 * description - pat the watchdog
5494 5497 * inputs - data from client driver
5495 5498 * outputs - none.
5496 5499 */
5497 5500 /*ARGSUSED*/
5498 5501 static boolean_t
5499 5502 bscv_wdog_pat(struct bscv_idi_info info)
5500 5503 {
5501 5504 /*
5502 5505 * This function remembers if it has ever been called with the
5503 5506 * configure option set.
5504 5507 */
5505 5508 bscv_soft_state_t *ssp;
5506 5509
5507 5510 ssp = ddi_get_soft_state(bscv_statep, bscv_idi_mgr.valid_inst);
5508 5511
5509 5512 if (ssp == NULL) {
5510 5513 if (bscv_idi_err())
5511 5514 cmn_err(CE_WARN, "!bscv_wdog_pat: cannot get ssp");
5512 5515 return (B_FALSE);
5513 5516 } else if (ssp->nchannels == 0) {
5514 5517 /* Didn't manage to map handles so ddi_{get,put}* broken */
5515 5518 if (bscv_idi_err())
5516 5519 cmn_err(CE_WARN, "!bscv_wdog_pat: handle not mapped");
5517 5520 return (B_FALSE);
5518 5521 }
5519 5522
5520 5523 bscv_wdog_do_pat(ssp);
5521 5524 return (B_TRUE);
5522 5525 }
5523 5526
5524 5527 /*
5525 5528 * function - bscv_wdog_cfg
5526 5529 * description - configure the watchdog
5527 5530 * inputs - data from client driver
5528 5531 * outputs - none.
5529 5532 */
5530 5533 static boolean_t
5531 5534 bscv_wdog_cfg(struct bscv_idi_info info)
5532 5535 {
5533 5536 bscv_soft_state_t *ssp;
5534 5537
5535 5538 ssp = ddi_get_soft_state(bscv_statep, bscv_idi_mgr.valid_inst);
5536 5539
5537 5540 if (ssp == NULL) {
5538 5541 if (bscv_idi_err())
5539 5542 cmn_err(CE_WARN, "!bscv_wdog_cfg: cannot get ssp");
5540 5543 return (B_FALSE);
5541 5544 } else if (ssp->nchannels == 0) {
5542 5545 /* Didn't manage to map handles so ddi_{get,put}* broken */
5543 5546 if (bscv_idi_err())
5544 5547 cmn_err(CE_WARN, "!bscv_wdog_cfg: handle not mapped");
5545 5548 return (B_FALSE);
5546 5549 }
5547 5550
5548 5551 if (sizeof (bscv_wdog_t) != info.size) {
5549 5552 BSCV_TRACE(ssp, 'W', "bscv_wdog_set", "data passed in is size"
5550 5553 " %d instead of %d", info.size,
5551 5554 sizeof (bscv_wdog_t));
5552 5555 return (B_FALSE);
5553 5556 }
5554 5557
5555 5558 BSCV_TRACE(ssp, 'W', "bscv_wdog_cfg", "enable_wdog %s, "
5556 5559 "wdog_timeout_s %d, reset_system_on_timeout %s",
5557 5560 ((bscv_wdog_t *)info.data)->enable_wdog ? "enabled" : "disabled",
5558 5561 ((bscv_wdog_t *)info.data)->wdog_timeout_s,
5559 5562 ((bscv_wdog_t *)info.data)->reset_system_on_timeout ? "yes" : "no");
5560 5563 bscv_write_wdog_cfg(ssp,
5561 5564 ((bscv_wdog_t *)info.data)->wdog_timeout_s,
5562 5565 ((bscv_wdog_t *)info.data)->enable_wdog,
5563 5566 ((bscv_wdog_t *)info.data)->reset_system_on_timeout);
5564 5567 return (B_TRUE);
5565 5568 }
5566 5569 #endif /* __sparc */
5567 5570
5568 5571 static void
5569 5572 bscv_write_wdog_cfg(bscv_soft_state_t *ssp,
5570 5573 uint_t wdog_timeout_s,
5571 5574 boolean_t enable_wdog,
5572 5575 uint8_t reset_system_on_timeout)
5573 5576 {
5574 5577 uint8_t cfg = EBUS_WDOG_NB_CFG;
5575 5578
5576 5579 /*
5577 5580 * Configure the timeout value (1 to 127 seconds).
5578 5581 * Note that a policy is implemented at the bsc/ssp which bounds
5579 5582 * the value further. The bounding here is to fit the timeout value
5580 5583 * into the 7 bits the bsc uses.
5581 5584 */
5582 5585 if (wdog_timeout_s < 1)
5583 5586 ssp->watchdog_timeout = 1;
5584 5587 else if (wdog_timeout_s > 127)
5585 5588 ssp->watchdog_timeout = 127;
5586 5589 else
5587 5590 ssp->watchdog_timeout = wdog_timeout_s;
5588 5591
5589 5592 /*
5590 5593 * Configure the watchdog on or off.
5591 5594 */
5592 5595 if (enable_wdog)
5593 5596 cfg |= EBUS_WDOG_NB_CFG_ENB;
5594 5597 else
5595 5598 cfg &= ~EBUS_WDOG_NB_CFG_ENB;
5596 5599
5597 5600 /*
5598 5601 * Configure whether the microcontroller should reset the system when
5599 5602 * the watchdog expires.
5600 5603 */
5601 5604 ssp->watchdog_reset_on_timeout = reset_system_on_timeout;
5602 5605
5603 5606 ddi_put8(ssp->channel[chan_wdogpat].handle,
5604 5607 ssp->channel[chan_wdogpat].regs, cfg);
5605 5608
5606 5609 /* have the event daemon set the timeout value and whether to reset */
5607 5610 ssp->watchdog_change = B_TRUE;
5608 5611
5609 5612 BSCV_TRACE(ssp, 'W', "bscv_wdog_cfg",
5610 5613 "configured the dog with cfg 0x%x", cfg);
5611 5614 }
5612 5615
5613 5616 /*
5614 5617 * function - bscv_setup_watchdog
5615 5618 * description - setup the bsc watchdog
5616 5619 * inputs - soft state ptr
5617 5620 * outputs -
5618 5621 */
5619 5622 static void bscv_setup_watchdog(bscv_soft_state_t *ssp)
5620 5623 {
5621 5624 uint8_t set = 0;
5622 5625 uint8_t clear = 0;
5623 5626 #ifdef __sparc
5624 5627 extern int watchdog_activated;
5625 5628 #endif /* __sparc */
5626 5629
5627 5630 ASSERT(bscv_held(ssp));
5628 5631
5629 5632 /* Set the timeout */
5630 5633 bscv_put8(ssp, chan_general,
5631 5634 EBUS_IDX_WDOG_TIME, ssp->watchdog_timeout);
5632 5635
5633 5636 /* Set whether to reset the system on timeout */
5634 5637 if (ssp->watchdog_reset_on_timeout) {
5635 5638 set |= EBUS_WDOG_RST;
5636 5639 } else {
5637 5640 clear |= EBUS_WDOG_RST;
5638 5641 }
5639 5642
5640 5643 if (watchdog_activated) {
5641 5644 set |= EBUS_WDOG_ENABLE;
5642 5645 } else {
5643 5646 clear |= EBUS_WDOG_ENABLE;
5644 5647 }
5645 5648
5646 5649 /* Set other host defaults */
5647 5650 clear |= (EBUS_WDOG_BREAK_DISABLE | EBUS_WDOG_AL3_FANPSU
5648 5651 | EBUS_WDOG_AL3_WDOG);
5649 5652
5650 5653 bscv_setclear8_volatile(ssp, chan_general, EBUS_IDX_WDOG_CTRL,
5651 5654 set, clear);
5652 5655
5653 5656 #if defined(__i386) || defined(__amd64)
5654 5657 /* start the cyclic based watchdog patter */
5655 5658 bscv_watchdog_cyclic_add(ssp);
5656 5659 #endif /* __i386 || __amd64 */
5657 5660 ssp->progress |= BSCV_WDOG_CFG;
5658 5661 }
5659 5662
5660 5663
5661 5664 /*
5662 5665 * function - bscv_setup_hostname
5663 5666 * description - setup the lom hostname if different from the nodename
5664 5667 * inputs - soft state ptr
5665 5668 * outputs - none
5666 5669 */
5667 5670
5668 5671 static void bscv_setup_hostname(bscv_soft_state_t *ssp)
5669 5672 {
5670 5673 char host_nodename[128];
5671 5674 char lom_nodename[128];
5672 5675 size_t hostlen;
5673 5676 size_t nodelen;
5674 5677
5675 5678 ASSERT(bscv_held(ssp));
5676 5679
5677 5680 /*
5678 5681 * Check machine label is the same as the
5679 5682 * system nodename.
5680 5683 */
5681 5684 (void) strncpy(host_nodename, utsname.nodename,
5682 5685 sizeof (host_nodename));
5683 5686
5684 5687 /* read in lom hostname */
5685 5688 bscv_read_hostname(ssp, lom_nodename);
5686 5689
5687 5690 /* Enforce null termination */
5688 5691 host_nodename[sizeof (host_nodename) - 1] = '\0';
5689 5692 lom_nodename[sizeof (lom_nodename) - 1] = '\0';
5690 5693
5691 5694 hostlen = (size_t)bscv_get8(ssp, chan_general, EBUS_IDX_HNAME_LENGTH);
5692 5695 nodelen = (size_t)strlen(host_nodename);
5693 5696 if ((nodelen > 0) &&
5694 5697 ((hostlen != nodelen) || (strcmp((const char *)&lom_nodename,
5695 5698 (const char *)&host_nodename)) ||
5696 5699 (hostlen == 0))) {
5697 5700 BSCV_TRACE(ssp, 'A', "bscv_setup_hostname",
5698 5701 "nodename(%s,%d) != bsc label(%s,%d)",
5699 5702 host_nodename, nodelen, lom_nodename, hostlen);
5700 5703
5701 5704 /* Write new label into LOM EEPROM */
5702 5705 bscv_write_hostname(ssp,
5703 5706 host_nodename,
5704 5707 (uint8_t)strlen(host_nodename));
5705 5708 }
5706 5709
5707 5710 ssp->progress |= BSCV_HOSTNAME_DONE;
5708 5711 }
5709 5712
5710 5713 /*
5711 5714 * function - bscv_read_hostname
5712 5715 * description - read the current hostname from the lom
5713 5716 * inputs - soft state pointer and buffer to store the hostname in.
5714 5717 * outputs - none
5715 5718 */
5716 5719
5717 5720 static void
5718 5721 bscv_read_hostname(bscv_soft_state_t *ssp, char *lom_nodename)
5719 5722 {
5720 5723 int num_failures;
5721 5724 boolean_t needretry;
5722 5725 int length;
5723 5726 int i;
5724 5727
5725 5728 ASSERT(bscv_held(ssp));
5726 5729
5727 5730 /*
5728 5731 * We have a special failure case here because a retry of a read
5729 5732 * causes data to be lost. Thus we handle the retries ourselves
5730 5733 * and are also responsible for detemining if the lom is faulty
5731 5734 */
5732 5735 for (num_failures = 0;
5733 5736 num_failures < BSC_FAILURE_RETRY_LIMIT;
5734 5737 num_failures++) {
5735 5738 bscv_clear_fault(ssp);
5736 5739 length = bscv_get8(ssp, chan_general, EBUS_IDX_HNAME_LENGTH);
5737 5740 if (bscv_faulty(ssp)) {
5738 5741 needretry = 1;
5739 5742 } else {
5740 5743 needretry = 0;
5741 5744 for (i = 0; i < length; i++) {
5742 5745 lom_nodename[i] = bscv_get8_once(ssp,
5743 5746 chan_general, EBUS_IDX_HNAME_CHAR);
5744 5747 /* Retry on any error */
5745 5748 if (bscv_retcode(ssp) != 0) {
5746 5749 needretry = 1;
5747 5750 break;
5748 5751 }
5749 5752 }
5750 5753 /* null terminate for strcmp later */
5751 5754 lom_nodename[length] = '\0';
5752 5755 }
5753 5756 if (!needretry) {
5754 5757 break;
5755 5758 }
5756 5759 /* Force the nodename to be empty */
5757 5760 lom_nodename[0] = '\0';
5758 5761 }
5759 5762
5760 5763 if (needretry) {
5761 5764 /* Failure - we ran out of retries */
5762 5765 cmn_err(CE_WARN,
5763 5766 "bscv_read_hostname: retried %d times, giving up",
5764 5767 num_failures);
5765 5768 ssp->had_fault = B_TRUE;
5766 5769 } else if (num_failures > 0) {
5767 5770 BSCV_TRACE(ssp, 'R', "bscv_read_hostname",
5768 5771 "retried %d times, succeeded", num_failures);
5769 5772 }
5770 5773 }
5771 5774
5772 5775 /*
5773 5776 * function - bscv_write_hostname
5774 5777 * description - write a new hostname to the lom
5775 5778 * inputs - soft state pointer, pointer to new name, name length
5776 5779 * outputs - none
5777 5780 */
5778 5781 static void
5779 5782 bscv_write_hostname(bscv_soft_state_t *ssp,
5780 5783 char *host_nodename, uint8_t length)
5781 5784 {
5782 5785 int num_failures;
5783 5786 boolean_t needretry;
5784 5787 int i;
5785 5788
5786 5789 ASSERT(bscv_held(ssp));
5787 5790
5788 5791 /*
5789 5792 * We have a special failure case here because a retry of a read
5790 5793 * causes data to be lost. Thus we handle the retries ourselves
5791 5794 * and are also responsible for detemining if the lom is faulty
5792 5795 */
5793 5796 for (num_failures = 0;
5794 5797 num_failures < BSC_FAILURE_RETRY_LIMIT;
5795 5798 num_failures++) {
5796 5799 bscv_clear_fault(ssp);
5797 5800 bscv_put8(ssp, chan_general, EBUS_IDX_HNAME_LENGTH, length);
5798 5801 if (bscv_faulty(ssp)) {
5799 5802 needretry = 1;
5800 5803 } else {
5801 5804 needretry = 0;
5802 5805 for (i = 0; i < length; i++) {
5803 5806 bscv_put8_once(ssp, chan_general,
5804 5807 EBUS_IDX_HNAME_CHAR, host_nodename[i]);
5805 5808 /* Retry on any error */
5806 5809 if (bscv_retcode(ssp) != 0) {
5807 5810 needretry = 1;
5808 5811 break;
5809 5812 }
5810 5813 }
5811 5814 }
5812 5815 if (!needretry) {
5813 5816 break;
5814 5817 }
5815 5818 }
5816 5819
5817 5820 if (needretry) {
5818 5821 /* Failure - we ran out of retries */
5819 5822 cmn_err(CE_WARN,
5820 5823 "bscv_write_hostname: retried %d times, giving up",
5821 5824 num_failures);
5822 5825 ssp->had_fault = B_TRUE;
5823 5826 } else if (num_failures > 0) {
5824 5827 BSCV_TRACE(ssp, 'R', "bscv_write_hostname",
5825 5828 "retried %d times, succeeded", num_failures);
5826 5829 }
5827 5830 }
5828 5831
5829 5832 /*
5830 5833 * function - bscv_setup_static_info
5831 5834 * description - read in static information from the lom at attach time.
5832 5835 * inputs - soft state ptr
5833 5836 * outputs - none
5834 5837 */
5835 5838
5836 5839 static void
5837 5840 bscv_setup_static_info(bscv_soft_state_t *ssp)
5838 5841 {
5839 5842 uint8_t addr_space_ptr;
5840 5843 uint16_t mask;
5841 5844 uint8_t fanspeed;
5842 5845 int oldtemps[MAX_TEMPS];
5843 5846 int8_t temp;
5844 5847 int i;
5845 5848
5846 5849 ASSERT(bscv_held(ssp));
5847 5850
5848 5851 /*
5849 5852 * Finally read in some static info like device names,
5850 5853 * shutdown enabled, etc before the queue starts.
5851 5854 */
5852 5855
5853 5856 /*
5854 5857 * To get the volts static info we need address space 2
5855 5858 */
5856 5859 bzero(&ssp->volts, sizeof (lom_volts_t));
5857 5860 ssp->volts.num = EBUS_CONFIG2_NSUPPLY_DEC(
5858 5861 bscv_get8(ssp, chan_general, EBUS_IDX_CONFIG2));
5859 5862 if (ssp->volts.num > MAX_VOLTS) {
5860 5863 cmn_err(CE_WARN,
5861 5864 "lom: firmware reported too many voltage lines. ");
5862 5865 cmn_err(CE_CONT, "Reported %d, maximum is %d",
5863 5866 ssp->volts.num, MAX_VOLTS);
5864 5867 ssp->volts.num = MAX_VOLTS;
5865 5868 }
5866 5869
5867 5870 BSCV_TRACE(ssp, 'A', "bscv_setup_static_info",
5868 5871 "num volts %d", ssp->volts.num);
5869 5872 (void) bscv_read_env_name(ssp,
5870 5873 EBUS_CMD_SPACE2,
5871 5874 EBUS_IDX2_SUPPLY_NAME_START,
5872 5875 EBUS_IDX2_SUPPLY_NAME_END,
5873 5876 ssp->volts.name,
5874 5877 ssp->volts.num);
5875 5878
5876 5879 mask = bscv_get8(ssp, chan_general, BSCVA(EBUS_CMD_SPACE2,
5877 5880 EBUS_IDX2_SUPPLY_FATAL_MASK1)) << 8;
5878 5881 mask |= bscv_get8(ssp, chan_general, BSCVA(EBUS_CMD_SPACE2,
5879 5882 EBUS_IDX2_SUPPLY_FATAL_MASK2));
5880 5883
5881 5884 for (i = 0; i < ssp->volts.num; i++) {
5882 5885 ssp->volts.shutdown_enabled[i] =
5883 5886 (((mask >> i) & 1) == 0) ? 0 : 1;
5884 5887 }
5885 5888
5886 5889 /*
5887 5890 * Get the temperature static info and populate initial temperatures.
5888 5891 * Do not destroy old temperature values if the new value is not
5889 5892 * known i.e. if the device is inaccessible.
5890 5893 */
5891 5894 bcopy(ssp->temps.temp, oldtemps, sizeof (oldtemps));
5892 5895
5893 5896 bzero(&ssp->temps, sizeof (lom_temp_t));
5894 5897 ssp->temps.num = EBUS_CONFIG2_NTEMP_DEC(
5895 5898 bscv_get8(ssp, chan_general, EBUS_IDX_CONFIG2));
5896 5899 if (ssp->temps.num > MAX_TEMPS) {
5897 5900 cmn_err(CE_WARN,
5898 5901 "lom: firmware reported too many temperatures being "
5899 5902 "monitored.");
5900 5903 cmn_err(CE_CONT, "Reported %d, maximum is %d",
5901 5904 ssp->temps.num, MAX_TEMPS);
5902 5905 ssp->temps.num = MAX_TEMPS;
5903 5906 }
5904 5907 ssp->temps.num_ov = EBUS_CONFIG3_NOTEMP_DEC(
5905 5908 bscv_get8(ssp, chan_general, EBUS_IDX_CONFIG3));
5906 5909 if (ssp->temps.num_ov > MAX_TEMPS) {
5907 5910 cmn_err(CE_WARN,
5908 5911 "lom: firmware reported too many over temperatures being "
5909 5912 "monitored.");
5910 5913 cmn_err(CE_CONT, "Reported %d, maximum is %d",
5911 5914 ssp->temps.num_ov, MAX_TEMPS);
5912 5915 ssp->temps.num_ov = MAX_TEMPS;
5913 5916 }
5914 5917 BSCV_TRACE(ssp, 'A', "bscv_setup_static_info",
5915 5918 "num temps %d, over temps %d",
5916 5919 ssp->temps.num, ssp->temps.num_ov);
5917 5920
5918 5921 addr_space_ptr = bscv_read_env_name(ssp,
5919 5922 EBUS_CMD_SPACE4,
5920 5923 EBUS_IDX4_TEMP_NAME_START,
5921 5924 EBUS_IDX4_TEMP_NAME_END,
5922 5925 ssp->temps.name,
5923 5926 ssp->temps.num);
5924 5927
5925 5928 for (i = 0; i < ssp->temps.num; i++) {
5926 5929 ssp->temps.warning[i] = (int8_t)bscv_get8(ssp, chan_general,
5927 5930 BSCVA(EBUS_CMD_SPACE4, EBUS_IDX4_TEMP_WARN1 + i));
5928 5931
5929 5932 /*
5930 5933 * If shutdown is not enabled then set it as zero so
5931 5934 * it is not displayed by the utility.
5932 5935 */
5933 5936 if ((bscv_get8(ssp, chan_general, BSCVA(EBUS_CMD_SPACE4,
5934 5937 EBUS_IDX4_TEMP_FATAL_MASK)) >> i) & 0x01) {
5935 5938 ssp->temps.shutdown[i] = (int8_t)bscv_get8(ssp,
5936 5939 chan_general,
5937 5940 BSCVA(EBUS_CMD_SPACE4, EBUS_IDX4_TEMP_SDOWN1 + i));
5938 5941 } else {
5939 5942 ssp->temps.shutdown[i] = 0;
5940 5943 }
5941 5944 }
5942 5945
5943 5946 for (i = 0; i < ssp->temps.num; i++) {
5944 5947 temp = bscv_get8(ssp, chan_general, EBUS_IDX_TEMP1 + i);
5945 5948 if ((temp <= LOM_TEMP_MAX_VALUE) ||
5946 5949 (temp == LOM_TEMP_STATE_NOT_PRESENT)) {
5947 5950 ssp->temps.temp[i] = temp;
5948 5951 } else {
5949 5952 /* New value is not known - use old value */
5950 5953 ssp->temps.temp[i] = oldtemps[i];
5951 5954 }
5952 5955 }
5953 5956
5954 5957 /*
5955 5958 * Check for and skip a single 0xff character between the
5956 5959 * temperature and over temperature names
5957 5960 */
5958 5961 if (bscv_get8(ssp, chan_general,
5959 5962 BSCVA(EBUS_CMD_SPACE4, addr_space_ptr)) == 0xff) {
5960 5963 addr_space_ptr++;
5961 5964 }
5962 5965
5963 5966 (void) bscv_read_env_name(ssp,
5964 5967 EBUS_CMD_SPACE4,
5965 5968 addr_space_ptr,
5966 5969 EBUS_IDX4_TEMP_NAME_END,
5967 5970 ssp->temps.name_ov,
5968 5971 ssp->temps.num_ov);
5969 5972
5970 5973 /*
5971 5974 * To get the CB static info we need address space 3
5972 5975 */
5973 5976 bzero(&ssp->sflags, sizeof (lom_sflags_t));
5974 5977 ssp->sflags.num = EBUS_CONFIG3_NBREAKERS_DEC(bscv_get8(ssp,
5975 5978 chan_general, EBUS_IDX_CONFIG3));
5976 5979 if (ssp->sflags.num > MAX_STATS) {
5977 5980 cmn_err(CE_WARN,
5978 5981 "lom: firmware reported too many status flags.");
5979 5982 cmn_err(CE_CONT,
5980 5983 "Reported %d, maximum is %d",
5981 5984 ssp->sflags.num, MAX_STATS);
5982 5985 ssp->sflags.num = MAX_STATS;
5983 5986 }
5984 5987 BSCV_TRACE(ssp, 'A', "bscv_setup_static_info",
5985 5988 "num sflags %d", ssp->sflags.num);
5986 5989
5987 5990 (void) bscv_read_env_name(ssp,
5988 5991 EBUS_CMD_SPACE3,
5989 5992 EBUS_IDX3_BREAKER_NAME_START,
5990 5993 EBUS_IDX3_BREAKER_NAME_END,
5991 5994 ssp->sflags.name,
5992 5995 ssp->sflags.num);
5993 5996
5994 5997
5995 5998 /*
5996 5999 * To get the fan static info we need address space 5
5997 6000 */
5998 6001 ssp->num_fans = EBUS_CONFIG_NFAN_DEC(
5999 6002 bscv_get8(ssp, chan_general, EBUS_IDX_CONFIG));
6000 6003 if (ssp->num_fans > MAX_FANS) {
6001 6004 cmn_err(CE_WARN,
6002 6005 "lom: firmware reported too many fans. ");
6003 6006 cmn_err(CE_CONT,
6004 6007 "Reported %d, maximum is %d",
6005 6008 ssp->num_fans, MAX_FANS);
6006 6009 ssp->num_fans = MAX_FANS;
6007 6010 }
6008 6011
6009 6012 for (i = 0; i < ssp->num_fans; i++) {
6010 6013 fanspeed = bscv_get8(ssp, chan_general,
6011 6014 EBUS_IDX_FAN1_SPEED + i);
6012 6015 if ((fanspeed <= LOM_FAN_MAX_SPEED) ||
6013 6016 (fanspeed == LOM_FAN_NOT_PRESENT)) {
6014 6017 /*
6015 6018 * Do not destroy previous values unless the
6016 6019 * value is definitive.
6017 6020 */
6018 6021 ssp->fanspeed[i] = fanspeed;
6019 6022 }
6020 6023 }
6021 6024
6022 6025 BSCV_TRACE(ssp, 'A', "bscv_setup_static_info",
6023 6026 "num fans %d", ssp->num_fans);
6024 6027
6025 6028 (void) bscv_read_env_name(ssp,
6026 6029 EBUS_CMD_SPACE5,
6027 6030 EBUS_IDX5_FAN_NAME_START,
6028 6031 EBUS_IDX5_FAN_NAME_END,
6029 6032 ssp->fan_names,
6030 6033 ssp->num_fans);
6031 6034
6032 6035 /* Get led static information from address space 10 */
6033 6036
6034 6037 (void) bscv_read_env_name(ssp,
6035 6038 EBUS_CMD_SPACE_LEDS,
6036 6039 EBUS_IDX10_LED_NAME_START,
6037 6040 EBUS_IDX10_LED_NAME_END,
6038 6041 ssp->led_names,
6039 6042 MAX_LED_ID);
6040 6043 }
6041 6044
6042 6045 /*
6043 6046 * function - bscv_read_env_name
6044 6047 * description - read in static environment names
6045 6048 * warning changes address space and the caller relies
6046 6049 * on this behaviour.
6047 6050 * inputs - soft state ptr, chosen address space,
6048 6051 * start of name data, end of name data,
6049 6052 * name storage, number of names.
6050 6053 * outputs - next address for reading name data.
6051 6054 */
6052 6055
6053 6056 static uint8_t
6054 6057 bscv_read_env_name(bscv_soft_state_t *ssp,
6055 6058 uint8_t addr_space,
6056 6059 uint8_t addr_start,
6057 6060 uint8_t addr_end,
6058 6061 char namebuf[][MAX_LOM2_NAME_STR],
6059 6062 int numnames)
6060 6063 {
6061 6064 int i;
6062 6065 int nameidx;
6063 6066 int namemax;
6064 6067 unsigned int addr_space_ptr;
6065 6068 uint8_t this_char;
6066 6069
6067 6070 ASSERT(bscv_held(ssp));
6068 6071
6069 6072 BSCV_TRACE(ssp, 'A', "bscv_read_env_name",
6070 6073 "bscv_read_env_name, space %d, start 0x%x, end 0x%x, numnames %d",
6071 6074 addr_space, addr_start, addr_end, numnames);
6072 6075
6073 6076 addr_space_ptr = addr_start;
6074 6077
6075 6078 for (i = 0; i < numnames; i++) {
6076 6079 nameidx = 0;
6077 6080 namemax = sizeof (namebuf[i]);
6078 6081 bzero(namebuf[i], namemax);
6079 6082
6080 6083 while (addr_space_ptr <= addr_end) {
6081 6084 /*
6082 6085 * Read the current character.
6083 6086 */
6084 6087 this_char = bscv_get8(ssp, chan_general,
6085 6088 BSCVA(addr_space, addr_space_ptr));
6086 6089
6087 6090 if (this_char == 0xff) {
6088 6091 /*
6089 6092 * Ran out of names - this must
6090 6093 * be the end of the name.
6091 6094 * This is really an error because
6092 6095 * we have just seen either a non-NUL
6093 6096 * terminated string or the number of
6094 6097 * strings did not match what was
6095 6098 * reported.
6096 6099 */
6097 6100 break;
6098 6101 }
6099 6102 /*
6100 6103 * We increment the buffer pointer now so that
6101 6104 * it is ready for the next read
6102 6105 */
6103 6106 addr_space_ptr++;
6104 6107
6105 6108 if (this_char == '\0') {
6106 6109 /* Found end of string - done */
6107 6110 break;
6108 6111 }
6109 6112 if (nameidx < (namemax - 1)) {
6110 6113 /*
6111 6114 * Buffer not full - record character
6112 6115 * NOTE we always leave room for the NUL
6113 6116 * terminator.
6114 6117 */
6115 6118 namebuf[i][nameidx++] = this_char;
6116 6119 }
6117 6120 }
6118 6121 /* Ensure null termination */
6119 6122 namebuf[i][nameidx] = '\0';
6120 6123 }
6121 6124 /* Clamp addr_space_ptr to 0xff because we return uint8_t */
6122 6125 if (addr_space_ptr > 0xff) {
6123 6126 addr_space_ptr = 0xff;
6124 6127 }
6125 6128 return (addr_space_ptr);
6126 6129 }
6127 6130
6128 6131 /*
6129 6132 * function - bscv_setup_events
6130 6133 * description - initialise the event reporting code
6131 6134 * inputs - soft state ptr
6132 6135 * outputs - DDI_SUCCESS or DDI_FAILURE
6133 6136 */
6134 6137
6135 6138 static void
6136 6139 bscv_setup_events(bscv_soft_state_t *ssp)
6137 6140 {
6138 6141 uint8_t bits2set;
6139 6142 uint8_t bits2clear;
6140 6143
6141 6144 ASSERT(bscv_held(ssp));
6142 6145
6143 6146 /*
6144 6147 * deal with event reporting - cover all cases
6145 6148 */
6146 6149
6147 6150 bits2set = 0;
6148 6151 bits2clear = 0;
6149 6152 if (ssp->serial_reporting == LOM_SER_EVENTS_ON) {
6150 6153 bits2clear |= EBUS_ALARM_NOEVENTS;
6151 6154 } else if (ssp->serial_reporting == LOM_SER_EVENTS_OFF) {
6152 6155 bits2set |= EBUS_ALARM_NOEVENTS;
6153 6156 } else if (ssp->serial_reporting == LOM_SER_EVENTS_DEF) {
6154 6157 bits2set |= EBUS_ALARM_NOEVENTS;
6155 6158 }
6156 6159 bscv_setclear8_volatile(ssp, chan_general, EBUS_IDX_ALARM,
6157 6160 bits2set, bits2clear);
6158 6161 }
6159 6162
6160 6163 #ifdef __sparc
6161 6164 /*
6162 6165 * function - bscv_write_sig
6163 6166 * description - write out a signature, taking care to deal with any strange
6164 6167 * values for CPU ID
6165 6168 * inputs - soft state ptr, signature
6166 6169 * outputs - none
6167 6170 */
6168 6171 static void
6169 6172 bscv_write_sig(bscv_soft_state_t *ssp, bscv_sig_t s)
6170 6173 {
6171 6174 ASSERT(bscv_held(ssp));
6172 6175
6173 6176 /* Upload the signature */
6174 6177 bscv_put32(ssp, chan_cpusig,
6175 6178 BSCVA(EBUS_CMD_SPACE_CPUSIG, EBUS_IDX11_CPU_SIG_MSB),
6176 6179 s.sig_info.signature);
6177 6180
6178 6181 /*
6179 6182 * We always write the CPU ID last because this tells the firmware
6180 6183 * that the signature is fully uploaded and therefore to consume the
6181 6184 * data. This is required since the signature is > 1 byte in size
6182 6185 * and we transmit data in single bytes.
6183 6186 */
6184 6187 if (s.cpu == ~0) {
6185 6188 /* ~0 means the signature applies to any CPU. */
6186 6189 bscv_put8(ssp, chan_cpusig,
6187 6190 BSCVA(EBUS_CMD_SPACE_CPUSIG, EBUS_IDX11_CPU_ID),
6188 6191 EBUS_ANY_CPU_ID);
6189 6192 } else {
6190 6193 if (s.cpu > 255) {
6191 6194 /*
6192 6195 * The CPU ID supplied is unexpectedly large. Lets
6193 6196 * just use the bottom bits, in case other high order
6194 6197 * bits are being used for special meaning.
6195 6198 */
6196 6199 cmn_err(CE_WARN, "CPU Signature ID 0x%x > 255", s.cpu);
6197 6200 s.cpu %= 256;
6198 6201 cmn_err(CE_CONT, "using ID 0x%x instead ", s.cpu);
6199 6202 }
6200 6203 bscv_put8(ssp, chan_cpusig,
6201 6204 BSCVA(EBUS_CMD_SPACE_CPUSIG, EBUS_IDX11_CPU_ID),
6202 6205 (uint8_t)s.cpu);
6203 6206 }
6204 6207
6205 6208 ssp->last_sig = s;
6206 6209 ssp->progress |= BSCV_SIG_SENT;
6207 6210 }
6208 6211 #endif /* __sparc */
6209 6212
6210 6213 #if defined(__i386) || defined(__amd64)
6211 6214
6212 6215 /*
6213 6216 * function - bscv_inform_bsc
6214 6217 * description - inform bsc of driver state for logging purposes
6215 6218 * inputs - driver soft state, state
6216 6219 * outputs - none
6217 6220 *
6218 6221 */
6219 6222 static void
6220 6223 bscv_inform_bsc(bscv_soft_state_t *ssp, uint32_t state)
6221 6224 {
6222 6225 ASSERT(bscv_held(ssp));
6223 6226
6224 6227 BSCV_TRACE(ssp, 'X', "bscv_inform_bsc",
6225 6228 "bscv_inform_bsc: state=%d", state);
6226 6229
6227 6230 bscv_put32(ssp, chan_general,
6228 6231 BSCVA(EBUS_CMD_SPACE_CPUSIG, EBUS_IDX11_CPU_SIG_MSB), state);
6229 6232 bscv_put8(ssp, chan_cpusig,
6230 6233 BSCVA(EBUS_CMD_SPACE_CPUSIG, EBUS_IDX11_CPU_ID), EBUS_ANY_CPU_ID);
6231 6234 }
6232 6235
6233 6236 /*
6234 6237 * function - bscv_watchdog_pat_request
6235 6238 * description - request a heartbeat pat
6236 6239 * inputs - timeout value in seconds
6237 6240 * outputs - none
6238 6241 */
6239 6242 static void
6240 6243 bscv_watchdog_pat_request(void *arg)
6241 6244 {
6242 6245 bscv_soft_state_t *ssp = (bscv_soft_state_t *)arg;
6243 6246
6244 6247 bscv_wdog_do_pat(ssp);
6245 6248 }
6246 6249
6247 6250 /*
6248 6251 * function - bscv_watchdog_cfg_request
6249 6252 * description - request configuration of the bsc hardware watchdog
6250 6253 * inputs - new state (0=disabled, 1=enabled)
6251 6254 * outputs - one if successful, zero if unsuccesful
6252 6255 */
6253 6256 static void
6254 6257 bscv_watchdog_cfg_request(bscv_soft_state_t *ssp, uint8_t new_state)
6255 6258 {
6256 6259 ASSERT(new_state == WDOG_ON || new_state == WDOG_OFF);
6257 6260
6258 6261 watchdog_activated = new_state;
6259 6262 BSCV_TRACE(ssp, 'X', "bscv_watchdog_cfg_request",
6260 6263 "watchdog_activated=%d", watchdog_activated);
6261 6264 bscv_write_wdog_cfg(ssp,
6262 6265 bscv_watchdog_timeout_seconds,
6263 6266 new_state,
6264 6267 wdog_reset_on_timeout);
6265 6268 }
6266 6269
6267 6270 /*
6268 6271 * function - bscv_set_watchdog_timer
6269 6272 * description - setup the heartbeat timeout value
6270 6273 * inputs - timeout value in seconds
6271 6274 * outputs - zero if the value was not changed
6272 6275 * otherwise the current value
6273 6276 */
6274 6277 static uint_t
6275 6278 bscv_set_watchdog_timer(bscv_soft_state_t *ssp, uint_t timeoutval)
6276 6279 {
6277 6280 BSCV_TRACE(ssp, 'X', "bscv_set_watchdog_timer:",
6278 6281 "timeout=%d", timeoutval);
6279 6282
6280 6283 /*
6281 6284 * We get started during bscv_attach only
6282 6285 * if bscv_watchdog_enable is set.
6283 6286 */
6284 6287 if (bscv_watchdog_available && (!watchdog_activated ||
6285 6288 (watchdog_activated &&
6286 6289 (timeoutval != bscv_watchdog_timeout_seconds)))) {
6287 6290 bscv_watchdog_timeout_seconds = timeoutval;
6288 6291 bscv_watchdog_cfg_request(ssp, WDOG_ON);
6289 6292 return (bscv_watchdog_timeout_seconds);
6290 6293 }
6291 6294 return (0);
6292 6295 }
6293 6296
6294 6297 /*
6295 6298 * function - bscv_clear_watchdog_timer
6296 6299 * description - add the watchdog patter cyclic
6297 6300 * inputs - driver soft state
6298 6301 * outputs - value of watchdog timeout in seconds
6299 6302 *
6300 6303 * This function is a copy of the SPARC implementation
6301 6304 * in the todblade clock driver.
6302 6305 */
6303 6306 static void
6304 6307 bscv_clear_watchdog_timer(bscv_soft_state_t *ssp)
6305 6308 {
6306 6309 BSCV_TRACE(ssp, 'X', "bscv_clear_watchdog_timer", "");
6307 6310
6308 6311 if (bscv_watchdog_available && watchdog_activated) {
6309 6312 bscv_watchdog_enable = 0;
6310 6313 bscv_watchdog_cfg_request(ssp, WDOG_OFF);
6311 6314 }
6312 6315 }
6313 6316
6314 6317 /*
6315 6318 * function - bscv_panic_callback
6316 6319 * description - called when we panic so we can disabled the watchdog
6317 6320 * inputs - driver soft state pointer
6318 6321 * outputs - DDI_SUCCESS
6319 6322 */
6320 6323 /*ARGSUSED1*/
6321 6324 static boolean_t
6322 6325 bscv_panic_callback(void *arg, int code)
6323 6326 {
6324 6327 bscv_soft_state_t *ssp = (bscv_soft_state_t *)arg;
6325 6328
6326 6329 BSCV_TRACE(ssp, 'X', "bscv_panic_callback",
6327 6330 "disabling watchdog");
6328 6331
6329 6332 bscv_clear_watchdog_timer(ssp);
6330 6333 /*
6331 6334 * We dont get interrupts during the panic callback. But bscbus
6332 6335 * takes care of all this
6333 6336 */
6334 6337 bscv_full_stop(ssp);
6335 6338 return (DDI_SUCCESS);
6336 6339 }
6337 6340
6338 6341 /*
6339 6342 * function - bscv_watchdog_cyclic_add
6340 6343 * description - add the watchdog patter cyclic
6341 6344 * inputs - driver soft state
6342 6345 * outputs - none
6343 6346 */
6344 6347 static void
6345 6348 bscv_watchdog_cyclic_add(bscv_soft_state_t *ssp)
6346 6349 {
6347 6350 if (ssp->periodic_id != NULL) {
6348 6351 return;
6349 6352 }
6350 6353
6351 6354 ssp->periodic_id = ddi_periodic_add(bscv_watchdog_pat_request, ssp,
6352 6355 WATCHDOG_PAT_INTERVAL, DDI_IPL_10);
6353 6356
6354 6357 BSCV_TRACE(ssp, 'X', "bscv_watchdog_cyclic_add:",
6355 6358 "cyclic added");
6356 6359 }
6357 6360
6358 6361 /*
6359 6362 * function - bscv_watchdog_cyclic_remove
6360 6363 * description - remove the watchdog patter cyclic
6361 6364 * inputs - soft state ptr
6362 6365 * outputs - none
6363 6366 */
6364 6367 static void
6365 6368 bscv_watchdog_cyclic_remove(bscv_soft_state_t *ssp)
6366 6369 {
6367 6370 if (ssp->periodic_id == NULL) {
6368 6371 return;
6369 6372 }
6370 6373 ddi_periodic_delete(ssp->periodic_id);
6371 6374 ssp->periodic_id = NULL;
6372 6375 BSCV_TRACE(ssp, 'X', "bscv_watchdog_cyclic_remove:",
6373 6376 "cyclic removed");
6374 6377 }
6375 6378 #endif /* __i386 || __amd64 */
6376 6379
6377 6380
6378 6381 /*
6379 6382 * General utility routines ...
6380 6383 */
6381 6384
6382 6385 #ifdef DEBUG
6383 6386
6384 6387 static void
6385 6388 bscv_trace(bscv_soft_state_t *ssp, char code, const char *caller,
6386 6389 const char *fmt, ...)
6387 6390 {
6388 6391 char buf[256];
6389 6392 char *p;
6390 6393 va_list va;
6391 6394
6392 6395 if (ssp->debug & (1 << (code-'@'))) {
6393 6396 p = buf;
6394 6397 (void) snprintf(p, sizeof (buf) - (p - buf),
6395 6398 "%s/%s: ", MYNAME, caller);
6396 6399 p += strlen(p);
6397 6400
6398 6401 va_start(va, fmt);
6399 6402 (void) vsnprintf(p, sizeof (buf) - (p - buf), fmt, va);
6400 6403 va_end(va);
6401 6404
6402 6405 buf[sizeof (buf) - 1] = '\0';
6403 6406 (void) strlog((short)ssp->majornum, (short)ssp->minornum, code,
6404 6407 SL_TRACE, buf);
6405 6408 }
6406 6409 }
6407 6410
6408 6411 #else /* DEBUG */
6409 6412
6410 6413 _NOTE(ARGSUSED(0))
6411 6414 static void
6412 6415 bscv_trace(bscv_soft_state_t *ssp, char code, const char *caller,
6413 6416 const char *fmt, ...)
6414 6417 {
6415 6418 }
6416 6419
6417 6420 #endif /* DEBUG */
↓ open down ↓ |
6000 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX