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