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