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 * Facility node support for SES enclosures. We support the following facility
33 * nodes, based on the node type:
60 * sensor=<name> (temperature)
61 * sensor=<name> (voltage)
62 * sensor=<name> (current)
64 * Most of these are handled by a single method that supports getting and
65 * setting boolean properties on the node. The fan speed sensor requires a
66 * special handler, while the analog enclosure sensors all have similar
67 * behavior and can be grouped together using a common method.
75 static int ses_indicator_mode(topo_mod_t
*, tnode_t
*, topo_version_t
,
76 nvlist_t
*, nvlist_t
**);
77 static int ses_sensor_reading(topo_mod_t
*, tnode_t
*, topo_version_t
,
78 nvlist_t
*, nvlist_t
**);
79 static int ses_sensor_state(topo_mod_t
*, tnode_t
*, topo_version_t
,
80 nvlist_t
*, nvlist_t
**);
81 static int ses_psu_state(topo_mod_t
*, tnode_t
*, topo_version_t
,
82 nvlist_t
*, nvlist_t
**);
84 #define SES_SUPP_WARN_UNDER 0x01
85 #define SES_SUPP_WARN_OVER 0x02
86 #define SES_SUPP_CRIT_UNDER 0x04
87 #define SES_SUPP_CRIT_OVER 0x08
89 typedef struct ses_sensor_desc
{
92 const char *sd_propname
;
96 #define TOPO_METH_SES_MODE_VERSION 0
97 #define TOPO_METH_SES_READING_VERSION 0
98 #define TOPO_METH_SES_STATE_VERSION 0
99 #define TOPO_METH_SES_PSU_VERSION 0
101 #define TOPO_METH_SES_READING_PROP "propname"
102 #define TOPO_METH_SES_READING_MULT "multiplier"
104 #define TOPO_METH_SES_STATE_PROP "propname"
106 #define TOPO_METH_SES_MODE_PROP "property-name"
107 #define TOPO_METH_SES_MODE_ALTPROP "alternate-property"
109 static const topo_method_t ses_indicator_methods
[] = {
110 { "ses_indicator_mode", TOPO_PROP_METH_DESC
,
111 TOPO_METH_SES_MODE_VERSION
, TOPO_STABILITY_INTERNAL
,
115 static const topo_method_t ses_sensor_methods
[] = {
116 { "ses_sensor_reading", TOPO_PROP_METH_DESC
,
117 TOPO_METH_SES_READING_VERSION
, TOPO_STABILITY_INTERNAL
,
118 ses_sensor_reading
},
119 { "ses_sensor_state", TOPO_PROP_METH_DESC
,
120 TOPO_METH_SES_STATE_VERSION
, TOPO_STABILITY_INTERNAL
,
122 { "ses_psu_state", TOPO_PROP_METH_DESC
,
123 TOPO_METH_SES_PSU_VERSION
, TOPO_STABILITY_INTERNAL
,
128 * Get or set an indicator. This method is invoked with arguments indicating
129 * the property to query to retrieve the value. Some elements (enclosures and
130 * devices) support a request property that is distinct from an array-detected
131 * property. Either of these conditions will result in the indicator being
132 * lit, so we have to check both properties.
135 ses_indicator_mode(topo_mod_t
*mod
, tnode_t
*tn
, topo_version_t vers
,
136 nvlist_t
*in
, nvlist_t
**out
)
139 nvlist_t
*args
, *pargs
, *props
;
140 char *propname
, *altprop
;
142 boolean_t current
, altcurrent
;
144 ses_enum_target_t
*tp
= topo_node_getspecific(tn
);
146 if (vers
> TOPO_METH_SES_MODE_VERSION
)
147 return (topo_mod_seterrno(mod
, ETOPO_METHOD_VERNEW
));
149 if (nvlist_lookup_nvlist(in
, TOPO_PROP_ARGS
, &args
) != 0 ||
150 nvlist_lookup_string(args
, TOPO_METH_SES_MODE_PROP
,
152 topo_mod_dprintf(mod
, "invalid arguments to 'mode' method\n");
153 return (topo_mod_seterrno(mod
, EMOD_NVL_INVAL
));
156 if (nvlist_lookup_string(args
, TOPO_METH_SES_MODE_ALTPROP
,
160 if ((np
= ses_node_lock(mod
, tn
)) == NULL
) {
161 topo_mod_dprintf(mod
, "failed to lookup ses node in 'mode' "
165 verify((props
= ses_node_props(np
)) != NULL
);
167 if (nvlist_lookup_nvlist(in
, TOPO_PROP_PARGS
, &pargs
) == 0 &&
168 nvlist_exists(pargs
, TOPO_PROP_VAL_VAL
)) {
170 if (nvlist_lookup_uint32(pargs
, TOPO_PROP_VAL_VAL
,
172 topo_mod_dprintf(mod
, "invalid type for indicator "
174 (void) topo_mod_seterrno(mod
, EMOD_NVL_INVAL
);
178 if (mode
!= TOPO_LED_STATE_OFF
&& mode
!= TOPO_LED_STATE_ON
) {
179 topo_mod_dprintf(mod
, "invalid indicator mode %d\n",
181 (void) topo_mod_seterrno(mod
, EMOD_NVL_INVAL
);
186 if (topo_mod_nvalloc(mod
, &nvl
, NV_UNIQUE_NAME
) != 0 ||
187 nvlist_add_boolean_value(nvl
, propname
,
188 mode
== TOPO_LED_STATE_ON
? B_TRUE
: B_FALSE
) != 0) {
190 (void) topo_mod_seterrno(mod
, EMOD_NOMEM
);
194 if (ses_node_ctl(np
, SES_CTL_OP_SETPROP
, nvl
) != 0) {
195 topo_mod_dprintf(mod
, "failed to set indicator: %s\n",
201 tp
->set_snaptime
= 0;
205 if (nvlist_lookup_boolean_value(props
,
206 propname
, ¤t
) != 0) {
207 topo_mod_dprintf(mod
, "failed to lookup %s in node "
208 "properties\n", propname
);
209 (void) topo_mod_seterrno(mod
, EMOD_METHOD_NOTSUP
);
213 if (altprop
!= NULL
&& nvlist_lookup_boolean_value(props
,
214 altprop
, &altcurrent
) == 0)
215 current
|= altcurrent
;
217 mode
= current
? TOPO_LED_STATE_ON
: TOPO_LED_STATE_OFF
;
221 if (topo_mod_nvalloc(mod
, &nvl
, NV_UNIQUE_NAME
) != 0 ||
222 nvlist_add_string(nvl
, TOPO_PROP_VAL_NAME
,
223 TOPO_LED_MODE
) != 0 ||
224 nvlist_add_uint32(nvl
, TOPO_PROP_VAL_TYPE
, TOPO_TYPE_UINT32
) != 0 ||
225 nvlist_add_uint32(nvl
, TOPO_PROP_VAL_VAL
, mode
) != 0) {
227 (void) topo_mod_seterrno(mod
, EMOD_NOMEM
);
231 ses_node_unlock(mod
, tn
);
236 ses_node_unlock(mod
, tn
);
241 * Read the given sensor value. This just looks up the value in the node
242 * properties, and multiplies by a fixed value (determined when the method is
246 ses_sensor_reading(topo_mod_t
*mod
, tnode_t
*tn
, topo_version_t vers
,
247 nvlist_t
*in
, nvlist_t
**out
)
250 nvlist_t
*args
, *props
;
252 double raw
, multiplier
;
257 if (vers
> TOPO_METH_SES_MODE_VERSION
)
258 return (topo_mod_seterrno(mod
, ETOPO_METHOD_VERNEW
));
260 if (nvlist_lookup_nvlist(in
, TOPO_PROP_ARGS
, &args
) != 0 ||
261 nvlist_lookup_string(args
, TOPO_METH_SES_READING_PROP
,
263 topo_mod_dprintf(mod
,
264 "invalid arguments to 'reading' method\n");
265 return (topo_mod_seterrno(mod
, EMOD_NVL_INVAL
));
268 if (nvlist_lookup_double(args
, TOPO_METH_SES_READING_MULT
,
272 if ((np
= ses_node_lock(mod
, tn
)) == NULL
) {
273 topo_mod_dprintf(mod
, "failed to lookup ses node in 'mode' "
277 verify((props
= ses_node_props(np
)) != NULL
);
279 if (nvlist_lookup_uint64(props
, prop
, ¤t
) == 0) {
280 raw
= (double)current
;
281 } else if (nvlist_lookup_int64(props
, prop
, &scurrent
) == 0) {
282 raw
= (double)scurrent
;
284 topo_mod_dprintf(mod
, "failed to lookup %s in node "
285 "properties\n", prop
);
286 ses_node_unlock(mod
, tn
);
287 return (topo_mod_seterrno(mod
, EMOD_METHOD_NOTSUP
));
290 ses_node_unlock(mod
, tn
);
293 if (topo_mod_nvalloc(mod
, &nvl
, NV_UNIQUE_NAME
) != 0 ||
294 nvlist_add_string(nvl
, TOPO_PROP_VAL_NAME
,
295 TOPO_SENSOR_READING
) != 0 ||
296 nvlist_add_uint32(nvl
, TOPO_PROP_VAL_TYPE
, TOPO_TYPE_DOUBLE
) != 0 ||
297 nvlist_add_double(nvl
, TOPO_PROP_VAL_VAL
, raw
* multiplier
) != 0) {
299 return (topo_mod_seterrno(mod
, EMOD_NOMEM
));
307 * Returns the current sensor state. This can be invoked for one of two
308 * different types of sensors: threshold or discrete sensors. For discrete
309 * sensors, we expect a name of a boolean property and indicate
310 * asserted/deasserted based on that. For threshold sensors, we check for the
311 * standard warning/critical properties and translate that into the appropriate
316 ses_sensor_state(topo_mod_t
*mod
, tnode_t
*tn
, topo_version_t vers
,
317 nvlist_t
*in
, nvlist_t
**out
)
319 nvlist_t
*nvl
, *args
, *props
;
326 if (nvlist_lookup_nvlist(in
, TOPO_PROP_ARGS
, &args
) != 0) {
327 topo_mod_dprintf(mod
,
328 "invalid arguments to 'state' method\n");
329 return (topo_mod_seterrno(mod
, EMOD_NVL_INVAL
));
332 if ((np
= ses_node_lock(mod
, tn
)) == NULL
) {
333 topo_mod_dprintf(mod
, "failed to lookup ses node in 'mode' "
337 verify((props
= ses_node_props(np
)) != NULL
);
339 if (nvlist_lookup_uint64(props
, SES_PROP_STATUS_CODE
, &status
) != 0)
340 status
= SES_ESC_UNSUPPORTED
;
343 if (nvlist_lookup_string(args
, TOPO_METH_SES_STATE_PROP
,
345 /* discrete (fault) sensor */
347 if (status
== SES_ESC_UNRECOVERABLE
)
348 state
|= TOPO_SENSOR_STATE_GENERIC_FAIL_NONRECOV
;
349 else if (status
== SES_ESC_CRITICAL
)
350 state
|= TOPO_SENSOR_STATE_GENERIC_FAIL_CRITICAL
;
351 else if (nvlist_lookup_boolean_value(props
, prop
,
352 &value
) == 0 && value
)
353 state
|= TOPO_SENSOR_STATE_GENERIC_FAIL_NONRECOV
;
355 state
|= TOPO_SENSOR_STATE_GENERIC_FAIL_DEASSERTED
;
357 /* threshold sensor */
358 if (nvlist_lookup_boolean_value(props
,
359 SES_PROP_WARN_UNDER
, &value
) == 0 && value
)
360 state
|= TOPO_SENSOR_STATE_THRESH_LOWER_NONCRIT
;
361 if (nvlist_lookup_boolean_value(props
,
362 SES_PROP_WARN_OVER
, &value
) == 0 && value
)
363 state
|= TOPO_SENSOR_STATE_THRESH_UPPER_NONCRIT
;
364 if (nvlist_lookup_boolean_value(props
,
365 SES_PROP_CRIT_UNDER
, &value
) == 0 && value
)
366 state
|= TOPO_SENSOR_STATE_THRESH_LOWER_CRIT
;
367 if (nvlist_lookup_boolean_value(props
,
368 SES_PROP_CRIT_OVER
, &value
) == 0 && value
)
369 state
|= TOPO_SENSOR_STATE_THRESH_UPPER_CRIT
;
372 ses_node_unlock(mod
, tn
);
375 if (topo_mod_nvalloc(mod
, &nvl
, NV_UNIQUE_NAME
) != 0 ||
376 nvlist_add_string(nvl
, TOPO_PROP_VAL_NAME
,
377 TOPO_SENSOR_STATE
) != 0 ||
378 nvlist_add_uint32(nvl
, TOPO_PROP_VAL_TYPE
, TOPO_TYPE_UINT32
) != 0 ||
379 nvlist_add_uint32(nvl
, TOPO_PROP_VAL_VAL
, state
) != 0) {
381 return (topo_mod_seterrno(mod
, EMOD_NOMEM
));
389 * Read the status of a PSU. This is such a specialized operation that it has
390 * its own method instead of trying to piggyback on ses_sensor_state(). We
391 * use the following mapping to get to the standard topo power supply states:
393 * acfail -> INPUT_LOST
394 * dcfail -> INPUT_LOST
395 * undervoltage -> INPUT_RANGE
396 * overvoltage -> INPUT_RANGE_PRES
397 * overcurrent -> INPUT_RANGE_PRES
400 * If we ever have a need for reading overtemp, we can expand the topo
401 * representation for power supplies, but at the moment this seems unnecessary.
405 ses_psu_state(topo_mod_t
*mod
, tnode_t
*tn
, topo_version_t vers
,
406 nvlist_t
*in
, nvlist_t
**out
)
408 nvlist_t
*nvl
, *props
;
413 if ((np
= ses_node_lock(mod
, tn
)) == NULL
) {
414 topo_mod_dprintf(mod
, "failed to lookup ses node in 'mode' "
418 verify((props
= ses_node_props(np
)) != NULL
);
421 if ((nvlist_lookup_boolean_value(props
, SES_PSU_PROP_DC_FAIL
,
422 &value
) == 0 && value
) ||
423 (nvlist_lookup_boolean_value(props
, SES_PSU_PROP_AC_FAIL
,
424 &value
) == 0 && value
))
425 state
|= TOPO_SENSOR_STATE_POWER_SUPPLY_INPUT_LOST
;
427 if (nvlist_lookup_boolean_value(props
, SES_PSU_PROP_DC_UNDER_VOLTAGE
,
428 &value
) == 0 && value
)
429 state
|= TOPO_SENSOR_STATE_POWER_SUPPLY_INPUT_RANGE
;
431 if ((nvlist_lookup_boolean_value(props
, SES_PSU_PROP_DC_OVER_VOLTAGE
,
432 &value
) == 0 && value
) ||
433 (nvlist_lookup_boolean_value(props
, SES_PSU_PROP_DC_OVER_CURRENT
,
434 &value
) == 0 && value
))
435 state
|= TOPO_SENSOR_STATE_POWER_SUPPLY_INPUT_RANGE_PRES
;
437 ses_node_unlock(mod
, tn
);
440 if (topo_mod_nvalloc(mod
, &nvl
, NV_UNIQUE_NAME
) != 0 ||
441 nvlist_add_string(nvl
, TOPO_PROP_VAL_NAME
,
442 TOPO_SENSOR_STATE
) != 0 ||
443 nvlist_add_uint32(nvl
, TOPO_PROP_VAL_TYPE
, TOPO_TYPE_UINT32
) != 0 ||
444 nvlist_add_uint32(nvl
, TOPO_PROP_VAL_VAL
, state
) != 0) {
446 return (topo_mod_seterrno(mod
, EMOD_NOMEM
));
454 * Create a facility node, either a sensor or an indicator.
457 ses_add_fac_common(topo_mod_t
*mod
, tnode_t
*pnode
, const char *name
,
458 const char *type
, uint64_t nodeid
)
461 topo_pgroup_info_t pgi
;
463 ses_enum_target_t
*stp
= topo_node_getspecific(pnode
);
465 if ((tn
= topo_node_facbind(mod
, pnode
, name
, type
)) == NULL
) {
466 topo_mod_dprintf(mod
, "failed to bind facility node %s\n",
472 topo_node_setspecific(tn
, stp
);
474 pgi
.tpi_name
= TOPO_PGROUP_FACILITY
;
475 pgi
.tpi_namestab
= TOPO_STABILITY_PRIVATE
;
476 pgi
.tpi_datastab
= TOPO_STABILITY_PRIVATE
;
479 if (topo_pgroup_create(tn
, &pgi
, &err
) != 0) {
480 topo_mod_dprintf(mod
, "failed to create facility property "
481 "group: %s\n", topo_strerror(err
));
482 topo_node_unbind(tn
);
487 * We need the node-id property for each facility node.
489 pgi
.tpi_name
= TOPO_PGROUP_SES
;
490 pgi
.tpi_namestab
= TOPO_STABILITY_PRIVATE
;
491 pgi
.tpi_datastab
= TOPO_STABILITY_PRIVATE
;
492 pgi
.tpi_version
= TOPO_VERSION
;
494 if (topo_pgroup_create(tn
, &pgi
, &err
) != 0) {
495 topo_mod_dprintf(mod
, "failed to create ses property "
496 "group: %s\n", topo_strerror(err
));
497 topo_node_unbind(tn
);
501 if (topo_prop_set_uint64(tn
, TOPO_PGROUP_SES
,
502 TOPO_PROP_NODE_ID
, TOPO_PROP_IMMUTABLE
,
503 nodeid
, &err
) != 0) {
504 topo_mod_dprintf(mod
,
505 "failed to create property %s: %s\n",
506 TOPO_PROP_NODE_ID
, topo_strerror(err
));
507 topo_node_unbind(tn
);
515 * Add an indicator. This can be represented by a single property, or by the
516 * union of two elements when SES is capable of distinguishing between
517 * requested failure and detected failure.
520 ses_add_indicator(topo_mod_t
*mod
, tnode_t
*pnode
, uint64_t nodeid
,
521 int type
, const char *name
, const char *propname
, const char *altprop
)
527 /* create facility node and add methods */
528 if ((tn
= ses_add_fac_common(mod
, pnode
, name
,
529 TOPO_FAC_TYPE_INDICATOR
, nodeid
)) == NULL
)
532 if (topo_method_register(mod
, tn
, ses_indicator_methods
) < 0) {
533 topo_mod_dprintf(mod
, "failed to register facility methods\n");
534 topo_node_unbind(tn
);
538 /* set standard properties */
539 if (topo_prop_set_uint32(tn
, TOPO_PGROUP_FACILITY
,
540 TOPO_FACILITY_TYPE
, TOPO_PROP_IMMUTABLE
, type
, &err
) != 0) {
541 topo_mod_dprintf(mod
,
542 "failed to set facility node properties: %s\n",
544 topo_node_unbind(tn
);
548 /* 'mode' property */
550 if (topo_mod_nvalloc(mod
, &nvl
, NV_UNIQUE_NAME
) != 0 ||
551 nvlist_add_string(nvl
, TOPO_METH_SES_MODE_PROP
,
553 (altprop
!= NULL
&& nvlist_add_string(nvl
,
554 TOPO_METH_SES_MODE_ALTPROP
, altprop
) != 0)) {
556 topo_mod_dprintf(mod
, "failed to setup method arguments\n");
557 topo_node_unbind(tn
);
558 return (topo_mod_seterrno(mod
, EMOD_NOMEM
));
561 if (topo_prop_method_register(tn
, TOPO_PGROUP_FACILITY
,
562 TOPO_LED_MODE
, TOPO_TYPE_UINT32
, "ses_indicator_mode",
565 topo_mod_dprintf(mod
, "failed to register reading method: %s\n",
570 if (topo_prop_setmutable(tn
, TOPO_PGROUP_FACILITY
,
571 TOPO_LED_MODE
, &err
) != 0) {
573 topo_mod_dprintf(mod
, "failed to set property as mutable: %s\n",
583 ses_add_sensor_common(topo_mod_t
*mod
, tnode_t
*pnode
, uint64_t nodeid
,
584 const char *name
, const char *class, int type
)
589 /* create facility node and add methods */
590 if ((tn
= ses_add_fac_common(mod
, pnode
, name
,
591 TOPO_FAC_TYPE_SENSOR
, nodeid
)) == NULL
)
594 if (topo_method_register(mod
, tn
, ses_sensor_methods
) < 0) {
595 topo_mod_dprintf(mod
, "failed to register facility methods\n");
596 topo_node_unbind(tn
);
600 /* set standard properties */
601 if (topo_prop_set_string(tn
, TOPO_PGROUP_FACILITY
,
602 TOPO_SENSOR_CLASS
, TOPO_PROP_IMMUTABLE
,
604 topo_prop_set_uint32(tn
, TOPO_PGROUP_FACILITY
,
605 TOPO_FACILITY_TYPE
, TOPO_PROP_IMMUTABLE
,
607 topo_mod_dprintf(mod
,
608 "failed to set facility node properties: %s\n",
610 topo_node_unbind(tn
);
618 * Add an analog (threshold) sensor to the enclosure. This is used for fan
619 * speed, voltage, current, and temperature sensors.
622 ses_add_sensor(topo_mod_t
*mod
, tnode_t
*pnode
, uint64_t nodeid
,
623 const char *name
, const ses_sensor_desc_t
*sdp
)
629 if ((tn
= ses_add_sensor_common(mod
, pnode
, nodeid
, name
,
630 TOPO_SENSOR_CLASS_THRESHOLD
, sdp
->sd_type
)) == NULL
)
633 if (topo_prop_set_uint32(tn
, TOPO_PGROUP_FACILITY
,
634 TOPO_SENSOR_UNITS
, TOPO_PROP_IMMUTABLE
, sdp
->sd_units
, &err
) != 0) {
635 topo_mod_dprintf(mod
,
636 "failed to set facility node properties: %s\n",
638 topo_node_unbind(tn
);
642 /* 'reading' property */
644 if (topo_mod_nvalloc(mod
, &nvl
, NV_UNIQUE_NAME
) != 0 ||
645 nvlist_add_string(nvl
, TOPO_METH_SES_READING_PROP
,
646 sdp
->sd_propname
) != 0 ||
647 (sdp
->sd_multiplier
!= 0 &&
648 nvlist_add_double(nvl
, TOPO_METH_SES_READING_MULT
,
649 sdp
->sd_multiplier
) != 0)) {
651 topo_mod_dprintf(mod
, "failed to setup method arguments\n");
652 topo_node_unbind(tn
);
656 if (topo_prop_method_register(tn
, TOPO_PGROUP_FACILITY
,
657 TOPO_SENSOR_READING
, TOPO_TYPE_DOUBLE
, "ses_sensor_reading",
660 topo_mod_dprintf(mod
, "failed to register reading method: %s\n",
666 if (topo_mod_nvalloc(mod
, &nvl
, NV_UNIQUE_NAME
) != 0) {
667 topo_mod_dprintf(mod
, "failed to setup method arguments\n");
668 topo_node_unbind(tn
);
672 /* 'state' property */
673 if (topo_prop_method_register(tn
, TOPO_PGROUP_FACILITY
,
674 TOPO_SENSOR_STATE
, TOPO_TYPE_UINT32
, "ses_sensor_state",
677 topo_mod_dprintf(mod
, "failed to register state method: %s\n",
687 * Add a discrete sensor for simple boolean values. This is used to indicate
688 * externally-detected failures for fans, bays, and enclosures.
691 ses_add_discrete(topo_mod_t
*mod
, tnode_t
*pnode
, uint64_t nodeid
,
692 const char *name
, const char *prop
)
698 if ((tn
= ses_add_sensor_common(mod
, pnode
, nodeid
, name
,
699 TOPO_SENSOR_CLASS_DISCRETE
,
700 TOPO_SENSOR_TYPE_GENERIC_FAILURE
)) == NULL
)
704 if (topo_mod_nvalloc(mod
, &nvl
, NV_UNIQUE_NAME
) != 0 ||
705 nvlist_add_string(nvl
, TOPO_METH_SES_STATE_PROP
, prop
) != 0) {
707 topo_mod_dprintf(mod
, "failed to setup method arguments\n");
708 topo_node_unbind(tn
);
712 /* 'state' property */
713 if (topo_prop_method_register(tn
, TOPO_PGROUP_FACILITY
,
714 TOPO_SENSOR_STATE
, TOPO_TYPE_UINT32
, "ses_sensor_state",
717 topo_mod_dprintf(mod
, "failed to register state method: %s\n",
728 ses_add_psu_status(topo_mod_t
*mod
, tnode_t
*pnode
, uint64_t nodeid
)
734 /* create facility node and add methods */
735 if ((tn
= ses_add_sensor_common(mod
, pnode
, nodeid
, "status",
736 TOPO_SENSOR_CLASS_DISCRETE
,
737 TOPO_SENSOR_TYPE_POWER_SUPPLY
)) == NULL
)
740 if (topo_mod_nvalloc(mod
, &nvl
, NV_UNIQUE_NAME
) != 0) {
742 topo_mod_dprintf(mod
, "failed to setup method arguments\n");
743 topo_node_unbind(tn
);
747 /* 'state' property */
748 if (topo_prop_method_register(tn
, TOPO_PGROUP_FACILITY
,
749 TOPO_SENSOR_STATE
, TOPO_TYPE_UINT32
, "ses_psu_state",
752 topo_mod_dprintf(mod
, "failed to register state method: %s\n",
763 ses_node_enum_facility(topo_mod_t
*mod
, tnode_t
*tn
, topo_version_t vers
,
764 nvlist_t
*in
, nvlist_t
**out
)
768 uint64_t type
, nodeid
;
769 ses_sensor_desc_t sd
= { 0 };
771 if ((np
= ses_node_lock(mod
, tn
)) == NULL
)
774 assert(ses_node_type(np
) == SES_NODE_ELEMENT
);
775 nodeid
= ses_node_id(np
);
776 verify((props
= ses_node_props(np
)) != NULL
);
777 verify(nvlist_lookup_uint64(props
, SES_PROP_ELEMENT_TYPE
, &type
) == 0);
779 if (type
!= SES_ET_DEVICE
&& type
!= SES_ET_ARRAY_DEVICE
&&
780 type
!= SES_ET_COOLING
&& type
!= SES_ET_POWER_SUPPLY
) {
781 ses_node_unlock(mod
, tn
);
786 * Every element supports an 'ident' indicator. All elements also
787 * support a 'fail' indicator, but the properties used to represent
788 * this condition differs between elements.
790 if (ses_add_indicator(mod
, tn
, nodeid
, TOPO_LED_TYPE_LOCATE
, "ident",
791 SES_PROP_IDENT
, NULL
) != 0)
796 case SES_ET_ARRAY_DEVICE
:
798 * Disks support an additional 'ok2rm' indicator, as well as
799 * externally detected 'fail' sensor.
801 if (ses_add_indicator(mod
, tn
, nodeid
, TOPO_LED_TYPE_SERVICE
,
802 "fail", SES_DEV_PROP_FAULT_RQSTD
,
803 SES_DEV_PROP_FAULT_SENSED
) != 0 ||
804 ses_add_indicator(mod
, tn
, nodeid
, TOPO_LED_TYPE_OK2RM
,
805 "ok2rm", SES_PROP_RMV
, SES_PROP_RMV
) != 0 ||
806 ses_add_discrete(mod
, tn
, nodeid
, "fault",
807 SES_DEV_PROP_FAULT_SENSED
) != 0)
813 * Add the fan speed sensor, and a discrete sensor for
816 sd
.sd_type
= TOPO_SENSOR_TYPE_THRESHOLD_STATE
;
817 sd
.sd_units
= TOPO_SENSOR_UNITS_RPM
;
818 sd
.sd_propname
= SES_COOLING_PROP_FAN_SPEED
;
819 if (ses_add_indicator(mod
, tn
, nodeid
, TOPO_LED_TYPE_SERVICE
,
820 "fail", SES_PROP_FAIL
, NULL
) != 0 ||
821 ses_add_sensor(mod
, tn
, nodeid
, "speed", &sd
) != 0 ||
822 ses_add_discrete(mod
, tn
, nodeid
, "fault",
827 case SES_ET_POWER_SUPPLY
:
829 * For power supplies, we have a number of different sensors:
830 * acfail, dcfail, overtemp, undervoltate, overvoltage,
831 * and overcurrent. Rather than expose these all as individual
832 * sensors, we lump them together into a 'status' sensor of
833 * type TOPO_SENSOR_TYPE_POWER_SUPPLY and export the
834 * appropriate status flags as defined by the libtopo standard.
836 if (ses_add_indicator(mod
, tn
, nodeid
, TOPO_LED_TYPE_SERVICE
,
837 "fail", SES_PROP_FAIL
, NULL
) != 0)
840 if (ses_add_psu_status(mod
, tn
, nodeid
) != 0)
848 ses_node_unlock(mod
, tn
);
852 ses_node_unlock(mod
, tn
);
857 * Add enclosure-wide sensors (temperature, voltage, and current) beneath the
861 ses_add_enclosure_sensors(topo_mod_t
*mod
, tnode_t
*tn
, ses_node_t
*agg
,
865 const char *defaultname
;
868 nvlist_t
*props
, *aprops
;
869 uint64_t index
, nodeid
;
870 ses_sensor_desc_t sd
= { 0 };
874 case SES_ET_TEMPERATURE_SENSOR
:
875 sd
.sd_type
= TOPO_SENSOR_TYPE_TEMP
;
876 sd
.sd_units
= TOPO_SENSOR_UNITS_DEGREES_C
;
877 sd
.sd_propname
= SES_TEMP_PROP_TEMP
;
878 defaultname
= "temperature";
881 case SES_ET_VOLTAGE_SENSOR
:
882 sd
.sd_type
= TOPO_SENSOR_TYPE_VOLTAGE
;
883 sd
.sd_units
= TOPO_SENSOR_UNITS_VOLTS
;
884 sd
.sd_propname
= SES_VS_PROP_VOLTAGE_MV
;
885 sd
.sd_multiplier
= 0.001;
886 defaultname
= "voltage";
889 case SES_ET_CURRENT_SENSOR
:
890 sd
.sd_type
= TOPO_SENSOR_TYPE_CURRENT
;
891 sd
.sd_units
= TOPO_SENSOR_UNITS_AMPS
;
892 sd
.sd_propname
= SES_CS_PROP_CURRENT_MA
;
893 sd
.sd_multiplier
= 0.001;
894 defaultname
= "current";
901 aprops
= ses_node_props(agg
);
903 for (child
= ses_node_child(agg
); child
!= NULL
;
904 child
= ses_node_sibling(child
)) {
906 * The only tricky part here is getting the name for the
907 * sensor, where we follow the algorithm of the standard
910 props
= ses_node_props(child
);
911 nodeid
= ses_node_id(child
);
912 if (nvlist_lookup_uint64(props
, SES_PROP_ELEMENT_CLASS_INDEX
,
916 if (nvlist_lookup_string(props
, SES_PROP_DESCRIPTION
,
917 &desc
) == 0 && desc
[0] != '\0') {
918 (void) strlcpy(rawname
, desc
, sizeof (rawname
));
920 if (nvlist_lookup_string(aprops
,
921 SES_PROP_CLASS_DESCRIPTION
, &desc
) != 0 ||
923 desc
= (char *)defaultname
;
926 while (len
> 0 && desc
[len
- 1] == ' ')
929 (void) snprintf(rawname
, sizeof (rawname
),
930 "%.*s %llu", len
, desc
, index
);
933 if ((name
= disk_auth_clean(mod
, rawname
)) == NULL
)
936 if (ses_add_sensor(mod
, tn
, nodeid
, name
, &sd
) != 0) {
937 topo_mod_strfree(mod
, name
);
941 topo_mod_strfree(mod
, name
);
949 ses_enc_enum_facility(topo_mod_t
*mod
, tnode_t
*tn
, topo_version_t vers
,
950 nvlist_t
*in
, nvlist_t
**out
)
952 ses_node_t
*np
, *agg
;
954 uint64_t type
, nodeid
;
956 if ((np
= ses_node_lock(mod
, tn
)) == NULL
)
959 assert(ses_node_type(np
) == SES_NODE_ENCLOSURE
);
960 nodeid
= ses_node_id(np
);
963 * 'ident' and 'fail' LEDs, and 'fault' sensor.
965 if (ses_add_indicator(mod
, tn
, nodeid
, TOPO_LED_TYPE_LOCATE
, "ident",
966 SES_PROP_IDENT
, NULL
) != 0 ||
967 ses_add_indicator(mod
, tn
, nodeid
, TOPO_LED_TYPE_SERVICE
, "fail",
968 SES_PROP_FAIL_REQ
, SES_PROP_FAIL
) != 0 ||
969 ses_add_discrete(mod
, tn
, nodeid
, "fault", SES_PROP_FAIL
) != 0)
973 * Environmental sensors (temperature, voltage, current). We have no
974 * way of knowing if any of these sensors correspond to a particular
975 * element, so we just attach them to the enclosure as a whole. In the
976 * future, some vendor-specific libses plugin knowledge could let us
977 * make this correlation clearer.
979 for (agg
= ses_node_child(np
); agg
!= NULL
;
980 agg
= ses_node_sibling(agg
)) {
981 if (ses_node_type(agg
) != SES_NODE_AGGREGATE
)
984 verify((aprops
= ses_node_props(agg
)) != NULL
);
985 if (nvlist_lookup_uint64(aprops
, SES_PROP_ELEMENT_TYPE
,
989 if (ses_add_enclosure_sensors(mod
, tn
, agg
, type
) != 0)
993 ses_node_unlock(mod
, tn
);
997 ses_node_unlock(mod
, tn
);