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