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