1 #include <string.h>
2 #include <errorlog.h>
3 #include <device.h>
4 #include <fsp.h>
5 #include <pel.h>
6 #include <rtc.h>
7 
8 /* Create MTMS section for sapphire log */
create_mtms_section(struct errorlog * elog_data,char * pel_buffer,int * pel_offset)9 static void create_mtms_section(struct errorlog *elog_data,
10 					char *pel_buffer, int *pel_offset)
11 {
12 	const struct dt_property *p;
13 
14 	struct opal_mtms_section *mtms = (struct opal_mtms_section *)
15 				(pel_buffer + *pel_offset);
16 
17 	mtms->v6header.id = ELOG_SID_MACHINE_TYPE;
18 	mtms->v6header.length = MTMS_SECTION_SIZE;
19 	mtms->v6header.version = OPAL_EXT_HRD_VER;
20 	mtms->v6header.subtype = 0;
21 	mtms->v6header.component_id = elog_data->component_id;
22 
23 	memset(mtms->model, 0x00, sizeof(mtms->model));
24 	memcpy(mtms->model, dt_prop_get(dt_root, "model"), OPAL_SYS_MODEL_LEN);
25 
26 	memset(mtms->serial_no, 0x00, sizeof(mtms->serial_no));
27 	p = dt_find_property(dt_root, "system-id");
28 	if (p)
29 		memcpy(mtms->serial_no, p->prop, OPAL_SYS_SERIAL_LEN);
30 	else
31 		memset(mtms->serial_no, 0, OPAL_SYS_SERIAL_LEN);
32 
33 	*pel_offset += MTMS_SECTION_SIZE;
34 }
35 
36 /* Create extended header section */
create_extended_header_section(struct errorlog * elog_data,char * pel_buffer,int * pel_offset)37 static void create_extended_header_section(struct errorlog *elog_data,
38 					char *pel_buffer, int *pel_offset)
39 {
40 	const char  *opalmodel = NULL;
41 	const struct dt_property *p;
42 	uint64_t extd_time;
43 
44 	struct opal_extended_header_section *extdhdr =
45 			(struct opal_extended_header_section *)
46 					(pel_buffer + *pel_offset);
47 
48 	extdhdr->v6header.id = ELOG_SID_EXTENDED_HEADER;
49 	extdhdr->v6header.length = EXTENDED_HEADER_SECTION_SIZE;
50 	extdhdr->v6header.version = OPAL_EXT_HRD_VER;
51 	extdhdr->v6header.subtype = 0;
52 	extdhdr->v6header.component_id = elog_data->component_id;
53 
54 	memset(extdhdr->model, 0x00, sizeof(extdhdr->model));
55 	opalmodel = dt_prop_get(dt_root, "model");
56 	memcpy(extdhdr->model, opalmodel, OPAL_SYS_MODEL_LEN);
57 
58 	memset(extdhdr->serial_no, 0x00, sizeof(extdhdr->serial_no));
59 	p = dt_find_property(dt_root, "system-id");
60 	if (p)
61 		memcpy(extdhdr->serial_no, p->prop, OPAL_SYS_SERIAL_LEN);
62 	else
63 		memset(extdhdr->serial_no, 0, OPAL_SYS_SERIAL_LEN);
64 
65 	memset(extdhdr->opal_release_version, 0x00,
66 				sizeof(extdhdr->opal_release_version));
67 	memset(extdhdr->opal_subsys_version, 0x00,
68 				sizeof(extdhdr->opal_subsys_version));
69 
70 	rtc_cache_get_datetime(&extdhdr->extended_header_date, &extd_time);
71 	extdhdr->extended_header_time = extd_time >> 32;
72 	extdhdr->opal_symid_len = 0;
73 
74 	*pel_offset += EXTENDED_HEADER_SECTION_SIZE;
75 }
76 
77 /* set src type */
settype(struct opal_src_section * src,uint8_t src_type)78 static void settype(struct opal_src_section *src, uint8_t src_type)
79 {
80 	char type[4];
81 	snprintf(type, sizeof(type), "%02X", src_type);
82 	memcpy(src->srcstring, type, 2);
83 }
84 
85 /* set SRC subsystem type */
setsubsys(struct opal_src_section * src,uint8_t src_subsys)86 static void setsubsys(struct opal_src_section *src, uint8_t src_subsys)
87 {
88 	char subsys[4];
89 	snprintf(subsys, sizeof(subsys), "%02X", src_subsys);
90 	memcpy(src->srcstring+2, subsys, 2);
91 }
92 
93 /* Ser reason code of SRC */
setrefcode(struct opal_src_section * src,uint16_t src_refcode)94 static void setrefcode(struct opal_src_section *src, uint16_t src_refcode)
95 {
96 	char refcode[8];
97 	snprintf(refcode, sizeof(refcode), "%04X", src_refcode);
98 	memcpy(src->srcstring+4, refcode, 4);
99 }
100 
101 /* Create SRC section of OPAL log */
create_src_section(struct errorlog * elog_data,char * pel_buffer,int * pel_offset)102 static void create_src_section(struct errorlog *elog_data,
103 					char *pel_buffer, int *pel_offset)
104 {
105 	struct opal_src_section *src = (struct opal_src_section *)
106 						(pel_buffer + *pel_offset);
107 
108 	src->v6header.id = ELOG_SID_PRIMARY_SRC;
109 	src->v6header.length = SRC_SECTION_SIZE;
110 	src->v6header.version = OPAL_ELOG_VERSION;
111 	src->v6header.subtype = OPAL_ELOG_SST;
112 	src->v6header.component_id = elog_data->component_id;
113 
114 	src->version = OPAL_SRC_SEC_VER;
115 	src->flags = 0;
116 	src->wordcount = OPAL_SRC_MAX_WORD_COUNT;
117 	src->srclength = SRC_LENGTH;
118 	settype(src, OPAL_SRC_TYPE_ERROR);
119 	setsubsys(src, OPAL_FAILING_SUBSYSTEM);
120 	setrefcode(src, elog_data->reason_code);
121 	memset(src->hexwords, 0 , (8 * 4));
122 	src->hexwords[0] = OPAL_SRC_FORMAT;
123 	src->hexwords[4] = elog_data->additional_info[0];
124 	src->hexwords[5] = elog_data->additional_info[1];
125 	src->hexwords[6] = elog_data->additional_info[2];
126 	src->hexwords[7] = elog_data->additional_info[3];
127 	*pel_offset += SRC_SECTION_SIZE;
128 }
129 
130 /* Create user header section */
create_user_header_section(struct errorlog * elog_data,char * pel_buffer,int * pel_offset)131 static void create_user_header_section(struct errorlog *elog_data,
132 					char *pel_buffer, int *pel_offset)
133 {
134 	struct opal_user_header_section *usrhdr =
135 				(struct opal_user_header_section *)
136 						(pel_buffer + *pel_offset);
137 
138 	usrhdr->v6header.id = ELOG_SID_USER_HEADER;
139 	usrhdr->v6header.length = USER_HEADER_SECTION_SIZE;
140 	usrhdr->v6header.version = OPAL_ELOG_VERSION;
141 	usrhdr->v6header.subtype = OPAL_ELOG_SST;
142 	usrhdr->v6header.component_id = elog_data->component_id;
143 
144 	usrhdr->subsystem_id = elog_data->subsystem_id;
145 	usrhdr->event_scope = 0;
146 	usrhdr->event_severity = elog_data->event_severity;
147 	usrhdr->event_type = elog_data->event_subtype;
148 
149 	if (elog_data->elog_origin == ORG_SAPPHIRE)
150 		usrhdr->action_flags = ERRL_ACTION_REPORT;
151 	else
152 		usrhdr->action_flags = ERRL_ACTION_NONE;
153 
154 	*pel_offset += USER_HEADER_SECTION_SIZE;
155 }
156 
157 /* Create private header section */
create_private_header_section(struct errorlog * elog_data,char * pel_buffer,int * pel_offset)158 static void create_private_header_section(struct errorlog *elog_data,
159 					char *pel_buffer, int *pel_offset)
160 {
161 	uint64_t ctime;
162 	struct opal_private_header_section *privhdr =
163 				(struct opal_private_header_section *)
164 								pel_buffer;
165 
166 	privhdr->v6header.id = ELOG_SID_PRIVATE_HEADER;
167 	privhdr->v6header.length = PRIVATE_HEADER_SECTION_SIZE;
168 	privhdr->v6header.version = OPAL_ELOG_VERSION;
169 	privhdr->v6header.subtype = OPAL_ELOG_SST;
170 	privhdr->v6header.component_id = elog_data->component_id;
171 	privhdr->plid = elog_data->plid;
172 
173 	rtc_cache_get_datetime(&privhdr->create_date, &ctime);
174 	privhdr->create_time = ctime >> 32;
175 	privhdr->section_count = 5;
176 
177 	privhdr->creator_subid_hi = 0x00;
178 	privhdr->creator_subid_lo = 0x00;
179 
180 	if (elog_data->elog_origin == ORG_SAPPHIRE)
181 		privhdr->creator_id = OPAL_CID_SAPPHIRE;
182 	else
183 		privhdr->creator_id = OPAL_CID_POWERNV;
184 
185 	privhdr->log_entry_id = elog_data->plid; /*entry id is updated by FSP*/
186 
187 	*pel_offset += PRIVATE_HEADER_SECTION_SIZE;
188 }
189 
create_user_defined_section(struct errorlog * elog_data,char * pel_buffer,int * pel_offset)190 static void create_user_defined_section(struct errorlog *elog_data,
191 					char *pel_buffer, int *pel_offset)
192 {
193 	char *dump = (char *)pel_buffer + *pel_offset;
194 	char *opal_buf = (char *)elog_data->user_data_dump;
195 	struct opal_user_section *usrhdr;
196 	struct elog_user_data_section *opal_usr_data;
197 	struct opal_private_header_section *privhdr =
198 			 (struct opal_private_header_section *)pel_buffer;
199 	int i;
200 
201 	for (i = 0; i < elog_data->user_section_count; i++) {
202 
203 		usrhdr = (struct opal_user_section *)dump;
204 		opal_usr_data = (struct elog_user_data_section *)opal_buf;
205 
206 		usrhdr->v6header.id = ELOG_SID_USER_DEFINED;
207 		usrhdr->v6header.version = OPAL_ELOG_VERSION;
208 		usrhdr->v6header.length = sizeof(struct opal_v6_header) +
209 							opal_usr_data->size;
210 		usrhdr->v6header.subtype = OPAL_ELOG_SST;
211 		usrhdr->v6header.component_id = elog_data->component_id;
212 
213 		memcpy(usrhdr->dump, opal_buf, opal_usr_data->size);
214 		*pel_offset += usrhdr->v6header.length;
215 		dump += usrhdr->v6header.length;
216 		opal_buf += opal_usr_data->size;
217 		privhdr->section_count++;
218 	}
219 }
220 
pel_user_section_size(struct errorlog * elog_data)221 static size_t pel_user_section_size(struct errorlog *elog_data)
222 {
223 	int i;
224 	size_t total = 0;
225 	char *opal_buf = (char *)elog_data->user_data_dump;
226 	struct elog_user_data_section *opal_usr_data;
227 
228 	for (i = 0; i < elog_data->user_section_count; i++) {
229 		opal_usr_data = (struct elog_user_data_section *)opal_buf;
230 		total += sizeof(struct opal_v6_header) +
231 			opal_usr_data->size;
232 		opal_buf += opal_usr_data->size;
233 	}
234 
235 	return total;
236 }
237 
pel_size(struct errorlog * elog_data)238 size_t pel_size(struct errorlog *elog_data)
239 {
240 	return PEL_MIN_SIZE + pel_user_section_size(elog_data);
241 }
242 
243 /* Converts an OPAL errorlog into a PEL formatted log */
create_pel_log(struct errorlog * elog_data,char * pel_buffer,size_t pel_buffer_size)244 int create_pel_log(struct errorlog *elog_data, char *pel_buffer,
245 		   size_t pel_buffer_size)
246 {
247 	int pel_offset = 0;
248 
249 	if (pel_buffer_size < pel_size(elog_data)) {
250 		prerror("PEL buffer too small to create record\n");
251 		return 0;
252 	}
253 
254 	memset(pel_buffer, 0, pel_buffer_size);
255 
256 	create_private_header_section(elog_data, pel_buffer, &pel_offset);
257 	create_user_header_section(elog_data, pel_buffer, &pel_offset);
258 	create_src_section(elog_data, pel_buffer, &pel_offset);
259 	create_extended_header_section(elog_data, pel_buffer, &pel_offset);
260 	create_mtms_section(elog_data, pel_buffer, &pel_offset);
261 	if (elog_data->user_section_count)
262 		create_user_defined_section(elog_data, pel_buffer, &pel_offset);
263 
264 	return pel_offset;
265 }
266