1 /* Copyright 2018 IBM Corp.
2  *
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *	http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
12  * implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <device.h>
18 #include <skiboot.h>
19 #include <stdlib.h>
20 #include <ipmi.h>
21 #include <mem_region-malloc.h>
22 #include <opal.h>
23 #include <timebase.h>
24 
25 /*
26  * Response data from IPMI Get device ID command (As defined in
27  * Section 20.1 Get Device ID Command - IPMI standard spec).
28  */
29 struct ipmi_dev_id {
30 	uint8_t	dev_id;
31 	uint8_t	dev_revision;
32 	uint8_t	fw_rev1;
33 	uint8_t	fw_rev2;
34 	uint8_t	ipmi_ver;
35 	uint8_t	add_dev_support;
36 	uint8_t	manufactur_id[3];
37 	uint8_t	product_id[2];
38 	uint8_t	aux_fw_rev[4];
39 };
40 static struct ipmi_dev_id *ipmi_dev_id;
41 
42 /*
43  * Response data from IPMI Chassis Get System Boot Option (As defined in
44  * Section 28.13 Get System Boot Options Command - IPMI standard spec).
45  */
46 struct ipmi_sys_boot_opt {
47 	uint8_t param_version;
48 	uint8_t param_valid;
49 	/*
50 	 * Fields for OEM parameter 0x62. This parameter does not follow
51 	 * the normal layout and just has a single byte to signal if it
52 	 * is active or not.
53 	 */
54 	uint8_t flag_set;
55 };
56 static struct ipmi_sys_boot_opt *ipmi_sys_boot_opt;
57 
58 /* Got response from BMC? */
59 static bool bmc_info_waiting = false;
60 static bool bmc_info_valid = false;
61 static bool bmc_boot_opt_waiting = false;
62 static bool bmc_boot_opt_valid = false;
63 
64 /* This will free ipmi_dev_id structure */
ipmi_dt_add_bmc_info(void)65 void ipmi_dt_add_bmc_info(void)
66 {
67 	char buf[8];
68 	struct dt_node *dt_fw_version;
69 
70 	while (bmc_info_waiting)
71 		time_wait_ms(5);
72 
73 	if (!bmc_info_valid)
74 		return;
75 
76 	dt_fw_version = dt_find_by_name(dt_root, "ibm,firmware-versions");
77 	if (!dt_fw_version) {
78 		free(ipmi_dev_id);
79 		return;
80 	}
81 
82 	memset(buf, 0, sizeof(buf));
83 	snprintf(buf, sizeof(buf), "%x.%02x",
84 		 ipmi_dev_id->fw_rev1, ipmi_dev_id->fw_rev2);
85 	dt_add_property_string(dt_fw_version, "bmc-firmware-version", buf);
86 
87 	free(ipmi_dev_id);
88 }
89 
ipmi_get_bmc_info_resp(struct ipmi_msg * msg)90 static void ipmi_get_bmc_info_resp(struct ipmi_msg *msg)
91 {
92 	bmc_info_waiting = false;
93 
94 	if (msg->cc != IPMI_CC_NO_ERROR) {
95 		prlog(PR_ERR, "IPMI: IPMI_BMC_GET_DEVICE_ID cmd returned error"
96 		      " [rc : 0x%x]\n", msg->data[0]);
97 		return;
98 	}
99 
100 	/* ipmi_dev_id has optional fields */
101 	if (msg->resp_size <= sizeof(struct ipmi_dev_id)) {
102 		bmc_info_valid = true;
103 		memcpy(ipmi_dev_id, msg->data, msg->resp_size);
104 	} else {
105 		prlog(PR_WARNING, "IPMI: IPMI_BMC_GET_DEVICE_ID unexpected response size\n");
106 	}
107 
108 	ipmi_free_msg(msg);
109 }
110 
ipmi_get_bmc_info_request(void)111 int ipmi_get_bmc_info_request(void)
112 {
113 	int rc;
114 	struct ipmi_msg *msg;
115 
116 	ipmi_dev_id = zalloc(sizeof(struct ipmi_dev_id));
117 	assert(ipmi_dev_id);
118 
119 	msg = ipmi_mkmsg(IPMI_DEFAULT_INTERFACE, IPMI_BMC_GET_DEVICE_ID,
120 			 ipmi_get_bmc_info_resp, NULL, NULL,
121 			 0, sizeof(struct ipmi_dev_id));
122 	if (!msg)
123 		return OPAL_NO_MEM;
124 
125 	msg->error = ipmi_get_bmc_info_resp;
126 	prlog(PR_INFO, "IPMI: Requesting IPMI_BMC_GET_DEVICE_ID\n");
127 	rc = ipmi_queue_msg(msg);
128 	if (rc) {
129 		prlog(PR_ERR, "IPMI: Failed to queue IPMI_BMC_GET_DEVICE_ID\n");
130 		ipmi_free_msg(msg);
131 		return rc;
132 	}
133 
134 	bmc_info_waiting = true;
135 	return rc;
136 }
137 
138 /* This will free ipmi_sys_boot_opt structure */
ipmi_chassis_check_sbe_validation(void)139 int ipmi_chassis_check_sbe_validation(void)
140 {
141 	int rc = -1;
142 
143 	while (bmc_boot_opt_waiting)
144 		time_wait_ms(10);
145 
146 	if (!bmc_boot_opt_valid)
147 		goto out;
148 
149 	if ((ipmi_sys_boot_opt->param_valid & 0x8) != 0)
150 		goto out;
151 	if (ipmi_sys_boot_opt->param_valid != 0x62)
152 		goto out;
153 
154 	rc = ipmi_sys_boot_opt->flag_set;
155 
156 out:
157 	free(ipmi_sys_boot_opt);
158 	return rc;
159 }
160 
ipmi_get_chassis_boot_opt_resp(struct ipmi_msg * msg)161 static void ipmi_get_chassis_boot_opt_resp(struct ipmi_msg *msg)
162 {
163 	bmc_boot_opt_waiting = false;
164 
165 	if (msg->cc != IPMI_CC_NO_ERROR) {
166 		prlog(PR_INFO, "IPMI: IPMI_CHASSIS_GET_BOOT_OPT cmd returned error"
167 		      " [rc : 0x%x]\n", msg->data[0]);
168 		ipmi_free_msg(msg);
169 		return;
170 	}
171 
172 	if (msg->resp_size == sizeof(struct ipmi_sys_boot_opt)) {
173 		bmc_boot_opt_valid = true;
174 		memcpy(ipmi_sys_boot_opt, msg->data, msg->resp_size);
175 	} else {
176 		prlog(PR_WARNING, "IPMI: IPMI_CHASSIS_GET_BOOT_OPT unexpected response size\n");
177 	}
178 
179 	ipmi_free_msg(msg);
180 }
181 
ipmi_get_chassis_boot_opt_request(void)182 int ipmi_get_chassis_boot_opt_request(void)
183 {
184 	int rc;
185 	struct ipmi_msg *msg;
186 	uint8_t req[] = {
187 		0x62, /* OEM parameter (SBE Validation on astbmc) */
188 		0x00, /* no set selector */
189 		0x00, /* no block selector */
190 	};
191 
192 	ipmi_sys_boot_opt = zalloc(sizeof(struct ipmi_sys_boot_opt));
193 	assert(ipmi_sys_boot_opt);
194 
195 	msg = ipmi_mkmsg(IPMI_DEFAULT_INTERFACE, IPMI_CHASSIS_GET_BOOT_OPT,
196 			 ipmi_get_chassis_boot_opt_resp, NULL, req,
197 			 sizeof(req), sizeof(struct ipmi_sys_boot_opt));
198 	if (!msg) {
199 		free(ipmi_sys_boot_opt);
200 		return OPAL_NO_MEM;
201 	}
202 
203 	msg->error = ipmi_get_chassis_boot_opt_resp;
204 	prlog(PR_INFO, "IPMI: Requesting IPMI_CHASSIS_GET_BOOT_OPT\n");
205 	rc = ipmi_queue_msg(msg);
206 	if (rc) {
207 		prlog(PR_ERR, "IPMI: Failed to queue IPMI_CHASSIS_GET_BOOT_OPT\n");
208 		free(ipmi_sys_boot_opt);
209 		ipmi_free_msg(msg);
210 		return rc;
211 	}
212 
213 	bmc_boot_opt_waiting = true;
214 	return rc;
215 }
216