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 (c) 2010, Oracle and/or its affiliates. All rights reserved.
27 * FMA capability messenger
29 * fdd-msg module is called once when fmd starts up. It does the following
30 * based on different scenarios
32 * 1. If it's on a x86 platform, fdd-msg module sends fdd running on service
33 * processor a message (ILOM) which indicates the Solaris host FMA capability.
34 * The message is sent via the BMC driver (KCS interface) to the IPMI stack
35 * of ILOM using the IPMI Sun OEM core tunnel command. The sub-command is
36 * CORE_TUNNEL_SUBCMD_HOSTCAP. The IPMI stack posts an host FMA capability
37 * event to the event manager upon receiving this message. fdd subscribes to
38 * the event manager for this event. Upon receving this event, fdd will adjust
41 * 2. If it's on a Sparc platform, fdd-msg module just exit for now.
47 #include <sys/systeminfo.h>
49 #include <sys/devfm.h>
50 #include <fm/fmd_api.h>
52 #include <sys/x86_archext.h>
53 #include <fm/fmd_agent.h>
54 #include <libnvpair.h>
57 #define CMD_SUNOEM_CORE_TUNNEL 0x44
58 #define CORE_TUNNEL_SUBCMD_HOSTFMACAP 2
59 #define OEM_DATA_LENGTH 3
63 typedef struct cpu_tbl
{
64 char vendor
[X86_VENDOR_STRLEN
];
70 static cpu_tbl_t fma_cap_list
[] = {
71 {"GenuineIntel", 6, 26, "NHMEP_fma_cap"},
72 {"GenuineIntel", 6, 46, "NHMEX_fma_cap"},
73 {"GenuineIntel", 6, 44, "WSMEP_fma_cap"},
74 {"GenuineIntel", 6, 47, "INTLN_fma_cap"},
80 check_sunoem(ipmi_handle_t
*ipmi_hdl
)
82 ipmi_deviceid_t
*devid
;
84 if ((devid
= ipmi_get_deviceid(ipmi_hdl
)) == NULL
)
87 if (!ipmi_is_sun_ilom(devid
))
95 fma_cap_cpu_info(cpu_tbl_t
*ci
)
97 nvlist_t
**cpus
, *nvl
;
101 int32_t family
, model
;
103 if ((hdl
= fmd_agent_open(FMD_AGENT_VERSION
)) == NULL
)
105 if (fmd_agent_physcpu_info(hdl
, &cpus
, &ncpu
) != 0) {
106 fmd_agent_close(hdl
);
109 fmd_agent_close(hdl
);
115 * There is no mixed CPU type on x86 systems, it's ok to
116 * just pick the first one
119 if (nvlist_lookup_string(nvl
, FM_PHYSCPU_INFO_VENDOR_ID
, &ven
) != 0 ||
120 nvlist_lookup_int32(nvl
, FM_PHYSCPU_INFO_FAMILY
, &family
) != 0 ||
121 nvlist_lookup_int32(nvl
, FM_PHYSCPU_INFO_MODEL
, &model
) != 0) {
122 for (i
= 0; i
< ncpu
; i
++)
123 nvlist_free(cpus
[i
]);
124 umem_free(cpus
, sizeof (nvlist_t
*) * ncpu
);
128 (void) snprintf(ci
->vendor
, X86_VENDOR_STRLEN
, "%s", ven
);
132 for (i
= 0; i
< ncpu
; i
++)
133 nvlist_free(cpus
[i
]);
134 umem_free(cpus
, sizeof (nvlist_t
*) * ncpu
);
140 get_cap_conf(fmd_hdl_t
*hdl
)
147 if (fma_cap_cpu_info(&ci
) == 0) {
148 fmd_hdl_debug(hdl
, "Got CPU info: vendor=%s, family=%d, "
149 "model=%d\n", ci
.vendor
, ci
.family
, ci
.model
);
150 for (cl
= fma_cap_list
; cl
->propname
!= NULL
; cl
++) {
151 if (strncmp(ci
.vendor
, cl
->vendor
,
152 X86_VENDOR_STRLEN
) == 0 &&
153 ci
.family
== cl
->family
&&
154 ci
.model
== cl
->model
) {
160 fmd_hdl_debug(hdl
, "Failed to get CPU info");
164 fma_cap
= fmd_prop_get_int32(hdl
, cl
->propname
);
165 fmd_hdl_debug(hdl
, "Found property, FMA capability=0x%x",
169 fma_cap
= fmd_prop_get_int32(hdl
, "default_fma_cap");
170 fmd_hdl_debug(hdl
, "Didn't find FMA capability property, "
171 "use default=0x%x", fma_cap
);
180 send_fma_cap_to_ilom(fmd_hdl_t
*hdl
, uint32_t fma_cap
)
184 ipmi_handle_t
*ipmi_hdl
;
186 uint8_t oem_data
[OEM_DATA_LENGTH
];
188 if ((ipmi_hdl
= ipmi_open(&error
, &msg
, IPMI_TRANSPORT_BMC
, NULL
))
191 * If /dev/ipmi0 doesn't exist on the system, then return
192 * without doing anything.
194 if (error
!= EIPMI_BMC_OPEN_FAILED
)
195 fmd_hdl_abort(hdl
, "Failed to initialize IPMI "
196 "connection: %s\n", msg
);
197 fmd_hdl_debug(hdl
, "Failed: no IPMI connection present");
202 * Check if it's Sun ILOM
204 if (check_sunoem(ipmi_hdl
) != 0) {
205 fmd_hdl_debug(hdl
, "Service Processor does not run "
207 ipmi_close(ipmi_hdl
);
211 oem_data
[0] = CORE_TUNNEL_SUBCMD_HOSTFMACAP
;
212 oem_data
[1] = VERSION
;
213 oem_data
[2] = fma_cap
;
215 cmd
.ic_netfn
= IPMI_NETFN_OEM
;
217 cmd
.ic_cmd
= CMD_SUNOEM_CORE_TUNNEL
;
218 cmd
.ic_dlen
= OEM_DATA_LENGTH
;
219 cmd
.ic_data
= oem_data
;
221 if (ipmi_send(ipmi_hdl
, &cmd
) == NULL
) {
222 fmd_hdl_debug(hdl
, "Failed to send Solaris FMA "
223 "capability to ilom: %s", ipmi_errmsg(ipmi_hdl
));
226 ipmi_close(ipmi_hdl
);
231 fma_cap_init(fmd_hdl_t
*hdl
, id_t id
, void *data
)
235 fma_cap
= get_cap_conf(hdl
);
236 send_fma_cap_to_ilom(hdl
, fma_cap
);
238 fmd_hdl_unregister(hdl
);
241 static const fmd_hdl_ops_t fmd_ops
= {
242 NULL
, /* fmdo_recv */
243 fma_cap_init
, /* fmdo_timeout */
244 NULL
, /* fmdo_close */
245 NULL
, /* fmdo_stats */
247 NULL
, /* fmdo_send */
248 NULL
, /* fmdo_topo */
251 static const fmd_prop_t fmd_props
[] = {
252 { "interval", FMD_TYPE_TIME
, "1s" },
253 { "default_fma_cap", FMD_TYPE_UINT32
, "0x3" },
254 { "NHMEP_fma_cap", FMD_TYPE_UINT32
, "0x3" },
255 { "NHMEX_fma_cap", FMD_TYPE_UINT32
, "0x2" },
256 { "WSMEP_fma_cap", FMD_TYPE_UINT32
, "0x3" },
257 { "INTLN_fma_cap", FMD_TYPE_UINT32
, "0x2" },
261 static const fmd_hdl_info_t fmd_info
= {
262 "FMA Capability Messenger", "1.1", &fmd_ops
, fmd_props
266 _fmd_init(fmd_hdl_t
*hdl
)
271 * For now the module only sends message to ILOM on i386 platforms
272 * till CR 6933053 is fixed. Module unregister may cause etm module
273 * core dump due to 6933053.
275 if ((sysinfo(SI_ARCHITECTURE
, isa
, sizeof (isa
)) == -1) ||
276 (strncmp(isa
, "i386", 4) != 0))
279 if (fmd_hdl_register(hdl
, FMD_API_VERSION
, &fmd_info
) != 0)
285 (void) fmd_timer_install(hdl
, NULL
, NULL
, 2000000000ULL);
290 _fmd_fini(fmd_hdl_t
*hdl
)