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.
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.
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]
23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
28 * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
32 * Copyright (c) 2018, Joyent, Inc.
36 * Facility node support for SES enclosures. We support the following facility
37 * nodes, based on the node type:
64 * sensor=<name> (temperature)
65 * sensor=<name> (voltage)
66 * sensor=<name> (current)
68 * Most of these are handled by a single method that supports getting and
69 * setting boolean properties on the node. The fan speed sensor requires a
70 * special handler, while the analog enclosure sensors all have similar
71 * behavior and can be grouped together using a common method.
79 static int ses_indicator_mode(topo_mod_t
*, tnode_t
*, topo_version_t
,
80 nvlist_t
*, nvlist_t
**);
81 static int ses_sensor_reading(topo_mod_t
*, tnode_t
*, topo_version_t
,
82 nvlist_t
*, nvlist_t
**);
83 static int ses_sensor_state(topo_mod_t
*, tnode_t
*, topo_version_t
,
84 nvlist_t
*, nvlist_t
**);
85 static int ses_psu_state(topo_mod_t
*, tnode_t
*, topo_version_t
,
86 nvlist_t
*, nvlist_t
**);
88 #define SES_SUPP_WARN_UNDER 0x01
89 #define SES_SUPP_WARN_OVER 0x02
90 #define SES_SUPP_CRIT_UNDER 0x04
91 #define SES_SUPP_CRIT_OVER 0x08
93 typedef struct ses_sensor_desc
{
96 const char *sd_propname
;
100 #define TOPO_METH_SES_MODE_VERSION 0
101 #define TOPO_METH_SES_READING_VERSION 0
102 #define TOPO_METH_SES_STATE_VERSION 0
103 #define TOPO_METH_SES_PSU_VERSION 0
105 #define TOPO_METH_SES_READING_PROP "propname"
106 #define TOPO_METH_SES_READING_MULT "multiplier"
108 #define TOPO_METH_SES_STATE_PROP "propname"
110 #define TOPO_METH_SES_MODE_PROP "property-name"
111 #define TOPO_METH_SES_MODE_ALTPROP "alternate-property"
113 static const topo_method_t ses_indicator_methods
[] = {
114 { "ses_indicator_mode", TOPO_PROP_METH_DESC
,
115 TOPO_METH_SES_MODE_VERSION
, TOPO_STABILITY_INTERNAL
,
119 static const topo_method_t ses_sensor_methods
[] = {
120 { "ses_sensor_reading", TOPO_PROP_METH_DESC
,
121 TOPO_METH_SES_READING_VERSION
, TOPO_STABILITY_INTERNAL
,
122 ses_sensor_reading
},
123 { "ses_sensor_state", TOPO_PROP_METH_DESC
,
124 TOPO_METH_SES_STATE_VERSION
, TOPO_STABILITY_INTERNAL
,
126 { "ses_psu_state", TOPO_PROP_METH_DESC
,
127 TOPO_METH_SES_PSU_VERSION
, TOPO_STABILITY_INTERNAL
,
132 * Get or set an indicator. This method is invoked with arguments indicating
133 * the property to query to retrieve the value. Some elements (enclosures and
134 * devices) support a request property that is distinct from an array-detected
135 * property. Either of these conditions will result in the indicator being
136 * lit, so we have to check both properties.
139 ses_indicator_mode(topo_mod_t
*mod
, tnode_t
*tn
, topo_version_t vers
,
140 nvlist_t
*in
, nvlist_t
**out
)
143 nvlist_t
*args
, *pargs
, *props
;
144 char *propname
, *altprop
;
146 boolean_t current
, altcurrent
;
148 ses_enum_target_t
*tp
= topo_node_getspecific(tn
);
150 if (vers
> TOPO_METH_SES_MODE_VERSION
)
151 return (topo_mod_seterrno(mod
, ETOPO_METHOD_VERNEW
));
153 if (nvlist_lookup_nvlist(in
, TOPO_PROP_ARGS
, &args
) != 0 ||
154 nvlist_lookup_string(args
, TOPO_METH_SES_MODE_PROP
,
156 topo_mod_dprintf(mod
, "invalid arguments to 'mode' method\n");
157 return (topo_mod_seterrno(mod
, EMOD_NVL_INVAL
));
160 if (nvlist_lookup_string(args
, TOPO_METH_SES_MODE_ALTPROP
,
164 if ((np
= ses_node_lock(mod
, tn
)) == NULL
) {
165 topo_mod_dprintf(mod
, "failed to lookup ses node in 'mode' "
169 verify((props
= ses_node_props(np
)) != NULL
);
171 if (nvlist_lookup_nvlist(in
, TOPO_PROP_PARGS
, &pargs
) == 0 &&
172 nvlist_exists(pargs
, TOPO_PROP_VAL_VAL
)) {
174 if (nvlist_lookup_uint32(pargs
, TOPO_PROP_VAL_VAL
,
176 topo_mod_dprintf(mod
, "invalid type for indicator "
178 (void) topo_mod_seterrno(mod
, EMOD_NVL_INVAL
);
182 if (mode
!= TOPO_LED_STATE_OFF
&& mode
!= TOPO_LED_STATE_ON
) {
183 topo_mod_dprintf(mod
, "invalid indicator mode %d\n",
185 (void) topo_mod_seterrno(mod
, EMOD_NVL_INVAL
);
190 if (topo_mod_nvalloc(mod
, &nvl
, NV_UNIQUE_NAME
) != 0 ||
191 nvlist_add_boolean_value(nvl
, propname
,
192 mode
== TOPO_LED_STATE_ON
? B_TRUE
: B_FALSE
) != 0) {
194 (void) topo_mod_seterrno(mod
, EMOD_NOMEM
);
198 if (ses_node_ctl(np
, SES_CTL_OP_SETPROP
, nvl
) != 0) {
199 topo_mod_dprintf(mod
, "failed to set indicator: %s\n",
205 tp
->set_snaptime
= 0;
209 if (nvlist_lookup_boolean_value(props
,
210 propname
, ¤t
) != 0) {
211 topo_mod_dprintf(mod
, "failed to lookup %s in node "
212 "properties\n", propname
);
213 (void) topo_mod_seterrno(mod
, EMOD_METHOD_NOTSUP
);
217 if (altprop
!= NULL
&& nvlist_lookup_boolean_value(props
,
218 altprop
, &altcurrent
) == 0)
219 current
|= altcurrent
;
221 mode
= current
? TOPO_LED_STATE_ON
: TOPO_LED_STATE_OFF
;
225 if (topo_mod_nvalloc(mod
, &nvl
, NV_UNIQUE_NAME
) != 0 ||
226 nvlist_add_string(nvl
, TOPO_PROP_VAL_NAME
,
227 TOPO_LED_MODE
) != 0 ||
228 nvlist_add_uint32(nvl
, TOPO_PROP_VAL_TYPE
, TOPO_TYPE_UINT32
) != 0 ||
229 nvlist_add_uint32(nvl
, TOPO_PROP_VAL_VAL
, mode
) != 0) {
231 (void) topo_mod_seterrno(mod
, EMOD_NOMEM
);
235 ses_node_unlock(mod
, tn
);
240 ses_node_unlock(mod
, tn
);
245 * Read the given sensor value. This just looks up the value in the node
246 * properties, and multiplies by a fixed value (determined when the method is
250 ses_sensor_reading(topo_mod_t
*mod
, tnode_t
*tn
, topo_version_t vers
,
251 nvlist_t
*in
, nvlist_t
**out
)
254 nvlist_t
*args
, *props
;
256 double raw
, multiplier
;
261 if (vers
> TOPO_METH_SES_MODE_VERSION
)
262 return (topo_mod_seterrno(mod
, ETOPO_METHOD_VERNEW
));
264 if (nvlist_lookup_nvlist(in
, TOPO_PROP_ARGS
, &args
) != 0 ||
265 nvlist_lookup_string(args
, TOPO_METH_SES_READING_PROP
,
267 topo_mod_dprintf(mod
,
268 "invalid arguments to 'reading' method\n");
269 return (topo_mod_seterrno(mod
, EMOD_NVL_INVAL
));
272 if (nvlist_lookup_double(args
, TOPO_METH_SES_READING_MULT
,
276 if ((np
= ses_node_lock(mod
, tn
)) == NULL
) {
277 topo_mod_dprintf(mod
, "failed to lookup ses node in 'mode' "
281 verify((props
= ses_node_props(np
)) != NULL
);
283 if (nvlist_lookup_uint64(props
, prop
, ¤t
) == 0) {
284 raw
= (double)current
;
285 } else if (nvlist_lookup_int64(props
, prop
, &scurrent
) == 0) {
286 raw
= (double)scurrent
;
288 topo_mod_dprintf(mod
, "failed to lookup %s in node "
289 "properties\n", prop
);
290 ses_node_unlock(mod
, tn
);
291 return (topo_mod_seterrno(mod
, EMOD_METHOD_NOTSUP
));
294 ses_node_unlock(mod
, tn
);
297 if (topo_mod_nvalloc(mod
, &nvl
, NV_UNIQUE_NAME
) != 0 ||
298 nvlist_add_string(nvl
, TOPO_PROP_VAL_NAME
,
299 TOPO_SENSOR_READING
) != 0 ||
300 nvlist_add_uint32(nvl
, TOPO_PROP_VAL_TYPE
, TOPO_TYPE_DOUBLE
) != 0 ||
301 nvlist_add_double(nvl
, TOPO_PROP_VAL_VAL
, raw
* multiplier
) != 0) {
303 return (topo_mod_seterrno(mod
, EMOD_NOMEM
));
311 * Returns the current sensor state. This can be invoked for one of two
312 * different types of sensors: threshold or discrete sensors. For discrete
313 * sensors, we expect a name of a boolean property and indicate
314 * asserted/deasserted based on that. For threshold sensors, we check for the
315 * standard warning/critical properties and translate that into the appropriate
320 ses_sensor_state(topo_mod_t
*mod
, tnode_t
*tn
, topo_version_t vers
,
321 nvlist_t
*in
, nvlist_t
**out
)
323 nvlist_t
*nvl
, *args
, *props
;
330 if (nvlist_lookup_nvlist(in
, TOPO_PROP_ARGS
, &args
) != 0) {
331 topo_mod_dprintf(mod
,
332 "invalid arguments to 'state' method\n");
333 return (topo_mod_seterrno(mod
, EMOD_NVL_INVAL
));
336 if ((np
= ses_node_lock(mod
, tn
)) == NULL
) {
337 topo_mod_dprintf(mod
, "failed to lookup ses node in 'mode' "
341 verify((props
= ses_node_props(np
)) != NULL
);
343 if (nvlist_lookup_uint64(props
, SES_PROP_STATUS_CODE
, &status
) != 0)
344 status
= SES_ESC_UNSUPPORTED
;
347 if (nvlist_lookup_string(args
, TOPO_METH_SES_STATE_PROP
,
349 /* discrete (fault) sensor */
351 if (status
== SES_ESC_UNRECOVERABLE
)
352 state
|= TOPO_SENSOR_STATE_GENERIC_FAIL_NONRECOV
;
353 else if (status
== SES_ESC_CRITICAL
)
354 state
|= TOPO_SENSOR_STATE_GENERIC_FAIL_CRITICAL
;
355 else if (nvlist_lookup_boolean_value(props
, prop
,
356 &value
) == 0 && value
)
357 state
|= TOPO_SENSOR_STATE_GENERIC_FAIL_NONRECOV
;
359 state
|= TOPO_SENSOR_STATE_GENERIC_FAIL_DEASSERTED
;
361 /* threshold sensor */
362 if (nvlist_lookup_boolean_value(props
,
363 SES_PROP_WARN_UNDER
, &value
) == 0 && value
)
364 state
|= TOPO_SENSOR_STATE_THRESH_LOWER_NONCRIT
;
365 if (nvlist_lookup_boolean_value(props
,
366 SES_PROP_WARN_OVER
, &value
) == 0 && value
)
367 state
|= TOPO_SENSOR_STATE_THRESH_UPPER_NONCRIT
;
368 if (nvlist_lookup_boolean_value(props
,
369 SES_PROP_CRIT_UNDER
, &value
) == 0 && value
)
370 state
|= TOPO_SENSOR_STATE_THRESH_LOWER_CRIT
;
371 if (nvlist_lookup_boolean_value(props
,
372 SES_PROP_CRIT_OVER
, &value
) == 0 && value
)
373 state
|= TOPO_SENSOR_STATE_THRESH_UPPER_CRIT
;
376 ses_node_unlock(mod
, tn
);
379 if (topo_mod_nvalloc(mod
, &nvl
, NV_UNIQUE_NAME
) != 0 ||
380 nvlist_add_string(nvl
, TOPO_PROP_VAL_NAME
,
381 TOPO_SENSOR_STATE
) != 0 ||
382 nvlist_add_uint32(nvl
, TOPO_PROP_VAL_TYPE
, TOPO_TYPE_UINT32
) != 0 ||
383 nvlist_add_uint32(nvl
, TOPO_PROP_VAL_VAL
, state
) != 0) {
385 return (topo_mod_seterrno(mod
, EMOD_NOMEM
));
393 * Read the status of a PSU. This is such a specialized operation that it has
394 * its own method instead of trying to piggyback on ses_sensor_state(). We
395 * use the following mapping to get to the standard topo power supply states:
397 * acfail -> INPUT_LOST
398 * dcfail -> INPUT_LOST
399 * undervoltage -> INPUT_RANGE
400 * overvoltage -> INPUT_RANGE_PRES
401 * overcurrent -> INPUT_RANGE_PRES
404 * If we ever have a need for reading overtemp, we can expand the topo
405 * representation for power supplies, but at the moment this seems unnecessary.
409 ses_psu_state(topo_mod_t
*mod
, tnode_t
*tn
, topo_version_t vers
,
410 nvlist_t
*in
, nvlist_t
**out
)
412 nvlist_t
*nvl
, *props
;
417 if ((np
= ses_node_lock(mod
, tn
)) == NULL
) {
418 topo_mod_dprintf(mod
, "failed to lookup ses node in 'mode' "
422 verify((props
= ses_node_props(np
)) != NULL
);
425 if ((nvlist_lookup_boolean_value(props
, SES_PSU_PROP_DC_FAIL
,
426 &value
) == 0 && value
) ||
427 (nvlist_lookup_boolean_value(props
, SES_PSU_PROP_AC_FAIL
,
428 &value
) == 0 && value
))
429 state
|= TOPO_SENSOR_STATE_POWER_SUPPLY_INPUT_LOST
;
431 if (nvlist_lookup_boolean_value(props
, SES_PSU_PROP_DC_UNDER_VOLTAGE
,
432 &value
) == 0 && value
)
433 state
|= TOPO_SENSOR_STATE_POWER_SUPPLY_INPUT_RANGE
;
435 if ((nvlist_lookup_boolean_value(props
, SES_PSU_PROP_DC_OVER_VOLTAGE
,
436 &value
) == 0 && value
) ||
437 (nvlist_lookup_boolean_value(props
, SES_PSU_PROP_DC_OVER_CURRENT
,
438 &value
) == 0 && value
))
439 state
|= TOPO_SENSOR_STATE_POWER_SUPPLY_INPUT_RANGE_PRES
;
441 ses_node_unlock(mod
, tn
);
444 if (topo_mod_nvalloc(mod
, &nvl
, NV_UNIQUE_NAME
) != 0 ||
445 nvlist_add_string(nvl
, TOPO_PROP_VAL_NAME
,
446 TOPO_SENSOR_STATE
) != 0 ||
447 nvlist_add_uint32(nvl
, TOPO_PROP_VAL_TYPE
, TOPO_TYPE_UINT32
) != 0 ||
448 nvlist_add_uint32(nvl
, TOPO_PROP_VAL_VAL
, state
) != 0) {
450 return (topo_mod_seterrno(mod
, EMOD_NOMEM
));
458 * Create a facility node, either a sensor or an indicator.
461 ses_add_fac_common(topo_mod_t
*mod
, tnode_t
*pnode
, const char *name
,
462 const char *type
, uint64_t nodeid
)
465 topo_pgroup_info_t pgi
;
467 ses_enum_target_t
*stp
= topo_node_getspecific(pnode
);
469 if ((tn
= topo_node_facbind(mod
, pnode
, name
, type
)) == NULL
) {
470 topo_mod_dprintf(mod
, "failed to bind facility node %s\n",
476 topo_node_setspecific(tn
, stp
);
478 pgi
.tpi_name
= TOPO_PGROUP_FACILITY
;
479 pgi
.tpi_namestab
= TOPO_STABILITY_PRIVATE
;
480 pgi
.tpi_datastab
= TOPO_STABILITY_PRIVATE
;
483 if (topo_pgroup_create(tn
, &pgi
, &err
) != 0) {
484 topo_mod_dprintf(mod
, "failed to create facility property "
485 "group: %s\n", topo_strerror(err
));
486 topo_node_unbind(tn
);
491 * We need the node-id property for each facility node.
493 pgi
.tpi_name
= TOPO_PGROUP_SES
;
494 pgi
.tpi_namestab
= TOPO_STABILITY_PRIVATE
;
495 pgi
.tpi_datastab
= TOPO_STABILITY_PRIVATE
;
496 pgi
.tpi_version
= TOPO_VERSION
;
498 if (topo_pgroup_create(tn
, &pgi
, &err
) != 0) {
499 topo_mod_dprintf(mod
, "failed to create ses property "
500 "group: %s\n", topo_strerror(err
));
501 topo_node_unbind(tn
);
505 if (topo_prop_set_uint64(tn
, TOPO_PGROUP_SES
,
506 TOPO_PROP_NODE_ID
, TOPO_PROP_IMMUTABLE
,
507 nodeid
, &err
) != 0) {
508 topo_mod_dprintf(mod
,
509 "failed to create property %s: %s\n",
510 TOPO_PROP_NODE_ID
, topo_strerror(err
));
511 topo_node_unbind(tn
);
519 * Add an indicator. This can be represented by a single property, or by the
520 * union of two elements when SES is capable of distinguishing between
521 * requested failure and detected failure.
524 ses_add_indicator(topo_mod_t
*mod
, tnode_t
*pnode
, uint64_t nodeid
,
525 int type
, const char *name
, const char *propname
, const char *altprop
)
531 /* create facility node and add methods */
532 if ((tn
= ses_add_fac_common(mod
, pnode
, name
,
533 TOPO_FAC_TYPE_INDICATOR
, nodeid
)) == NULL
)
536 if (topo_method_register(mod
, tn
, ses_indicator_methods
) < 0) {
537 topo_mod_dprintf(mod
, "failed to register facility methods\n");
538 topo_node_unbind(tn
);
542 /* set standard properties */
543 if (topo_prop_set_uint32(tn
, TOPO_PGROUP_FACILITY
,
544 TOPO_FACILITY_TYPE
, TOPO_PROP_IMMUTABLE
, type
, &err
) != 0) {
545 topo_mod_dprintf(mod
,
546 "failed to set facility node properties: %s\n",
548 topo_node_unbind(tn
);
552 /* 'mode' property */
554 if (topo_mod_nvalloc(mod
, &nvl
, NV_UNIQUE_NAME
) != 0 ||
555 nvlist_add_string(nvl
, TOPO_METH_SES_MODE_PROP
,
557 (altprop
!= NULL
&& nvlist_add_string(nvl
,
558 TOPO_METH_SES_MODE_ALTPROP
, altprop
) != 0)) {
560 topo_mod_dprintf(mod
, "failed to setup method arguments\n");
561 topo_node_unbind(tn
);
562 return (topo_mod_seterrno(mod
, EMOD_NOMEM
));
565 if (topo_prop_method_register(tn
, TOPO_PGROUP_FACILITY
,
566 TOPO_LED_MODE
, TOPO_TYPE_UINT32
, "ses_indicator_mode",
569 topo_mod_dprintf(mod
, "failed to register reading method: %s\n",
574 if (topo_prop_setmutable(tn
, TOPO_PGROUP_FACILITY
,
575 TOPO_LED_MODE
, &err
) != 0) {
577 topo_mod_dprintf(mod
, "failed to set property as mutable: %s\n",
587 ses_add_sensor_common(topo_mod_t
*mod
, tnode_t
*pnode
, uint64_t nodeid
,
588 const char *name
, const char *class, int type
)
593 /* create facility node and add methods */
594 if ((tn
= ses_add_fac_common(mod
, pnode
, name
,
595 TOPO_FAC_TYPE_SENSOR
, nodeid
)) == NULL
)
598 if (topo_method_register(mod
, tn
, ses_sensor_methods
) < 0) {
599 topo_mod_dprintf(mod
, "failed to register facility methods\n");
600 topo_node_unbind(tn
);
604 /* set standard properties */
605 if (topo_prop_set_string(tn
, TOPO_PGROUP_FACILITY
,
606 TOPO_SENSOR_CLASS
, TOPO_PROP_IMMUTABLE
,
608 topo_prop_set_uint32(tn
, TOPO_PGROUP_FACILITY
,
609 TOPO_FACILITY_TYPE
, TOPO_PROP_IMMUTABLE
,
611 topo_mod_dprintf(mod
,
612 "failed to set facility node properties: %s\n",
614 topo_node_unbind(tn
);
622 * Add an analog (threshold) sensor to the enclosure. This is used for fan
623 * speed, voltage, current, and temperature sensors.
626 ses_add_sensor(topo_mod_t
*mod
, tnode_t
*pnode
, uint64_t nodeid
,
627 const char *name
, const ses_sensor_desc_t
*sdp
)
633 if ((tn
= ses_add_sensor_common(mod
, pnode
, nodeid
, name
,
634 TOPO_SENSOR_CLASS_THRESHOLD
, sdp
->sd_type
)) == NULL
)
637 if (topo_prop_set_uint32(tn
, TOPO_PGROUP_FACILITY
,
638 TOPO_SENSOR_UNITS
, TOPO_PROP_IMMUTABLE
, sdp
->sd_units
, &err
) != 0) {
639 topo_mod_dprintf(mod
,
640 "failed to set facility node properties: %s\n",
642 topo_node_unbind(tn
);
646 /* 'reading' property */
648 if (topo_mod_nvalloc(mod
, &nvl
, NV_UNIQUE_NAME
) != 0 ||
649 nvlist_add_string(nvl
, TOPO_METH_SES_READING_PROP
,
650 sdp
->sd_propname
) != 0 ||
651 (sdp
->sd_multiplier
!= 0 &&
652 nvlist_add_double(nvl
, TOPO_METH_SES_READING_MULT
,
653 sdp
->sd_multiplier
) != 0)) {
655 topo_mod_dprintf(mod
, "failed to setup method arguments\n");
656 topo_node_unbind(tn
);
660 if (topo_prop_method_register(tn
, TOPO_PGROUP_FACILITY
,
661 TOPO_SENSOR_READING
, TOPO_TYPE_DOUBLE
, "ses_sensor_reading",
664 topo_mod_dprintf(mod
, "failed to register reading method: %s\n",
670 if (topo_mod_nvalloc(mod
, &nvl
, NV_UNIQUE_NAME
) != 0) {
671 topo_mod_dprintf(mod
, "failed to setup method arguments\n");
672 topo_node_unbind(tn
);
676 /* 'state' property */
677 if (topo_prop_method_register(tn
, TOPO_PGROUP_FACILITY
,
678 TOPO_SENSOR_STATE
, TOPO_TYPE_UINT32
, "ses_sensor_state",
681 topo_mod_dprintf(mod
, "failed to register state method: %s\n",
691 * Add a discrete sensor for simple boolean values. This is used to indicate
692 * externally-detected failures for fans, bays, and enclosures.
695 ses_add_discrete(topo_mod_t
*mod
, tnode_t
*pnode
, uint64_t nodeid
,
696 const char *name
, const char *prop
)
702 if ((tn
= ses_add_sensor_common(mod
, pnode
, nodeid
, name
,
703 TOPO_SENSOR_CLASS_DISCRETE
,
704 TOPO_SENSOR_TYPE_GENERIC_FAILURE
)) == NULL
)
708 if (topo_mod_nvalloc(mod
, &nvl
, NV_UNIQUE_NAME
) != 0 ||
709 nvlist_add_string(nvl
, TOPO_METH_SES_STATE_PROP
, prop
) != 0) {
711 topo_mod_dprintf(mod
, "failed to setup method arguments\n");
712 topo_node_unbind(tn
);
716 /* 'state' property */
717 if (topo_prop_method_register(tn
, TOPO_PGROUP_FACILITY
,
718 TOPO_SENSOR_STATE
, TOPO_TYPE_UINT32
, "ses_sensor_state",
721 topo_mod_dprintf(mod
, "failed to register state method: %s\n",
732 ses_add_psu_status(topo_mod_t
*mod
, tnode_t
*pnode
, uint64_t nodeid
)
738 /* create facility node and add methods */
739 if ((tn
= ses_add_sensor_common(mod
, pnode
, nodeid
, "status",
740 TOPO_SENSOR_CLASS_DISCRETE
,
741 TOPO_SENSOR_TYPE_POWER_SUPPLY
)) == NULL
)
744 if (topo_mod_nvalloc(mod
, &nvl
, NV_UNIQUE_NAME
) != 0) {
746 topo_mod_dprintf(mod
, "failed to setup method arguments\n");
747 topo_node_unbind(tn
);
751 /* 'state' property */
752 if (topo_prop_method_register(tn
, TOPO_PGROUP_FACILITY
,
753 TOPO_SENSOR_STATE
, TOPO_TYPE_UINT32
, "ses_psu_state",
756 topo_mod_dprintf(mod
, "failed to register state method: %s\n",
767 ses_node_enum_facility(topo_mod_t
*mod
, tnode_t
*tn
, topo_version_t vers
,
768 nvlist_t
*in
, nvlist_t
**out
)
772 uint64_t type
, nodeid
;
773 ses_sensor_desc_t sd
= { 0 };
775 if ((np
= ses_node_lock(mod
, tn
)) == NULL
)
778 assert(ses_node_type(np
) == SES_NODE_ELEMENT
);
779 nodeid
= ses_node_id(np
);
780 verify((props
= ses_node_props(np
)) != NULL
);
781 verify(nvlist_lookup_uint64(props
, SES_PROP_ELEMENT_TYPE
, &type
) == 0);
783 if (type
!= SES_ET_DEVICE
&& type
!= SES_ET_ARRAY_DEVICE
&&
784 type
!= SES_ET_COOLING
&& type
!= SES_ET_POWER_SUPPLY
) {
785 ses_node_unlock(mod
, tn
);
790 * Every element supports an 'ident' indicator. All elements also
791 * support a 'fail' indicator, but the properties used to represent
792 * this condition differs between elements.
794 if (ses_add_indicator(mod
, tn
, nodeid
, TOPO_LED_TYPE_LOCATE
, "ident",
795 SES_PROP_IDENT
, NULL
) != 0)
800 case SES_ET_ARRAY_DEVICE
:
802 * Disks support an additional 'ok2rm' indicator, as well as
803 * externally detected 'fail' sensor.
805 if (ses_add_indicator(mod
, tn
, nodeid
, TOPO_LED_TYPE_SERVICE
,
806 "fail", SES_DEV_PROP_FAULT_RQSTD
,
807 SES_DEV_PROP_FAULT_SENSED
) != 0 ||
808 ses_add_indicator(mod
, tn
, nodeid
, TOPO_LED_TYPE_OK2RM
,
809 "ok2rm", SES_PROP_RMV
, SES_PROP_RMV
) != 0 ||
810 ses_add_discrete(mod
, tn
, nodeid
, "fault",
811 SES_DEV_PROP_FAULT_SENSED
) != 0)
817 * Add the fan speed sensor, and a discrete sensor for
820 sd
.sd_type
= TOPO_SENSOR_TYPE_THRESHOLD_STATE
;
821 sd
.sd_units
= TOPO_SENSOR_UNITS_RPM
;
822 sd
.sd_propname
= SES_COOLING_PROP_FAN_SPEED
;
823 if (ses_add_indicator(mod
, tn
, nodeid
, TOPO_LED_TYPE_SERVICE
,
824 "fail", SES_PROP_FAIL
, NULL
) != 0 ||
825 ses_add_sensor(mod
, tn
, nodeid
, "speed", &sd
) != 0 ||
826 ses_add_discrete(mod
, tn
, nodeid
, "fault",
831 case SES_ET_POWER_SUPPLY
:
833 * For power supplies, we have a number of different sensors:
834 * acfail, dcfail, overtemp, undervoltate, overvoltage,
835 * and overcurrent. Rather than expose these all as individual
836 * sensors, we lump them together into a 'status' sensor of
837 * type TOPO_SENSOR_TYPE_POWER_SUPPLY and export the
838 * appropriate status flags as defined by the libtopo standard.
840 if (ses_add_indicator(mod
, tn
, nodeid
, TOPO_LED_TYPE_SERVICE
,
841 "fail", SES_PROP_FAIL
, NULL
) != 0)
844 if (ses_add_psu_status(mod
, tn
, nodeid
) != 0)
852 ses_node_unlock(mod
, tn
);
856 ses_node_unlock(mod
, tn
);
861 * Add enclosure-wide sensors (temperature, voltage, and current) beneath the
865 ses_add_enclosure_sensors(topo_mod_t
*mod
, tnode_t
*tn
, ses_node_t
*agg
,
869 const char *defaultname
;
872 nvlist_t
*props
, *aprops
;
873 uint64_t index
, nodeid
;
874 ses_sensor_desc_t sd
= { 0 };
878 case SES_ET_TEMPERATURE_SENSOR
:
879 sd
.sd_type
= TOPO_SENSOR_TYPE_TEMP
;
880 sd
.sd_units
= TOPO_SENSOR_UNITS_DEGREES_C
;
881 sd
.sd_propname
= SES_TEMP_PROP_TEMP
;
882 defaultname
= "temperature";
885 case SES_ET_VOLTAGE_SENSOR
:
886 sd
.sd_type
= TOPO_SENSOR_TYPE_VOLTAGE
;
887 sd
.sd_units
= TOPO_SENSOR_UNITS_VOLTS
;
888 sd
.sd_propname
= SES_VS_PROP_VOLTAGE_MV
;
889 sd
.sd_multiplier
= 0.001;
890 defaultname
= "voltage";
893 case SES_ET_CURRENT_SENSOR
:
894 sd
.sd_type
= TOPO_SENSOR_TYPE_CURRENT
;
895 sd
.sd_units
= TOPO_SENSOR_UNITS_AMPS
;
896 sd
.sd_propname
= SES_CS_PROP_CURRENT_MA
;
897 sd
.sd_multiplier
= 0.001;
898 defaultname
= "current";
905 aprops
= ses_node_props(agg
);
907 for (child
= ses_node_child(agg
); child
!= NULL
;
908 child
= ses_node_sibling(child
)) {
910 * The only tricky part here is getting the name for the
911 * sensor, where we follow the algorithm of the standard
914 props
= ses_node_props(child
);
915 nodeid
= ses_node_id(child
);
916 if (nvlist_lookup_uint64(props
, SES_PROP_ELEMENT_CLASS_INDEX
,
920 if (nvlist_lookup_string(props
, SES_PROP_DESCRIPTION
,
921 &desc
) == 0 && desc
[0] != '\0') {
922 (void) strlcpy(rawname
, desc
, sizeof (rawname
));
924 if (nvlist_lookup_string(aprops
,
925 SES_PROP_CLASS_DESCRIPTION
, &desc
) != 0 ||
927 desc
= (char *)defaultname
;
930 while (len
> 0 && desc
[len
- 1] == ' ')
933 (void) snprintf(rawname
, sizeof (rawname
),
934 "%.*s %llu", len
, desc
, index
);
937 if ((name
= topo_mod_clean_str(mod
, rawname
)) == NULL
)
940 if (ses_add_sensor(mod
, tn
, nodeid
, name
, &sd
) != 0) {
941 topo_mod_strfree(mod
, name
);
945 topo_mod_strfree(mod
, name
);
953 ses_enc_enum_facility(topo_mod_t
*mod
, tnode_t
*tn
, topo_version_t vers
,
954 nvlist_t
*in
, nvlist_t
**out
)
956 ses_node_t
*np
, *agg
;
958 uint64_t type
, nodeid
;
960 if ((np
= ses_node_lock(mod
, tn
)) == NULL
)
963 assert(ses_node_type(np
) == SES_NODE_ENCLOSURE
);
964 nodeid
= ses_node_id(np
);
967 * 'ident' and 'fail' LEDs, and 'fault' sensor.
969 if (ses_add_indicator(mod
, tn
, nodeid
, TOPO_LED_TYPE_LOCATE
, "ident",
970 SES_PROP_IDENT
, NULL
) != 0 ||
971 ses_add_indicator(mod
, tn
, nodeid
, TOPO_LED_TYPE_SERVICE
, "fail",
972 SES_PROP_FAIL_REQ
, SES_PROP_FAIL
) != 0 ||
973 ses_add_discrete(mod
, tn
, nodeid
, "fault", SES_PROP_FAIL
) != 0)
977 * Environmental sensors (temperature, voltage, current). We have no
978 * way of knowing if any of these sensors correspond to a particular
979 * element, so we just attach them to the enclosure as a whole. In the
980 * future, some vendor-specific libses plugin knowledge could let us
981 * make this correlation clearer.
983 for (agg
= ses_node_child(np
); agg
!= NULL
;
984 agg
= ses_node_sibling(agg
)) {
985 if (ses_node_type(agg
) != SES_NODE_AGGREGATE
)
988 verify((aprops
= ses_node_props(agg
)) != NULL
);
989 if (nvlist_lookup_uint64(aprops
, SES_PROP_ELEMENT_TYPE
,
993 if (ses_add_enclosure_sensors(mod
, tn
, agg
, type
) != 0)
997 ses_node_unlock(mod
, tn
);
1001 ses_node_unlock(mod
, tn
);