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 /*
  23  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
  24  * Use is subject to license terms.
  25  */
  26 
  27 
  28 #include <sys/types.h>
  29 #include <sys/stat.h>
  30 #include <sys/conf.h>
  31 #include <sys/modctl.h>
  32 #include <sys/callb.h>
  33 #include <sys/strlog.h>
  34 #include <sys/cyclic.h>
  35 #include <sys/rmc_comm_dp.h>
  36 #include <sys/rmc_comm_dp_boot.h>
  37 #include <sys/rmc_comm_drvintf.h>
  38 #include <sys/rmc_comm.h>
  39 #include <sys/machsystm.h>
  40 #include <sys/sysevent.h>
  41 #include <sys/sysevent/dr.h>
  42 #include <sys/sysevent/env.h>
  43 #include <sys/sysevent/eventdefs.h>
  44 #include <sys/file.h>
  45 #include <sys/disp.h>
  46 #include <sys/reboot.h>
  47 #include <sys/envmon.h>
  48 #include <sys/rmclomv_impl.h>
  49 #include <sys/cpu_sgnblk_defs.h>
  50 #include <sys/utsname.h>
  51 #include <sys/systeminfo.h>
  52 #include <sys/ddi.h>
  53 #include <sys/time.h>
  54 #include <sys/promif.h>
  55 
  56 #if defined(__GNUC__)
  57 #define offsetof(s, m)  __builtin_offsetof(s, m)
  58 #else
  59 #define offsetof(s, m)  ((size_t)(&(((s *)0)->m)))
  60 #endif
  61 #define RMCRESBUFLEN    1024
  62 #define DATE_TIME_MSG_SIZE      78
  63 #define RMCLOMV_WATCHDOG_MODE   "rmclomv-watchdog-mode"
  64 #define DELAY_TIME      5000000  /* 5 seconds, in microseconds */
  65 #define CPU_SIGNATURE_DELAY_TIME        5000000  /* 5 secs, in microsecs */
  66 
  67 extern void     pmugpio_watchdog_pat();
  68 
  69 extern int      watchdog_activated;
  70 static int      last_watchdog_msg = 1;
  71 extern int      watchdog_enable;
  72 extern int      boothowto;
  73 
  74 int             rmclomv_watchdog_mode;
  75 
  76 /*
  77  * functions local to this driver.
  78  */
  79 static int      rmclomv_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg,
  80     void **resultp);
  81 static int      rmclomv_attach(dev_info_t *dip, ddi_attach_cmd_t cmd);
  82 static int      rmclomv_detach(dev_info_t *dip, ddi_detach_cmd_t cmd);
  83 static uint_t   rmclomv_break_intr(caddr_t arg);
  84 static int      rmclomv_add_intr_handlers(void);
  85 static int      rmclomv_remove_intr_handlers(void);
  86 static uint_t   rmclomv_event_data_handler(char *);
  87 static void     rmclomv_dr_data_handler(const char *, int);
  88 static int      rmclomv_open(dev_t *dev_p, int flag, int otyp, cred_t *cred_p);
  89 static int      rmclomv_close(dev_t dev, int flag, int otyp, cred_t *cred_p);
  90 static int      rmclomv_ioctl(dev_t dev, int cmd, intptr_t arg, int mode,
  91     cred_t *cred_p, int *rval_p);
  92 static void     rmclomv_checkrmc_start(void);
  93 static void     rmclomv_checkrmc_destroy(void);
  94 static void     rmclomv_checkrmc_wakeup(void *);
  95 static void     rmclomv_refresh_start(void);
  96 static void     rmclomv_refresh_destroy(void);
  97 static void     rmclomv_refresh_wakeup(void);
  98 static void     rmclomv_reset_cache(rmclomv_cache_section_t *new_chain,
  99     rmclomv_cache_section_t *new_subchain, dp_get_sysinfo_r_t *sysinfo);
 100 static rmclomv_cache_section_t *rmclomv_find_section(
 101     rmclomv_cache_section_t *start, uint16_t sensor);
 102 static rmclomv_cache_section_t *create_cache_section(int sensor_type, int num);
 103 static int      get_sensor_by_name(const rmclomv_cache_section_t *section,
 104     const char *name, int *index);
 105 static int      validate_section_entry(rmclomv_cache_section_t *section,
 106     int index);
 107 static int      add_names_to_section(rmclomv_cache_section_t *section);
 108 static void     free_section(rmclomv_cache_section_t *section);
 109 static void     add_section(rmclomv_cache_section_t **head,
 110     rmclomv_cache_section_t *section);
 111 static int      rmclomv_do_cmd(int req_cmd, int resp_cmd, int resp_len,
 112     intptr_t arg_req, intptr_t arg_res);
 113 static void     refresh_name_cache(int force_fail);
 114 static void     set_val_unav(envmon_sensor_t *sensor);
 115 static void     set_fan_unav(envmon_fan_t *fan);
 116 static int      do_psu_cmd(intptr_t arg, int mode, envmon_indicator_t *env_ind,
 117     dp_get_psu_status_t *rmc_psu, dp_get_psu_status_r_t *rmc_psu_r,
 118     int detector_type);
 119 static uint_t rmc_set_watchdog_timer(uint_t timeoutval);
 120 static uint_t rmc_clear_watchdog_timer(void);
 121 static void send_watchdog_msg(int msg);
 122 static void plat_timesync(void *arg);
 123 
 124 static kmutex_t         timesync_lock;
 125 static clock_t          timesync_interval = 0;
 126 static timeout_id_t     timesync_tid = 0;
 127 
 128 /*
 129  * Driver entry points
 130  */
 131 static struct cb_ops rmclomv_cb_ops = {
 132         rmclomv_open,   /* open */
 133         rmclomv_close,  /* close */
 134         nodev,          /* strategy() */
 135         nodev,          /* print() */
 136         nodev,          /* dump() */
 137         nodev,          /* read() */
 138         nodev,          /* write() */
 139         rmclomv_ioctl,  /* ioctl() */
 140         nodev,          /* devmap() */
 141         nodev,          /* mmap() */
 142         ddi_segmap,     /* segmap() */
 143         nochpoll,       /* poll() */
 144         ddi_prop_op,    /* prop_op() */
 145         NULL,           /* cb_str */
 146         D_NEW | D_MP    /* cb_flag */
 147 };
 148 
 149 
 150 static struct dev_ops rmclomv_ops = {
 151         DEVO_REV,
 152         0,                      /* ref count */
 153         rmclomv_getinfo,        /* getinfo() */
 154         nulldev,                /* identify() */
 155         nulldev,                /* probe() */
 156         rmclomv_attach,         /* attach() */
 157         rmclomv_detach,         /* detach */
 158         nodev,                  /* reset */
 159         &rmclomv_cb_ops,            /* pointer to cb_ops structure */
 160         (struct bus_ops *)NULL,
 161         nulldev,                /* power() */
 162         ddi_quiesce_not_supported,      /* devo_quiesce */
 163 };
 164 
 165 /*
 166  * Loadable module support.
 167  */
 168 extern struct mod_ops mod_driverops;
 169 
 170 static struct modldrv modldrv = {
 171         &mod_driverops,                     /* Type of module. This is a driver */
 172         "rmclomv control driver",       /* Name of the module */
 173         &rmclomv_ops                        /* pointer to the dev_ops structure */
 174 };
 175 
 176 static struct modlinkage modlinkage = {
 177         MODREV_1,
 178         &modldrv,
 179         NULL
 180 };
 181 
 182 /*
 183  * Device info
 184  */
 185 static dev_info_t               *rmclomv_dip = NULL;
 186 static int                      rmclomv_break_requested = B_FALSE;
 187 static ddi_softintr_t           rmclomv_softintr_id;
 188 static ddi_iblock_cookie_t      rmclomv_soft_iblock_cookie;
 189 
 190 extern void (*abort_seq_handler)();
 191 /* key_position is effective key-position. Set to locked if unknown */
 192 static rsci8 key_position = RMC_KEYSWITCH_POS_LOCKED;
 193 /* real_key_position starts off as unknown and records value actually seen */
 194 static rsci8 real_key_position = RMC_KEYSWITCH_POS_UNKNOWN;
 195 static void rmclomv_abort_seq_handler(char *msg);
 196 
 197 /*
 198  * mutexes which protect the interrupt handlers.
 199  */
 200 static kmutex_t         rmclomv_event_hdlr_lock;
 201 static kmutex_t         rmclomv_refresh_lock;
 202 static kcondvar_t       rmclomv_refresh_sig_cv;
 203 static kmutex_t         rmclomv_checkrmc_lock;
 204 static kcondvar_t       rmclomv_checkrmc_sig_cv;
 205 
 206 /*
 207  * mutex to protect the handle_name cache
 208  */
 209 static kmutex_t         rmclomv_cache_lock;
 210 
 211 /*
 212  * mutex to protect the RMC state
 213  */
 214 static kmutex_t         rmclomv_state_lock;
 215 
 216 /*
 217  * Payloads of the event handlers.
 218  */
 219 static dp_event_notification_t  rmclomv_event_payload;
 220 static rmc_comm_msg_t   rmclomv_event_payload_msg;
 221 
 222 /*
 223  * Checkrmc commands..
 224  */
 225 #define RMCLOMV_CHECKRMC_EXITNOW        (-1)
 226 #define RMCLOMV_CHECKRMC_WAIT           0
 227 #define RMCLOMV_CHECKRMC_PROCESSNOW     1
 228 
 229 /*
 230  * Checkrmc thread state
 231  */
 232 static int rmclomv_checkrmc_sig = RMCLOMV_CHECKRMC_WAIT;
 233 static kt_did_t rmclomv_checkrmc_tid = 0;
 234 
 235 /*
 236  * RMC state data
 237  */
 238 #define RMCLOMV_RMCSTATE_UNKNOWN        0
 239 #define RMCLOMV_RMCSTATE_OK             1
 240 #define RMCLOMV_RMCSTATE_FAILED         2
 241 #define RMCLOMV_RMCSTATE_DOWNLOAD       3
 242 
 243 /*
 244  * RMC error indicator values (status from last RMC command)
 245  */
 246 #define RMCLOMV_RMCERROR_NONE           0
 247 
 248 /* fail RMC after 5 minutes without a good response */
 249 #define RMCLOMV_RMCFAILTHRESHOLD        5
 250 
 251 /*
 252  * rmclomv_rmc_state is the state reported in OperationalStatus.
 253  * rmclomv_rmc_error reflects the result of the last RMC interaction.
 254  * rmclomv_rmcfailcount is used by the rmclomv_checkrmc thread to count
 255  * failures in its regular status polls. Once RMCLOMV_RMCFAILTHRESHOLD
 256  * is reached, rmclomv_rmc_state is marked as RMCLOMV_RMCSTATE_FAILED.
 257  */
 258 static int      rmclomv_rmc_state = RMCLOMV_RMCSTATE_UNKNOWN;
 259 static int      rmclomv_rmc_error = RMCLOMV_RMCERROR_NONE;
 260 static int      rmclomv_rmcfailcount;
 261 
 262 /*
 263  * Refresh commands..
 264  */
 265 #define RMCLOMV_REFRESH_EXITNOW         (-1)
 266 #define RMCLOMV_REFRESH_WAIT            0
 267 #define RMCLOMV_REFRESH_PROCESSNOW      1
 268 
 269 /*
 270  * Refresh thread state
 271  */
 272 static int rmclomv_refresh_sig = RMCLOMV_REFRESH_WAIT;
 273 static kt_did_t rmclomv_refresh_tid = 0;
 274 
 275 /*
 276  * timeout id
 277  */
 278 static timeout_id_t     timer_id;
 279 
 280 /*
 281  * Handle-name cache
 282  */
 283 #define LOCK_CACHE              mutex_enter(&rmclomv_cache_lock);
 284 #define RELEASE_CACHE           mutex_exit(&rmclomv_cache_lock);
 285 static rmclomv_cache_section_t  *rmclomv_cache;         /* main handle-names */
 286 static rmclomv_cache_section_t  *rmclomv_subcache;      /* derived names */
 287 static dp_get_sysinfo_r_t       rmclomv_sysinfo_data;
 288 static boolean_t                rmclomv_sysinfo_valid;
 289 static int                      rmclomv_cache_valid;
 290 
 291 extern pri_t maxclsyspri;
 292 
 293 /*
 294  * static strings
 295  */
 296 static const char       str_percent[]           = "%";
 297 static const char       str_rpm[]               = " rpm";
 298 static const char       str_ip_volts_ind[]      = "P_PWR";
 299 static const char       str_ip2_volts_ind[]     = "P_PWR2";
 300 static const char       str_ff_pok_ind[]        = "FF_POK";
 301 static const char       str_vlo_volts_ind[]     = "FF_UV";
 302 static const char       str_vhi_volts_ind[]     = "FF_OV";
 303 static const char       str_chi_amps_ind[]      = "FF_OC";
 304 static const char       str_chi_nr_ind[]        = "FF_NR";
 305 static const char       str_ot_tmpr_ind[]       = "FF_OT";
 306 static const char       str_fan_ind[]           = "FF_FAN";
 307 static const char       str_pdct_fan_ind[]      = "FF_PDCT_FAN";
 308 static const char       str_sc[]                = "SC";
 309 
 310 int
 311 _init(void)
 312 {
 313         int     error = 0;
 314 
 315         mutex_init(&rmclomv_event_hdlr_lock, NULL, MUTEX_DEFAULT, NULL);
 316         mutex_init(&rmclomv_checkrmc_lock, NULL, MUTEX_DRIVER, NULL);
 317         mutex_init(&rmclomv_refresh_lock, NULL, MUTEX_DRIVER, NULL);
 318         mutex_init(&rmclomv_cache_lock, NULL, MUTEX_DRIVER, NULL);
 319         mutex_init(&rmclomv_state_lock, NULL, MUTEX_DRIVER, NULL);
 320         mutex_init(&timesync_lock, NULL, MUTEX_DEFAULT, NULL);
 321         cv_init(&rmclomv_checkrmc_sig_cv, NULL, CV_DRIVER, NULL);
 322         cv_init(&rmclomv_refresh_sig_cv, NULL, CV_DRIVER, NULL);
 323 
 324         error = mod_install(&modlinkage);
 325         if (error) {
 326                 cv_destroy(&rmclomv_refresh_sig_cv);
 327                 cv_destroy(&rmclomv_checkrmc_sig_cv);
 328                 mutex_destroy(&rmclomv_state_lock);
 329                 mutex_destroy(&rmclomv_cache_lock);
 330                 mutex_destroy(&rmclomv_refresh_lock);
 331                 mutex_destroy(&rmclomv_checkrmc_lock);
 332                 mutex_destroy(&rmclomv_event_hdlr_lock);
 333         }
 334         return (error);
 335 }
 336 
 337 
 338 int
 339 _info(struct modinfo *modinfop)
 340 {
 341         return (mod_info(&modlinkage, modinfop));
 342 }
 343 
 344 
 345 int
 346 _fini(void)
 347 {
 348         int     error = 0;
 349 
 350         error = mod_remove(&modlinkage);
 351         if (error)
 352                 return (error);
 353         cv_destroy(&rmclomv_refresh_sig_cv);
 354         cv_destroy(&rmclomv_checkrmc_sig_cv);
 355         mutex_destroy(&timesync_lock);
 356         mutex_destroy(&rmclomv_state_lock);
 357         mutex_destroy(&rmclomv_cache_lock);
 358         mutex_destroy(&rmclomv_refresh_lock);
 359         mutex_destroy(&rmclomv_checkrmc_lock);
 360         mutex_destroy(&rmclomv_event_hdlr_lock);
 361         return (error);
 362 }
 363 
 364 
 365 /* ARGSUSED */
 366 static int
 367 rmclomv_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **resultp)
 368 {
 369         minor_t m = getminor((dev_t)arg);
 370 
 371         switch (cmd) {
 372         case DDI_INFO_DEVT2DEVINFO:
 373                 if ((m != 0) || (rmclomv_dip == NULL)) {
 374                         *resultp = NULL;
 375                         return (DDI_FAILURE);
 376                 }
 377                 *resultp = rmclomv_dip;
 378                 return (DDI_SUCCESS);
 379         case DDI_INFO_DEVT2INSTANCE:
 380                 *resultp = (void *)(uintptr_t)m;
 381                 return (DDI_SUCCESS);
 382         default:
 383                 return (DDI_FAILURE);
 384         }
 385 }
 386 
 387 
 388 static int
 389 rmclomv_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
 390 {
 391         int                     instance;
 392         int                     err;
 393         char                    *wdog_state;
 394         int                     attaching = 1;
 395 
 396         switch (cmd) {
 397         case DDI_ATTACH:
 398                 /*
 399                  * only allow one instance
 400                  */
 401                 instance = ddi_get_instance(dip);
 402                 if (instance != 0)
 403                         return (DDI_FAILURE);
 404 
 405                 err = ddi_create_minor_node(dip, "rmclomv", S_IFCHR,
 406                     instance, DDI_PSEUDO, NULL);
 407                 if (err != DDI_SUCCESS)
 408                         return (DDI_FAILURE);
 409 
 410                 /*
 411                  * Register with rmc_comm to prevent it being detached
 412                  * (in the unlikely event that its attach succeeded on a
 413                  * platform whose platmod doesn't lock it down).
 414                  */
 415                 err = rmc_comm_register();
 416                 if (err != DDI_SUCCESS) {
 417                         ddi_remove_minor_node(dip, NULL);
 418                         return (DDI_FAILURE);
 419                 }
 420 
 421                 /* Remember the dev info */
 422                 rmclomv_dip = dip;
 423 
 424                 /*
 425                  * Add the handlers which watch for unsolicited messages
 426                  * and post event to Sysevent Framework.
 427                  */
 428                 err = rmclomv_add_intr_handlers();
 429                 if (err != DDI_SUCCESS) {
 430                         rmc_comm_unregister();
 431                         ddi_remove_minor_node(dip, NULL);
 432                         rmclomv_dip = NULL;
 433                         return (DDI_FAILURE);
 434                 }
 435 
 436                 rmclomv_checkrmc_start();
 437                 rmclomv_refresh_start();
 438 
 439                 abort_seq_handler = rmclomv_abort_seq_handler;
 440                 ddi_report_dev(dip);
 441 
 442                 /*
 443                  * Check whether we have an application watchdog
 444                  */
 445                 if (ddi_prop_lookup_string(DDI_DEV_T_ANY, dip,
 446                     DDI_PROP_DONTPASS, RMCLOMV_WATCHDOG_MODE,
 447                     &wdog_state) == DDI_PROP_SUCCESS) {
 448                         if (strcmp(wdog_state, "app") == 0) {
 449                                 rmclomv_watchdog_mode = 1;
 450                                 watchdog_enable = 0;
 451                         }
 452                         else
 453                                 rmclomv_watchdog_mode = 0;
 454                         ddi_prop_free(wdog_state);
 455                 }
 456 
 457                 tod_ops.tod_set_watchdog_timer = rmc_set_watchdog_timer;
 458                 tod_ops.tod_clear_watchdog_timer = rmc_clear_watchdog_timer;
 459 
 460                 /*
 461                  * Now is a good time to activate hardware watchdog
 462                  * (if one exists).
 463                  */
 464                 mutex_enter(&tod_lock);
 465                 if (watchdog_enable && tod_ops.tod_set_watchdog_timer != NULL)
 466                         err = tod_ops.tod_set_watchdog_timer(0);
 467                 mutex_exit(&tod_lock);
 468                 if (err != 0)
 469                         printf("Hardware watchdog enabled\n");
 470 
 471                 /*
 472                  * Set time interval and start timesync routine.
 473                  * Also just this once set the Solaris clock
 474                  * to the RMC clock.
 475                  */
 476                 timesync_interval = drv_usectohz(5*60 * MICROSEC);
 477                 plat_timesync((void *) &attaching);
 478 
 479                 return (DDI_SUCCESS);
 480         case DDI_RESUME:
 481                 return (DDI_SUCCESS);
 482         default:
 483                 return (DDI_FAILURE);
 484         }
 485 }
 486 
 487 
 488 static int
 489 rmclomv_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
 490 {
 491         timeout_id_t    tid;
 492         int             instance;
 493         int             err;
 494 
 495         switch (cmd) {
 496         case DDI_DETACH:
 497                 instance = ddi_get_instance(dip);
 498                 if (instance != 0)
 499                         return (DDI_FAILURE);
 500 
 501                 /*
 502                  * Remove the handlers which watch for unsolicited messages
 503                  * and post event to Sysevent Framework.
 504                  */
 505                 err = rmclomv_remove_intr_handlers();
 506                 if (err != DDI_SUCCESS) {
 507                         cmn_err(CE_WARN, "Failed to remove event handlers");
 508                         return (DDI_FAILURE);
 509                 }
 510                 rmclomv_checkrmc_destroy();
 511                 rmclomv_refresh_destroy();
 512                 rmclomv_reset_cache(NULL, NULL, NULL);
 513                 ddi_remove_minor_node(dip, NULL);
 514 
 515                 mutex_enter(&timesync_lock);
 516                 tid = timesync_tid;
 517                 timesync_tid = 0;
 518                 timesync_interval = 0;
 519                 mutex_exit(&timesync_lock);
 520                 (void) untimeout(tid);
 521 
 522                 /* Forget the dev info */
 523                 rmclomv_dip = NULL;
 524                 rmc_comm_unregister();
 525                 return (DDI_SUCCESS);
 526         case DDI_SUSPEND:
 527                 return (DDI_SUCCESS);
 528         default:
 529                 return (DDI_FAILURE);
 530         }
 531 }
 532 
 533 static int
 534 rmclomv_add_intr_handlers()
 535 {
 536         int     err;
 537 
 538         if (ddi_get_soft_iblock_cookie(rmclomv_dip, DDI_SOFTINT_HIGH,
 539             &rmclomv_soft_iblock_cookie) != DDI_SUCCESS) {
 540                 return (DDI_FAILURE);
 541         }
 542         err = ddi_add_softintr(rmclomv_dip, DDI_SOFTINT_HIGH,
 543             &rmclomv_softintr_id, &rmclomv_soft_iblock_cookie, NULL,
 544             rmclomv_break_intr, NULL);
 545         if (err != DDI_SUCCESS)
 546                 return (DDI_FAILURE);
 547         rmclomv_event_payload_msg.msg_buf = (caddr_t)&rmclomv_event_payload;
 548         rmclomv_event_payload_msg.msg_len = sizeof (rmclomv_event_payload);
 549         err = rmc_comm_reg_intr(DP_RMC_EVENTS, rmclomv_event_data_handler,
 550             &rmclomv_event_payload_msg, NULL, &rmclomv_event_hdlr_lock);
 551         if (err != 0) {
 552                 ddi_remove_softintr(rmclomv_softintr_id);
 553                 return (DDI_FAILURE);
 554         }
 555         return (DDI_SUCCESS);
 556 }
 557 
 558 static int
 559 rmclomv_remove_intr_handlers(void)
 560 {
 561         int err = rmc_comm_unreg_intr(DP_RMC_EVENTS,
 562             rmclomv_event_data_handler);
 563         if (err != 0) {
 564                 cmn_err(CE_WARN, "Failed to unregister DP_RMC_EVENTS "
 565                     "handler. Err=%d", err);
 566                 return (DDI_FAILURE);
 567         }
 568         ddi_remove_softintr(rmclomv_softintr_id);
 569         return (DDI_SUCCESS);
 570 }
 571 
 572 static void
 573 rmclomv_abort_seq_handler(char *msg)
 574 {
 575         if (key_position == RMC_KEYSWITCH_POS_LOCKED)
 576                 cmn_err(CE_CONT, "KEY in LOCKED position, "
 577                     "ignoring debug enter sequence");
 578         else  {
 579                 rmclomv_break_requested = B_TRUE;
 580                 if (msg != NULL)
 581                         prom_printf("%s\n", msg);
 582 
 583                 ddi_trigger_softintr(rmclomv_softintr_id);
 584         }
 585 }
 586 
 587 /* ARGSUSED */
 588 static uint_t
 589 rmclomv_break_intr(caddr_t arg)
 590 {
 591         if (rmclomv_break_requested) {
 592                 rmclomv_break_requested = B_FALSE;
 593                 debug_enter(NULL);
 594                 return (DDI_INTR_CLAIMED);
 595         }
 596 
 597         return (DDI_INTR_UNCLAIMED);
 598 }
 599 
 600 /*
 601  * Create a cache section structure
 602  */
 603 static rmclomv_cache_section_t *
 604 create_cache_section(int sensor_type, int num)
 605 {
 606         size_t len = offsetof(rmclomv_cache_section_t, entry[0]) +
 607             num * sizeof (rmclomv_cache_entry_t);
 608         rmclomv_cache_section_t *ptr = kmem_zalloc(len, KM_SLEEP);
 609         ptr->next_section = NULL;
 610         ptr->sensor_type = sensor_type;
 611         ptr->num_entries = num;
 612         ptr->section_len = len;
 613         return (ptr);
 614 }
 615 
 616 /*
 617  * Free a cache_section.
 618  */
 619 static void
 620 free_section(rmclomv_cache_section_t *section)
 621 {
 622         size_t len = section->section_len;
 623         kmem_free(section, len);
 624 }
 625 
 626 /*
 627  * adds supplied section to end of cache chain
 628  * must be called with cache locked
 629  */
 630 static void
 631 add_section(rmclomv_cache_section_t **head, rmclomv_cache_section_t *section)
 632 {
 633         section->next_section = *head;
 634         *head = section;
 635 }
 636 
 637 /*
 638  * This function releases all cache sections and exchanges the two
 639  * chain heads for new values.
 640  */
 641 static void
 642 rmclomv_reset_cache(rmclomv_cache_section_t *new_chain,
 643     rmclomv_cache_section_t *new_subchain, dp_get_sysinfo_r_t *sysinfo)
 644 {
 645         rmclomv_cache_section_t *first;
 646         rmclomv_cache_section_t *sub_first;
 647         rmclomv_cache_section_t *next;
 648 
 649         LOCK_CACHE
 650 
 651         rmclomv_cache_valid = (new_chain != NULL);
 652         first = rmclomv_cache;
 653         rmclomv_cache = new_chain;
 654         sub_first = rmclomv_subcache;
 655         rmclomv_subcache = new_subchain;
 656 
 657         if (sysinfo == NULL)
 658                 bzero(&rmclomv_sysinfo_data, sizeof (rmclomv_sysinfo_data));
 659         else
 660                 bcopy(sysinfo, &rmclomv_sysinfo_data,
 661                     sizeof (rmclomv_sysinfo_data));
 662 
 663         rmclomv_sysinfo_valid = (sysinfo != NULL);
 664 
 665         RELEASE_CACHE
 666 
 667         while (first != NULL) {
 668                 next = first->next_section;
 669                 free_section(first);
 670                 first = next;
 671         }
 672 
 673         while (sub_first != NULL) {
 674                 next = sub_first->next_section;
 675                 free_section(sub_first);
 676                 sub_first = next;
 677         }
 678 }
 679 
 680 /*
 681  * cache must be locked before calling rmclomv_find_section
 682  */
 683 static rmclomv_cache_section_t *
 684 rmclomv_find_section(rmclomv_cache_section_t *start, uint16_t sensor)
 685 {
 686         rmclomv_cache_section_t *next = start;
 687 
 688         while ((next != NULL) && (next->sensor_type != sensor))
 689                 next = next->next_section;
 690 
 691         return (next);
 692 }
 693 
 694 /*
 695  * Return a string presenting the keyswitch position
 696  * For unknown values returns "Unknown"
 697  */
 698 static char *
 699 rmclomv_key_position(enum rmc_keyswitch_pos pos)
 700 {
 701         switch (pos) {
 702 
 703         case RMC_KEYSWITCH_POS_NORMAL:
 704                 return ("NORMAL");
 705         case RMC_KEYSWITCH_POS_DIAG:
 706                 return ("DIAG");
 707         case RMC_KEYSWITCH_POS_LOCKED:
 708                 return ("LOCKED");
 709         case RMC_KEYSWITCH_POS_OFF:
 710                 return ("STBY");
 711         default:
 712                 return ("UNKNOWN");
 713         }
 714 }
 715 
 716 /*
 717  * The sensor id name is sought in the supplied section and if found
 718  * its index within the section is written to *index.
 719  * Return value is zero for success, otherwise -1.
 720  * The cache must be locked before calling get_sensor_by_name
 721  */
 722 static int
 723 get_sensor_by_name(const rmclomv_cache_section_t *section,
 724     const char *name, int *index)
 725 {
 726         int i;
 727 
 728         for (i = 0; i < section->num_entries; i++) {
 729                 if (strcmp(name, section->entry[i].handle_name.name) == 0) {
 730                         *index = i;
 731                         return (0);
 732                 }
 733         }
 734 
 735         *index = 0;
 736         return (-1);
 737 }
 738 
 739 /*
 740  * fills in the envmon_handle name
 741  * if it is unknown (not cached), the dp_handle_t is returned as a hex-digit
 742  * string
 743  */
 744 static void
 745 rmclomv_hdl_to_envhdl(dp_handle_t hdl, envmon_handle_t *envhdl)
 746 {
 747         rmclomv_cache_section_t *next;
 748         int                     i;
 749 
 750         LOCK_CACHE
 751 
 752         for (next = rmclomv_cache; next != NULL; next = next->next_section) {
 753                 for (i = 0; i < next->num_entries; i++) {
 754                         if (next->entry[i].handle == hdl) {
 755                                 *envhdl = next->entry[i].handle_name;
 756                                         RELEASE_CACHE
 757                                         return;
 758                         }
 759                 }
 760         }
 761 
 762         /*
 763          * Sought handle not currently cached.
 764          */
 765         RELEASE_CACHE
 766 
 767         (void) snprintf(envhdl->name, sizeof (envhdl->name),
 768             "Unknown SC node 0x%x", hdl);
 769 }
 770 
 771 static void
 772 rmclomv_dr_data_handler(const char *fru_name, int hint)
 773 {
 774         int                             err = 0;
 775         nvlist_t                        *attr_list;
 776         char                            attach_pnt[MAXPATHLEN];
 777 
 778         (void) snprintf(attach_pnt, sizeof (attach_pnt), "%s", fru_name);
 779 
 780         err = nvlist_alloc(&attr_list, NV_UNIQUE_NAME_TYPE, KM_NOSLEEP);
 781         if (err != 0) {
 782                 cmn_err(CE_WARN,
 783                     "Failed to allocate name-value list for %s event", EC_DR);
 784                 return;
 785         }
 786 
 787         err = nvlist_add_string(attr_list, DR_AP_ID, attach_pnt);
 788         if (err != 0) {
 789                 cmn_err(CE_WARN, "Failed to add attr [%s] for %s event",
 790                     DR_AP_ID, EC_DR);
 791                 nvlist_free(attr_list);
 792                 return;
 793         }
 794 
 795         /*
 796          * Add the hint
 797          */
 798         err = nvlist_add_string(attr_list, DR_HINT, SE_HINT2STR(hint));
 799         if (err != 0) {
 800                 cmn_err(CE_WARN, "Failed to add attr [%s] for %s event",
 801                     DR_HINT, EC_DR);
 802                 nvlist_free(attr_list);
 803                 return;
 804         }
 805 
 806         err = ddi_log_sysevent(rmclomv_dip, DDI_VENDOR_SUNW, EC_DR,
 807             ESC_DR_AP_STATE_CHANGE, attr_list, NULL, DDI_NOSLEEP);
 808         if (err != 0) {
 809                 cmn_err(CE_WARN, "Failed to log %s/%s event",
 810                     DR_AP_ID, EC_DR);
 811         }
 812 
 813         nvlist_free(attr_list);
 814 }
 815 
 816 static void
 817 fan_sysevent(char *fru_name, char *sensor_name, int sub_event)
 818 {
 819         nvlist_t                *attr_list;
 820         char                    fan_str[MAXNAMELEN];
 821         int                     err;
 822 
 823         err = nvlist_alloc(&attr_list, NV_UNIQUE_NAME_TYPE, KM_NOSLEEP);
 824         if (err != 0) {
 825                 cmn_err(CE_WARN,
 826                     "Failed to allocate name-value list for %s/%s event",
 827                     EC_ENV, ESC_ENV_FAN);
 828                 return;
 829         }
 830 
 831         err = nvlist_add_string(attr_list, ENV_FRU_ID, fru_name);
 832         if (err != 0) {
 833                 cmn_err(CE_WARN, "Failed to add attr [%s] for %s/%s event",
 834                     ENV_FRU_ID, EC_ENV, ESC_ENV_FAN);
 835                 nvlist_free(attr_list);
 836                 return;
 837         }
 838 
 839         err = nvlist_add_string(attr_list, ENV_FRU_RESOURCE_ID, sensor_name);
 840         if (err != 0) {
 841                 cmn_err(CE_WARN, "Failed to add attr [%s] for %s/%s event",
 842                     ENV_FRU_RESOURCE_ID, EC_ENV, ESC_ENV_FAN);
 843                 nvlist_free(attr_list);
 844                 return;
 845         }
 846 
 847         err = nvlist_add_string(attr_list, ENV_FRU_DEVICE, ENV_RESERVED_ATTR);
 848         if (err != 0) {
 849                 cmn_err(CE_WARN, "Failed to add attr [%s] for %s/%s event",
 850                     ENV_FRU_DEVICE, EC_ENV, ESC_ENV_FAN);
 851                 nvlist_free(attr_list);
 852                 return;
 853         }
 854 
 855         err = nvlist_add_int32(attr_list, ENV_FRU_STATE,
 856             (sub_event == RMC_ENV_FAULT_EVENT) ? ENV_FAILED : ENV_OK);
 857         if (err != 0) {
 858                 cmn_err(CE_WARN, "Failed to add attr [%s] for %s/%s event",
 859                     ENV_FRU_STATE, EC_ENV, ESC_ENV_FAN);
 860                 nvlist_free(attr_list);
 861                 return;
 862         }
 863 
 864         if (sub_event == RMC_ENV_FAULT_EVENT) {
 865                 (void) snprintf(fan_str, sizeof (fan_str),
 866                     "fan %s/%s is now failed", fru_name, sensor_name);
 867         } else {
 868                 (void) snprintf(fan_str, sizeof (fan_str),
 869                     "fan %s/%s is now ok", fru_name, sensor_name);
 870         }
 871         err = nvlist_add_string(attr_list, ENV_MSG, fan_str);
 872         if (err != 0) {
 873                 cmn_err(CE_WARN, "Failed to add attr [%s] for %s/%s event",
 874                     ENV_MSG, EC_ENV, ESC_ENV_FAN);
 875                 nvlist_free(attr_list);
 876                 return;
 877         }
 878 
 879         err = ddi_log_sysevent(rmclomv_dip, DDI_VENDOR_SUNW, EC_ENV,
 880             ESC_ENV_FAN, attr_list, NULL, DDI_NOSLEEP);
 881         if (err != 0) {
 882                 cmn_err(CE_WARN, "Failed to log %s/%s event",
 883                     EC_ENV, ESC_ENV_FAN);
 884         }
 885 
 886         cmn_err(CE_NOTE, "%s", fan_str);
 887         nvlist_free(attr_list);
 888 }
 889 
 890 static void
 891 threshold_sysevent(char *fru_name, char *sensor_name, int sub_event,
 892         char event_type)
 893 {
 894         nvlist_t                *attr_list;
 895         int                     err;
 896         char                    *subclass;
 897         char                    sensor_str[MAXNAMELEN];
 898 
 899         subclass = (event_type == 'T') ? ESC_ENV_TEMP : ESC_ENV_POWER;
 900 
 901         err = nvlist_alloc(&attr_list, NV_UNIQUE_NAME_TYPE, KM_NOSLEEP);
 902         if (err != 0) {
 903                 cmn_err(CE_WARN,
 904                     "Failed to allocate name-value list for %s/%s event",
 905                     EC_ENV, subclass);
 906                 return;
 907         }
 908 
 909         err = nvlist_add_string(attr_list, ENV_FRU_ID, fru_name);
 910         if (err != 0) {
 911                 cmn_err(CE_WARN, "Failed to add attr [%s] for %s/%s event",
 912                     ENV_FRU_ID, EC_ENV, subclass);
 913                 nvlist_free(attr_list);
 914                 return;
 915         }
 916 
 917         err = nvlist_add_string(attr_list, ENV_FRU_RESOURCE_ID, sensor_name);
 918         if (err != 0) {
 919                 cmn_err(CE_WARN, "Failed to add attr [%s] for %s/%s event",
 920                     ENV_FRU_RESOURCE_ID, EC_ENV, subclass);
 921                 nvlist_free(attr_list);
 922                 return;
 923         }
 924 
 925         err = nvlist_add_string(attr_list, ENV_FRU_DEVICE, ENV_RESERVED_ATTR);
 926         if (err != 0) {
 927                 cmn_err(CE_WARN, "Failed to add attr [%s] for %s/%s event",
 928                     ENV_FRU_DEVICE, EC_ENV, subclass);
 929                 nvlist_free(attr_list);
 930                 return;
 931         }
 932 
 933         switch (sub_event) {
 934         case RMC_ENV_OK_EVENT:
 935                 err = nvlist_add_int32(attr_list, ENV_FRU_STATE, ENV_OK);
 936                 break;
 937         case RMC_ENV_WARNING_THRESHOLD_EVENT:
 938                 err = nvlist_add_int32(attr_list, ENV_FRU_STATE, ENV_WARNING);
 939                 break;
 940         case RMC_ENV_SHUTDOWN_THRESHOLD_EVENT:
 941                 err = nvlist_add_int32(attr_list, ENV_FRU_STATE, ENV_FAILED);
 942                 break;
 943         }
 944         if (err != 0) {
 945                 cmn_err(CE_WARN, "Failed to add attr [%s] for %s/%s event",
 946                     ENV_FRU_STATE, EC_ENV, subclass);
 947                 nvlist_free(attr_list);
 948                 return;
 949         }
 950 
 951         switch (sub_event) {
 952         case RMC_ENV_OK_EVENT:
 953                 (void) snprintf(sensor_str, sizeof (sensor_str),
 954                     "sensor %s/%s is now ok", fru_name,
 955                     sensor_name);
 956                 break;
 957         case RMC_ENV_WARNING_THRESHOLD_EVENT:
 958                 (void) snprintf(sensor_str, sizeof (sensor_str),
 959                     "sensor %s/%s is now outside warning thresholds", fru_name,
 960                     sensor_name);
 961                 break;
 962         case RMC_ENV_SHUTDOWN_THRESHOLD_EVENT:
 963                 (void) snprintf(sensor_str, sizeof (sensor_str),
 964                     "sensor %s/%s is now outside shutdown thresholds", fru_name,
 965                     sensor_name);
 966                 break;
 967         }
 968         err = nvlist_add_string(attr_list, ENV_MSG, sensor_str);
 969         if (err != 0) {
 970                 cmn_err(CE_WARN, "Failed to add attr [%s] for %s/%s event",
 971                     ENV_MSG, EC_ENV, subclass);
 972                 nvlist_free(attr_list);
 973                 return;
 974         }
 975 
 976         err = ddi_log_sysevent(rmclomv_dip, DDI_VENDOR_SUNW, EC_ENV,
 977             subclass, attr_list, NULL, DDI_NOSLEEP);
 978         if (err != 0) {
 979                 cmn_err(CE_WARN, "Failed to log %s/%s event",
 980                     EC_ENV, subclass);
 981         }
 982 
 983         cmn_err(CE_NOTE, "%s", sensor_str);
 984         nvlist_free(attr_list);
 985 }
 986 
 987 static uint_t
 988 rmclomv_event_data_handler(char *arg)
 989 {
 990         dp_event_notification_t *payload;
 991         rmc_comm_msg_t  *msg;
 992         envmon_handle_t envhdl;
 993         int hint;
 994         char *ptr, *save_ptr;
 995 
 996         if (arg == NULL) {
 997                 return (DDI_INTR_CLAIMED);
 998         }
 999 
1000         msg = (rmc_comm_msg_t *)arg;
1001         if (msg->msg_buf == NULL) {
1002                 return (DDI_INTR_CLAIMED);
1003         }
1004 
1005         payload = (dp_event_notification_t *)msg->msg_buf;
1006         switch (payload->event) {
1007 
1008         case RMC_KEYSWITCH_EVENT:
1009                 real_key_position = payload->event_info.ev_keysw.key_position;
1010                 cmn_err(CE_NOTE, "keyswitch change event - state = %s",
1011                     rmclomv_key_position(real_key_position));
1012                 if ((real_key_position != RMC_KEYSWITCH_POS_UNKNOWN) &&
1013                     (real_key_position <= RMC_KEYSWITCH_POS_OFF)) {
1014                         key_position = real_key_position;
1015                 } else {
1016                         /* treat unknown key position as locked */
1017                         key_position = RMC_KEYSWITCH_POS_LOCKED;
1018                 }
1019                 break;
1020 
1021         case RMC_HPU_EVENT:
1022                 /*
1023                  * send appropriate sysevent
1024                  */
1025                 switch (payload->event_info.ev_hpunot.sub_event) {
1026                 case RMC_HPU_REMOVE_EVENT:
1027                         hint = SE_HINT_REMOVE;
1028                         break;
1029                 case RMC_HPU_INSERT_EVENT:
1030                         hint = SE_HINT_INSERT;
1031                         break;
1032                 default:
1033                         hint = SE_NO_HINT;
1034                         break;
1035                 }
1036                 rmclomv_hdl_to_envhdl(payload->event_info.ev_hpunot.hpu_hdl,
1037                     &envhdl);
1038                 rmclomv_dr_data_handler(envhdl.name, hint);
1039                 break;
1040 
1041         case RMC_INIT_EVENT:
1042                 /*
1043                  * Wake up the refresh thread.
1044                  */
1045                 rmclomv_refresh_wakeup();
1046 
1047                 /*
1048                  * Wake up the checkrmc thread for an early indication to PICL
1049                  */
1050                 rmclomv_checkrmc_wakeup(NULL);
1051                 break;
1052 
1053         case RMC_ENV_EVENT:
1054                 rmclomv_hdl_to_envhdl(payload->event_info.ev_envnot.env_hdl,
1055                     &envhdl);
1056 
1057                 /* split name into fru name and sensor name */
1058                 ptr = strchr(envhdl.name, '.');
1059 
1060                 /* must have at least one '.' */
1061                 if (ptr == NULL)
1062                         break;
1063 
1064                 /* find last '.' - convert the others to '/' */
1065                 for (;;) {
1066                         save_ptr = ptr;
1067                         ptr = strchr(ptr, '.');
1068                         if (ptr == NULL) {
1069                                 ptr = save_ptr;
1070                                 break;
1071                         }
1072                         *save_ptr = '/';
1073                 }
1074                 *ptr = '\0';
1075                 ptr++;
1076                 /* is it a voltage or temperature sensor? */
1077                 if ((*ptr == 'V' || *ptr == 'T') && *(ptr + 1) == '_') {
1078                         switch (payload->event_info.ev_envnot.sub_event) {
1079                         case RMC_ENV_WARNING_THRESHOLD_EVENT:
1080                         case RMC_ENV_SHUTDOWN_THRESHOLD_EVENT:
1081                         case RMC_ENV_OK_EVENT:
1082                                 threshold_sysevent(envhdl.name, ptr,
1083                                     payload->event_info.ev_envnot.sub_event,
1084                                     *ptr);
1085                                 break;
1086                         default:
1087                                 break;
1088                         }
1089                 }
1090 
1091                 /*
1092                  * is it a fan sensor?
1093                  * Fan sensor names end either in RS, F0 or F1
1094                  */
1095                 if ((*ptr == 'R' && *(ptr + 1) == 'S' && *(ptr + 2) == '\0') ||
1096                     (*ptr == 'F' && *(ptr + 1) == '0' && *(ptr + 2) == '\0') ||
1097                     (*ptr == 'F' && *(ptr + 1) == '1' && *(ptr + 2) == '\0')) {
1098                         switch (payload->event_info.ev_envnot.sub_event) {
1099                         case RMC_ENV_FAULT_EVENT:
1100                         case RMC_ENV_OK_EVENT:
1101                                 fan_sysevent(envhdl.name, ptr,
1102                                     payload->event_info.ev_envnot.sub_event);
1103                                 break;
1104                         default:
1105                                 break;
1106                         }
1107                 }
1108                 break;
1109 
1110         case RMC_LOG_EVENT:
1111         {
1112                 int level = 10;
1113                 int flags = SL_NOTE | SL_CONSOLE;
1114                 char *message =
1115                     (char *)payload->event_info.ev_rmclog.log_record;
1116 
1117                 message[ payload->event_info.ev_rmclog.log_record_size] = '\0';
1118 
1119                 /*
1120                  * Logs have a 10 character prefix - specifying the severity of
1121                  * the event being logged. Thus all the magic number 10s down
1122                  * here
1123                  */
1124                 if (0 == strncmp("CRITICAL: ", message, 10)) {
1125                         message += 10;
1126                         level = 0;
1127                         flags = SL_FATAL | SL_ERROR | SL_CONSOLE;
1128                 } else if (0 == strncmp("MAJOR:    ", message, 10)) {
1129                         message += 10;
1130                         level = 5;
1131                         flags = SL_WARN | SL_ERROR | SL_CONSOLE;
1132                 } else if (0 == strncmp("MINOR:    ", message, 10)) {
1133                         message += 10;
1134                         level = 10;
1135                         flags = SL_NOTE | SL_CONSOLE;
1136                 }
1137 
1138                 (void) strlog(0, 0, level, flags, message);
1139                 break;
1140         }
1141 
1142         default:
1143                 return (DDI_INTR_CLAIMED);
1144         }
1145 
1146         return (DDI_INTR_CLAIMED);
1147 }
1148 
1149 /*ARGSUSED*/
1150 static int
1151 rmclomv_open(dev_t *dev_p, int flag, int otyp, cred_t *cred_p)
1152 {
1153         int error = 0;
1154         int instance = getminor(*dev_p);
1155 
1156         if (instance != 0)
1157                 return (ENXIO);
1158 
1159         if ((flag & FWRITE) != 0 && (error = drv_priv(cred_p)) != 0)
1160                 return (error);
1161 
1162         return (0);
1163 }
1164 
1165 /*ARGSUSED*/
1166 static int
1167 rmclomv_close(dev_t dev, int flag, int otyp, cred_t *cred_p)
1168 {
1169         return (DDI_SUCCESS);
1170 }
1171 
1172 static int
1173 rmclomv_do_cmd(int req_cmd, int resp_cmd, int resp_len, intptr_t arg_req,
1174     intptr_t arg_res)
1175 {
1176         rmc_comm_msg_t request, *reqp = &request;
1177         rmc_comm_msg_t response, *resp = &response;
1178         int rv = 0;
1179 
1180         bzero((caddr_t)&request, sizeof (request));
1181         reqp->msg_type = req_cmd;
1182         reqp->msg_buf = (caddr_t)arg_req;
1183         bzero((caddr_t)&response, sizeof (response));
1184         resp->msg_type = resp_cmd;
1185         resp->msg_buf = (caddr_t)arg_res;
1186         resp->msg_len = resp_len;
1187 
1188         switch (req_cmd) {
1189         case DP_GET_SYSINFO:
1190                 resp->msg_len = sizeof (dp_get_sysinfo_r_t);
1191                 break;
1192         case DP_GET_EVENT_LOG:
1193                 resp->msg_len = sizeof (dp_get_event_log_r_t);
1194                 break;
1195         case DP_GET_VOLTS:
1196                 reqp->msg_len = sizeof (dp_get_volts_t);
1197                 break;
1198         case DP_GET_TEMPERATURES:
1199                 reqp->msg_len = sizeof (dp_get_temperatures_t);
1200                 break;
1201         case DP_GET_CIRCUIT_BRKS:
1202                 reqp->msg_len = sizeof (dp_get_circuit_brks_t);
1203                 break;
1204         case DP_GET_FAN_STATUS:
1205                 reqp->msg_len = sizeof (dp_get_fan_status_t);
1206                 break;
1207         case DP_GET_PSU_STATUS:
1208                 reqp->msg_len = sizeof (dp_get_psu_status_t);
1209                 break;
1210         case DP_GET_LED_STATE:
1211                 reqp->msg_len = sizeof (dp_get_led_state_t);
1212                 break;
1213         case DP_SET_LED_STATE:
1214                 reqp->msg_len = sizeof (dp_set_led_state_t);
1215                 break;
1216         case DP_GET_FRU_STATUS:
1217                 reqp->msg_len = sizeof (dp_get_fru_status_t);
1218                 break;
1219         case DP_GET_HANDLE_NAME:
1220                 reqp->msg_len = sizeof (dp_get_handle_name_t);
1221                 break;
1222         case DP_GET_ALARM_STATE:
1223                 reqp->msg_len = sizeof (dp_get_alarm_state_t);
1224                 break;
1225         case DP_SET_ALARM_STATE:
1226                 reqp->msg_len = sizeof (dp_set_alarm_state_t);
1227                 break;
1228         case DP_GET_SDP_VERSION:
1229                 resp->msg_len = sizeof (dp_get_sdp_version_r_t);
1230                 break;
1231         case DP_GET_CHASSIS_SERIALNUM:
1232                 reqp->msg_len = 0;
1233                 break;
1234         case DP_GET_DATE_TIME:
1235                 reqp->msg_len = 0;
1236                 break;
1237         default:
1238                 return (EINVAL);
1239         }
1240 
1241         rv = rmc_comm_request_response(reqp, resp,
1242             RMCLOMV_DEFAULT_MAX_MBOX_WAIT_TIME);
1243 
1244         if (rv != RCNOERR) {
1245                 /*
1246                  * RMC returned an error or failed to respond.
1247                  * Where the RMC itself is implicated, rmclomv_rmc_error
1248                  * is set non-zero. It is cleared after an error free exchange.
1249                  * Two failure cases are distinguished:
1250                  * RMCLOMV_RMCSTATE_FAILED and RMCLOMV_RMCSTATE_DOWNLOAD.
1251                  */
1252                 switch (rv) {
1253                 case RCENOSOFTSTATE:
1254                         /* invalid/NULL soft state structure */
1255                         return (EIO);
1256                 case RCENODATALINK:
1257                         /*
1258                          * firmware download in progress,
1259                          * can you come back later?
1260                          */
1261                         rmclomv_rmc_error = RMCLOMV_RMCSTATE_DOWNLOAD;
1262                         rmclomv_rmc_state = RMCLOMV_RMCSTATE_DOWNLOAD;
1263                         return (EAGAIN);
1264                 case RCENOMEM:
1265                         /* memory problems */
1266                         return (ENOMEM);
1267                 case RCECANTRESEND:
1268                         /* resend failed */
1269                         rmclomv_rmc_error = RMCLOMV_RMCSTATE_FAILED;
1270                         return (EIO);
1271                 case RCEMAXRETRIES:
1272                         /* reply not received - retries exceeded */
1273                         rmclomv_rmc_error = RMCLOMV_RMCSTATE_FAILED;
1274                         return (EINTR);
1275                 case RCETIMEOUT:
1276                         /* reply not received - command has timed out */
1277                         rmclomv_rmc_error = RMCLOMV_RMCSTATE_FAILED;
1278                         return (EINTR);
1279                 case RCEINVCMD:
1280                         /* data protocol cmd not supported */
1281                         return (ENOTSUP);
1282                 case RCEINVARG:
1283                         /* invalid argument(s) */
1284                         return (ENOTSUP);
1285                 case RCEGENERIC:
1286                         /* generic error */
1287                         rmclomv_rmc_error = RMCLOMV_RMCSTATE_FAILED;
1288                         return (EIO);
1289                 default:
1290                         rmclomv_rmc_error = RMCLOMV_RMCSTATE_FAILED;
1291                         return (EIO);
1292                 }
1293         }
1294 
1295         rmclomv_rmc_error = RMCLOMV_RMCERROR_NONE;
1296         return (0);
1297 }
1298 
1299 /*
1300  * validate_section_entry checks that the entry at the specified index
1301  * is valid and not duplicated by an entry above. If these tests fail
1302  * the entry is removed and B_FALSE returned. Otherwise returns B_TRUE.
1303  */
1304 static int
1305 validate_section_entry(rmclomv_cache_section_t *section, int index)
1306 {
1307         int                     i;
1308         rmclomv_cache_entry_t   *entry;
1309 
1310         for (i = index; i < section->num_entries; i++) {
1311                 entry = &section->entry[i];
1312                 if (entry->handle_name.name[0] == '\0') {
1313                         cmn_err(CE_WARN,
1314                             "rmclomv: empty handle_name, handle 0x%x type %x",
1315                             entry->handle, section->sensor_type);
1316                 } else if (entry->ind_mask != 0) {
1317                         continue;       /* skip special entries */
1318                 } else if (entry->handle == DP_NULL_HANDLE) {
1319                         cmn_err(CE_WARN,
1320                             "rmclomv: null handle id for \"%s\" type %x",
1321                             entry->handle_name.name, section->sensor_type);
1322                 } else if (i == index) {
1323                         continue;
1324                 } else if (section->entry[index].handle == entry->handle) {
1325                         cmn_err(CE_WARN,
1326                             "rmclomv: duplicate handle 0x%x type %x",
1327                             entry->handle, section->sensor_type);
1328                 } else if (strcmp(entry->handle_name.name,
1329                     section->entry[index].handle_name.name) == 0) {
1330                         cmn_err(CE_WARN,
1331                             "rmclomv: duplicate handle_name \"%s\", "
1332                             "handle 0x%x type %x", entry->handle_name.name,
1333                             entry->handle, section->sensor_type);
1334                 } else
1335                         continue;
1336 
1337                 /*
1338                  * need to remove the entry at index
1339                  */
1340                 section->num_entries--;
1341 
1342                 for (i = index; i < section->num_entries; i++) {
1343                         section->entry[i] = section->entry[i + 1];
1344                 }
1345 
1346                 return (B_FALSE);
1347         }
1348 
1349         return (B_TRUE);
1350 }
1351 
1352 /*
1353  * Populate a section containing handles with corresponding names
1354  * The supplied section structure must not be publically visible and the
1355  * name cache must not be locked either (because RMC i/o is required).
1356  *
1357  * This is the place where a sanity check is applied. Entries containing
1358  * duplicate handles, duplicate names or empty names are removed and the
1359  * structure is compacted. As a result num_entries may be reduced.
1360  */
1361 static int
1362 add_names_to_section(rmclomv_cache_section_t *section)
1363 {
1364         int                     retval = 0;
1365         int                     ditched = B_FALSE;
1366         int                     index;
1367         dp_get_handle_name_r_t  handle_name_r;
1368         rmclomv_cache_entry_t   *entry;
1369 
1370         for (index = 0; index < section->num_entries; index++) {
1371                 entry = &section->entry[index];
1372                 if (entry->ind_mask != 0)
1373                         continue;       /* skip special entries */
1374                 handle_name_r.handle = entry->handle;
1375                 retval = rmclomv_do_cmd(DP_GET_HANDLE_NAME,
1376                     DP_GET_HANDLE_NAME_R, sizeof (handle_name_r),
1377                     (intptr_t)&handle_name_r, (intptr_t)&handle_name_r);
1378                 if (retval == 0)
1379                         bcopy(handle_name_r.name,
1380                             entry->handle_name.name, DP_MAX_HANDLE_NAME);
1381         }
1382 
1383         /*
1384          * now ditch invalid and duplicate entries
1385          */
1386         for (index = 0; index < section->num_entries; index++) {
1387                 while (validate_section_entry(section, index) == B_FALSE)
1388                         ditched = B_TRUE;
1389         }
1390 
1391         if (ditched)
1392                 cmn_err(CE_WARN, "Retaining %d nodes of type %d",
1393                     section->num_entries, section->sensor_type);
1394 
1395         return (retval);
1396 }
1397 
1398 /*
1399  * The supplied (PSU) cache section is traversed and entries are created
1400  * for the individual indicators belonging to a PSU. These entries are
1401  * placed in a private chain. The caller, subsequently acquires the
1402  * cache lock and copies the chain head to make it public.
1403  * The handle-names for PSU indicators are derived from the parent PSU
1404  * handle-name.
1405  * NOTE: add_names_to_section() may have reduced psu_section->num_entries
1406  *       so DON'T USE psu_resp->num_psus
1407  */
1408 static void
1409 make_psu_subsections(rmclomv_cache_section_t *psu_section,
1410     rmclomv_cache_section_t **chain_head, dp_get_psu_status_r_t *psu_resp)
1411 {
1412         int                     index;
1413         int                     subindex = 0;
1414         rmclomv_cache_section_t *subsection;
1415         rmclomv_cache_entry_t   *src_entry;
1416         rmclomv_cache_entry_t   *dst_entry;
1417 
1418         subsection = create_cache_section(RMCLOMV_VOLT_IND,
1419             RMCLOMV_MAX_VI_PER_PSU * psu_section->num_entries);
1420         for (index = 0; index < psu_section->num_entries; index++) {
1421                 src_entry = &psu_section->entry[index];
1422                 if ((psu_resp->psu_status[index].mask &
1423                     DP_PSU_INPUT_STATUS) != 0) {
1424                         dst_entry = &subsection->entry[subindex++];
1425                         dst_entry->handle = src_entry->handle;
1426                         dst_entry->ind_mask = DP_PSU_INPUT_STATUS;
1427                         (void) snprintf(dst_entry->handle_name.name,
1428                             ENVMON_MAXNAMELEN, "%s.%s",
1429                             src_entry->handle_name.name,
1430                             str_ip_volts_ind);
1431                 }
1432 
1433                 if ((psu_resp->psu_status[index].mask &
1434                     DP_PSU_SEC_INPUT_STATUS) != 0) {
1435                         dst_entry = &subsection->entry[subindex++];
1436                         dst_entry->handle = src_entry->handle;
1437                         dst_entry->ind_mask = DP_PSU_SEC_INPUT_STATUS;
1438                         (void) snprintf(dst_entry->handle_name.name,
1439                             ENVMON_MAXNAMELEN, "%s.%s",
1440                             src_entry->handle_name.name,
1441                             str_ip2_volts_ind);
1442                 }
1443 
1444                 if ((psu_resp->psu_status[index].mask &
1445                     DP_PSU_OUTPUT_STATUS) != 0) {
1446                         dst_entry = &subsection->entry[subindex++];
1447                         dst_entry->handle = src_entry->handle;
1448                         dst_entry->ind_mask = DP_PSU_OUTPUT_STATUS;
1449                         (void) snprintf(dst_entry->handle_name.name,
1450                             ENVMON_MAXNAMELEN, "%s.%s",
1451                             src_entry->handle_name.name,
1452                             str_ff_pok_ind);
1453                 }
1454 
1455                 if ((psu_resp->psu_status[index].mask &
1456                     DP_PSU_OUTPUT_VLO_STATUS) != 0) {
1457                         dst_entry = &subsection->entry[subindex++];
1458                         dst_entry->handle = src_entry->handle;
1459                         dst_entry->ind_mask = DP_PSU_OUTPUT_VLO_STATUS;
1460                         (void) snprintf(dst_entry->handle_name.name,
1461                             ENVMON_MAXNAMELEN, "%s.%s",
1462                             src_entry->handle_name.name,
1463                             str_vlo_volts_ind);
1464                 }
1465 
1466                 if ((psu_resp->psu_status[index].mask &
1467                     DP_PSU_OUTPUT_VHI_STATUS) != 0) {
1468                         dst_entry = &subsection->entry[subindex++];
1469                         dst_entry->handle = src_entry->handle;
1470                         dst_entry->ind_mask = DP_PSU_OUTPUT_VHI_STATUS;
1471                         (void) snprintf(dst_entry->handle_name.name,
1472                             ENVMON_MAXNAMELEN, "%s.%s",
1473                             src_entry->handle_name.name,
1474                             str_vhi_volts_ind);
1475                 }
1476         }
1477         /*
1478          * Adjust number of entries value in cache section
1479          * to match the facts.
1480          */
1481         subsection->num_entries = subindex;
1482         add_section(chain_head, subsection);
1483 
1484         subsection = create_cache_section(RMCLOMV_AMP_IND,
1485             RMCLOMV_MAX_CI_PER_PSU * psu_section->num_entries);
1486         subindex = 0;
1487         for (index = 0; index < psu_section->num_entries; index++) {
1488                 int mask = psu_resp->psu_status[index].mask;
1489                 src_entry = &psu_section->entry[index];
1490                 if ((mask & DP_PSU_OUTPUT_AHI_STATUS) != 0) {
1491                         dst_entry = &subsection->entry[subindex++];
1492                         dst_entry->handle = src_entry->handle;
1493                         dst_entry->ind_mask = DP_PSU_OUTPUT_AHI_STATUS;
1494                         (void) snprintf(dst_entry->handle_name.name,
1495                             ENVMON_MAXNAMELEN, "%s.%s",
1496                             src_entry->handle_name.name,
1497                             str_chi_amps_ind);
1498                 }
1499                 if ((mask & DP_PSU_NR_WARNING) != 0) {
1500                         dst_entry = &subsection->entry[subindex++];
1501                         dst_entry->handle = src_entry->handle;
1502                         dst_entry->ind_mask = DP_PSU_NR_WARNING;
1503                         (void) snprintf(dst_entry->handle_name.name,
1504                             ENVMON_MAXNAMELEN, "%s.%s",
1505                             src_entry->handle_name.name,
1506                             str_chi_nr_ind);
1507                 }
1508         }
1509         subsection->num_entries = subindex;
1510         add_section(chain_head, subsection);
1511 
1512         subsection = create_cache_section(RMCLOMV_TEMP_IND,
1513             psu_section->num_entries);
1514         subindex = 0;
1515         for (index = 0; index < psu_section->num_entries; index++) {
1516                 if ((psu_resp->psu_status[index].mask &
1517                     DP_PSU_OVERTEMP_FAULT) != 0) {
1518                         src_entry = &psu_section->entry[index];
1519                         dst_entry = &subsection->entry[subindex++];
1520                         dst_entry->handle = src_entry->handle;
1521                         dst_entry->ind_mask = DP_PSU_OVERTEMP_FAULT;
1522                         (void) snprintf(dst_entry->handle_name.name,
1523                             ENVMON_MAXNAMELEN, "%s.%s",
1524                             src_entry->handle_name.name,
1525                             str_ot_tmpr_ind);
1526                 }
1527         }
1528         subsection->num_entries = subindex;
1529         add_section(chain_head, subsection);
1530 
1531         subsection = create_cache_section(RMCLOMV_FAN_IND,
1532             RMCLOMV_MAX_FI_PER_PSU * psu_section->num_entries);
1533         subindex = 0;
1534         for (index = 0; index < psu_section->num_entries; index++) {
1535                 int mask = psu_resp->psu_status[index].mask;
1536                 src_entry = &psu_section->entry[index];
1537                 if ((mask & DP_PSU_FAN_FAULT) != 0) {
1538                         dst_entry = &subsection->entry[subindex++];
1539                         dst_entry->handle = src_entry->handle;
1540                         dst_entry->ind_mask = DP_PSU_FAN_FAULT;
1541                         (void) snprintf(dst_entry->handle_name.name,
1542                             ENVMON_MAXNAMELEN, "%s.%s",
1543                             src_entry->handle_name.name, str_fan_ind);
1544                 }
1545                 if ((mask & DP_PSU_PDCT_FAN) != 0) {
1546                         dst_entry = &subsection->entry[subindex++];
1547                         dst_entry->handle = src_entry->handle;
1548                         dst_entry->ind_mask = DP_PSU_PDCT_FAN;
1549                         (void) snprintf(dst_entry->handle_name.name,
1550                             ENVMON_MAXNAMELEN, "%s.%s",
1551                             src_entry->handle_name.name, str_pdct_fan_ind);
1552                 }
1553         }
1554         subsection->num_entries = subindex;
1555         add_section(chain_head, subsection);
1556 }
1557 
1558 static void
1559 refresh_name_cache(int force_fail)
1560 {
1561         union {
1562                 dp_get_volts_t          u_volts_cmd;
1563                 dp_get_temperatures_t   u_temp_cmd;
1564                 dp_get_circuit_brks_t   u_ampi_cmd;
1565                 dp_get_fan_status_t     u_fan_cmd;
1566                 dp_get_psu_status_t     u_psu_cmd;
1567                 dp_get_fru_status_t     u_fru_cmd;
1568                 dp_get_led_state_t      u_led_cmd;
1569                 dp_set_led_state_t      u_setled_cmd;
1570                 dp_get_alarm_state_t    u_alarm_cmd;
1571                 dp_set_alarm_state_t    u_setalarm_cmd;
1572         } rmc_cmdbuf;
1573 
1574 /* defines for accessing union fields */
1575 #define volts_cmd       rmc_cmdbuf.u_volts_cmd
1576 #define temp_cmd        rmc_cmdbuf.u_temp_cmd
1577 #define ampi_cmd        rmc_cmdbuf.u_ampi_cmd
1578 #define fan_cmd         rmc_cmdbuf.u_fan_cmd
1579 #define psu_cmd         rmc_cmdbuf.u_psu_cmd
1580 #define fru_cmd         rmc_cmdbuf.u_fru_cmd
1581 #define led_cmd         rmc_cmdbuf.u_led_cmd
1582 #define setled_cmd      rmc_cmdbuf.u_setled_cmd
1583 #define alarm_cmd       rmc_cmdbuf.u_alarm_cmd
1584 #define setalarm_cmd    rmc_cmdbuf.u_setalarm_cmd
1585 
1586         /*
1587          * Data area to read sensor data into
1588          */
1589         static union {
1590                 char                    reservation[RMCRESBUFLEN];
1591                 dp_get_volts_r_t        u_volts_r;
1592                 dp_get_temperatures_r_t u_temp_r;
1593                 dp_get_circuit_brks_r_t u_ampi_r;
1594                 dp_get_fan_status_r_t   u_fan_r;
1595                 dp_get_psu_status_r_t   u_psu_r;
1596                 dp_get_fru_status_r_t   u_fru_r;
1597                 dp_get_led_state_r_t    u_led_r;
1598                 dp_set_led_state_r_t    u_setled_r;
1599                 dp_get_alarm_state_r_t  u_alarm_r;
1600                 dp_set_alarm_state_r_t  u_setalarm_r;
1601         } rmc_sensbuf;
1602 
1603 /* defines for accessing union fields */
1604 #define volts_r         rmc_sensbuf.u_volts_r
1605 #define temp_r          rmc_sensbuf.u_temp_r
1606 #define ampi_r          rmc_sensbuf.u_ampi_r
1607 #define fan_r           rmc_sensbuf.u_fan_r
1608 #define psu_r           rmc_sensbuf.u_psu_r
1609 #define fru_r           rmc_sensbuf.u_fru_r
1610 #define led_r           rmc_sensbuf.u_led_r
1611 #define setled_r        rmc_sensbuf.u_setled_r
1612 #define alarm_r         rmc_sensbuf.u_alarm_r
1613 #define setalarm_r      rmc_sensbuf.u_setalarm_r
1614 
1615         int                     retval = force_fail;
1616         int                     retval1 = retval;
1617         int                     index;
1618         rmclomv_cache_section_t *my_chain = NULL;
1619         rmclomv_cache_section_t *derived_chain = NULL;
1620         rmclomv_cache_section_t *section;
1621         rmclomv_cache_section_t *psu_section;
1622         rmclomv_cache_section_t *fru_section;
1623         dp_get_sysinfo_r_t      sysinfo;
1624         rmclomv_cache_entry_t   *entry;
1625 
1626         if (retval == 0) {
1627                 retval = rmclomv_do_cmd(DP_GET_SYSINFO, DP_GET_SYSINFO_R,
1628                     sizeof (sysinfo), NULL, (intptr_t)&sysinfo);
1629         }
1630         if (retval == 0) {
1631                 fru_cmd.handle = DP_NULL_HANDLE;
1632                 retval = rmclomv_do_cmd(DP_GET_FRU_STATUS, DP_GET_FRU_STATUS_R,
1633                     RMCRESBUFLEN, (intptr_t)&fru_cmd, (intptr_t)&fru_r);
1634         }
1635         if (retval != 0)
1636                 fru_r.num_frus = 0;
1637 
1638         /*
1639          * Reserve space for special additional entries in the FRU section
1640          */
1641         fru_section = create_cache_section(RMCLOMV_HPU_IND,
1642             RMCLOMV_NUM_SPECIAL_FRUS + fru_r.num_frus);
1643 
1644         /*
1645          * add special entry for RMC itself
1646          */
1647         entry = &fru_section->entry[0];
1648         (void) snprintf(entry->handle_name.name, sizeof (envmon_handle_t),
1649             "SC");
1650         entry->handle = 0;
1651         entry->ind_mask = 1; /* flag as a special entry */
1652 
1653         /*
1654          * populate any other FRU entries
1655          */
1656         for (index = 0; index < fru_r.num_frus; index++) {
1657                 fru_section->entry[RMCLOMV_NUM_SPECIAL_FRUS + index].handle =
1658                     fru_r.fru_status[index].handle;
1659                 fru_section->entry[RMCLOMV_NUM_SPECIAL_FRUS + index].ind_mask =
1660                     0;
1661         }
1662 
1663         my_chain = fru_section;
1664 
1665         if (retval == 0) {
1666                 volts_cmd.handle = DP_NULL_HANDLE;
1667                 retval = rmclomv_do_cmd(DP_GET_VOLTS, DP_GET_VOLTS_R,
1668                     RMCRESBUFLEN, (intptr_t)&volts_cmd, (intptr_t)&volts_r);
1669         }
1670         if (retval == 0) {
1671                 section = create_cache_section(RMCLOMV_VOLT_SENS,
1672                     volts_r.num_volts);
1673                 for (index = 0; index < volts_r.num_volts; index++) {
1674                         section->entry[index].handle =
1675                             volts_r.volt_status[index].handle;
1676                 }
1677                 add_section(&my_chain, section);
1678         }
1679         if (retval == 0) {
1680                 temp_cmd.handle = DP_NULL_HANDLE;
1681                 retval = rmclomv_do_cmd(DP_GET_TEMPERATURES,
1682                     DP_GET_TEMPERATURES_R, RMCRESBUFLEN,
1683                     (intptr_t)&temp_cmd, (intptr_t)&temp_r);
1684         }
1685         if (retval == 0) {
1686                 section = create_cache_section(RMCLOMV_TEMP_SENS,
1687                     temp_r.num_temps);
1688                 for (index = 0; index < temp_r.num_temps; index++) {
1689                         section->entry[index].handle =
1690                             temp_r.temp_status[index].handle;
1691                 }
1692                 add_section(&my_chain, section);
1693         }
1694         if (retval == 0) {
1695                 fan_cmd.handle = DP_NULL_HANDLE;
1696                 retval = rmclomv_do_cmd(DP_GET_FAN_STATUS, DP_GET_FAN_STATUS_R,
1697                     RMCRESBUFLEN, (intptr_t)&fan_cmd, (intptr_t)&fan_r);
1698         }
1699         if (retval == 0) {
1700                 section = create_cache_section(RMCLOMV_FAN_SENS,
1701                     fan_r.num_fans);
1702                 for (index = 0; index < fan_r.num_fans; index++) {
1703                         section->entry[index].handle =
1704                             fan_r.fan_status[index].handle;
1705                 }
1706                 add_section(&my_chain, section);
1707         }
1708         if (retval == 0) {
1709                 ampi_cmd.handle = DP_NULL_HANDLE;
1710                 retval = rmclomv_do_cmd(DP_GET_CIRCUIT_BRKS,
1711                     DP_GET_CIRCUIT_BRKS_R, RMCRESBUFLEN,
1712                     (intptr_t)&ampi_cmd, (intptr_t)&ampi_r);
1713         }
1714         if (retval == 0) {
1715                 section = create_cache_section(RMCLOMV_AMP_IND,
1716                     ampi_r.num_circuit_brks);
1717                 for (index = 0; index < ampi_r.num_circuit_brks; index++) {
1718                         section->entry[index].handle =
1719                             ampi_r.circuit_brk_status[index].handle;
1720                 }
1721                 add_section(&my_chain, section);
1722         }
1723         if (retval == 0) {
1724                 led_cmd.handle = DP_NULL_HANDLE;
1725                 retval = rmclomv_do_cmd(DP_GET_LED_STATE, DP_GET_LED_STATE_R,
1726                     RMCRESBUFLEN, (intptr_t)&led_cmd, (intptr_t)&led_r);
1727         }
1728         if (retval == 0) {
1729                 section = create_cache_section(RMCLOMV_LED_IND,
1730                     led_r.num_leds);
1731                 for (index = 0; index < led_r.num_leds; index++) {
1732                         section->entry[index].handle =
1733                             led_r.led_state[index].handle;
1734                 }
1735                 add_section(&my_chain, section);
1736         }
1737         /*
1738          * The command DP_GET_ALARM_STATE may not be valid on
1739          * some RMC versions, so we ignore the return value
1740          * and proceed
1741          */
1742         if (retval == 0) {
1743                 alarm_cmd.handle = DP_NULL_HANDLE;
1744                 retval1 = rmclomv_do_cmd(DP_GET_ALARM_STATE,
1745                     DP_GET_ALARM_STATE_R, RMCRESBUFLEN,
1746                     (intptr_t)&alarm_cmd, (intptr_t)&alarm_r);
1747                 if ((retval1 == 0) && alarm_r.num_alarms) {
1748                         section = create_cache_section(RMCLOMV_ALARM_IND,
1749                             alarm_r.num_alarms);
1750                         for (index = 0; index < alarm_r.num_alarms; index++) {
1751                                 section->entry[index].handle =
1752                                     alarm_r.alarm_state[index].handle;
1753                         }
1754                         add_section(&my_chain, section);
1755                 }
1756         }
1757         if (retval == 0) {
1758                 psu_cmd.handle = DP_NULL_HANDLE;
1759                 retval = rmclomv_do_cmd(DP_GET_PSU_STATUS, DP_GET_PSU_STATUS_R,
1760                     RMCRESBUFLEN, (intptr_t)&psu_cmd, (intptr_t)&psu_r);
1761         }
1762         if (retval == 0) {
1763                 /*
1764                  * WARNING:
1765                  * =======
1766                  * The PSUs must be probed last so that the response data
1767                  * (psu_r) is available for make_psu_subsections() below.
1768                  * Note that all the responses share the same data area
1769                  * which is declared as a union.
1770                  */
1771                 psu_section = create_cache_section(RMCLOMV_PSU_IND,
1772                     psu_r.num_psus);
1773                 for (index = 0; index < psu_r.num_psus; index++) {
1774                         psu_section->entry[index].handle =
1775                             psu_r.psu_status[index].handle;
1776                 }
1777                 add_section(&my_chain, psu_section);
1778         }
1779         if (retval == 0) {
1780                 for (section = my_chain;
1781                     section != NULL;
1782                     section = section->next_section) {
1783                         retval = add_names_to_section(section);
1784                         if (retval != 0) {
1785                                 break;
1786                         }
1787                 }
1788         }
1789 
1790         /*
1791          * now add nodes derived from PSUs
1792          */
1793         if (retval == 0) {
1794                 make_psu_subsections(psu_section, &derived_chain, &psu_r);
1795                 /*
1796                  * name cache sections all set, exchange new for old
1797                  */
1798                 rmclomv_reset_cache(my_chain, derived_chain, &sysinfo);
1799         } else {
1800                 /*
1801                  * RMC is not responding, ditch any existing cache
1802                  * and just leave the special SC FRU node
1803                  */
1804                 rmclomv_reset_cache(my_chain, NULL, NULL);
1805         }
1806 }
1807 
1808 static void
1809 set_val_unav(envmon_sensor_t *sensor)
1810 {
1811         sensor->value = ENVMON_VAL_UNAVAILABLE;
1812         sensor->lowthresholds.warning = ENVMON_VAL_UNAVAILABLE;
1813         sensor->lowthresholds.shutdown = ENVMON_VAL_UNAVAILABLE;
1814         sensor->lowthresholds.poweroff = ENVMON_VAL_UNAVAILABLE;
1815         sensor->highthresholds.warning = ENVMON_VAL_UNAVAILABLE;
1816         sensor->highthresholds.shutdown = ENVMON_VAL_UNAVAILABLE;
1817         sensor->highthresholds.poweroff = ENVMON_VAL_UNAVAILABLE;
1818 }
1819 
1820 static void
1821 set_fan_unav(envmon_fan_t *fan)
1822 {
1823         fan->speed = ENVMON_VAL_UNAVAILABLE;
1824         fan->units[0] = '\0';
1825         fan->lowthresholds.warning = ENVMON_VAL_UNAVAILABLE;
1826         fan->lowthresholds.shutdown = ENVMON_VAL_UNAVAILABLE;
1827         fan->lowthresholds.poweroff = ENVMON_VAL_UNAVAILABLE;
1828 }
1829 
1830 static int
1831 do_psu_cmd(intptr_t arg, int mode, envmon_indicator_t *env_ind,
1832     dp_get_psu_status_t *rmc_psu, dp_get_psu_status_r_t *rmc_psu_r,
1833     int detector_type)
1834 {
1835         int                     index;
1836         uint16_t                sensor_status;
1837         rmclomv_cache_section_t *section;
1838         uint16_t                indicator_mask;
1839 
1840         if (ddi_copyin((caddr_t)arg, (caddr_t)env_ind,
1841             sizeof (envmon_indicator_t), mode) != 0)
1842                 return (EFAULT);
1843 
1844         /* ensure we've got PSU handles cached */
1845         LOCK_CACHE
1846 
1847         sensor_status = ENVMON_SENSOR_OK;
1848         section = rmclomv_find_section(rmclomv_subcache, detector_type);
1849         if (env_ind->id.name[0] == '\0') {
1850                 /* request for first handle */
1851                 if ((section == NULL) || (section->num_entries == 0))
1852                         env_ind->next_id.name[0] = '\0';
1853                 else
1854                         env_ind->next_id = section->entry[0].handle_name;
1855                 sensor_status = ENVMON_NOT_PRESENT;
1856         } else {
1857                 /* ensure name is properly terminated */
1858                 env_ind->id.name[ENVMON_MAXNAMELEN - 1] = '\0';
1859                 if ((section == NULL) || (get_sensor_by_name(section,
1860                     env_ind->id.name, &index)) != 0) {
1861                         env_ind->next_id.name[0] = '\0';
1862                         sensor_status = ENVMON_NOT_PRESENT;
1863                 } else if (index + 1 < section->num_entries)
1864                         env_ind->next_id =
1865                             section->entry[index + 1].handle_name;
1866                 else
1867                         env_ind->next_id.name[0] = '\0';
1868         }
1869         if (sensor_status == ENVMON_SENSOR_OK) {
1870                 /*
1871                  * user correctly identified a sensor, note its
1872                  * handle value and request the indicator status
1873                  */
1874                 rmc_psu->handle = section->entry[index].handle;
1875                 indicator_mask = section->entry[index].ind_mask;
1876         }
1877 
1878         RELEASE_CACHE
1879 
1880         if ((sensor_status == ENVMON_SENSOR_OK) && (rmclomv_rmc_error ||
1881             rmclomv_do_cmd(DP_GET_PSU_STATUS, DP_GET_PSU_STATUS_R,
1882             sizeof (dp_get_psu_status_r_t), (intptr_t)rmc_psu,
1883             (intptr_t)rmc_psu_r) != 0)) {
1884                 sensor_status = ENVMON_INACCESSIBLE;
1885         }
1886         if ((env_ind->sensor_status = sensor_status) == ENVMON_SENSOR_OK) {
1887                 /*
1888                  * copy results into buffer for user
1889                  */
1890                 if ((rmc_psu_r->psu_status[0].flag & DP_PSU_PRESENCE) == 0)
1891                         env_ind->sensor_status |= ENVMON_NOT_PRESENT;
1892                 if (rmc_psu_r->psu_status[0].sensor_status !=
1893                     DP_SENSOR_DATA_AVAILABLE)
1894                         env_ind->sensor_status |= ENVMON_INACCESSIBLE;
1895                 env_ind->condition =
1896                     (rmc_psu_r->psu_status[0].flag & indicator_mask) == 0 ?
1897                     0 : 1;
1898         }
1899 
1900         if (rmclomv_rmc_error != RMCLOMV_RMCERROR_NONE)
1901                 env_ind->sensor_status = ENVMON_INACCESSIBLE;
1902 
1903         if (ddi_copyout((caddr_t)env_ind, (caddr_t)arg,
1904             sizeof (envmon_indicator_t), mode) != 0)
1905                 return (EFAULT);
1906 
1907         return (0);
1908 }
1909 
1910 /*ARGSUSED*/
1911 static int
1912 rmclomv_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *cred_p,
1913     int *rval_p)
1914 {
1915         int instance = getminor(dev);
1916         envmon_sysinfo_t lomv_sysinfo;
1917         union {
1918                 envmon_sensor_t         u_env_sensor;
1919                 envmon_indicator_t      u_env_ind;
1920                 envmon_fan_t            u_env_fan;
1921                 envmon_led_info_t       u_env_ledinfo;
1922                 envmon_led_ctl_t        u_env_ledctl;
1923                 envmon_hpu_t            u_env_hpu;
1924                 envmon_alarm_info_t     u_env_alarminfo;
1925                 envmon_alarm_ctl_t      u_env_alarmctl;
1926         } env_buf;
1927 #define env_sensor      env_buf.u_env_sensor
1928 #define env_ind         env_buf.u_env_ind
1929 #define env_fan         env_buf.u_env_fan
1930 #define env_ledinfo     env_buf.u_env_ledinfo
1931 #define env_ledctl      env_buf.u_env_ledctl
1932 #define env_hpu         env_buf.u_env_hpu
1933 #define env_alarminfo   env_buf.u_env_alarminfo
1934 #define env_alarmctl    env_buf.u_env_alarmctl
1935 
1936         union {
1937                 dp_get_volts_t          u_rmc_volts;
1938                 dp_get_temperatures_t   u_rmc_temp;
1939                 dp_get_circuit_brks_t   u_rmc_ampi;
1940                 dp_get_fan_status_t     u_rmc_fan;
1941                 dp_get_psu_status_t     u_rmc_psu;
1942                 dp_get_fru_status_t     u_rmc_fru;
1943                 dp_get_led_state_t      u_rmc_led;
1944                 dp_set_led_state_t      u_rmc_setled;
1945                 dp_get_alarm_state_t    u_rmc_alarm;
1946                 dp_set_alarm_state_t    u_rmc_setalarm;
1947         } rmc_reqbuf;
1948 #define rmc_volts       rmc_reqbuf.u_rmc_volts
1949 #define rmc_temp        rmc_reqbuf.u_rmc_temp
1950 #define rmc_ampi        rmc_reqbuf.u_rmc_ampi
1951 #define rmc_fan         rmc_reqbuf.u_rmc_fan
1952 #define rmc_psu         rmc_reqbuf.u_rmc_psu
1953 #define rmc_fru         rmc_reqbuf.u_rmc_fru
1954 #define rmc_led         rmc_reqbuf.u_rmc_led
1955 #define rmc_setled      rmc_reqbuf.u_rmc_setled
1956 #define rmc_alarm       rmc_reqbuf.u_rmc_alarm
1957 #define rmc_setalarm    rmc_reqbuf.u_rmc_setalarm
1958 
1959         union {
1960                 dp_get_volts_r_t        u_rmc_volts_r;
1961                 dp_get_temperatures_r_t u_rmc_temp_r;
1962                 dp_get_circuit_brks_r_t u_rmc_ampi_r;
1963                 dp_get_fan_status_r_t   u_rmc_fan_r;
1964                 dp_get_psu_status_r_t   u_rmc_psu_r;
1965                 dp_get_fru_status_r_t   u_rmc_fru_r;
1966                 dp_get_led_state_r_t    u_rmc_led_r;
1967                 dp_set_led_state_r_t    u_rmc_setled_r;
1968                 dp_get_alarm_state_r_t  u_rmc_alarm_r;
1969                 dp_set_alarm_state_r_t  u_rmc_setalarm_r;
1970                 dp_get_sdp_version_r_t  u_rmc_sdpversion_r;
1971                 dp_get_serialnum_r_t    u_rmc_serialnum_r;
1972         } rmc_resbuf;
1973 #define rmc_volts_r     rmc_resbuf.u_rmc_volts_r
1974 #define rmc_temp_r      rmc_resbuf.u_rmc_temp_r
1975 #define rmc_ampi_r      rmc_resbuf.u_rmc_ampi_r
1976 #define rmc_fan_r       rmc_resbuf.u_rmc_fan_r
1977 #define rmc_psu_r       rmc_resbuf.u_rmc_psu_r
1978 #define rmc_fru_r       rmc_resbuf.u_rmc_fru_r
1979 #define rmc_led_r       rmc_resbuf.u_rmc_led_r
1980 #define rmc_setled_r    rmc_resbuf.u_rmc_setled_r
1981 #define rmc_alarm_r     rmc_resbuf.u_rmc_alarm_r
1982 #define rmc_setalarm_r  rmc_resbuf.u_rmc_setalarm_r
1983 #define rmc_sdpver_r    rmc_resbuf.u_rmc_sdpversion_r
1984 #define rmc_serialnum_r rmc_resbuf.u_rmc_serialnum_r
1985 
1986         int                     retval = 0;
1987         int                     special = 0;
1988         int                     index;
1989         uint16_t                sensor_status;
1990         rmclomv_cache_section_t *section;
1991         envmon_chassis_t chassis;
1992 
1993         if (instance != 0)
1994                 return (ENXIO);
1995 
1996         switch (cmd) {
1997         case ENVMONIOCSYSINFO:
1998 
1999                 LOCK_CACHE
2000 
2001                 /*
2002                  * A number of OK/not_OK indicators are supported by PSUs
2003                  * (voltage, current, fan, temperature). So the maximum
2004                  * number of such indicators relates to the maximum number
2005                  * of power-supplies.
2006                  */
2007                 if (rmclomv_sysinfo_valid) {
2008                         lomv_sysinfo.maxVoltSens = rmclomv_sysinfo_data.maxVolt;
2009                         lomv_sysinfo.maxVoltInd =
2010                             RMCLOMV_MAX_VI_PER_PSU *
2011                             rmclomv_sysinfo_data.maxPSU;
2012                         /*
2013                          * the ALOM-Solaris interface does not include
2014                          * amp sensors, so we can hard code this value
2015                          */
2016                         lomv_sysinfo.maxAmpSens = 0;
2017                         lomv_sysinfo.maxAmpInd =
2018                             rmclomv_sysinfo_data.maxCircuitBrks +
2019                             (RMCLOMV_MAX_CI_PER_PSU *
2020                             rmclomv_sysinfo_data.maxPSU);
2021                         lomv_sysinfo.maxTempSens = rmclomv_sysinfo_data.maxTemp;
2022                         lomv_sysinfo.maxTempInd =
2023                             (RMCLOMV_MAX_TI_PER_PSU *
2024                             rmclomv_sysinfo_data.maxPSU);
2025                         lomv_sysinfo.maxFanSens = rmclomv_sysinfo_data.maxFan;
2026                         lomv_sysinfo.maxFanInd =
2027                             RMCLOMV_MAX_FI_PER_PSU *
2028                             rmclomv_sysinfo_data.maxPSU;
2029                         lomv_sysinfo.maxLED = rmclomv_sysinfo_data.maxLED;
2030                         lomv_sysinfo.maxHPU = RMCLOMV_NUM_SPECIAL_FRUS +
2031                             rmclomv_sysinfo_data.maxFRU;
2032                 } else {
2033                         bzero(&lomv_sysinfo, sizeof (lomv_sysinfo));
2034                         lomv_sysinfo.maxHPU = 1;        /* just the SC node */
2035                 }
2036 
2037                 RELEASE_CACHE
2038 
2039                 if (ddi_copyout((caddr_t)&lomv_sysinfo, (caddr_t)arg,
2040                     sizeof (lomv_sysinfo), mode) != 0)
2041                         return (EFAULT);
2042                 break;
2043 
2044         case ENVMONIOCVOLTSENSOR:
2045                 if (ddi_copyin((caddr_t)arg, (caddr_t)&env_sensor,
2046                     sizeof (envmon_sensor_t), mode) != 0)
2047                         return (EFAULT);
2048 
2049                 /* see if we've got volts handles cached */
2050                 LOCK_CACHE
2051                 sensor_status = ENVMON_SENSOR_OK;
2052 
2053                 if ((rmclomv_cache_valid == B_FALSE) ||
2054                     ((section = rmclomv_find_section(rmclomv_cache,
2055                     RMCLOMV_VOLT_SENS)) == NULL)) {
2056                         env_sensor.next_id.name[0] = '\0';
2057                         sensor_status = ENVMON_NOT_PRESENT;
2058                 } else if (env_sensor.id.name[0] == '\0') {
2059                         /* request for first handle */
2060                         if (section->num_entries == 0)
2061                                 env_sensor.next_id.name[0] = '\0';
2062                         else
2063                                 env_sensor.next_id =
2064                                     section->entry[0].handle_name;
2065                         sensor_status = ENVMON_NOT_PRESENT;
2066                 } else {
2067                         /* ensure name is properly terminated */
2068                         env_sensor.id.name[ENVMON_MAXNAMELEN - 1] = '\0';
2069                         if (get_sensor_by_name(section, env_sensor.id.name,
2070                             &index) != 0) {
2071                                 env_sensor.next_id.name[0] = '\0';
2072                                 sensor_status = ENVMON_NOT_PRESENT;
2073                         } else if (index + 1 < section->num_entries)
2074                                 env_sensor.next_id =
2075                                     section->entry[index + 1].handle_name;
2076                         else
2077                                 env_sensor.next_id.name[0] = '\0';
2078                 }
2079                 if (sensor_status == ENVMON_SENSOR_OK) {
2080                         /*
2081                          * user correctly identified a sensor, note its
2082                          * handle value and request the sensor value
2083                          */
2084                         rmc_volts.handle = section->entry[index].handle;
2085                 }
2086                 RELEASE_CACHE
2087                 if ((sensor_status == ENVMON_SENSOR_OK) && (rmclomv_rmc_error ||
2088                     rmclomv_do_cmd(DP_GET_VOLTS, DP_GET_VOLTS_R,
2089                     sizeof (rmc_volts_r), (intptr_t)&rmc_volts,
2090                     (intptr_t)&rmc_volts_r) != 0)) {
2091                         sensor_status = ENVMON_INACCESSIBLE;
2092                 }
2093                 if ((sensor_status == ENVMON_SENSOR_OK) &&
2094                     (rmc_volts_r.volt_status[0].sensor_status ==
2095                     DP_SENSOR_NOT_PRESENT)) {
2096                         sensor_status = ENVMON_NOT_PRESENT;
2097                 }
2098                 if ((env_sensor.sensor_status = sensor_status) ==
2099                     ENVMON_SENSOR_OK) {
2100                         /*
2101                          * copy results into buffer for user
2102                          */
2103                         if (rmc_volts_r.volt_status[0].sensor_status !=
2104                             DP_SENSOR_DATA_AVAILABLE)
2105                                 env_sensor.sensor_status = ENVMON_INACCESSIBLE;
2106                         env_sensor.value =
2107                             rmc_volts_r.volt_status[0].reading;
2108                         env_sensor.lowthresholds.warning =
2109                             rmc_volts_r.volt_status[0].low_warning;
2110                         env_sensor.lowthresholds.shutdown =
2111                             rmc_volts_r.volt_status[0].low_soft_shutdown;
2112                         env_sensor.lowthresholds.poweroff =
2113                             rmc_volts_r.volt_status[0].low_hard_shutdown;
2114                         env_sensor.highthresholds.warning =
2115                             rmc_volts_r.volt_status[0].high_warning;
2116                         env_sensor.highthresholds.shutdown =
2117                             rmc_volts_r.volt_status[0].high_soft_shutdown;
2118                         env_sensor.highthresholds.poweroff =
2119                             rmc_volts_r.volt_status[0].high_hard_shutdown;
2120                 }
2121                 if (env_sensor.sensor_status != ENVMON_SENSOR_OK ||
2122                     rmclomv_rmc_error != RMCLOMV_RMCERROR_NONE)
2123                         set_val_unav(&env_sensor);
2124 
2125                 if (ddi_copyout((caddr_t)&env_sensor, (caddr_t)arg,
2126                     sizeof (envmon_sensor_t), mode) != 0)
2127                         return (EFAULT);
2128                 break;
2129 
2130         case ENVMONIOCVOLTIND:
2131                 return (do_psu_cmd(arg, mode, &env_ind, &rmc_psu, &rmc_psu_r,
2132                     RMCLOMV_VOLT_IND));
2133 
2134         case ENVMONIOCTEMPIND:
2135                 return (do_psu_cmd(arg, mode, &env_ind, &rmc_psu, &rmc_psu_r,
2136                     RMCLOMV_TEMP_IND));
2137 
2138         case ENVMONIOCFANIND:
2139                 return (do_psu_cmd(arg, mode, &env_ind, &rmc_psu, &rmc_psu_r,
2140                     RMCLOMV_FAN_IND));
2141 
2142         case ENVMONIOCAMPSENSOR:
2143                 if (ddi_copyin((caddr_t)arg, (caddr_t)&env_sensor,
2144                     sizeof (envmon_sensor_t), mode) != 0)
2145                         return (EFAULT);
2146 
2147                 env_sensor.sensor_status = ENVMON_NOT_PRESENT;
2148                 env_sensor.next_id.name[0] = '\0';
2149 
2150                 if (ddi_copyout((caddr_t)&env_sensor, (caddr_t)arg,
2151                     sizeof (envmon_sensor_t), mode) != 0)
2152                         return (EFAULT);
2153                 break;
2154 
2155         case ENVMONIOCTEMPSENSOR:
2156                 if (ddi_copyin((caddr_t)arg, (caddr_t)&env_sensor,
2157                     sizeof (envmon_sensor_t), mode) != 0)
2158                         return (EFAULT);
2159 
2160                 /* see if we've got temperature handles cached */
2161                 LOCK_CACHE
2162                 sensor_status = ENVMON_SENSOR_OK;
2163 
2164                 if ((rmclomv_cache_valid == B_FALSE) ||
2165                     ((section = rmclomv_find_section(rmclomv_cache,
2166                     RMCLOMV_TEMP_SENS)) == NULL)) {
2167                         env_sensor.next_id.name[0] = '\0';
2168                         sensor_status = ENVMON_NOT_PRESENT;
2169                 } else if (env_sensor.id.name[0] == '\0') {
2170                         /* request for first handle */
2171                         if (section->num_entries == 0)
2172                                 env_sensor.next_id.name[0] = '\0';
2173                         else
2174                                 env_sensor.next_id =
2175                                     section->entry[0].handle_name;
2176                         sensor_status = ENVMON_NOT_PRESENT;
2177                 } else {
2178                         /* ensure name is properly terminated */
2179                         env_sensor.id.name[ENVMON_MAXNAMELEN - 1] = '\0';
2180                         if (get_sensor_by_name(section, env_sensor.id.name,
2181                             &index) != 0) {
2182                                 env_sensor.next_id.name[0] = '\0';
2183                                 sensor_status = ENVMON_NOT_PRESENT;
2184                         } else if (index + 1 < section->num_entries)
2185                                 env_sensor.next_id =
2186                                     section->entry[index + 1].handle_name;
2187                         else
2188                                 env_sensor.next_id.name[0] = '\0';
2189                 }
2190                 if (sensor_status == ENVMON_SENSOR_OK) {
2191                         /*
2192                          * user correctly identified a sensor, note its
2193                          * handle value and request the sensor value
2194                          */
2195                         rmc_temp.handle = section->entry[index].handle;
2196                 }
2197                 RELEASE_CACHE
2198                 if ((sensor_status == ENVMON_SENSOR_OK) && (rmclomv_rmc_error ||
2199                     rmclomv_do_cmd(DP_GET_TEMPERATURES, DP_GET_TEMPERATURES_R,
2200                     sizeof (rmc_temp_r), (intptr_t)&rmc_temp,
2201                     (intptr_t)&rmc_temp_r) != 0)) {
2202                         sensor_status = ENVMON_INACCESSIBLE;
2203                 }
2204                 if ((sensor_status == ENVMON_SENSOR_OK) &&
2205                     (rmc_temp_r.temp_status[0].sensor_status ==
2206                     DP_SENSOR_NOT_PRESENT)) {
2207                         sensor_status = ENVMON_NOT_PRESENT;
2208                 }
2209                 if ((env_sensor.sensor_status = sensor_status) ==
2210                     ENVMON_SENSOR_OK) {
2211                         /*
2212                          * copy results into buffer for user
2213                          */
2214                         if (rmc_temp_r.temp_status[0].sensor_status !=
2215                             DP_SENSOR_DATA_AVAILABLE)
2216                                 env_sensor.sensor_status = ENVMON_INACCESSIBLE;
2217                         env_sensor.value =
2218                             rmc_temp_r.temp_status[0].value;
2219                         env_sensor.lowthresholds.warning =
2220                             rmc_temp_r.temp_status[0].low_warning;
2221                         env_sensor.lowthresholds.shutdown =
2222                             rmc_temp_r.temp_status[0].low_soft_shutdown;
2223                         env_sensor.lowthresholds.poweroff =
2224                             rmc_temp_r.temp_status[0].low_hard_shutdown;
2225                         env_sensor.highthresholds.warning =
2226                             rmc_temp_r.temp_status[0].high_warning;
2227                         env_sensor.highthresholds.shutdown =
2228                             rmc_temp_r.temp_status[0].high_soft_shutdown;
2229                         env_sensor.highthresholds.poweroff =
2230                             rmc_temp_r.temp_status[0].high_hard_shutdown;
2231                 }
2232                 if (env_sensor.sensor_status != ENVMON_SENSOR_OK ||
2233                     rmclomv_rmc_error != RMCLOMV_RMCERROR_NONE)
2234                         set_val_unav(&env_sensor);
2235 
2236                 if (ddi_copyout((caddr_t)&env_sensor, (caddr_t)arg,
2237                     sizeof (envmon_sensor_t), mode) != 0)
2238                         return (EFAULT);
2239                 break;
2240 
2241 
2242         case ENVMONIOCFAN:
2243                 if (ddi_copyin((caddr_t)arg, (caddr_t)&env_fan,
2244                     sizeof (envmon_fan_t), mode) != 0)
2245                         return (EFAULT);
2246 
2247                 /* see if we've got fan handles cached */
2248                 LOCK_CACHE
2249                 sensor_status = ENVMON_SENSOR_OK;
2250 
2251                 if ((rmclomv_cache_valid == B_FALSE) ||
2252                     ((section = rmclomv_find_section(rmclomv_cache,
2253                     RMCLOMV_FAN_SENS)) == NULL)) {
2254                         env_fan.next_id.name[0] = '\0';
2255                         sensor_status = ENVMON_NOT_PRESENT;
2256                 } else if (env_fan.id.name[0] == '\0') {
2257                         /* request for first handle */
2258                         if (section->num_entries == 0)
2259                                 env_fan.next_id.name[0] = '\0';
2260                         else
2261                                 env_fan.next_id =
2262                                     section->entry[0].handle_name;
2263                         sensor_status = ENVMON_NOT_PRESENT;
2264                 } else {
2265                         /* ensure name is properly terminated */
2266                         env_fan.id.name[ENVMON_MAXNAMELEN - 1] = '\0';
2267                         if (get_sensor_by_name(section, env_fan.id.name,
2268                             &index) != 0) {
2269                                 env_fan.next_id.name[0] = '\0';
2270                                 sensor_status = ENVMON_NOT_PRESENT;
2271                         } else if (index + 1 < section->num_entries)
2272                                 env_fan.next_id =
2273                                     section->entry[index + 1].handle_name;
2274                         else
2275                                 env_fan.next_id.name[0] = '\0';
2276                 }
2277                 if (sensor_status == ENVMON_SENSOR_OK) {
2278                         /*
2279                          * user correctly identified a sensor, note its
2280                          * handle value and request the sensor value
2281                          */
2282                         rmc_fan.handle = section->entry[index].handle;
2283                 }
2284                 RELEASE_CACHE
2285                 if ((sensor_status == ENVMON_SENSOR_OK) && (rmclomv_rmc_error ||
2286                     rmclomv_do_cmd(DP_GET_FAN_STATUS, DP_GET_FAN_STATUS_R,
2287                     sizeof (rmc_fan_r), (intptr_t)&rmc_fan,
2288                     (intptr_t)&rmc_fan_r) != 0)) {
2289                         sensor_status = ENVMON_INACCESSIBLE;
2290                 }
2291                 if ((sensor_status == ENVMON_SENSOR_OK) &&
2292                     (rmc_fan_r.fan_status[0].sensor_status ==
2293                     DP_SENSOR_NOT_PRESENT)) {
2294                         sensor_status = ENVMON_NOT_PRESENT;
2295                 }
2296                 if ((env_fan.sensor_status = sensor_status) ==
2297                     ENVMON_SENSOR_OK) {
2298                         if ((rmc_fan_r.fan_status[0].flag &
2299                             DP_FAN_PRESENCE) == 0)
2300                                 env_fan.sensor_status = ENVMON_NOT_PRESENT;
2301                         if (rmc_fan_r.fan_status[0].sensor_status !=
2302                             DP_SENSOR_DATA_AVAILABLE)
2303                                 env_fan.sensor_status |= ENVMON_INACCESSIBLE;
2304                         if (env_fan.sensor_status == ENVMON_SENSOR_OK) {
2305                                 /*
2306                                  * copy results into buffer for user
2307                                  */
2308                                 env_fan.speed =
2309                                     rmc_fan_r.fan_status[0].speed;
2310                                 env_fan.lowthresholds.warning =
2311                                     rmc_fan_r.fan_status[0].minspeed;
2312                                 env_fan.lowthresholds.shutdown =
2313                                     ENVMON_VAL_UNAVAILABLE;
2314                                 env_fan.lowthresholds.poweroff =
2315                                     ENVMON_VAL_UNAVAILABLE;
2316                                 if ((rmc_fan_r.fan_status[0].flag &
2317                                     DP_FAN_SPEED_VAL_UNIT) == 0)
2318                                         bcopy(str_rpm, env_fan.units,
2319                                             sizeof (str_rpm));
2320                                 else
2321                                         bcopy(str_percent, env_fan.units,
2322                                             sizeof (str_percent));
2323                         }
2324                 }
2325                 if (env_fan.sensor_status != ENVMON_SENSOR_OK ||
2326                     rmclomv_rmc_error != RMCLOMV_RMCERROR_NONE)
2327                         set_fan_unav(&env_fan);
2328 
2329                 if (ddi_copyout((caddr_t)&env_fan, (caddr_t)arg,
2330                     sizeof (envmon_fan_t), mode) != 0)
2331                         return (EFAULT);
2332                 break;
2333 
2334         case ENVMONIOCAMPIND:
2335                 if (ddi_copyin((caddr_t)arg, (caddr_t)&env_ind,
2336                     sizeof (envmon_indicator_t), mode) != 0)
2337                         return (EFAULT);
2338 
2339                 /* see if we've got amp indicator handles cached */
2340                 LOCK_CACHE
2341                 sensor_status = ENVMON_SENSOR_OK;
2342 
2343                 if ((rmclomv_cache_valid == B_FALSE) ||
2344                     ((section = rmclomv_find_section(rmclomv_cache,
2345                     RMCLOMV_AMP_IND)) == NULL)) {
2346                         RELEASE_CACHE
2347                         return (do_psu_cmd(arg, mode, &env_ind, &rmc_psu,
2348                             &rmc_psu_r, RMCLOMV_AMP_IND));
2349                 } else if (env_ind.id.name[0] == '\0') {
2350                         /* request for first handle */
2351                         if (section->num_entries == 0) {
2352                                 RELEASE_CACHE
2353                                 return (do_psu_cmd(arg, mode, &env_ind,
2354                                     &rmc_psu, &rmc_psu_r, RMCLOMV_AMP_IND));
2355                         }
2356                         env_ind.next_id = section->entry[0].handle_name;
2357                         sensor_status = ENVMON_NOT_PRESENT;
2358                 } else {
2359                         /* ensure name is properly terminated */
2360                         env_ind.id.name[ENVMON_MAXNAMELEN - 1] = '\0';
2361                         if (get_sensor_by_name(section, env_ind.id.name,
2362                             &index) != 0) {
2363                                 RELEASE_CACHE
2364                                 return (do_psu_cmd(arg, mode, &env_ind,
2365                                     &rmc_psu, &rmc_psu_r, RMCLOMV_AMP_IND));
2366                         }
2367                         if (index + 1 < section->num_entries) {
2368                                 env_ind.next_id =
2369                                     section->entry[index + 1].handle_name;
2370                         } else {
2371                                 rmclomv_cache_section_t *sub_section =
2372                                     rmclomv_find_section(rmclomv_subcache,
2373                                     RMCLOMV_AMP_IND);
2374                                 if ((sub_section == NULL) ||
2375                                     (sub_section->num_entries == 0))
2376                                         env_ind.next_id.name[0] = '\0';
2377                                 else
2378                                         env_ind.next_id =
2379                                             sub_section->entry[0].handle_name;
2380                         }
2381                 }
2382                 if (sensor_status == ENVMON_SENSOR_OK) {
2383                         /*
2384                          * user correctly identified an indicator, note its
2385                          * handle value and request the indicator status
2386                          */
2387                         rmc_ampi.handle = section->entry[index].handle;
2388                 }
2389                 RELEASE_CACHE
2390                 if ((sensor_status == ENVMON_SENSOR_OK) && (rmclomv_rmc_error ||
2391                     rmclomv_do_cmd(DP_GET_CIRCUIT_BRKS, DP_GET_CIRCUIT_BRKS_R,
2392                     sizeof (rmc_ampi_r), (intptr_t)&rmc_ampi,
2393                     (intptr_t)&rmc_ampi_r) != 0)) {
2394                         sensor_status = ENVMON_INACCESSIBLE;
2395                 }
2396                 if ((sensor_status == ENVMON_SENSOR_OK) &&
2397                     (rmc_ampi_r.circuit_brk_status[0].sensor_status ==
2398                     DP_SENSOR_NOT_PRESENT)) {
2399                         sensor_status = ENVMON_NOT_PRESENT;
2400                 }
2401                 if ((env_ind.sensor_status = sensor_status) ==
2402                     ENVMON_SENSOR_OK) {
2403                         /*
2404                          * copy results into buffer for user
2405                          */
2406                         if (rmc_ampi_r.circuit_brk_status[0].sensor_status !=
2407                             DP_SENSOR_DATA_AVAILABLE)
2408                                 env_ind.sensor_status = ENVMON_INACCESSIBLE;
2409                         env_ind.condition =
2410                             rmc_ampi_r.circuit_brk_status[0].status;
2411                 }
2412 
2413                 /*
2414                  * If rmclomv_rmc_error is set there is no way
2415                  * that we read information from RSC. Just copy
2416                  * out an inaccessible evironmental.
2417                  */
2418                 if (rmclomv_rmc_error != RMCLOMV_RMCERROR_NONE) {
2419                         env_ind.sensor_status = ENVMON_INACCESSIBLE;
2420                         env_ind.condition = ENVMON_INACCESSIBLE;
2421                 }
2422 
2423                 if (ddi_copyout((caddr_t)&env_ind, (caddr_t)arg,
2424                     sizeof (envmon_indicator_t), mode) != 0)
2425                         return (EFAULT);
2426                 break;
2427 
2428         case ENVMONIOCHPU:
2429                 if (ddi_copyin((caddr_t)arg, (caddr_t)&env_hpu,
2430                     sizeof (envmon_hpu_t), mode) != 0)
2431                         return (EFAULT);
2432 
2433                 /* see if we've got hpu handles cached */
2434                 LOCK_CACHE
2435 
2436                 if ((rmclomv_cache_valid == B_FALSE) ||
2437                     ((section = rmclomv_find_section(rmclomv_cache,
2438                     RMCLOMV_HPU_IND)) == NULL)) {
2439                         RELEASE_CACHE
2440                         return (EAGAIN);
2441                 }
2442 
2443                 /*
2444                  * At this point the cache is locked and section points to
2445                  * the section relating to hpus.
2446                  */
2447                 sensor_status = ENVMON_SENSOR_OK;
2448                 if (env_hpu.id.name[0] == '\0') {
2449                         /* request for first handle */
2450                         if (section->num_entries == 0)
2451                                 env_hpu.next_id.name[0] = '\0';
2452                         else
2453                                 env_hpu.next_id =
2454                                     section->entry[0].handle_name;
2455                         sensor_status = ENVMON_NOT_PRESENT;
2456                 } else {
2457                         /* ensure name is properly terminated */
2458                         env_hpu.id.name[ENVMON_MAXNAMELEN - 1] = '\0';
2459                         if (get_sensor_by_name(section, env_hpu.id.name,
2460                             &index) != 0) {
2461                                 env_hpu.next_id.name[0] = '\0';
2462                                 sensor_status = ENVMON_NOT_PRESENT;
2463                         } else if (index + 1 < section->num_entries)
2464                                 env_hpu.next_id =
2465                                     section->entry[index + 1].handle_name;
2466                         else
2467                                 env_hpu.next_id.name[0] = '\0';
2468                 }
2469                 if (sensor_status == ENVMON_SENSOR_OK) {
2470                         /*
2471                          * user correctly identified an hpu, note its
2472                          * handle value and request the hpu status
2473                          */
2474                         rmc_fru.handle = section->entry[index].handle;
2475                         special = section->entry[index].ind_mask;
2476                 }
2477                 RELEASE_CACHE
2478                 if ((env_hpu.sensor_status = sensor_status) ==
2479                     ENVMON_SENSOR_OK) {
2480                         env_hpu.fru_status = ENVMON_FRU_PRESENT;
2481 
2482                         if (special != 0) {
2483                                 /* this is the pseudo SC node */
2484                                 mutex_enter(&rmclomv_state_lock);
2485                                 switch (rmclomv_rmc_state) {
2486                                 case RMCLOMV_RMCSTATE_OK:
2487                                         break;
2488                                 case RMCLOMV_RMCSTATE_FAILED:
2489                                         env_hpu.fru_status = ENVMON_FRU_FAULT;
2490                                         break;
2491                                 case RMCLOMV_RMCSTATE_DOWNLOAD:
2492                                         env_hpu.fru_status =
2493                                             ENVMON_FRU_DOWNLOAD;
2494                                         break;
2495                                 default:
2496                                         env_hpu.sensor_status =
2497                                             ENVMON_INACCESSIBLE;
2498                                         break;
2499                                 }
2500                                 mutex_exit(&rmclomv_state_lock);
2501                         } else if (rmclomv_rmc_error ||
2502                             rmclomv_do_cmd(DP_GET_FRU_STATUS,
2503                             DP_GET_FRU_STATUS_R, sizeof (rmc_fru_r),
2504                             (intptr_t)&rmc_fru, (intptr_t)&rmc_fru_r) != 0) {
2505                                 env_hpu.sensor_status = ENVMON_INACCESSIBLE;
2506                         } else {
2507                                 /*
2508                                  * copy results into buffer for user
2509                                  */
2510                                 if (rmc_fru_r.fru_status[0].presence == 0) {
2511                                         env_hpu.sensor_status =
2512                                             ENVMON_NOT_PRESENT;
2513                                         env_hpu.fru_status =
2514                                             ENVMON_FRU_NOT_PRESENT;
2515                                 } else if (rmc_fru_r.fru_status[0].sensor_status
2516                                     != DP_SENSOR_DATA_AVAILABLE) {
2517                                         env_hpu.sensor_status =
2518                                             ENVMON_INACCESSIBLE;
2519                                 } else {
2520                                         uint8_t status =
2521                                             rmc_fru_r.fru_status[0].status;
2522                                         if (status == DP_FRU_STATUS_UNKNOWN) {
2523                                                 env_hpu.sensor_status =
2524                                                     ENVMON_INACCESSIBLE;
2525                                         } else if (status != DP_FRU_STATUS_OK) {
2526                                                 env_hpu.fru_status =
2527                                                     ENVMON_FRU_FAULT;
2528                                         }
2529                                 }
2530                         }
2531                 }
2532 
2533                 /*
2534                  * If rmclomv_rmc_error is set there is no way
2535                  * that we read information from RSC. Just copy
2536                  * out an inaccessible environmental.
2537                  */
2538                 if (rmclomv_rmc_error != RMCLOMV_RMCERROR_NONE) {
2539                         env_hpu.sensor_status = ENVMON_INACCESSIBLE;
2540                         env_hpu.fru_status = ENVMON_INACCESSIBLE;
2541                 }
2542 
2543                 if (ddi_copyout((caddr_t)&env_hpu, (caddr_t)arg,
2544                     sizeof (envmon_hpu_t), mode) != 0)
2545                         return (EFAULT);
2546                 break;
2547 
2548         case ENVMONIOCGETLED:
2549                 if (ddi_copyin((caddr_t)arg, (caddr_t)&env_ledinfo,
2550                     sizeof (envmon_led_info_t), mode) != 0)
2551                         return (EFAULT);
2552 
2553                 /* see if we've got LED handles cached */
2554                 LOCK_CACHE
2555                 sensor_status = ENVMON_SENSOR_OK;
2556 
2557                 if ((rmclomv_cache_valid == B_FALSE) ||
2558                     ((section = rmclomv_find_section(rmclomv_cache,
2559                     RMCLOMV_LED_IND)) == NULL)) {
2560                         env_ledinfo.next_id.name[0] = '\0';
2561                         sensor_status = ENVMON_NOT_PRESENT;
2562                 } else if (env_ledinfo.id.name[0] == '\0') {
2563                         /* request for first handle */
2564                         if (section->num_entries == 0)
2565                                 env_ledinfo.next_id.name[0] = '\0';
2566                         else
2567                                 env_ledinfo.next_id =
2568                                     section->entry[0].handle_name;
2569                         sensor_status = ENVMON_NOT_PRESENT;
2570                 } else {
2571                         /* ensure name is properly terminated */
2572                         env_ledinfo.id.name[ENVMON_MAXNAMELEN - 1] = '\0';
2573                         if (get_sensor_by_name(section, env_ledinfo.id.name,
2574                             &index) != 0) {
2575                                 env_ledinfo.next_id.name[0] = '\0';
2576                                 sensor_status = ENVMON_NOT_PRESENT;
2577                         } else if (index + 1 < section->num_entries)
2578                                 env_ledinfo.next_id =
2579                                     section->entry[index + 1].handle_name;
2580                         else
2581                                 env_ledinfo.next_id.name[0] = '\0';
2582                 }
2583                 if (sensor_status == ENVMON_SENSOR_OK) {
2584                         /*
2585                          * user correctly identified a LED, note its
2586                          * handle value and request the LED status
2587                          */
2588                         rmc_led.handle = section->entry[index].handle;
2589                 }
2590                 RELEASE_CACHE
2591                 if ((sensor_status == ENVMON_SENSOR_OK) && (rmclomv_rmc_error ||
2592                     rmclomv_do_cmd(DP_GET_LED_STATE, DP_GET_LED_STATE_R,
2593                     sizeof (rmc_led_r), (intptr_t)&rmc_led,
2594                     (intptr_t)&rmc_led_r) != 0)) {
2595                         sensor_status = ENVMON_INACCESSIBLE;
2596                 }
2597                 if ((sensor_status == ENVMON_SENSOR_OK) &&
2598                     (rmc_led_r.led_state[0].sensor_status ==
2599                     DP_SENSOR_NOT_PRESENT)) {
2600                         sensor_status = ENVMON_NOT_PRESENT;
2601                 }
2602                 if ((env_ledinfo.sensor_status = sensor_status) ==
2603                     ENVMON_SENSOR_OK) {
2604                         /*
2605                          * copy results into buffer for user
2606                          * start with some defaults then override
2607                          */
2608                         env_ledinfo.sensor_status = ENVMON_SENSOR_OK;
2609                         env_ledinfo.led_state = ENVMON_LED_OFF;
2610                         env_ledinfo.led_color = ENVMON_LED_CLR_NONE;
2611 
2612                         if (rmc_led_r.led_state[0].sensor_status !=
2613                             DP_SENSOR_DATA_AVAILABLE)
2614                                 env_ledinfo.sensor_status = ENVMON_INACCESSIBLE;
2615                         else {
2616                                 dp_led_state_t ledState;
2617                                 ledState = rmc_led_r.led_state[0];
2618                                 env_ledinfo.led_color = (int8_t)ledState.colour;
2619 
2620                                 switch (ledState.state) {
2621                                 case (rsci8)DP_LED_OFF:
2622                                         break;
2623                                 case (rsci8)DP_LED_ON:
2624                                         env_ledinfo.led_state = ENVMON_LED_ON;
2625                                         break;
2626                                 case (rsci8)DP_LED_BLINKING:
2627                                         env_ledinfo.led_state =
2628                                             ENVMON_LED_BLINKING;
2629                                         break;
2630                                 case (rsci8)DP_LED_FLASHING:
2631                                         env_ledinfo.led_state =
2632                                             ENVMON_LED_FLASHING;
2633                                         break;
2634                                 default:
2635                                         break;
2636                                 }
2637                         }
2638                 }
2639 
2640                 /*
2641                  * If rmclomv_rmc_error is set there is no way
2642                  * that we read information from RSC. Just copy
2643                  * out an inaccessible environmental.
2644                  */
2645                 if (rmclomv_rmc_error != RMCLOMV_RMCERROR_NONE) {
2646                         env_ledinfo.sensor_status = ENVMON_INACCESSIBLE;
2647                         env_ledinfo.led_state = ENVMON_INACCESSIBLE;
2648                 }
2649 
2650                 if (ddi_copyout((caddr_t)&env_ledinfo, (caddr_t)arg,
2651                     sizeof (envmon_led_info_t), mode) != 0)
2652                         return (EFAULT);
2653                 break;
2654 
2655         case ENVMONIOCSETLED:
2656                 if ((mode & FWRITE) == 0)
2657                         return (EACCES);
2658                 if (drv_priv(cred_p) != 0)
2659                         return (EPERM);
2660                 if (ddi_copyin((caddr_t)arg, (caddr_t)&env_ledctl,
2661                     sizeof (envmon_led_ctl_t), mode) != 0)
2662                         return (EFAULT);
2663                 if (env_ledctl.led_state < RMCLOMV_MIN_LED_STATE ||
2664                     env_ledctl.led_state > RMCLOMV_MAX_LED_STATE)
2665                         return (EINVAL);
2666                 /*
2667                  * Ensure name is properly terminated.
2668                  */
2669                 env_ledctl.id.name[ENVMON_MAXNAMELEN - 1] = '\0';
2670 
2671                 /* see if we've got LED handles cached */
2672                 LOCK_CACHE
2673 
2674                 if ((rmclomv_cache_valid == B_FALSE) ||
2675                     ((section = rmclomv_find_section(rmclomv_cache,
2676                     RMCLOMV_LED_IND)) == NULL) ||
2677                     (get_sensor_by_name(section, env_ledctl.id.name,
2678                     &index) != 0)) {
2679                         RELEASE_CACHE
2680                         return (EINVAL);        /* no such LED */
2681                 }
2682                 /*
2683                  * user correctly identified a LED, note its handle value
2684                  */
2685                 rmc_setled.handle = section->entry[index].handle;
2686                 RELEASE_CACHE
2687                 switch (env_ledctl.led_state) {
2688                 case ENVMON_LED_ON:
2689                         rmc_setled.state = DP_LED_ON;
2690                         break;
2691                 case ENVMON_LED_BLINKING:
2692                         rmc_setled.state = DP_LED_BLINKING;
2693                         break;
2694                 case ENVMON_LED_FLASHING:
2695                         rmc_setled.state = DP_LED_FLASHING;
2696                         break;
2697                 default:
2698                         rmc_setled.state = DP_LED_OFF;
2699                         break;
2700                 }
2701                 retval = rmclomv_do_cmd(DP_SET_LED_STATE, DP_SET_LED_STATE_R,
2702                     sizeof (rmc_setled_r), (intptr_t)&rmc_setled,
2703                     (intptr_t)&rmc_setled_r);
2704 
2705                 if (retval != 0) {
2706                         break;
2707                 }
2708 
2709                 if (rmc_setled_r.status != 0) {
2710                         cmn_err(CE_WARN, "ENVMONIOCSETLED: \"%s\" status: 0x%x",
2711                             env_ledctl.id.name, rmc_setled_r.status);
2712                         return (EIO);
2713                 }
2714                 break;
2715 
2716         case ENVMONIOCGETKEYSW:
2717         {
2718                 enum rmc_keyswitch_pos  rmc_pos = real_key_position;
2719                 envmon_keysw_pos_t      envmon_pos;
2720 
2721                 /*
2722                  * Yes, I know this is ugly, but the V210 has no keyswitch,
2723                  * even though the ALOM returns a value for it
2724                  */
2725                 if (strcmp(platform, "SUNW,Sun-Fire-V210") == 0) {
2726                         return (ENOTSUP);
2727                 }
2728 
2729                 switch (rmc_pos) {
2730 
2731                 case RMC_KEYSWITCH_POS_NORMAL:
2732                         envmon_pos = ENVMON_KEYSW_POS_NORMAL;
2733                         break;
2734                 case RMC_KEYSWITCH_POS_DIAG:
2735                         envmon_pos = ENVMON_KEYSW_POS_DIAG;
2736                         break;
2737                 case RMC_KEYSWITCH_POS_LOCKED:
2738                         envmon_pos = ENVMON_KEYSW_POS_LOCKED;
2739                         break;
2740                 case RMC_KEYSWITCH_POS_OFF:
2741                         envmon_pos = ENVMON_KEYSW_POS_OFF;
2742                         break;
2743                 default:
2744                         envmon_pos = ENVMON_KEYSW_POS_UNKNOWN;
2745                         break;
2746                 }
2747 
2748                 if (ddi_copyout((caddr_t)&envmon_pos, (caddr_t)arg,
2749                     sizeof (envmon_pos), mode) != 0)
2750                         return (EFAULT);
2751                 break;
2752         }
2753 
2754         case ENVMONIOCGETALARM:
2755                 if (ddi_copyin((caddr_t)arg, (caddr_t)&env_alarminfo,
2756                     sizeof (envmon_alarm_info_t), mode) != 0)
2757                         return (EFAULT);
2758 
2759                 /* see if we've got ALARM handles cached */
2760                 LOCK_CACHE
2761                 sensor_status = ENVMON_SENSOR_OK;
2762 
2763                 if ((rmclomv_cache_valid == B_FALSE) ||
2764                     ((section = rmclomv_find_section(rmclomv_cache,
2765                     RMCLOMV_ALARM_IND)) == NULL)) {
2766                         env_alarminfo.next_id.name[0] = '\0';
2767                         sensor_status = ENVMON_NOT_PRESENT;
2768                 } else if (env_alarminfo.id.name[0] == '\0') {
2769                         /* request for first handle */
2770                         if (section->num_entries == 0)
2771                                 env_alarminfo.next_id.name[0] = '\0';
2772                         else
2773                                 env_alarminfo.next_id =
2774                                     section->entry[0].handle_name;
2775                         sensor_status = ENVMON_NOT_PRESENT;
2776                 } else {
2777                         /* ensure name is properly terminated */
2778                         env_alarminfo.id.name[ENVMON_MAXNAMELEN - 1] = '\0';
2779                         if (get_sensor_by_name(section, env_alarminfo.id.name,
2780                             &index) != 0) {
2781                                 env_alarminfo.next_id.name[0] = '\0';
2782                                 sensor_status = ENVMON_NOT_PRESENT;
2783                         } else if (index + 1 < section->num_entries)
2784                                 env_alarminfo.next_id =
2785                                     section->entry[index + 1].handle_name;
2786                         else
2787                                 env_alarminfo.next_id.name[0] = '\0';
2788                 }
2789                 if (sensor_status == ENVMON_SENSOR_OK) {
2790                         /*
2791                          * user correctly identified a ALARM, note its
2792                          * handle value and request the ALARM status
2793                          */
2794                         rmc_alarm.handle = section->entry[index].handle;
2795                 }
2796                 RELEASE_CACHE
2797                 if ((sensor_status == ENVMON_SENSOR_OK) &&
2798                     (rmclomv_rmc_error ||
2799                     rmclomv_do_cmd(DP_GET_ALARM_STATE, DP_GET_ALARM_STATE_R,
2800                     sizeof (rmc_alarm_r), (intptr_t)&rmc_alarm,
2801                     (intptr_t)&rmc_alarm_r) != 0)) {
2802                         sensor_status = ENVMON_INACCESSIBLE;
2803                 }
2804                 if ((env_alarminfo.sensor_status = sensor_status) ==
2805                     ENVMON_SENSOR_OK) {
2806                         /*
2807                          * copy results into buffer for user
2808                          * start with some defaults then override
2809                          */
2810                         env_alarminfo.sensor_status = ENVMON_SENSOR_OK;
2811                         env_alarminfo.alarm_state = ENVMON_ALARM_OFF;
2812 
2813                         if (rmc_alarm_r.alarm_state[0].sensor_status !=
2814                             DP_SENSOR_DATA_AVAILABLE)
2815                                 env_alarminfo.sensor_status =
2816                                     ENVMON_INACCESSIBLE;
2817                         else {
2818                                 dp_alarm_state_t alarmState;
2819                                 alarmState = rmc_alarm_r.alarm_state[0];
2820 
2821                                 switch (alarmState.state) {
2822                                 case DP_ALARM_OFF:
2823                                         break;
2824                                 case DP_ALARM_ON:
2825                                         env_alarminfo.alarm_state =
2826                                             ENVMON_ALARM_ON;
2827                                         break;
2828                                 default:
2829                                         break;
2830                                 }
2831                         }
2832                 }
2833 
2834                 /*
2835                  * If rmclomv_rmc_error is set there is no way
2836                  * that we read information from RSC. Just copy
2837                  * out an inaccessible environmental.
2838                  */
2839                 if (rmclomv_rmc_error != RMCLOMV_RMCERROR_NONE) {
2840                         env_alarminfo.sensor_status = ENVMON_INACCESSIBLE;
2841                         env_alarminfo.alarm_state = ENVMON_INACCESSIBLE;
2842                 }
2843 
2844                 if (ddi_copyout((caddr_t)&env_alarminfo, (caddr_t)arg,
2845                     sizeof (envmon_alarm_info_t), mode) != 0)
2846                         return (EFAULT);
2847                 break;
2848 
2849         case ENVMONIOCSETALARM:
2850                 if ((mode & FWRITE) == 0)
2851                         return (EACCES);
2852                 if (drv_priv(cred_p) != 0)
2853                         return (EPERM);
2854                 if (ddi_copyin((caddr_t)arg, (caddr_t)&env_alarmctl,
2855                     sizeof (envmon_alarm_ctl_t), mode) != 0)
2856                         return (EFAULT);
2857                 if (env_alarmctl.alarm_state < RMCLOMV_MIN_ALARM_STATE ||
2858                     env_alarmctl.alarm_state > RMCLOMV_MAX_ALARM_STATE)
2859                         return (EINVAL);
2860                 /*
2861                  * Ensure name is properly terminated.
2862                  */
2863                 env_alarmctl.id.name[ENVMON_MAXNAMELEN - 1] = '\0';
2864 
2865                 /* see if we've got ALARM handles cached */
2866                 LOCK_CACHE
2867 
2868                 if ((rmclomv_cache_valid == B_FALSE) ||
2869                     ((section = rmclomv_find_section(rmclomv_cache,
2870                     RMCLOMV_ALARM_IND)) == NULL) ||
2871                     (get_sensor_by_name(section, env_alarmctl.id.name,
2872                     &index) != 0)) {
2873                         RELEASE_CACHE
2874                         return (EINVAL);        /* no such ALARM */
2875                 }
2876                 /*
2877                  * user correctly identified a ALARM, note its handle value
2878                  */
2879                 rmc_setalarm.handle = section->entry[index].handle;
2880                 RELEASE_CACHE
2881                 rmc_setalarm.state = (rsci8)env_alarmctl.alarm_state;
2882                 retval = rmclomv_do_cmd(DP_SET_ALARM_STATE,
2883                     DP_SET_ALARM_STATE_R,
2884                     sizeof (rmc_setalarm_r),
2885                     (intptr_t)&rmc_setalarm,
2886                     (intptr_t)&rmc_setalarm_r);
2887 
2888                 if (retval != 0) {
2889                         break;
2890                 }
2891 
2892                 if (rmc_setalarm_r.status != 0) {
2893                         cmn_err(CE_WARN, "ENVMONIOCSETALARM: \"%s\" status: "
2894                             "0x%x", env_alarmctl.id.name,
2895                             rmc_setalarm_r.status);
2896                         return (EIO);
2897                 }
2898                 break;
2899 
2900         case ENVMONIOCCHASSISSERIALNUM:
2901                 retval = rmclomv_do_cmd(DP_GET_SDP_VERSION,
2902                     DP_GET_SDP_VERSION_R, sizeof (rmc_sdpver_r),
2903                     NULL, (intptr_t)&rmc_sdpver_r);
2904 
2905                 if (retval != 0) {
2906                         cmn_err(CE_WARN, "DP_GET_SDP_VERSION failed, ret=%d\n",
2907                             retval);
2908                         break;
2909                 } else if (rmc_sdpver_r.version < SDP_RESPONDS_TO_ALL_CMDS) {
2910                         retval = ENOTSUP;
2911                         break;
2912                 }
2913                 retval = rmclomv_do_cmd(DP_GET_CHASSIS_SERIALNUM,
2914                     DP_GET_CHASSIS_SERIALNUM_R, sizeof (rmc_serialnum_r),
2915                     NULL, (intptr_t)&rmc_serialnum_r);
2916 
2917                 if (retval != 0) {
2918                         break;
2919                 }
2920                 bcopy(rmc_serialnum_r.chassis_serial_number,
2921                     chassis.serial_number,
2922                     sizeof (rmc_serialnum_r.chassis_serial_number));
2923 
2924                 if (ddi_copyout((caddr_t)&chassis, (caddr_t)arg,
2925                     sizeof (chassis), mode) != 0) {
2926                         return (EFAULT);
2927                 }
2928                 sensor_status = ENVMON_SENSOR_OK;
2929                 break;
2930 
2931         default:
2932                 retval = ENOTSUP;
2933                 break;
2934         }
2935 
2936         return (retval);
2937 }
2938 
2939 /* ARGSUSED */
2940 static void
2941 rmclomv_checkrmc(caddr_t arg)
2942 {
2943         callb_cpr_t             cprinfo;
2944         int                     err;
2945         int                     retries;
2946         int                     state;
2947         dp_get_sysinfo_r_t      sysinfo;
2948 
2949         CALLB_CPR_INIT(&cprinfo, &rmclomv_checkrmc_lock, callb_generic_cpr,
2950             "rmclomv_checkrmc");
2951 
2952         mutex_enter(&rmclomv_checkrmc_lock);
2953         for (;;) {
2954                 /*
2955                  * Initial entry to this for loop is made with
2956                  * rmclomv_checkrmc_sig set to RMCLOMV_PROCESS_NOW. So the
2957                  * following while loop drops through the first time. A
2958                  * timeout call is made just before polling the RMC. Its
2959                  * interrupt routine sustains this loop by injecting additional
2960                  * state changes and cv events.
2961                  */
2962                 /*
2963                  * Wait for someone to tell me to continue.
2964                  */
2965                 while (rmclomv_checkrmc_sig == RMCLOMV_CHECKRMC_WAIT) {
2966                         CALLB_CPR_SAFE_BEGIN(&cprinfo);
2967                         cv_wait(&rmclomv_checkrmc_sig_cv,
2968                             &rmclomv_checkrmc_lock);
2969                         CALLB_CPR_SAFE_END(&cprinfo, &rmclomv_checkrmc_lock);
2970                 }
2971 
2972                 mutex_exit(&rmclomv_checkrmc_lock);
2973                 /*
2974                  * mustn't hold same lock as timeout called with
2975                  * when cancelling timer
2976                  */
2977                 if (timer_id != 0) {
2978                         (void) untimeout(timer_id);
2979                         timer_id = 0;
2980                 }
2981                 mutex_enter(&rmclomv_checkrmc_lock);
2982 
2983                 /* RMCLOMV_CHECKRMC_EXITNOW implies signal by _detach(). */
2984                 if (rmclomv_checkrmc_sig == RMCLOMV_CHECKRMC_EXITNOW) {
2985                         rmclomv_checkrmc_sig = RMCLOMV_CHECKRMC_WAIT;
2986 
2987                         /* rmclomv_checkrmc_lock is held at this point! */
2988                         CALLB_CPR_EXIT(&cprinfo);
2989 
2990                         thread_exit();
2991                         /* NOTREACHED */
2992                 }
2993 
2994                 rmclomv_checkrmc_sig = RMCLOMV_CHECKRMC_WAIT;
2995 
2996                 /*
2997                  * If the RMC is not responding, rmclomv_do_cmd() takes a
2998                  * long time and eventually times out. We conclude that the
2999                  * RMC is broken if it doesn't respond to a number of polls
3000                  * made 60 secs apart. So that the rmclomv_do_cmd() time-out
3001                  * period isn't added to our 60 second timer, make the
3002                  * timeout() call before calling rmclomv_do_cmd().
3003                  */
3004                 if (timer_id == 0) {
3005                         timer_id = timeout(rmclomv_checkrmc_wakeup, NULL,
3006                             60 * drv_usectohz(1000000));
3007                 }
3008 
3009                 mutex_exit(&rmclomv_checkrmc_lock);
3010 
3011                 err = rmclomv_do_cmd(DP_GET_SYSINFO, DP_GET_SYSINFO_R,
3012                     sizeof (sysinfo), NULL, (intptr_t)&sysinfo);
3013                 if (err == 0) {
3014                         mutex_enter(&rmclomv_state_lock);
3015                         state = rmclomv_rmc_state;
3016                         /* successful poll, reset fail count */
3017                         rmclomv_rmcfailcount = 0;
3018                         mutex_exit(&rmclomv_state_lock);
3019 
3020                         if (state != RMCLOMV_RMCSTATE_OK) {
3021                                 rmclomv_refresh_wakeup();
3022                         }
3023                 }
3024                 if ((err != 0) &&
3025                     (rmclomv_rmc_error != RMCLOMV_RMCSTATE_DOWNLOAD)) {
3026                         /*
3027                          * Failed response or no response from RMC.
3028                          * Count the failure.
3029                          * If threshold exceeded, send a DR event.
3030                          */
3031                         mutex_enter(&rmclomv_state_lock);
3032                         retries = rmclomv_rmcfailcount;
3033                         state = rmclomv_rmc_state;
3034                         if (retries == RMCLOMV_RMCFAILTHRESHOLD)
3035                                 rmclomv_rmc_state = RMCLOMV_RMCSTATE_FAILED;
3036                         if (rmclomv_rmcfailcount <= RMCLOMV_RMCFAILTHRESHOLD)
3037                                 rmclomv_rmcfailcount++;
3038                         mutex_exit(&rmclomv_state_lock);
3039 
3040                         if (retries == RMCLOMV_RMCFAILTHRESHOLD) {
3041                                 cmn_err(CE_WARN, "SC %s responding",
3042                                     state == RMCLOMV_RMCSTATE_OK ?
3043                                     "has stopped" : "is not");
3044                                 refresh_name_cache(B_TRUE);
3045                                 rmclomv_dr_data_handler(str_sc, SE_NO_HINT);
3046                         }
3047                 }
3048 
3049                 /*
3050                  * Re-enter the lock to prepare for another iteration.
3051                  * We must have the lock here to protect rmclomv_checkrmc_sig.
3052                  */
3053                 mutex_enter(&rmclomv_checkrmc_lock);
3054         }
3055 }
3056 
3057 static void
3058 rmclomv_checkrmc_start(void)
3059 {
3060         kthread_t *tp;
3061 
3062         mutex_enter(&rmclomv_checkrmc_lock);
3063 
3064         if (rmclomv_checkrmc_tid == 0) {
3065                 rmclomv_checkrmc_sig = RMCLOMV_CHECKRMC_PROCESSNOW;
3066 
3067                 tp = thread_create(NULL, 0, rmclomv_checkrmc, NULL, 0,
3068                     &p0, TS_RUN, maxclsyspri);
3069                 rmclomv_checkrmc_tid = tp->t_did;
3070         }
3071 
3072         mutex_exit(&rmclomv_checkrmc_lock);
3073 }
3074 
3075 static void
3076 rmclomv_checkrmc_destroy(void)
3077 {
3078         kt_did_t tid;
3079 
3080         mutex_enter(&rmclomv_checkrmc_lock);
3081         tid = rmclomv_checkrmc_tid;
3082         if (tid != 0) {
3083                 rmclomv_checkrmc_sig = RMCLOMV_CHECKRMC_EXITNOW;
3084                 cv_signal(&rmclomv_checkrmc_sig_cv);
3085                 rmclomv_checkrmc_tid = 0;
3086         }
3087         mutex_exit(&rmclomv_checkrmc_lock);
3088 
3089         /*
3090          * Wait for rmclomv_checkrmc() to finish
3091          */
3092         if (tid != 0)
3093                 thread_join(tid);
3094 }
3095 
3096 /*ARGSUSED*/
3097 static void
3098 rmclomv_checkrmc_wakeup(void *arg)
3099 {
3100         mutex_enter(&rmclomv_checkrmc_lock);
3101 
3102         if (rmclomv_checkrmc_sig != RMCLOMV_CHECKRMC_EXITNOW)
3103                 rmclomv_checkrmc_sig = RMCLOMV_CHECKRMC_PROCESSNOW;
3104         cv_signal(&rmclomv_checkrmc_sig_cv);
3105 
3106         mutex_exit(&rmclomv_checkrmc_lock);
3107 }
3108 
3109 /* ARGSUSED */
3110 static void
3111 rmclomv_refresh(caddr_t arg)
3112 {
3113         void                    (*plat_nodename_set_fun)(void);
3114         sig_state_t             *current_sgn_p;
3115         callb_cpr_t             cprinfo;
3116         int                     state;
3117         int                     tmp_checkrmc_sig;
3118 
3119         CALLB_CPR_INIT(&cprinfo, &rmclomv_refresh_lock, callb_generic_cpr,
3120             "rmclomv_refresh");
3121 
3122         /*
3123          * Wait until the rmclomv_checkrmc() thread has had a chance to
3124          * run its main loop.  This is done so that rmclomv_refresh will
3125          * only run its main loop once at start of day; otherwise, it may
3126          * run twice and generate warning messages when redundantly populating
3127          * its internal cache.
3128          */
3129         do {
3130                 delay(drv_usectohz(DELAY_TIME));
3131                 mutex_enter(&rmclomv_checkrmc_lock);
3132                 tmp_checkrmc_sig = rmclomv_checkrmc_sig;
3133                 mutex_exit(&rmclomv_checkrmc_lock);
3134         } while (tmp_checkrmc_sig != RMCLOMV_CHECKRMC_WAIT);
3135 
3136         mutex_enter(&rmclomv_refresh_lock);
3137         for (;;) {
3138 
3139                 /*
3140                  * Wait for someone to tell me to continue.
3141                  */
3142                 while (rmclomv_refresh_sig == RMCLOMV_REFRESH_WAIT) {
3143                         CALLB_CPR_SAFE_BEGIN(&cprinfo);
3144                         cv_wait(&rmclomv_refresh_sig_cv, &rmclomv_refresh_lock);
3145                         CALLB_CPR_SAFE_END(&cprinfo, &rmclomv_refresh_lock);
3146                 }
3147 
3148                 /* RMCLOMV_REFRESH_EXITNOW implies signal by _detach(). */
3149                 if (rmclomv_refresh_sig == RMCLOMV_REFRESH_EXITNOW) {
3150                         rmclomv_refresh_sig = RMCLOMV_REFRESH_WAIT;
3151 
3152                         /* rmclomv_refresh_lock is held at this point! */
3153                         CALLB_CPR_EXIT(&cprinfo);
3154 
3155                         thread_exit();
3156                         /* NOTREACHED */
3157                 }
3158 
3159                 ASSERT(rmclomv_refresh_sig == RMCLOMV_REFRESH_PROCESSNOW);
3160                 rmclomv_refresh_sig = RMCLOMV_REFRESH_WAIT;
3161 
3162                 mutex_exit(&rmclomv_refresh_lock);
3163 
3164                 refresh_name_cache(B_FALSE);
3165 
3166                 /*
3167                  * We're not going to access rmclomv_sysinfo_data here,
3168                  * so there's no point in locking it before reading
3169                  * rmclomv_sysinfo_valid. Also this avoids holding two
3170                  * locks at once and the concommitant worry about deadlocks.
3171                  */
3172                 if (rmclomv_sysinfo_valid) {
3173                         /*
3174                          * We've just successfully read the RMC sysinfo
3175                          * so the RMC must be operational. Update its
3176                          * state and if it was previously not OK, refresh
3177                          * nodename, CPU signatures and watchdog settings.
3178                          */
3179                         mutex_enter(&rmclomv_state_lock);
3180                         rmclomv_rmcfailcount = 0;
3181                         state = rmclomv_rmc_state;
3182                         rmclomv_rmc_state = RMCLOMV_RMCSTATE_OK;
3183                         mutex_exit(&rmclomv_state_lock);
3184 
3185                         if (state != RMCLOMV_RMCSTATE_OK) {
3186                                 rmclomv_dr_data_handler(str_sc, SE_NO_HINT);
3187                                 if (state == RMCLOMV_RMCSTATE_FAILED) {
3188                                         cmn_err(CE_NOTE, "SC recovered");
3189                                 }
3190                         }
3191 
3192                         if (utsname.nodename[0] != 0) {
3193                                 plat_nodename_set_fun =
3194                                     (void (*)(void))modgetsymvalue(
3195                                     "plat_nodename_set", 0);
3196                                 if (plat_nodename_set_fun != NULL)
3197                                         plat_nodename_set_fun();
3198                         }
3199 
3200                         current_sgn_p = (sig_state_t *)modgetsymvalue(
3201                             "current_sgn", 0);
3202 
3203                         /*
3204                          * Delay before calling CPU_SIGNATURE, to allow
3205                          * any pending asynchronous communications (i.e.
3206                          * plat_timesync()) to complete.  This helps to
3207                          * prevent the situation where the message associated
3208                          * with the CPU_SIGNATURE state cannot be sent to the
3209                          * system controller.
3210                          */
3211                         if ((current_sgn_p != NULL) &&
3212                             (current_sgn_p->state_t.sig != 0)) {
3213                                 delay(drv_usectohz(CPU_SIGNATURE_DELAY_TIME));
3214                                 CPU_SIGNATURE(current_sgn_p->state_t.sig,
3215                                     current_sgn_p->state_t.state,
3216                                     current_sgn_p->state_t.sub_state, -1);
3217 
3218                                 if (!(boothowto & RB_DEBUG)) {
3219                                         /*
3220                                          * Delay before calling
3221                                          * send_watchdog_msg, to allow
3222                                          * CPU_SIGNATURE() time to
3223                                          * complete; this increases the
3224                                          * chances of successfully sending
3225                                          * the watchdog message to the
3226                                          * system controller.
3227                                          */
3228                                         delay(drv_usectohz(
3229                                             CPU_SIGNATURE_DELAY_TIME));
3230                                         send_watchdog_msg(last_watchdog_msg);
3231                                 }
3232                         }
3233                 }
3234 
3235                 /*
3236                  * update keyswitch value in case it changed while the
3237                  * RMC was out of action
3238                  */
3239                 LOCK_CACHE
3240                 if (rmclomv_sysinfo_valid) {
3241                         real_key_position = rmclomv_sysinfo_data.keyswitch;
3242                         if ((real_key_position != RMC_KEYSWITCH_POS_UNKNOWN) &&
3243                             (real_key_position <= RMC_KEYSWITCH_POS_OFF)) {
3244                                 key_position = real_key_position;
3245                         } else {
3246                                 /* treat unknown key position as locked */
3247                                 key_position = RMC_KEYSWITCH_POS_LOCKED;
3248                         }
3249                 } else {
3250                         /* treat unreadable key position as locked */
3251                         key_position = RMC_KEYSWITCH_POS_LOCKED;
3252                         real_key_position = RMC_KEYSWITCH_POS_UNKNOWN;
3253                 }
3254                 RELEASE_CACHE
3255 
3256                 /*
3257                  * Re-enter the lock to prepare for another iteration.
3258                  * We must have the lock here to protect rmclomv_refresh_sig.
3259                  */
3260                 mutex_enter(&rmclomv_refresh_lock);
3261         }
3262 }
3263 
3264 static void
3265 rmclomv_refresh_start(void)
3266 {
3267         kthread_t *tp;
3268 
3269         mutex_enter(&rmclomv_refresh_lock);
3270 
3271         if (rmclomv_refresh_tid == 0) {
3272                 rmclomv_refresh_sig = RMCLOMV_REFRESH_PROCESSNOW;
3273 
3274                 tp = thread_create(NULL, 0, rmclomv_refresh, NULL, 0,
3275                     &p0, TS_RUN, maxclsyspri);
3276                 rmclomv_refresh_tid = tp->t_did;
3277         }
3278 
3279         mutex_exit(&rmclomv_refresh_lock);
3280 }
3281 
3282 static void
3283 rmclomv_refresh_destroy(void)
3284 {
3285         kt_did_t tid;
3286 
3287         mutex_enter(&rmclomv_refresh_lock);
3288         tid = rmclomv_refresh_tid;
3289         if (tid != 0) {
3290                 rmclomv_refresh_sig = RMCLOMV_REFRESH_EXITNOW;
3291                 cv_signal(&rmclomv_refresh_sig_cv);
3292                 rmclomv_refresh_tid = 0;
3293         }
3294         mutex_exit(&rmclomv_refresh_lock);
3295 
3296         /*
3297          * Wait for rmclomv_refresh() to finish
3298          */
3299         if (tid != 0)
3300                 thread_join(tid);
3301 }
3302 
3303 static void
3304 rmclomv_refresh_wakeup(void)
3305 {
3306         mutex_enter(&rmclomv_refresh_lock);
3307 
3308         if (rmclomv_refresh_sig != RMCLOMV_REFRESH_EXITNOW)
3309                 rmclomv_refresh_sig = RMCLOMV_REFRESH_PROCESSNOW;
3310         cv_signal(&rmclomv_refresh_sig_cv);
3311 
3312         mutex_exit(&rmclomv_refresh_lock);
3313 }
3314 
3315 static void
3316 send_watchdog_msg(int msg)
3317 {
3318         rmc_comm_msg_t request;
3319         dp_set_host_watchdog_t watchdog_msg;
3320 
3321         if (rmclomv_watchdog_mode)
3322                 return;
3323 
3324         watchdog_msg.enable = msg;
3325         request.msg_type = DP_SET_HOST_WATCHDOG;
3326         request.msg_len = sizeof (watchdog_msg);
3327         request.msg_buf = (caddr_t)&watchdog_msg;
3328         (void) rmc_comm_request_nowait(&request, (msg == 1) ?
3329             RMC_COMM_DREQ_URGENT : 0);
3330 }
3331 
3332 /*ARGSUSED*/
3333 static uint_t
3334 rmc_set_watchdog_timer(uint_t timeoutval)
3335 {
3336         ASSERT(MUTEX_HELD(&tod_lock));
3337 
3338         if ((watchdog_enable == 0) || (watchdog_available == 0)) {
3339                 return (0);
3340         }
3341 
3342         /*
3343          * If boothowto has RB_DEBUG set we never want to set the watchdog
3344          * support on.
3345          */
3346         if (boothowto & RB_DEBUG) {
3347                 return (0);
3348         }
3349 
3350         /*
3351          * When the watchdog is shut off last_watchdog_msg goes from a
3352          * 0 to a 1. So we must test to see that last_watchdog_msg is
3353          * set to 1 indicating that watchdog was shut off and
3354          * After which we set last_watchdog_msg back to 0 so that we do not
3355          * run this code
3356          * again.
3357          */
3358         if (last_watchdog_msg == 1) {
3359                 send_watchdog_msg(0);
3360                 last_watchdog_msg = 0;
3361         }
3362 
3363         pmugpio_watchdog_pat();
3364 
3365         watchdog_activated = 1;
3366 
3367         return (1);
3368 }
3369 
3370 static uint_t
3371 rmc_clear_watchdog_timer(void)
3372 {
3373         ASSERT(MUTEX_HELD(&tod_lock));
3374         if ((watchdog_activated == 0) || (boothowto & RB_DEBUG))
3375                 return (0);
3376 
3377         send_watchdog_msg(1);
3378         last_watchdog_msg = 1;
3379         watchdog_activated = 0;
3380 
3381         return (0);
3382 }
3383 
3384 static void
3385 plat_timesync(void *arg)
3386 {
3387         timestruc_t now;
3388         todinfo_t tod;
3389         rmc_comm_msg_t request;
3390         dp_set_date_time_t set_time_msg;
3391         int retval;
3392         timestruc_t ts;
3393         dp_get_date_time_r_t *date_and_time_info;
3394         int buffer[DATE_TIME_MSG_SIZE];
3395 
3396         /* Is the system coming up? */
3397         if (arg != NULL) {
3398                 /* Request the time from the RMC clock. */
3399                 retval = rmclomv_do_cmd(DP_GET_DATE_TIME, DP_GET_DATE_TIME_R,
3400                     DATE_TIME_MSG_SIZE, NULL, (intptr_t)&buffer);
3401 
3402                 /*
3403                  * If we were able to get the time lets set the local clock.
3404                  * The time returned from RMC is in Unix time format.
3405                  *
3406                  * If we couldn't get the time we'll accept the drift so as not
3407                  * to cause congestion on the I2C bus or cause boot
3408                  * performance regressions.
3409                  */
3410                 if (retval == RCNOERR) {
3411                         date_and_time_info = (dp_get_date_time_r_t *)buffer;
3412                         ts.tv_sec = date_and_time_info->current_datetime;
3413                         ts.tv_nsec = 0;
3414                         mutex_enter(&tod_lock);
3415                         tod_set(ts);
3416                         set_hrestime(&ts);
3417                         mutex_exit(&tod_lock);
3418                 }
3419         }
3420 
3421         gethrestime(&now);
3422         mutex_enter(&tod_lock);
3423         tod = utc_to_tod(now.tv_sec);
3424         mutex_exit(&tod_lock);
3425 
3426         set_time_msg.year       = tod.tod_year;
3427         set_time_msg.month      = tod.tod_month - 1;
3428         set_time_msg.day        = tod.tod_day;
3429         set_time_msg.hour       = tod.tod_hour;
3430         set_time_msg.minute     = tod.tod_min;
3431         set_time_msg.second     = tod.tod_sec;
3432 
3433         request.msg_type = DP_SET_DATE_TIME;
3434         request.msg_len = sizeof (set_time_msg);
3435         request.msg_buf = (caddr_t)&set_time_msg;
3436 
3437         (void) rmc_comm_request_nowait(&request, 0);
3438 
3439         mutex_enter(&timesync_lock);
3440         if (timesync_interval != 0)
3441                 timesync_tid = timeout(plat_timesync, NULL, timesync_interval);
3442         mutex_exit(&timesync_lock);
3443 }
3444 
3445 /*
3446  * Interfaces to get/set alarm relays from outside
3447  */
3448 int
3449 rmclomv_alarm_get(int alarm_type, int *alarm_state)
3450 {
3451         rmclomv_cache_section_t *section;
3452         int                     index;
3453         uint16_t                sensor_status;
3454         dp_get_alarm_state_t    u_rmc_alarm;
3455         dp_get_alarm_state_r_t  u_rmc_alarm_r;
3456 
3457         /* see if we've got ALARM handles cached */
3458         LOCK_CACHE
3459         sensor_status = ENVMON_SENSOR_OK;
3460 
3461         if ((rmclomv_cache_valid == B_FALSE) ||
3462             ((section = rmclomv_find_section(rmclomv_cache,
3463             RMCLOMV_ALARM_IND)) == NULL)) {
3464                 sensor_status = ENVMON_NOT_PRESENT;
3465         }
3466         if (sensor_status == ENVMON_SENSOR_OK) {
3467                 /*
3468                  * user correctly identified a ALARM, note its
3469                  * handle value and request the ALARM status
3470                  */
3471                 index = alarm_type;
3472                 if (index >= section->num_entries)
3473                         sensor_status = ENVMON_INACCESSIBLE;
3474                 else
3475                         u_rmc_alarm.handle = section->entry[index].handle;
3476         }
3477         RELEASE_CACHE
3478         if ((sensor_status == ENVMON_SENSOR_OK) && (rmclomv_rmc_error ||
3479             rmclomv_do_cmd(DP_GET_ALARM_STATE, DP_GET_ALARM_STATE_R,
3480             sizeof (u_rmc_alarm_r), (intptr_t)&u_rmc_alarm,
3481             (intptr_t)&u_rmc_alarm_r) != 0)) {
3482                 sensor_status = ENVMON_INACCESSIBLE;
3483         }
3484         if (sensor_status == ENVMON_SENSOR_OK) {
3485                 /*
3486                  * copy results into buffer for user
3487                  * start with some defaults then override
3488                  */
3489                 *alarm_state = 0;
3490 
3491                 if (u_rmc_alarm_r.alarm_state[0].sensor_status !=
3492                     DP_SENSOR_DATA_AVAILABLE)
3493                         return (ENXIO);
3494                 else {
3495                         dp_alarm_state_t alarmState;
3496                         alarmState = u_rmc_alarm_r.alarm_state[0];
3497 
3498                         switch (alarmState.state) {
3499                         case DP_ALARM_OFF:
3500                                 break;
3501                         case DP_ALARM_ON:
3502                                 *alarm_state = 1;
3503                                 break;
3504                         default:
3505                                 break;
3506                         }
3507                 }
3508         } else
3509                 return (ENXIO);
3510 
3511         return (0);
3512 }
3513 
3514 int
3515 rmclomv_alarm_set(int alarm_type, int new_state)
3516 {
3517         rmclomv_cache_section_t *section;
3518         int                     index;
3519         uint16_t                sensor_status;
3520         dp_set_alarm_state_t    u_rmc_setalarm;
3521         dp_set_alarm_state_r_t  u_rmc_setalarm_r;
3522 
3523         /* see if we've got ALARM handles cached */
3524         LOCK_CACHE
3525         sensor_status = ENVMON_SENSOR_OK;
3526 
3527         if ((rmclomv_cache_valid == B_FALSE) ||
3528             ((section = rmclomv_find_section(rmclomv_cache,
3529             RMCLOMV_ALARM_IND)) == NULL)) {
3530                 sensor_status = ENVMON_NOT_PRESENT;
3531         }
3532         if (sensor_status == ENVMON_SENSOR_OK) {
3533                 /*
3534                  * user correctly identified a ALARM, note its
3535                  * handle value and request the ALARM status
3536                  */
3537                 index = alarm_type;
3538                 if (index >= section->num_entries)
3539                         sensor_status = ENVMON_INACCESSIBLE;
3540                 else {
3541                         u_rmc_setalarm.handle = section->entry[index].handle;
3542                         u_rmc_setalarm.state = new_state;
3543                 }
3544         }
3545         RELEASE_CACHE
3546         if ((sensor_status == ENVMON_SENSOR_OK) &&
3547             (rmclomv_rmc_error ||
3548             rmclomv_do_cmd(DP_SET_ALARM_STATE, DP_SET_ALARM_STATE_R,
3549             sizeof (u_rmc_setalarm_r), (intptr_t)&u_rmc_setalarm,
3550             (intptr_t)&u_rmc_setalarm_r) != 0)) {
3551                 sensor_status = ENVMON_INACCESSIBLE;
3552         }
3553 
3554         if (u_rmc_setalarm_r.status != DP_SET_ALARM_OK) {
3555                 return (EIO);
3556         }
3557 
3558         if (sensor_status != ENVMON_SENSOR_OK) {
3559                 return (ENXIO);
3560         }
3561 
3562         return (0);
3563 }