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