1491f61a1SYanmin Sun /*
2491f61a1SYanmin Sun * CDDL HEADER START
3491f61a1SYanmin Sun *
4491f61a1SYanmin Sun * The contents of this file are subject to the terms of the
5491f61a1SYanmin Sun * Common Development and Distribution License (the "License").
6491f61a1SYanmin Sun * You may not use this file except in compliance with the License.
7491f61a1SYanmin Sun *
8491f61a1SYanmin Sun * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9491f61a1SYanmin Sun * or http://www.opensolaris.org/os/licensing.
10491f61a1SYanmin Sun * See the License for the specific language governing permissions
11491f61a1SYanmin Sun * and limitations under the License.
12491f61a1SYanmin Sun *
13491f61a1SYanmin Sun * When distributing Covered Code, include this CDDL HEADER in each
14491f61a1SYanmin Sun * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15491f61a1SYanmin Sun * If applicable, add the following below this CDDL HEADER, with the
16491f61a1SYanmin Sun * fields enclosed by brackets "[]" replaced with your own identifying
17491f61a1SYanmin Sun * information: Portions Copyright [yyyy] [name of copyright owner]
18491f61a1SYanmin Sun *
19491f61a1SYanmin Sun * CDDL HEADER END
20491f61a1SYanmin Sun */
21491f61a1SYanmin Sun
22491f61a1SYanmin Sun /*
2363d763c8SLuping Quan * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
24491f61a1SYanmin Sun */
25491f61a1SYanmin Sun
26491f61a1SYanmin Sun /*
2763d763c8SLuping Quan * FMA capability messenger
28491f61a1SYanmin Sun *
2963d763c8SLuping Quan * fdd-msg module is called once when fmd starts up. It does the following
3063d763c8SLuping Quan * based on different scenarios
31491f61a1SYanmin Sun *
3263d763c8SLuping Quan * 1. If it's on a x86 platform, fdd-msg module sends fdd running on service
3363d763c8SLuping Quan * processor a message (ILOM) which indicates the Solaris host FMA capability.
3463d763c8SLuping Quan * The message is sent via the BMC driver (KCS interface) to the IPMI stack
3563d763c8SLuping Quan * of ILOM using the IPMI Sun OEM core tunnel command. The sub-command is
3663d763c8SLuping Quan * CORE_TUNNEL_SUBCMD_HOSTCAP. The IPMI stack posts an host FMA capability
3763d763c8SLuping Quan * event to the event manager upon receiving this message. fdd subscribes to
3863d763c8SLuping Quan * the event manager for this event. Upon receving this event, fdd will adjust
3963d763c8SLuping Quan * its configuration.
4063d763c8SLuping Quan *
4163d763c8SLuping Quan * 2. If it's on a Sparc platform, fdd-msg module just exit for now.
42491f61a1SYanmin Sun */
43491f61a1SYanmin Sun
44491f61a1SYanmin Sun #include <errno.h>
45491f61a1SYanmin Sun #include <stdio.h>
46491f61a1SYanmin Sun #include <strings.h>
47dfe4040dSLuping Quan #include <sys/systeminfo.h>
48491f61a1SYanmin Sun #include <libipmi.h>
4963d763c8SLuping Quan #include <sys/devfm.h>
50491f61a1SYanmin Sun #include <fm/fmd_api.h>
5163d763c8SLuping Quan #if defined(__x86)
5263d763c8SLuping Quan #include <sys/x86_archext.h>
5363d763c8SLuping Quan #include <fm/fmd_agent.h>
5463d763c8SLuping Quan #include <libnvpair.h>
5563d763c8SLuping Quan #endif
56491f61a1SYanmin Sun
57491f61a1SYanmin Sun #define CMD_SUNOEM_CORE_TUNNEL 0x44
58491f61a1SYanmin Sun #define CORE_TUNNEL_SUBCMD_HOSTFMACAP 2
59491f61a1SYanmin Sun #define OEM_DATA_LENGTH 3
60491f61a1SYanmin Sun #define VERSION 0x10
6163d763c8SLuping Quan
6263d763c8SLuping Quan #if defined(__x86)
6363d763c8SLuping Quan typedef struct cpu_tbl {
6463d763c8SLuping Quan char vendor[X86_VENDOR_STRLEN];
6563d763c8SLuping Quan int32_t family;
6663d763c8SLuping Quan int32_t model;
6763d763c8SLuping Quan char *propname;
6863d763c8SLuping Quan } cpu_tbl_t;
6963d763c8SLuping Quan
7063d763c8SLuping Quan static cpu_tbl_t fma_cap_list[] = {
7163d763c8SLuping Quan {"GenuineIntel", 6, 26, "NHMEP_fma_cap"},
7263d763c8SLuping Quan {"GenuineIntel", 6, 46, "NHMEX_fma_cap"},
7363d763c8SLuping Quan {"GenuineIntel", 6, 44, "WSMEP_fma_cap"},
7463d763c8SLuping Quan {"GenuineIntel", 6, 47, "INTLN_fma_cap"},
75*940f2f58SToomas Soome {0, 0, 0, 0}
7663d763c8SLuping Quan };
7763d763c8SLuping Quan #endif
78491f61a1SYanmin Sun
79491f61a1SYanmin Sun static int
check_sunoem(ipmi_handle_t * ipmi_hdl)80491f61a1SYanmin Sun check_sunoem(ipmi_handle_t *ipmi_hdl)
81491f61a1SYanmin Sun {
82491f61a1SYanmin Sun ipmi_deviceid_t *devid;
83491f61a1SYanmin Sun
84491f61a1SYanmin Sun if ((devid = ipmi_get_deviceid(ipmi_hdl)) == NULL)
85491f61a1SYanmin Sun return (-1);
86491f61a1SYanmin Sun
87491f61a1SYanmin Sun if (!ipmi_is_sun_ilom(devid))
88491f61a1SYanmin Sun return (-2);
89491f61a1SYanmin Sun
90491f61a1SYanmin Sun return (0);
91491f61a1SYanmin Sun }
92491f61a1SYanmin Sun
9363d763c8SLuping Quan #if defined(__x86)
9463d763c8SLuping Quan static int32_t
fma_cap_cpu_info(cpu_tbl_t * ci)9563d763c8SLuping Quan fma_cap_cpu_info(cpu_tbl_t *ci)
9663d763c8SLuping Quan {
9763d763c8SLuping Quan nvlist_t **cpus, *nvl;
9863d763c8SLuping Quan uint_t ncpu, i;
9963d763c8SLuping Quan fmd_agent_hdl_t *hdl;
10063d763c8SLuping Quan char *ven;
10163d763c8SLuping Quan int32_t family, model;
10263d763c8SLuping Quan
10363d763c8SLuping Quan if ((hdl = fmd_agent_open(FMD_AGENT_VERSION)) == NULL)
10463d763c8SLuping Quan return (-1);
10563d763c8SLuping Quan if (fmd_agent_physcpu_info(hdl, &cpus, &ncpu) != 0) {
10663d763c8SLuping Quan fmd_agent_close(hdl);
10763d763c8SLuping Quan return (-1);
10863d763c8SLuping Quan }
10963d763c8SLuping Quan fmd_agent_close(hdl);
11063d763c8SLuping Quan
11163d763c8SLuping Quan if (cpus == NULL)
11263d763c8SLuping Quan return (-1);
11363d763c8SLuping Quan
11463d763c8SLuping Quan /*
11563d763c8SLuping Quan * There is no mixed CPU type on x86 systems, it's ok to
11663d763c8SLuping Quan * just pick the first one
11763d763c8SLuping Quan */
11863d763c8SLuping Quan nvl = cpus[0];
11963d763c8SLuping Quan if (nvlist_lookup_string(nvl, FM_PHYSCPU_INFO_VENDOR_ID, &ven) != 0 ||
12063d763c8SLuping Quan nvlist_lookup_int32(nvl, FM_PHYSCPU_INFO_FAMILY, &family) != 0 ||
12163d763c8SLuping Quan nvlist_lookup_int32(nvl, FM_PHYSCPU_INFO_MODEL, &model) != 0) {
12263d763c8SLuping Quan for (i = 0; i < ncpu; i++)
12363d763c8SLuping Quan nvlist_free(cpus[i]);
12463d763c8SLuping Quan umem_free(cpus, sizeof (nvlist_t *) * ncpu);
12563d763c8SLuping Quan return (-1);
12663d763c8SLuping Quan }
12763d763c8SLuping Quan
12863d763c8SLuping Quan (void) snprintf(ci->vendor, X86_VENDOR_STRLEN, "%s", ven);
12963d763c8SLuping Quan ci->family = family;
13063d763c8SLuping Quan ci->model = model;
13163d763c8SLuping Quan
13263d763c8SLuping Quan for (i = 0; i < ncpu; i++)
13363d763c8SLuping Quan nvlist_free(cpus[i]);
13463d763c8SLuping Quan umem_free(cpus, sizeof (nvlist_t *) * ncpu);
13563d763c8SLuping Quan return (0);
13663d763c8SLuping Quan }
13763d763c8SLuping Quan #endif
13863d763c8SLuping Quan
13963d763c8SLuping Quan static uint32_t
get_cap_conf(fmd_hdl_t * hdl)14063d763c8SLuping Quan get_cap_conf(fmd_hdl_t *hdl)
14163d763c8SLuping Quan {
14263d763c8SLuping Quan uint32_t fma_cap;
14363d763c8SLuping Quan #if defined(__x86)
14463d763c8SLuping Quan int found = 0;
14563d763c8SLuping Quan cpu_tbl_t *cl, ci;
14663d763c8SLuping Quan
14763d763c8SLuping Quan if (fma_cap_cpu_info(&ci) == 0) {
14863d763c8SLuping Quan fmd_hdl_debug(hdl, "Got CPU info: vendor=%s, family=%d, "
14963d763c8SLuping Quan "model=%d\n", ci.vendor, ci.family, ci.model);
15063d763c8SLuping Quan for (cl = fma_cap_list; cl->propname != NULL; cl++) {
15163d763c8SLuping Quan if (strncmp(ci.vendor, cl->vendor,
15263d763c8SLuping Quan X86_VENDOR_STRLEN) == 0 &&
15363d763c8SLuping Quan ci.family == cl->family &&
15463d763c8SLuping Quan ci.model == cl->model) {
15563d763c8SLuping Quan found++;
15663d763c8SLuping Quan break;
15763d763c8SLuping Quan }
15863d763c8SLuping Quan }
15963d763c8SLuping Quan } else {
16063d763c8SLuping Quan fmd_hdl_debug(hdl, "Failed to get CPU info");
16163d763c8SLuping Quan }
16263d763c8SLuping Quan
16363d763c8SLuping Quan if (found) {
16463d763c8SLuping Quan fma_cap = fmd_prop_get_int32(hdl, cl->propname);
16563d763c8SLuping Quan fmd_hdl_debug(hdl, "Found property, FMA capability=0x%x",
16663d763c8SLuping Quan fma_cap);
16763d763c8SLuping Quan } else {
16863d763c8SLuping Quan #endif
16963d763c8SLuping Quan fma_cap = fmd_prop_get_int32(hdl, "default_fma_cap");
17063d763c8SLuping Quan fmd_hdl_debug(hdl, "Didn't find FMA capability property, "
17163d763c8SLuping Quan "use default=0x%x", fma_cap);
17263d763c8SLuping Quan #if defined(__x86)
17363d763c8SLuping Quan }
17463d763c8SLuping Quan #endif
17563d763c8SLuping Quan
17663d763c8SLuping Quan return (fma_cap);
17763d763c8SLuping Quan }
17863d763c8SLuping Quan
179491f61a1SYanmin Sun static void
send_fma_cap_to_ilom(fmd_hdl_t * hdl,uint32_t fma_cap)18063d763c8SLuping Quan send_fma_cap_to_ilom(fmd_hdl_t *hdl, uint32_t fma_cap)
181491f61a1SYanmin Sun {
18263d763c8SLuping Quan int error;
18363d763c8SLuping Quan char *msg;
184491f61a1SYanmin Sun ipmi_handle_t *ipmi_hdl;
185491f61a1SYanmin Sun ipmi_cmd_t cmd;
186491f61a1SYanmin Sun uint8_t oem_data[OEM_DATA_LENGTH];
187491f61a1SYanmin Sun
18863d763c8SLuping Quan if ((ipmi_hdl = ipmi_open(&error, &msg, IPMI_TRANSPORT_BMC, NULL))
18963d763c8SLuping Quan == NULL) {
19063d763c8SLuping Quan /*
191989f2807SJerry Jelinek * If /dev/ipmi0 doesn't exist on the system, then return
19263d763c8SLuping Quan * without doing anything.
19363d763c8SLuping Quan */
19463d763c8SLuping Quan if (error != EIPMI_BMC_OPEN_FAILED)
19563d763c8SLuping Quan fmd_hdl_abort(hdl, "Failed to initialize IPMI "
19663d763c8SLuping Quan "connection: %s\n", msg);
19763d763c8SLuping Quan fmd_hdl_debug(hdl, "Failed: no IPMI connection present");
19863d763c8SLuping Quan return;
19963d763c8SLuping Quan }
20063d763c8SLuping Quan
20163d763c8SLuping Quan /*
20263d763c8SLuping Quan * Check if it's Sun ILOM
20363d763c8SLuping Quan */
20463d763c8SLuping Quan if (check_sunoem(ipmi_hdl) != 0) {
20563d763c8SLuping Quan fmd_hdl_debug(hdl, "Service Processor does not run "
20663d763c8SLuping Quan "Sun ILOM");
20763d763c8SLuping Quan ipmi_close(ipmi_hdl);
20863d763c8SLuping Quan return;
20963d763c8SLuping Quan }
210491f61a1SYanmin Sun
211491f61a1SYanmin Sun oem_data[0] = CORE_TUNNEL_SUBCMD_HOSTFMACAP;
212491f61a1SYanmin Sun oem_data[1] = VERSION;
21363d763c8SLuping Quan oem_data[2] = fma_cap;
214491f61a1SYanmin Sun
215491f61a1SYanmin Sun cmd.ic_netfn = IPMI_NETFN_OEM;
216491f61a1SYanmin Sun cmd.ic_lun = 0;
217491f61a1SYanmin Sun cmd.ic_cmd = CMD_SUNOEM_CORE_TUNNEL;
218491f61a1SYanmin Sun cmd.ic_dlen = OEM_DATA_LENGTH;
219491f61a1SYanmin Sun cmd.ic_data = oem_data;
220491f61a1SYanmin Sun
221491f61a1SYanmin Sun if (ipmi_send(ipmi_hdl, &cmd) == NULL) {
222491f61a1SYanmin Sun fmd_hdl_debug(hdl, "Failed to send Solaris FMA "
22363d763c8SLuping Quan "capability to ilom: %s", ipmi_errmsg(ipmi_hdl));
224491f61a1SYanmin Sun }
225491f61a1SYanmin Sun
226491f61a1SYanmin Sun ipmi_close(ipmi_hdl);
22763d763c8SLuping Quan }
22863d763c8SLuping Quan
22963d763c8SLuping Quan /*ARGSUSED*/
23063d763c8SLuping Quan static void
fma_cap_init(fmd_hdl_t * hdl,id_t id,void * data)23163d763c8SLuping Quan fma_cap_init(fmd_hdl_t *hdl, id_t id, void *data)
23263d763c8SLuping Quan {
23363d763c8SLuping Quan uint32_t fma_cap;
23463d763c8SLuping Quan
23563d763c8SLuping Quan fma_cap = get_cap_conf(hdl);
23663d763c8SLuping Quan send_fma_cap_to_ilom(hdl, fma_cap);
23763d763c8SLuping Quan
238491f61a1SYanmin Sun fmd_hdl_unregister(hdl);
239491f61a1SYanmin Sun }
240491f61a1SYanmin Sun
241491f61a1SYanmin Sun static const fmd_hdl_ops_t fmd_ops = {
242491f61a1SYanmin Sun NULL, /* fmdo_recv */
24363d763c8SLuping Quan fma_cap_init, /* fmdo_timeout */
244491f61a1SYanmin Sun NULL, /* fmdo_close */
245491f61a1SYanmin Sun NULL, /* fmdo_stats */
246491f61a1SYanmin Sun NULL, /* fmdo_gc */
247dfe4040dSLuping Quan NULL, /* fmdo_send */
248dfe4040dSLuping Quan NULL, /* fmdo_topo */
249491f61a1SYanmin Sun };
250491f61a1SYanmin Sun
251491f61a1SYanmin Sun static const fmd_prop_t fmd_props[] = {
252491f61a1SYanmin Sun { "interval", FMD_TYPE_TIME, "1s" },
25363d763c8SLuping Quan { "default_fma_cap", FMD_TYPE_UINT32, "0x3" },
25463d763c8SLuping Quan { "NHMEP_fma_cap", FMD_TYPE_UINT32, "0x3" },
25563d763c8SLuping Quan { "NHMEX_fma_cap", FMD_TYPE_UINT32, "0x2" },
25663d763c8SLuping Quan { "WSMEP_fma_cap", FMD_TYPE_UINT32, "0x3" },
25763d763c8SLuping Quan { "INTLN_fma_cap", FMD_TYPE_UINT32, "0x2" },
258491f61a1SYanmin Sun { NULL, 0, NULL }
259491f61a1SYanmin Sun };
260491f61a1SYanmin Sun
261491f61a1SYanmin Sun static const fmd_hdl_info_t fmd_info = {
26263d763c8SLuping Quan "FMA Capability Messenger", "1.1", &fmd_ops, fmd_props
263491f61a1SYanmin Sun };
264491f61a1SYanmin Sun
265491f61a1SYanmin Sun void
_fmd_init(fmd_hdl_t * hdl)266491f61a1SYanmin Sun _fmd_init(fmd_hdl_t *hdl)
267491f61a1SYanmin Sun {
268dfe4040dSLuping Quan char isa[8];
269dfe4040dSLuping Quan
27063d763c8SLuping Quan /*
27163d763c8SLuping Quan * For now the module only sends message to ILOM on i386 platforms
27263d763c8SLuping Quan * till CR 6933053 is fixed. Module unregister may cause etm module
27363d763c8SLuping Quan * core dump due to 6933053.
27463d763c8SLuping Quan */
275dfe4040dSLuping Quan if ((sysinfo(SI_ARCHITECTURE, isa, sizeof (isa)) == -1) ||
276dfe4040dSLuping Quan (strncmp(isa, "i386", 4) != 0))
277dfe4040dSLuping Quan return;
278491f61a1SYanmin Sun
279491f61a1SYanmin Sun if (fmd_hdl_register(hdl, FMD_API_VERSION, &fmd_info) != 0)
280491f61a1SYanmin Sun return;
281491f61a1SYanmin Sun
282491f61a1SYanmin Sun /*
283491f61a1SYanmin Sun * Setup the timer.
284491f61a1SYanmin Sun */
285dfe4040dSLuping Quan (void) fmd_timer_install(hdl, NULL, NULL, 2000000000ULL);
286491f61a1SYanmin Sun }
287491f61a1SYanmin Sun
28863d763c8SLuping Quan /*ARGSUSED*/
289491f61a1SYanmin Sun void
_fmd_fini(fmd_hdl_t * hdl)290491f61a1SYanmin Sun _fmd_fini(fmd_hdl_t *hdl)
291491f61a1SYanmin Sun {
292491f61a1SYanmin Sun }
293