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