1 #include <assert.h>
2 #include <ccan/container_of/container_of.h>
3 #include <libflash/blocklevel.h>
4 #include <lock.h>
5 #include <lpc.h>
6 #include <hiomap.h>
7 #include <ipmi.h>
8 #include <opal-api.h>
9 #include <platform.h>
10 #include <stdio.h>
11 #include <stdlib.h>
12 
13 #include "../ipmi-hiomap.h"
14 #include "../errors.h"
15 
16 /* Stub for blocklevel debug macros */
17 bool libflash_debug;
18 
19 const struct bmc_sw_config bmc_sw_hiomap = {
20 	.ipmi_oem_hiomap_cmd         = IPMI_CODE(0x3a, 0x5a),
21 };
22 
23 const struct bmc_platform _bmc_platform = {
24 	.name = "generic:hiomap",
25 	.sw = &bmc_sw_hiomap,
26 };
27 
28 enum scenario_event_type {
29 	scenario_sentinel = 0,
30 	scenario_event_p,
31 	scenario_cmd,
32 	scenario_sel,
33 	scenario_delay,
34 };
35 
36 struct scenario_cmd_data {
37 	uint8_t cmd;
38 	uint8_t seq;
39 	uint8_t args[13];
40 } __attribute__((packed));
41 
42 struct scenario_cmd {
43 	struct scenario_cmd_data req;
44 	struct scenario_cmd_data resp;
45 	uint8_t cc;
46 	size_t resp_size;
47 };
48 
49 struct scenario_sel {
50 	uint8_t bmc_state;
51 };
52 
53 struct scenario_event {
54 	enum scenario_event_type type;
55 	union {
56 		const struct scenario_event *p;
57 		struct scenario_cmd c;
58 		struct scenario_sel s;
59 	};
60 };
61 
62 #define SCENARIO_SENTINEL { .type = scenario_sentinel }
63 
64 struct ipmi_sel {
65 	void (*fn)(uint8_t data, void *context);
66 	void *context;
67 };
68 
69 struct ipmi_msg_ctx {
70 	const struct scenario_event *scenario;
71 	const struct scenario_event *cursor;
72 
73 	struct ipmi_sel sel;
74 
75 	struct ipmi_msg msg;
76 };
77 
78 struct ipmi_msg_ctx ipmi_msg_ctx;
79 
80 const struct bmc_platform *bmc_platform = &_bmc_platform;
81 
scenario_enter(const struct scenario_event * scenario)82 static void scenario_enter(const struct scenario_event *scenario)
83 {
84 	ipmi_msg_ctx.scenario = scenario;
85 	ipmi_msg_ctx.cursor = scenario;
86 }
87 
scenario_advance(void)88 static void scenario_advance(void)
89 {
90 	struct ipmi_msg_ctx *ctx = &ipmi_msg_ctx;
91 
92 	assert(ctx->cursor->type == scenario_delay);
93 	ctx->cursor++;
94 
95 	/* Deliver all the undelayed, scheduled SELs */
96 	while (ctx->cursor->type == scenario_sel) {
97 		ctx->sel.fn(ctx->cursor->s.bmc_state, ctx->sel.context);
98 		ctx->cursor++;
99 	}
100 }
101 
scenario_exit(void)102 static void scenario_exit(void)
103 {
104 	if (ipmi_msg_ctx.cursor->type != scenario_sentinel) {
105 		ptrdiff_t d = ipmi_msg_ctx.cursor - ipmi_msg_ctx.scenario;
106 		printf("%s: Exiting on event %tu with event type %d \n",
107 		       __func__, d, ipmi_msg_ctx.cursor->type);
108 		assert(false);
109 	}
110 }
111 
ipmi_init_msg(struct ipmi_msg * msg,int interface,uint32_t code,void (* complete)(struct ipmi_msg *),void * user_data,size_t req_size,size_t resp_size)112 void ipmi_init_msg(struct ipmi_msg *msg, int interface __attribute__((unused)),
113 		   uint32_t code, void (*complete)(struct ipmi_msg *),
114 		   void *user_data, size_t req_size, size_t resp_size)
115 {
116 	msg->backend = NULL;
117 	msg->cmd = IPMI_CMD(code);
118 	msg->netfn = IPMI_NETFN(code) << 2;
119 	msg->req_size = req_size;
120 	msg->resp_size = resp_size;
121 	msg->complete = complete;
122 	msg->user_data = user_data;
123 }
124 
ipmi_mkmsg(int interface,uint32_t code,void (* complete)(struct ipmi_msg *),void * user_data,void * req_data,size_t req_size,size_t resp_size)125 struct ipmi_msg *ipmi_mkmsg(int interface __attribute__((unused)),
126 			    uint32_t code, void (*complete)(struct ipmi_msg *),
127 			    void *user_data, void *req_data, size_t req_size,
128 			    size_t resp_size)
129 {
130 	struct ipmi_msg *msg = &ipmi_msg_ctx.msg;
131 
132 	ipmi_init_msg(msg, 0 /* some bogus value */, code, complete, user_data,
133 		      req_size, resp_size);
134 
135 	msg->data = malloc(req_size > resp_size ? req_size : resp_size);
136 	if (req_data)
137 		memcpy(msg->data, req_data, req_size);
138 
139 	return msg;
140 }
141 
ipmi_free_msg(struct ipmi_msg * msg)142 void ipmi_free_msg(struct ipmi_msg *msg __attribute__((unused)))
143 {
144 	if (msg)
145 		free(msg->data);
146 }
147 
ipmi_queue_msg_sync(struct ipmi_msg * msg)148 void ipmi_queue_msg_sync(struct ipmi_msg *msg)
149 {
150 	struct ipmi_msg_ctx *ctx = container_of(msg, struct ipmi_msg_ctx, msg);
151 	const struct scenario_cmd *cmd;
152 
153 	if (ctx->cursor->type == scenario_cmd) {
154 		cmd = &ctx->cursor->c;
155 	} else if (ctx->cursor->type == scenario_event_p) {
156 		assert(ctx->cursor->p->type == scenario_cmd);
157 		cmd = &ctx->cursor->p->c;
158 	} else {
159 		printf("Got unexpected request:\n");
160 		for (ssize_t i = 0; i < msg->req_size; i++)
161 			printf("msg->data[%zd]: 0x%02x\n", i, msg->data[i]);
162 		assert(false);
163 	}
164 
165 	assert((msg->netfn >> 2) == 0x3a);
166 	assert(msg->cmd == 0x5a);
167 	assert(msg->req_size >= 2);
168 
169 	if (memcmp(msg->data, &cmd->req, msg->req_size)) {
170 		printf("Comparing received vs expected message\n");
171 		for (ssize_t i = 0; i < msg->req_size; i++) {
172 			printf("msg->data[%zd]: 0x%02x, cmd->req[%zd]: 0x%02x\n",
173 			       i, msg->data[i], i, ((uint8_t *)(&cmd->req))[i]);
174 		}
175 		assert(false);
176 	}
177 
178 	msg->cc = cmd->cc;
179 	memcpy(msg->data, &cmd->resp, msg->resp_size);
180 
181 	if (cmd->resp_size)
182 		msg->resp_size = cmd->resp_size;
183 
184 	msg->complete(msg);
185 
186 	ctx->cursor++;
187 
188 	/* Deliver all the scheduled SELs */
189 	while (ctx->cursor->type == scenario_sel) {
190 		ctx->sel.fn(ctx->cursor->s.bmc_state, ctx->sel.context);
191 		ctx->cursor++;
192 	}
193 }
194 
ipmi_sel_register(uint8_t oem_cmd,void (* fn)(uint8_t data,void * context),void * context)195 int ipmi_sel_register(uint8_t oem_cmd __attribute__((unused)),
196 		      void (*fn)(uint8_t data, void *context),
197 		      void *context)
198 {
199 	ipmi_msg_ctx.sel.fn = fn;
200 	ipmi_msg_ctx.sel.context = context;
201 
202 	return 0;
203 }
204 
lpc_write(enum OpalLPCAddressType addr_type,uint32_t addr,uint32_t data,uint32_t sz)205 int64_t lpc_write(enum OpalLPCAddressType addr_type __attribute__((unused)),
206 		  uint32_t addr __attribute__((unused)),
207 		  uint32_t data __attribute__((unused)),
208 		  uint32_t sz)
209 {
210 	assert(sz != 0);
211 	return 0;
212 }
213 
lpc_read(enum OpalLPCAddressType addr_type,uint32_t addr,uint32_t * data,uint32_t sz)214 int64_t lpc_read(enum OpalLPCAddressType addr_type __attribute__((unused)),
215 		 uint32_t addr __attribute__((unused)), uint32_t *data,
216 		 uint32_t sz)
217 {
218 	memset(data, 0xaa, sz);
219 
220 	return 0;
221 }
222 
lpc_read_success(const uint8_t * buf,size_t len)223 static bool lpc_read_success(const uint8_t *buf, size_t len)
224 {
225 	if (len < 64) {
226 		while (len--)
227 			if (*buf++ != 0xaa)
228 				return false;
229 		return true;
230 	}
231 
232 	for (int i = 0; i < 64; i++)
233 		if (buf[i] != 0xaa)
234 			return false;
235 
236 	return !memcmp(buf, buf + 64, len - 64);
237 }
238 
239 /* Commonly used messages */
240 
241 static const struct scenario_event hiomap_ack_call = {
242 	.type = scenario_cmd,
243 	.c = {
244 		.req = {
245 			.cmd = HIOMAP_C_ACK,
246 			.seq = 1,
247 			.args = {
248 				[0] = HIOMAP_E_ACK_MASK,
249 			},
250 		},
251 		.cc = IPMI_CC_NO_ERROR,
252 		.resp = {
253 			.cmd = HIOMAP_C_ACK,
254 			.seq = 1,
255 		},
256 	},
257 };
258 
259 static const struct scenario_event hiomap_get_info_call = {
260 	.type = scenario_cmd,
261 	.c = {
262 		.req = {
263 			.cmd = HIOMAP_C_GET_INFO,
264 			.seq = 2,
265 			.args = {
266 				[0] = HIOMAP_V2,
267 			},
268 		},
269 		.cc = IPMI_CC_NO_ERROR,
270 		.resp = {
271 			.cmd = HIOMAP_C_GET_INFO,
272 			.seq = 2,
273 			.args = {
274 				[0] = HIOMAP_V2,
275 				[1] = 12,
276 				[2] = 8, [3] = 0,
277 			},
278 		},
279 	},
280 };
281 
282 static const struct scenario_event hiomap_get_flash_info_call = {
283 	.type = scenario_cmd,
284 	.c = {
285 		.req = {
286 			.cmd = HIOMAP_C_GET_FLASH_INFO,
287 			.seq = 3,
288 			.args = {
289 			},
290 		},
291 		.cc = IPMI_CC_NO_ERROR,
292 		.resp = {
293 			.cmd = HIOMAP_C_GET_FLASH_INFO,
294 			.seq = 3,
295 			.args = {
296 				[0] = 0x00, [1] = 0x20,
297 				[2] = 0x01, [3] = 0x00,
298 			},
299 		},
300 	},
301 };
302 
303 static const struct scenario_event
304 hiomap_create_read_window_qs0l1_rs0l1_call = {
305 	.type = scenario_cmd,
306 	.c = {
307 		.req = {
308 			.cmd = HIOMAP_C_CREATE_READ_WINDOW,
309 			.seq = 4,
310 			.args = {
311 				[0] = 0x00, [1] = 0x00,
312 				[2] = 0x01, [3] = 0x00,
313 			},
314 		},
315 		.cc = IPMI_CC_NO_ERROR,
316 		.resp = {
317 			.cmd = HIOMAP_C_CREATE_READ_WINDOW,
318 			.seq = 4,
319 			.args = {
320 				[0] = 0xff, [1] = 0x0f,
321 				[2] = 0x01, [3] = 0x00,
322 				[4] = 0x00, [5] = 0x00,
323 			},
324 		},
325 	},
326 };
327 
328 static const struct scenario_event
329 hiomap_create_read_window_qs0l2_rs0l1_call = {
330 	.type = scenario_cmd,
331 	.c = {
332 		.req = {
333 			.cmd = HIOMAP_C_CREATE_READ_WINDOW,
334 			.seq = 4,
335 			.args = {
336 				[0] = 0x00, [1] = 0x00,
337 				[2] = 0x02, [3] = 0x00,
338 			},
339 		},
340 		.cc = IPMI_CC_NO_ERROR,
341 		.resp = {
342 			.cmd = HIOMAP_C_CREATE_READ_WINDOW,
343 			.seq = 4,
344 			.args = {
345 				[0] = 0xff, [1] = 0x0f,
346 				[2] = 0x01, [3] = 0x00,
347 				[4] = 0x00, [5] = 0x00,
348 			},
349 		},
350 	},
351 };
352 
353 static const struct scenario_event
354 hiomap_create_write_window_qs0l1_rs0l1_call = {
355 	.type = scenario_cmd,
356 	.c = {
357 		.req = {
358 			.cmd = HIOMAP_C_CREATE_WRITE_WINDOW,
359 			.seq = 4,
360 			.args = {
361 				[0] = 0x00, [1] = 0x00,
362 				[2] = 0x01, [3] = 0x00,
363 			},
364 		},
365 		.cc = IPMI_CC_NO_ERROR,
366 		.resp = {
367 			.cmd = HIOMAP_C_CREATE_WRITE_WINDOW,
368 			.seq = 4,
369 			.args = {
370 				[0] = 0xff, [1] = 0x0f,
371 				[2] = 0x01, [3] = 0x00,
372 				[4] = 0x00, [5] = 0x00,
373 			},
374 		},
375 	},
376 };
377 
378 static const struct scenario_event hiomap_mark_dirty_qs0l1_call = {
379 	.type = scenario_cmd,
380 	.c = {
381 		.req = {
382 			.cmd = HIOMAP_C_MARK_DIRTY,
383 			.seq = 5,
384 			.args = {
385 				[0] = 0x00, [1] = 0x00,
386 				[2] = 0x01, [3] = 0x00,
387 			},
388 		},
389 		.cc = IPMI_CC_NO_ERROR,
390 		.resp = {
391 			.cmd = HIOMAP_C_MARK_DIRTY,
392 			.seq = 5,
393 		},
394 	},
395 };
396 
397 static const struct scenario_event
398 hiomap_create_write_window_qs0l2_rs0l1_call = {
399 	.type = scenario_cmd,
400 	.c = {
401 		.req = {
402 			.cmd = HIOMAP_C_CREATE_WRITE_WINDOW,
403 			.seq = 4,
404 			.args = {
405 				[0] = 0x00, [1] = 0x00,
406 				[2] = 0x02, [3] = 0x00,
407 			},
408 		},
409 		.cc = IPMI_CC_NO_ERROR,
410 		.resp = {
411 			.cmd = HIOMAP_C_CREATE_WRITE_WINDOW,
412 			.seq = 4,
413 			.args = {
414 				[0] = 0xff, [1] = 0x0f,
415 				[2] = 0x01, [3] = 0x00,
416 				[4] = 0x00, [5] = 0x00,
417 			},
418 		},
419 	},
420 };
421 
422 static const struct scenario_event hiomap_flush_call = {
423 	.type = scenario_cmd,
424 	.c = {
425 		.req = {
426 			.cmd = HIOMAP_C_FLUSH,
427 			.seq = 6,
428 		},
429 		.resp = {
430 			.cmd = HIOMAP_C_FLUSH,
431 			.seq = 6,
432 		},
433 	},
434 };
435 
436 static const struct scenario_event
437 hiomap_create_write_window_qs1l1_rs1l1_call = {
438 	.type = scenario_cmd,
439 	.c = {
440 		.req = {
441 			.cmd = HIOMAP_C_CREATE_WRITE_WINDOW,
442 			.seq = 7,
443 			.args = {
444 				[0] = 0x01, [1] = 0x00,
445 				[2] = 0x01, [3] = 0x00,
446 			},
447 		},
448 		.cc = IPMI_CC_NO_ERROR,
449 		.resp = {
450 			.cmd = HIOMAP_C_CREATE_WRITE_WINDOW,
451 			.seq = 7,
452 			.args = {
453 				[0] = 0xfe, [1] = 0x0f,
454 				[2] = 0x01, [3] = 0x00,
455 				[4] = 0x01, [5] = 0x00,
456 			},
457 		},
458 	},
459 };
460 
461 static const struct scenario_event hiomap_erase_qs0l1_call = {
462 	.type = scenario_cmd,
463 	.c = {
464 		.req = {
465 			.cmd = HIOMAP_C_ERASE,
466 			.seq = 5,
467 			.args = {
468 				[0] = 0x00, [1] = 0x00,
469 				[2] = 0x01, [3] = 0x00,
470 			},
471 		},
472 		.resp = {
473 			.cmd = HIOMAP_C_ERASE,
474 			.seq = 5,
475 		},
476 	},
477 };
478 
479 static const struct scenario_event scenario_hiomap_init[] = {
480 	{ .type = scenario_event_p, .p = &hiomap_ack_call, },
481 	{ .type = scenario_event_p, .p = &hiomap_get_info_call, },
482 	{ .type = scenario_event_p, .p = &hiomap_get_flash_info_call, },
483 	SCENARIO_SENTINEL,
484 };
485 
test_hiomap_init(void)486 static void test_hiomap_init(void)
487 {
488 	struct blocklevel_device *bl;
489 
490 	scenario_enter(scenario_hiomap_init);
491 	assert(!ipmi_hiomap_init(&bl));
492 	ipmi_hiomap_exit(bl);
493 	scenario_exit();
494 }
495 
496 static const struct scenario_event scenario_hiomap_event_daemon_ready[] = {
497 	{ .type = scenario_event_p, .p = &hiomap_ack_call, },
498 	{ .type = scenario_event_p, .p = &hiomap_get_info_call, },
499 	{ .type = scenario_event_p, .p = &hiomap_get_flash_info_call, },
500 	{ .type = scenario_sel, .s = { .bmc_state = HIOMAP_E_DAEMON_READY } },
501 	SCENARIO_SENTINEL,
502 };
503 
test_hiomap_event_daemon_ready(void)504 static void test_hiomap_event_daemon_ready(void)
505 {
506 	struct blocklevel_device *bl;
507 	struct ipmi_hiomap *ctx;
508 
509 	scenario_enter(scenario_hiomap_event_daemon_ready);
510 	assert(!ipmi_hiomap_init(&bl));
511 	ctx = container_of(bl, struct ipmi_hiomap, bl);
512 	assert(ctx->bmc_state == HIOMAP_E_DAEMON_READY);
513 	ipmi_hiomap_exit(bl);
514 	scenario_exit();
515 }
516 
517 static const struct scenario_event scenario_hiomap_event_daemon_stopped[] = {
518 	{ .type = scenario_event_p, .p = &hiomap_ack_call, },
519 	{ .type = scenario_event_p, .p = &hiomap_get_info_call, },
520 	{ .type = scenario_event_p, .p = &hiomap_get_flash_info_call, },
521 	{ .type = scenario_sel, .s = { .bmc_state = HIOMAP_E_DAEMON_READY } },
522 	{ .type = scenario_sel, .s = { .bmc_state = HIOMAP_E_PROTOCOL_RESET } },
523 	SCENARIO_SENTINEL,
524 };
525 
test_hiomap_event_daemon_stopped(void)526 static void test_hiomap_event_daemon_stopped(void)
527 {
528 	struct blocklevel_device *bl;
529 	struct ipmi_hiomap *ctx;
530 
531 	scenario_enter(scenario_hiomap_event_daemon_stopped);
532 	assert(!ipmi_hiomap_init(&bl));
533 	ctx = container_of(bl, struct ipmi_hiomap, bl);
534 	assert(ctx->bmc_state == HIOMAP_E_PROTOCOL_RESET);
535 	ipmi_hiomap_exit(bl);
536 	scenario_exit();
537 }
538 
539 static const struct scenario_event scenario_hiomap_event_daemon_restarted[] = {
540 	{ .type = scenario_event_p, .p = &hiomap_ack_call, },
541 	{ .type = scenario_event_p, .p = &hiomap_get_info_call, },
542 	{ .type = scenario_event_p, .p = &hiomap_get_flash_info_call, },
543 	{ .type = scenario_sel, .s = { .bmc_state = HIOMAP_E_DAEMON_READY } },
544 	{ .type = scenario_sel, .s = { .bmc_state = HIOMAP_E_PROTOCOL_RESET } },
545 	{ .type = scenario_sel, .s = { .bmc_state = HIOMAP_E_DAEMON_READY } },
546 	SCENARIO_SENTINEL,
547 };
548 
test_hiomap_event_daemon_restarted(void)549 static void test_hiomap_event_daemon_restarted(void)
550 {
551 	struct blocklevel_device *bl;
552 	struct ipmi_hiomap *ctx;
553 
554 	scenario_enter(scenario_hiomap_event_daemon_restarted);
555 	assert(!ipmi_hiomap_init(&bl));
556 	ctx = container_of(bl, struct ipmi_hiomap, bl);
557 	assert(ctx->bmc_state == (HIOMAP_E_DAEMON_READY | HIOMAP_E_PROTOCOL_RESET));
558 	ipmi_hiomap_exit(bl);
559 	scenario_exit();
560 }
561 
562 static const struct scenario_event
563 scenario_hiomap_event_daemon_lost_flash_control[] = {
564 	{ .type = scenario_event_p, .p = &hiomap_ack_call, },
565 	{ .type = scenario_event_p, .p = &hiomap_get_info_call, },
566 	{ .type = scenario_event_p, .p = &hiomap_get_flash_info_call, },
567 	{ .type = scenario_sel, .s = { .bmc_state = HIOMAP_E_DAEMON_READY } },
568 	{
569 		.type = scenario_sel,
570 		.s = {
571 			.bmc_state = (HIOMAP_E_DAEMON_READY
572 					| HIOMAP_E_FLASH_LOST),
573 		}
574 	},
575 	SCENARIO_SENTINEL,
576 };
577 
test_hiomap_event_daemon_lost_flash_control(void)578 static void test_hiomap_event_daemon_lost_flash_control(void)
579 {
580 	struct blocklevel_device *bl;
581 	size_t len = 2 * (1 << 12);
582 	void *buf;
583 
584 	buf = malloc(len);
585 	assert(buf);
586 
587 	scenario_enter(scenario_hiomap_event_daemon_lost_flash_control);
588 	assert(!ipmi_hiomap_init(&bl));
589 	assert(bl->read(bl, 0, buf, len) == FLASH_ERR_AGAIN);
590 	ipmi_hiomap_exit(bl);
591 	scenario_exit();
592 
593 	free(buf);
594 }
595 
596 static const struct scenario_event
597 scenario_hiomap_event_daemon_regained_flash_control_dirty[] = {
598 	{ .type = scenario_event_p, .p = &hiomap_ack_call, },
599 	{ .type = scenario_event_p, .p = &hiomap_get_info_call, },
600 	{ .type = scenario_event_p, .p = &hiomap_get_flash_info_call, },
601 	{ .type = scenario_sel, .s = { .bmc_state = HIOMAP_E_DAEMON_READY } },
602 	{
603 		.type = scenario_cmd,
604 		.c = {
605 			.req = {
606 				.cmd = HIOMAP_C_CREATE_READ_WINDOW,
607 				.seq = 4,
608 				.args = {
609 					[0] = 0x00, [1] = 0x00,
610 					[2] = 0x02, [3] = 0x00,
611 				},
612 			},
613 			.cc = IPMI_CC_NO_ERROR,
614 			.resp = {
615 				.cmd = HIOMAP_C_CREATE_READ_WINDOW,
616 				.seq = 4,
617 				.args = {
618 					[0] = 0xfe, [1] = 0x0f,
619 					[2] = 0x02, [3] = 0x00,
620 					[4] = 0x00, [5] = 0x00,
621 				},
622 			},
623 		},
624 	},
625 	{
626 		.type = scenario_delay
627 	},
628 	{
629 		.type = scenario_sel,
630 		.s = {
631 			.bmc_state = (HIOMAP_E_DAEMON_READY
632 					| HIOMAP_E_FLASH_LOST),
633 		}
634 	},
635 	{
636 		.type = scenario_sel,
637 		.s = {
638 			.bmc_state = (HIOMAP_E_DAEMON_READY
639 					| HIOMAP_E_WINDOW_RESET),
640 		}
641 	},
642 	{
643 		.type = scenario_cmd,
644 		.c = {
645 			.req = {
646 				.cmd = HIOMAP_C_ACK,
647 				.seq = 5,
648 				.args = { [0] = HIOMAP_E_WINDOW_RESET },
649 			},
650 			.cc = IPMI_CC_NO_ERROR,
651 			.resp = {
652 				.cmd = HIOMAP_C_ACK,
653 				.seq = 5,
654 			}
655 		}
656 	},
657 	{
658 		.type = scenario_cmd,
659 		.c = {
660 			.req = {
661 				.cmd = HIOMAP_C_CREATE_READ_WINDOW,
662 				.seq = 6,
663 				.args = {
664 					[0] = 0x00, [1] = 0x00,
665 					[2] = 0x02, [3] = 0x00,
666 				},
667 			},
668 			.cc = IPMI_CC_NO_ERROR,
669 			.resp = {
670 				.cmd = HIOMAP_C_CREATE_READ_WINDOW,
671 				.seq = 6,
672 				.args = {
673 					[0] = 0xfe, [1] = 0x0f,
674 					[2] = 0x02, [3] = 0x00,
675 					[4] = 0x00, [5] = 0x00,
676 				},
677 			},
678 		},
679 	},
680 	SCENARIO_SENTINEL,
681 };
682 
test_hiomap_event_daemon_regained_flash_control_dirty(void)683 static void test_hiomap_event_daemon_regained_flash_control_dirty(void)
684 {
685 	struct blocklevel_device *bl;
686 	size_t len = 2 * (1 << 12);
687 	void *buf;
688 
689 	buf = malloc(len);
690 	assert(buf);
691 
692 	scenario_enter(scenario_hiomap_event_daemon_regained_flash_control_dirty);
693 	assert(!ipmi_hiomap_init(&bl));
694 	assert(!bl->read(bl, 0, buf, len));
695 	scenario_advance();
696 	assert(!bl->read(bl, 0, buf, len));
697 	ipmi_hiomap_exit(bl);
698 	scenario_exit();
699 
700 	free(buf);
701 }
702 
703 static const struct scenario_event scenario_hiomap_protocol_reset_recovery[] = {
704 	{ .type = scenario_event_p, .p = &hiomap_ack_call, },
705 	{ .type = scenario_event_p, .p = &hiomap_get_info_call, },
706 	{ .type = scenario_event_p, .p = &hiomap_get_flash_info_call, },
707 	{ .type = scenario_sel, .s = { .bmc_state = HIOMAP_E_DAEMON_READY } },
708 	{
709 		.type = scenario_cmd,
710 		.c = {
711 			.req = {
712 				.cmd = HIOMAP_C_CREATE_READ_WINDOW,
713 				.seq = 4,
714 				.args = {
715 					[0] = 0x00, [1] = 0x00,
716 					[2] = 0x02, [3] = 0x00,
717 				},
718 			},
719 			.cc = IPMI_CC_NO_ERROR,
720 			.resp = {
721 				.cmd = HIOMAP_C_CREATE_READ_WINDOW,
722 				.seq = 4,
723 				.args = {
724 					[0] = 0xfe, [1] = 0x0f,
725 					[2] = 0x02, [3] = 0x00,
726 					[4] = 0x00, [5] = 0x00,
727 				},
728 			},
729 		},
730 	},
731 	{
732 		.type = scenario_delay
733 	},
734 	{
735 		.type = scenario_sel,
736 		.s = { .bmc_state = HIOMAP_E_PROTOCOL_RESET, }
737 	},
738 	{
739 		.type = scenario_sel,
740 		.s = { .bmc_state = HIOMAP_E_DAEMON_READY, }
741 	},
742 	{
743 		.type = scenario_cmd,
744 		.c = {
745 			.req = {
746 				.cmd = HIOMAP_C_ACK,
747 				.seq = 5,
748 				.args = { [0] = HIOMAP_E_PROTOCOL_RESET },
749 			},
750 			.cc = IPMI_CC_NO_ERROR,
751 			.resp = {
752 				.cmd = HIOMAP_C_ACK,
753 				.seq = 5,
754 			}
755 		}
756 	},
757 	{
758 		.type = scenario_cmd,
759 		.c = {
760 			.req = {
761 				.cmd = HIOMAP_C_GET_INFO,
762 				.seq = 6,
763 				.args = {
764 					[0] = HIOMAP_V2,
765 				},
766 			},
767 			.cc = IPMI_CC_NO_ERROR,
768 			.resp = {
769 				.cmd = HIOMAP_C_GET_INFO,
770 				.seq = 6,
771 				.args = {
772 					[0] = HIOMAP_V2,
773 					[1] = 12,
774 					[2] = 8, [3] = 0,
775 				},
776 			},
777 		},
778 	},
779 	{
780 		.type = scenario_cmd,
781 		.c = {
782 			.req = {
783 				.cmd = HIOMAP_C_GET_FLASH_INFO,
784 				.seq = 7,
785 				.args = {
786 				},
787 			},
788 			.cc = IPMI_CC_NO_ERROR,
789 			.resp = {
790 				.cmd = HIOMAP_C_GET_FLASH_INFO,
791 				.seq = 7,
792 				.args = {
793 					[0] = 0x00, [1] = 0x20,
794 					[2] = 0x01, [3] = 0x00,
795 				},
796 			},
797 		},
798 	},
799 	{
800 		.type = scenario_cmd,
801 		.c = {
802 			.req = {
803 				.cmd = HIOMAP_C_CREATE_READ_WINDOW,
804 				.seq = 8,
805 				.args = {
806 					[0] = 0x00, [1] = 0x00,
807 					[2] = 0x02, [3] = 0x00,
808 				},
809 			},
810 			.cc = IPMI_CC_NO_ERROR,
811 			.resp = {
812 				.cmd = HIOMAP_C_CREATE_READ_WINDOW,
813 				.seq = 8,
814 				.args = {
815 					[0] = 0xfe, [1] = 0x0f,
816 					[2] = 0x02, [3] = 0x00,
817 					[4] = 0x00, [5] = 0x00,
818 				},
819 			},
820 		},
821 	},
822 	SCENARIO_SENTINEL,
823 };
824 
test_hiomap_protocol_reset_recovery(void)825 static void test_hiomap_protocol_reset_recovery(void)
826 {
827 	struct blocklevel_device *bl;
828 	size_t len = 2 * (1 << 12);
829 	void *buf;
830 
831 	buf = malloc(len);
832 	assert(buf);
833 
834 	scenario_enter(scenario_hiomap_protocol_reset_recovery);
835 	assert(!ipmi_hiomap_init(&bl));
836 	assert(!bl->read(bl, 0, buf, len));
837 	scenario_advance();
838 	assert(!bl->read(bl, 0, buf, len));
839 	ipmi_hiomap_exit(bl);
840 	scenario_exit();
841 
842 	free(buf);
843 }
844 
845 static const struct scenario_event
846 scenario_hiomap_protocol_read_one_block[] = {
847 	{ .type = scenario_event_p, .p = &hiomap_ack_call, },
848 	{ .type = scenario_event_p, .p = &hiomap_get_info_call, },
849 	{ .type = scenario_event_p, .p = &hiomap_get_flash_info_call, },
850 	{
851 		.type = scenario_event_p,
852 		.p = &hiomap_create_read_window_qs0l1_rs0l1_call,
853 	},
854 	SCENARIO_SENTINEL,
855 };
856 
test_hiomap_protocol_read_one_block(void)857 static void test_hiomap_protocol_read_one_block(void)
858 {
859 	struct blocklevel_device *bl;
860 	struct ipmi_hiomap *ctx;
861 	uint8_t *buf;
862 	size_t len;
863 
864 	scenario_enter(scenario_hiomap_protocol_read_one_block);
865 	assert(!ipmi_hiomap_init(&bl));
866 	ctx = container_of(bl, struct ipmi_hiomap, bl);
867 	len = 1 << ctx->block_size_shift;
868 	buf = calloc(1, len);
869 	assert(buf);
870 	assert(!bl->read(bl, 0, buf, len));
871 	assert(lpc_read_success(buf, len));
872 	free(buf);
873 	ipmi_hiomap_exit(bl);
874 	scenario_exit();
875 }
876 
test_hiomap_protocol_read_one_byte(void)877 static void test_hiomap_protocol_read_one_byte(void)
878 {
879 	struct blocklevel_device *bl;
880 	uint8_t *buf;
881 	size_t len;
882 
883 	scenario_enter(scenario_hiomap_protocol_read_one_block);
884 	assert(!ipmi_hiomap_init(&bl));
885 	len = 1;
886 	buf = calloc(1, len);
887 	assert(buf);
888 	assert(!bl->read(bl, 0, buf, len));
889 	assert(lpc_read_success(buf, len));
890 	free(buf);
891 	ipmi_hiomap_exit(bl);
892 	scenario_exit();
893 }
894 
895 static const struct scenario_event
896 scenario_hiomap_protocol_read_two_blocks[] = {
897 	{ .type = scenario_event_p, .p = &hiomap_ack_call, },
898 	{ .type = scenario_event_p, .p = &hiomap_get_info_call, },
899 	{ .type = scenario_event_p, .p = &hiomap_get_flash_info_call, },
900 	{
901 		.type = scenario_event_p,
902 		.p = &hiomap_create_read_window_qs0l2_rs0l1_call,
903 	},
904 	{
905 		.type = scenario_cmd,
906 		.c = {
907 			.req = {
908 				.cmd = HIOMAP_C_CREATE_READ_WINDOW,
909 				.seq = 5,
910 				.args = {
911 					[0] = 0x01, [1] = 0x00,
912 					[2] = 0x01, [3] = 0x00,
913 				},
914 			},
915 			.cc = IPMI_CC_NO_ERROR,
916 			.resp = {
917 				.cmd = HIOMAP_C_CREATE_READ_WINDOW,
918 				.seq = 5,
919 				.args = {
920 					[0] = 0xfe, [1] = 0x0f,
921 					[2] = 0x01, [3] = 0x00,
922 					[4] = 0x01, [5] = 0x00,
923 				},
924 			},
925 		},
926 	},
927 	SCENARIO_SENTINEL,
928 };
929 
test_hiomap_protocol_read_two_blocks(void)930 static void test_hiomap_protocol_read_two_blocks(void)
931 {
932 	struct blocklevel_device *bl;
933 	struct ipmi_hiomap *ctx;
934 	uint8_t *buf;
935 	size_t len;
936 
937 	scenario_enter(scenario_hiomap_protocol_read_two_blocks);
938 	assert(!ipmi_hiomap_init(&bl));
939 	ctx = container_of(bl, struct ipmi_hiomap, bl);
940 	len = 2 * (1 << ctx->block_size_shift);
941 	buf = calloc(1, len);
942 	assert(buf);
943 	assert(!bl->read(bl, 0, buf, len));
944 	assert(lpc_read_success(buf, len));
945 	free(buf);
946 	ipmi_hiomap_exit(bl);
947 	scenario_exit();
948 }
949 
test_hiomap_protocol_read_1block_1byte(void)950 static void test_hiomap_protocol_read_1block_1byte(void)
951 {
952 	struct blocklevel_device *bl;
953 	struct ipmi_hiomap *ctx;
954 	uint8_t *buf;
955 	size_t len;
956 
957 	scenario_enter(scenario_hiomap_protocol_read_two_blocks);
958 	assert(!ipmi_hiomap_init(&bl));
959 	ctx = container_of(bl, struct ipmi_hiomap, bl);
960 	len = (1 << ctx->block_size_shift) + 1;
961 	buf = calloc(1, len);
962 	assert(buf);
963 	assert(!bl->read(bl, 0, buf, len));
964 	assert(lpc_read_success(buf, len));
965 	free(buf);
966 	ipmi_hiomap_exit(bl);
967 	scenario_exit();
968 }
969 
970 static const struct scenario_event
971 scenario_hiomap_protocol_read_one_block_twice[] = {
972 	{ .type = scenario_event_p, .p = &hiomap_ack_call, },
973 	{ .type = scenario_event_p, .p = &hiomap_get_info_call, },
974 	{ .type = scenario_event_p, .p = &hiomap_get_flash_info_call, },
975 	{
976 		.type = scenario_event_p,
977 		.p = &hiomap_create_read_window_qs0l1_rs0l1_call,
978 	},
979 	SCENARIO_SENTINEL,
980 };
981 
test_hiomap_protocol_read_one_block_twice(void)982 static void test_hiomap_protocol_read_one_block_twice(void)
983 {
984 	struct blocklevel_device *bl;
985 	struct ipmi_hiomap *ctx;
986 	uint8_t *buf;
987 	size_t len;
988 
989 	scenario_enter(scenario_hiomap_protocol_read_one_block_twice);
990 	assert(!ipmi_hiomap_init(&bl));
991 	ctx = container_of(bl, struct ipmi_hiomap, bl);
992 	len = 1 << ctx->block_size_shift;
993 	buf = calloc(1, len);
994 	assert(buf);
995 	assert(!bl->read(bl, 0, buf, len));
996 	assert(!bl->read(bl, 0, buf, len));
997 	free(buf);
998 	ipmi_hiomap_exit(bl);
999 	scenario_exit();
1000 }
1001 
1002 static const struct scenario_event
1003 scenario_hiomap_protocol_event_before_action[] = {
1004 	{ .type = scenario_event_p, .p = &hiomap_ack_call, },
1005 	{ .type = scenario_event_p, .p = &hiomap_get_info_call, },
1006 	{ .type = scenario_event_p, .p = &hiomap_get_flash_info_call, },
1007 	{
1008 		.type = scenario_sel,
1009 		.s = {
1010 			.bmc_state = HIOMAP_E_DAEMON_READY |
1011 					HIOMAP_E_FLASH_LOST,
1012 		}
1013 	},
1014 	SCENARIO_SENTINEL,
1015 };
1016 
test_hiomap_protocol_event_before_read(void)1017 static void test_hiomap_protocol_event_before_read(void)
1018 {
1019 	struct blocklevel_device *bl;
1020 	char buf;
1021 	int rc;
1022 
1023 	scenario_enter(scenario_hiomap_protocol_event_before_action);
1024 	assert(!ipmi_hiomap_init(&bl));
1025 	rc = bl->read(bl, 0, &buf, sizeof(buf));
1026 	assert(rc == FLASH_ERR_AGAIN);
1027 	ipmi_hiomap_exit(bl);
1028 	scenario_exit();
1029 }
1030 
1031 static const struct scenario_event
1032 scenario_hiomap_protocol_event_during_read[] = {
1033 	{ .type = scenario_event_p, .p = &hiomap_ack_call, },
1034 	{ .type = scenario_event_p, .p = &hiomap_get_info_call, },
1035 	{ .type = scenario_event_p, .p = &hiomap_get_flash_info_call, },
1036 	{
1037 		.type = scenario_event_p,
1038 		.p = &hiomap_create_read_window_qs0l1_rs0l1_call,
1039 	},
1040 	{
1041 		.type = scenario_sel,
1042 		.s = {
1043 			.bmc_state = HIOMAP_E_DAEMON_READY |
1044 					HIOMAP_E_FLASH_LOST,
1045 		}
1046 	},
1047 	SCENARIO_SENTINEL,
1048 };
1049 
test_hiomap_protocol_event_during_read(void)1050 static void test_hiomap_protocol_event_during_read(void)
1051 {
1052 	struct blocklevel_device *bl;
1053 	struct ipmi_hiomap *ctx;
1054 	uint8_t *buf;
1055 	size_t len;
1056 	int rc;
1057 
1058 	scenario_enter(scenario_hiomap_protocol_event_during_read);
1059 	assert(!ipmi_hiomap_init(&bl));
1060 	ctx = container_of(bl, struct ipmi_hiomap, bl);
1061 	len = 1 << ctx->block_size_shift;
1062 	buf = calloc(1, len);
1063 	assert(buf);
1064 	rc = bl->read(bl, 0, buf, len);
1065 	assert(rc == FLASH_ERR_AGAIN);
1066 	free(buf);
1067 	ipmi_hiomap_exit(bl);
1068 	scenario_exit();
1069 }
1070 
1071 static const struct scenario_event
1072 scenario_hiomap_protocol_write_one_block[] = {
1073 	{ .type = scenario_event_p, .p = &hiomap_ack_call, },
1074 	{ .type = scenario_event_p, .p = &hiomap_get_info_call, },
1075 	{ .type = scenario_event_p, .p = &hiomap_get_flash_info_call, },
1076 	{
1077 		.type = scenario_event_p,
1078 		.p = &hiomap_create_write_window_qs0l1_rs0l1_call,
1079 	},
1080 	{ .type = scenario_event_p, .p = &hiomap_mark_dirty_qs0l1_call, },
1081 	{ .type = scenario_event_p, .p = &hiomap_flush_call, },
1082 	SCENARIO_SENTINEL,
1083 };
1084 
test_hiomap_protocol_write_one_block(void)1085 static void test_hiomap_protocol_write_one_block(void)
1086 {
1087 	struct blocklevel_device *bl;
1088 	struct ipmi_hiomap *ctx;
1089 	uint8_t *buf;
1090 	size_t len;
1091 
1092 	scenario_enter(scenario_hiomap_protocol_write_one_block);
1093 	assert(!ipmi_hiomap_init(&bl));
1094 	ctx = container_of(bl, struct ipmi_hiomap, bl);
1095 	len = 1 << ctx->block_size_shift;
1096 	buf = calloc(1, len);
1097 	assert(buf);
1098 	assert(!bl->write(bl, 0, buf, len));
1099 	free(buf);
1100 	ipmi_hiomap_exit(bl);
1101 	scenario_exit();
1102 }
1103 
test_hiomap_protocol_write_one_byte(void)1104 static void test_hiomap_protocol_write_one_byte(void)
1105 {
1106 	struct blocklevel_device *bl;
1107 	uint8_t *buf;
1108 	size_t len;
1109 
1110 	scenario_enter(scenario_hiomap_protocol_write_one_block);
1111 	assert(!ipmi_hiomap_init(&bl));
1112 	len = 1;
1113 	buf = calloc(1, len);
1114 	assert(buf);
1115 	assert(!bl->write(bl, 0, buf, len));
1116 	free(buf);
1117 	ipmi_hiomap_exit(bl);
1118 	scenario_exit();
1119 }
1120 
1121 static const struct scenario_event
1122 scenario_hiomap_protocol_write_two_blocks[] = {
1123 	{ .type = scenario_event_p, .p = &hiomap_ack_call, },
1124 	{ .type = scenario_event_p, .p = &hiomap_get_info_call, },
1125 	{ .type = scenario_event_p, .p = &hiomap_get_flash_info_call, },
1126 	{
1127 		.type = scenario_event_p,
1128 		.p = &hiomap_create_write_window_qs0l2_rs0l1_call,
1129 	},
1130 	{ .type = scenario_event_p, .p = &hiomap_mark_dirty_qs0l1_call, },
1131 	{ .type = scenario_event_p, .p = &hiomap_flush_call, },
1132 	{
1133 		.type = scenario_event_p,
1134 		.p = &hiomap_create_write_window_qs1l1_rs1l1_call,
1135 	},
1136 	{
1137 		.type = scenario_cmd,
1138 		.c = {
1139 			.req = {
1140 				.cmd = HIOMAP_C_MARK_DIRTY,
1141 				.seq = 8,
1142 				.args = {
1143 					[0] = 0x00, [1] = 0x00,
1144 					[2] = 0x01, [3] = 0x00,
1145 				},
1146 			},
1147 			.resp = {
1148 				.cmd = HIOMAP_C_MARK_DIRTY,
1149 				.seq = 8,
1150 			},
1151 		},
1152 	},
1153 	{
1154 		.type = scenario_cmd,
1155 		.c = {
1156 			.req = {
1157 				.cmd = HIOMAP_C_FLUSH,
1158 				.seq = 9,
1159 			},
1160 			.resp = {
1161 				.cmd = HIOMAP_C_FLUSH,
1162 				.seq = 9,
1163 			},
1164 		},
1165 	},
1166 	SCENARIO_SENTINEL,
1167 };
1168 
test_hiomap_protocol_write_two_blocks(void)1169 static void test_hiomap_protocol_write_two_blocks(void)
1170 {
1171 	struct blocklevel_device *bl;
1172 	struct ipmi_hiomap *ctx;
1173 	uint8_t *buf;
1174 	size_t len;
1175 
1176 	scenario_enter(scenario_hiomap_protocol_write_two_blocks);
1177 	assert(!ipmi_hiomap_init(&bl));
1178 	ctx = container_of(bl, struct ipmi_hiomap, bl);
1179 	len = 2 * (1 << ctx->block_size_shift);
1180 	buf = calloc(1, len);
1181 	assert(buf);
1182 	assert(!bl->write(bl, 0, buf, len));
1183 	free(buf);
1184 	ipmi_hiomap_exit(bl);
1185 	scenario_exit();
1186 }
1187 
test_hiomap_protocol_write_1block_1byte(void)1188 static void test_hiomap_protocol_write_1block_1byte(void)
1189 {
1190 	struct blocklevel_device *bl;
1191 	struct ipmi_hiomap *ctx;
1192 	uint8_t *buf;
1193 	size_t len;
1194 
1195 	scenario_enter(scenario_hiomap_protocol_write_two_blocks);
1196 	assert(!ipmi_hiomap_init(&bl));
1197 	ctx = container_of(bl, struct ipmi_hiomap, bl);
1198 	len =  (1 << ctx->block_size_shift) + 1;
1199 	buf = calloc(1, len);
1200 	assert(buf);
1201 	assert(!bl->write(bl, 0, buf, len));
1202 	free(buf);
1203 	ipmi_hiomap_exit(bl);
1204 	scenario_exit();
1205 }
1206 
1207 static const struct scenario_event
1208 scenario_hiomap_protocol_write_one_block_twice[] = {
1209 	{ .type = scenario_event_p, .p = &hiomap_ack_call, },
1210 	{ .type = scenario_event_p, .p = &hiomap_get_info_call, },
1211 	{ .type = scenario_event_p, .p = &hiomap_get_flash_info_call, },
1212 	{
1213 		.type = scenario_event_p,
1214 		.p = &hiomap_create_write_window_qs0l1_rs0l1_call,
1215 	},
1216 	{ .type = scenario_event_p, .p = &hiomap_mark_dirty_qs0l1_call, },
1217 	{ .type = scenario_event_p, .p = &hiomap_flush_call, },
1218 	{
1219 		.type = scenario_cmd,
1220 		.c = {
1221 			.req = {
1222 				.cmd = HIOMAP_C_MARK_DIRTY,
1223 				.seq = 7,
1224 				.args = {
1225 					[0] = 0x00, [1] = 0x00,
1226 					[2] = 0x01, [3] = 0x00,
1227 				},
1228 			},
1229 			.resp = {
1230 				.cmd = HIOMAP_C_MARK_DIRTY,
1231 				.seq = 7,
1232 			},
1233 		},
1234 	},
1235 	{
1236 		.type = scenario_cmd,
1237 		.c = {
1238 			.req = {
1239 				.cmd = HIOMAP_C_FLUSH,
1240 				.seq = 8,
1241 			},
1242 			.resp = {
1243 				.cmd = HIOMAP_C_FLUSH,
1244 				.seq = 8,
1245 			},
1246 		},
1247 	},
1248 	SCENARIO_SENTINEL,
1249 };
1250 
test_hiomap_protocol_write_one_block_twice(void)1251 static void test_hiomap_protocol_write_one_block_twice(void)
1252 {
1253 	struct blocklevel_device *bl;
1254 	struct ipmi_hiomap *ctx;
1255 	uint8_t *buf;
1256 	size_t len;
1257 
1258 	scenario_enter(scenario_hiomap_protocol_write_one_block_twice);
1259 	assert(!ipmi_hiomap_init(&bl));
1260 	ctx = container_of(bl, struct ipmi_hiomap, bl);
1261 	len = 1 << ctx->block_size_shift;
1262 	buf = calloc(1, len);
1263 	assert(buf);
1264 	assert(!bl->write(bl, 0, buf, len));
1265 	assert(!bl->write(bl, 0, buf, len));
1266 	free(buf);
1267 	ipmi_hiomap_exit(bl);
1268 	scenario_exit();
1269 }
1270 
test_hiomap_protocol_event_before_write(void)1271 static void test_hiomap_protocol_event_before_write(void)
1272 {
1273 	struct blocklevel_device *bl;
1274 	char buf;
1275 	int rc;
1276 
1277 	scenario_enter(scenario_hiomap_protocol_event_before_action);
1278 	assert(!ipmi_hiomap_init(&bl));
1279 	rc = bl->write(bl, 0, &buf, sizeof(buf));
1280 	assert(rc == FLASH_ERR_AGAIN);
1281 	ipmi_hiomap_exit(bl);
1282 	scenario_exit();
1283 }
1284 
1285 static const struct scenario_event
1286 scenario_hiomap_protocol_event_during_write[] = {
1287 	{ .type = scenario_event_p, .p = &hiomap_ack_call, },
1288 	{ .type = scenario_event_p, .p = &hiomap_get_info_call, },
1289 	{ .type = scenario_event_p, .p = &hiomap_get_flash_info_call, },
1290 	{
1291 		.type = scenario_event_p,
1292 		.p = &hiomap_create_write_window_qs0l1_rs0l1_call,
1293 	},
1294 	{
1295 		.type = scenario_sel,
1296 		.s = {
1297 			.bmc_state = HIOMAP_E_DAEMON_READY |
1298 					HIOMAP_E_FLASH_LOST,
1299 		}
1300 	},
1301 	SCENARIO_SENTINEL,
1302 };
1303 
test_hiomap_protocol_event_during_write(void)1304 static void test_hiomap_protocol_event_during_write(void)
1305 {
1306 	struct blocklevel_device *bl;
1307 	struct ipmi_hiomap *ctx;
1308 	size_t len;
1309 	char *buf;
1310 	int rc;
1311 
1312 	scenario_enter(scenario_hiomap_protocol_event_during_write);
1313 	assert(!ipmi_hiomap_init(&bl));
1314 	ctx = container_of(bl, struct ipmi_hiomap, bl);
1315 	len = 1 << ctx->block_size_shift;
1316 	buf = calloc(1, len);
1317 	assert(buf);
1318 	rc = bl->write(bl, 0, buf, len);
1319 	free(buf);
1320 	assert(rc == FLASH_ERR_AGAIN);
1321 	ipmi_hiomap_exit(bl);
1322 	scenario_exit();
1323 }
1324 
1325 static const struct scenario_event
1326 scenario_hiomap_protocol_erase_one_block[] = {
1327 	{ .type = scenario_event_p, .p = &hiomap_ack_call, },
1328 	{ .type = scenario_event_p, .p = &hiomap_get_info_call, },
1329 	{ .type = scenario_event_p, .p = &hiomap_get_flash_info_call, },
1330 	{
1331 		.type = scenario_event_p,
1332 		.p = &hiomap_create_write_window_qs0l1_rs0l1_call,
1333 	},
1334 	{
1335 		.type = scenario_event_p,
1336 		.p = &hiomap_erase_qs0l1_call,
1337 	},
1338 	{
1339 		.type = scenario_event_p,
1340 		.p = &hiomap_flush_call,
1341 	},
1342 	SCENARIO_SENTINEL,
1343 };
1344 
1345 static const struct scenario_event
1346 scenario_hiomap_protocol_erase_two_blocks[] = {
1347 	{ .type = scenario_event_p, .p = &hiomap_ack_call, },
1348 	{ .type = scenario_event_p, .p = &hiomap_get_info_call, },
1349 	{ .type = scenario_event_p, .p = &hiomap_get_flash_info_call, },
1350 	{
1351 		.type = scenario_event_p,
1352 		.p = &hiomap_create_write_window_qs0l2_rs0l1_call,
1353 	},
1354 	{ .type = scenario_event_p, .p = &hiomap_erase_qs0l1_call, },
1355 	{ .type = scenario_event_p, .p = &hiomap_flush_call, },
1356 	{
1357 		.type = scenario_event_p,
1358 		.p = &hiomap_create_write_window_qs1l1_rs1l1_call,
1359 	},
1360 	{
1361 		.type = scenario_cmd,
1362 		.c = {
1363 			.req = {
1364 				.cmd = HIOMAP_C_ERASE,
1365 				.seq = 8,
1366 				.args = {
1367 					[0] = 0x00, [1] = 0x00,
1368 					[2] = 0x01, [3] = 0x00,
1369 				},
1370 			},
1371 			.resp = {
1372 				.cmd = HIOMAP_C_ERASE,
1373 				.seq = 8,
1374 			},
1375 		},
1376 	},
1377 	{
1378 		.type = scenario_cmd,
1379 		.c = {
1380 			.req = {
1381 				.cmd = HIOMAP_C_FLUSH,
1382 				.seq = 9,
1383 			},
1384 			.resp = {
1385 				.cmd = HIOMAP_C_FLUSH,
1386 				.seq = 9,
1387 			},
1388 		},
1389 	},
1390 	SCENARIO_SENTINEL,
1391 };
1392 
test_hiomap_protocol_erase_two_blocks(void)1393 static void test_hiomap_protocol_erase_two_blocks(void)
1394 {
1395 	struct blocklevel_device *bl;
1396 	struct ipmi_hiomap *ctx;
1397 	size_t len;
1398 
1399 	scenario_enter(scenario_hiomap_protocol_erase_two_blocks);
1400 	assert(!ipmi_hiomap_init(&bl));
1401 	ctx = container_of(bl, struct ipmi_hiomap, bl);
1402 	len = 2 * (1 << ctx->block_size_shift);
1403 	assert(!bl->erase(bl, 0, len));
1404 	ipmi_hiomap_exit(bl);
1405 	scenario_exit();
1406 }
1407 
1408 static const struct scenario_event
1409 scenario_hiomap_protocol_erase_one_block_twice[] = {
1410 	{ .type = scenario_event_p, .p = &hiomap_ack_call, },
1411 	{ .type = scenario_event_p, .p = &hiomap_get_info_call, },
1412 	{ .type = scenario_event_p, .p = &hiomap_get_flash_info_call, },
1413 	{
1414 		.type = scenario_event_p,
1415 		.p = &hiomap_create_write_window_qs0l1_rs0l1_call,
1416 	},
1417 	{ .type = scenario_event_p, .p = &hiomap_erase_qs0l1_call, },
1418 	{ .type = scenario_event_p, .p = &hiomap_flush_call, },
1419 	{
1420 		.type = scenario_cmd,
1421 		.c = {
1422 			.req = {
1423 				.cmd = HIOMAP_C_ERASE,
1424 				.seq = 7,
1425 				.args = {
1426 					[0] = 0x00, [1] = 0x00,
1427 					[2] = 0x01, [3] = 0x00,
1428 				},
1429 			},
1430 			.resp = {
1431 				.cmd = HIOMAP_C_ERASE,
1432 				.seq = 7,
1433 			},
1434 		},
1435 	},
1436 	{
1437 		.type = scenario_cmd,
1438 		.c = {
1439 			.req = {
1440 				.cmd = HIOMAP_C_FLUSH,
1441 				.seq = 8,
1442 			},
1443 			.resp = {
1444 				.cmd = HIOMAP_C_FLUSH,
1445 				.seq = 8,
1446 			},
1447 		},
1448 	},
1449 	SCENARIO_SENTINEL,
1450 };
1451 
test_hiomap_protocol_erase_one_block_twice(void)1452 static void test_hiomap_protocol_erase_one_block_twice(void)
1453 {
1454 	struct blocklevel_device *bl;
1455 	struct ipmi_hiomap *ctx;
1456 	size_t len;
1457 
1458 	scenario_enter(scenario_hiomap_protocol_erase_one_block_twice);
1459 	assert(!ipmi_hiomap_init(&bl));
1460 	ctx = container_of(bl, struct ipmi_hiomap, bl);
1461 	len = 1 << ctx->block_size_shift;
1462 	assert(!bl->erase(bl, 0, len));
1463 	assert(!bl->erase(bl, 0, len));
1464 	ipmi_hiomap_exit(bl);
1465 	scenario_exit();
1466 }
1467 
test_hiomap_protocol_erase_one_block(void)1468 static void test_hiomap_protocol_erase_one_block(void)
1469 {
1470 	struct blocklevel_device *bl;
1471 	struct ipmi_hiomap *ctx;
1472 	size_t len;
1473 
1474 	scenario_enter(scenario_hiomap_protocol_erase_one_block);
1475 	assert(!ipmi_hiomap_init(&bl));
1476 	ctx = container_of(bl, struct ipmi_hiomap, bl);
1477 	len = 1 << ctx->block_size_shift;
1478 	assert(!bl->erase(bl, 0, len));
1479 	ipmi_hiomap_exit(bl);
1480 	scenario_exit();
1481 }
1482 
test_hiomap_protocol_event_before_erase(void)1483 static void test_hiomap_protocol_event_before_erase(void)
1484 {
1485 	struct blocklevel_device *bl;
1486 	struct ipmi_hiomap *ctx;
1487 	size_t len;
1488 	int rc;
1489 
1490 	scenario_enter(scenario_hiomap_protocol_event_before_action);
1491 	assert(!ipmi_hiomap_init(&bl));
1492 	ctx = container_of(bl, struct ipmi_hiomap, bl);
1493 	len = 1 << ctx->block_size_shift;
1494 	rc = bl->erase(bl, 0, len);
1495 	assert(rc == FLASH_ERR_AGAIN);
1496 	ipmi_hiomap_exit(bl);
1497 	scenario_exit();
1498 }
1499 
1500 static const struct scenario_event
1501 scenario_hiomap_protocol_event_during_erase[] = {
1502 	{ .type = scenario_event_p, .p = &hiomap_ack_call, },
1503 	{ .type = scenario_event_p, .p = &hiomap_get_info_call, },
1504 	{ .type = scenario_event_p, .p = &hiomap_get_flash_info_call, },
1505 	{
1506 		.type = scenario_event_p,
1507 		.p = &hiomap_create_write_window_qs0l1_rs0l1_call,
1508 	},
1509 	{
1510 		.type = scenario_sel,
1511 		.s = {
1512 			.bmc_state = HIOMAP_E_DAEMON_READY |
1513 					HIOMAP_E_FLASH_LOST,
1514 		}
1515 	},
1516 	SCENARIO_SENTINEL,
1517 };
1518 
test_hiomap_protocol_event_during_erase(void)1519 static void test_hiomap_protocol_event_during_erase(void)
1520 {
1521 	struct blocklevel_device *bl;
1522 	struct ipmi_hiomap *ctx;
1523 	size_t len;
1524 	int rc;
1525 
1526 	scenario_enter(scenario_hiomap_protocol_event_during_erase);
1527 	assert(!ipmi_hiomap_init(&bl));
1528 	ctx = container_of(bl, struct ipmi_hiomap, bl);
1529 	len = 1 << ctx->block_size_shift;
1530 	rc = bl->erase(bl, 0, len);
1531 	assert(rc == FLASH_ERR_AGAIN);
1532 	ipmi_hiomap_exit(bl);
1533 	scenario_exit();
1534 }
1535 
1536 static const struct scenario_event scenario_hiomap_protocol_bad_sequence[] = {
1537 	{
1538 		.type = scenario_cmd,
1539 		.c = {
1540 			.req = {
1541 				.cmd = HIOMAP_C_ACK,
1542 				.seq = 1,
1543 				.args = {
1544 					[0] = HIOMAP_E_ACK_MASK,
1545 				},
1546 			},
1547 			.cc = IPMI_CC_NO_ERROR,
1548 			.resp = {
1549 				.cmd = HIOMAP_C_ACK,
1550 				.seq = 0,
1551 			},
1552 		},
1553 	},
1554 	SCENARIO_SENTINEL,
1555 };
1556 
test_hiomap_protocol_bad_sequence(void)1557 static void test_hiomap_protocol_bad_sequence(void)
1558 {
1559 	struct blocklevel_device *bl;
1560 
1561 	scenario_enter(scenario_hiomap_protocol_bad_sequence);
1562 	assert(ipmi_hiomap_init(&bl) > 0);
1563 	scenario_exit();
1564 }
1565 
1566 static const struct scenario_event scenario_hiomap_protocol_action_error[] = {
1567 	{
1568 		.type = scenario_cmd,
1569 		.c = {
1570 			/* Ack is legitimate, but we'll pretend it's invalid */
1571 			.req = {
1572 				.cmd = HIOMAP_C_ACK,
1573 				.seq = 1,
1574 				.args = { [0] = 0x3 },
1575 			},
1576 			.cc = IPMI_INVALID_COMMAND_ERR,
1577 			.resp = {
1578 				.cmd = HIOMAP_C_ACK,
1579 				.seq = 1,
1580 			},
1581 		},
1582 	},
1583 	SCENARIO_SENTINEL,
1584 };
1585 
test_hiomap_protocol_action_error(void)1586 static void test_hiomap_protocol_action_error(void)
1587 {
1588 	struct blocklevel_device *bl;
1589 
1590 	scenario_enter(scenario_hiomap_protocol_action_error);
1591 	assert(ipmi_hiomap_init(&bl) > 0);
1592 	scenario_exit();
1593 }
1594 
1595 static const struct scenario_event
1596 scenario_hiomap_protocol_get_flash_info[] = {
1597 	{ .type = scenario_event_p, .p = &hiomap_ack_call, },
1598 	{ .type = scenario_event_p, .p = &hiomap_get_info_call, },
1599 	{ .type = scenario_event_p, .p = &hiomap_get_flash_info_call, },
1600 	{
1601 		.type = scenario_cmd,
1602 		.c = {
1603 			.req = {
1604 				.cmd = HIOMAP_C_GET_FLASH_INFO,
1605 				.seq = 4,
1606 				.args = {
1607 				},
1608 			},
1609 			.cc = IPMI_CC_NO_ERROR,
1610 			.resp = {
1611 				.cmd = HIOMAP_C_GET_FLASH_INFO,
1612 				.seq = 4,
1613 				.args = {
1614 					[0] = 0x00, [1] = 0x20,
1615 					[2] = 0x01, [3] = 0x00,
1616 				},
1617 			},
1618 		},
1619 	},
1620 	SCENARIO_SENTINEL,
1621 };
1622 
test_hiomap_protocol_get_flash_info(void)1623 static void test_hiomap_protocol_get_flash_info(void)
1624 {
1625 	struct blocklevel_device *bl;
1626 	const char *name;
1627 	uint32_t granule;
1628 	uint64_t size;
1629 
1630 	scenario_enter(scenario_hiomap_protocol_get_flash_info);
1631 	assert(!ipmi_hiomap_init(&bl));
1632 	assert(!bl->get_info(bl, &name, &size, &granule));
1633 	assert(!name);
1634 	assert(size == (32 * 1024 * 1024));
1635 	assert(granule == (4 * 1024));
1636 	ipmi_hiomap_exit(bl);
1637 	scenario_exit();
1638 }
1639 
1640 static const struct scenario_event
1641 scenario_hiomap_protocol_persistent_error[] = {
1642 	{ .type = scenario_event_p, .p = &hiomap_ack_call, },
1643 	{ .type = scenario_event_p, .p = &hiomap_get_info_call, },
1644 	{ .type = scenario_event_p, .p = &hiomap_get_flash_info_call, },
1645 	{ .type = scenario_sel, .s = { .bmc_state = HIOMAP_E_PROTOCOL_RESET } },
1646 	SCENARIO_SENTINEL,
1647 };
1648 
test_hiomap_protocol_persistent_error(void)1649 static void test_hiomap_protocol_persistent_error(void)
1650 {
1651 	struct blocklevel_device *bl;
1652 	struct ipmi_hiomap *ctx;
1653 	char buf;
1654 	int rc;
1655 
1656 	scenario_enter(scenario_hiomap_protocol_persistent_error);
1657 	assert(!ipmi_hiomap_init(&bl));
1658 	ctx = container_of(bl, struct ipmi_hiomap, bl);
1659 	assert(ctx->bmc_state == HIOMAP_E_PROTOCOL_RESET);
1660 	rc = bl->read(bl, 0, &buf, sizeof(buf));
1661 	assert(rc == FLASH_ERR_DEVICE_GONE);
1662 	rc = bl->read(bl, 0, &buf, sizeof(buf));
1663 	assert(rc == FLASH_ERR_DEVICE_GONE);
1664 	ipmi_hiomap_exit(bl);
1665 	scenario_exit();
1666 }
1667 
1668 static const struct scenario_event
1669 scenario_hiomap_get_info_error[] = {
1670 	{ .type = scenario_event_p, .p = &hiomap_ack_call, },
1671 	{
1672 		.type = scenario_cmd,
1673 		.c = {
1674 			.req = {
1675 				.cmd = HIOMAP_C_GET_INFO,
1676 				.seq = 2,
1677 				.args = {
1678 					[0] = HIOMAP_V2,
1679 				},
1680 			},
1681 			.cc = IPMI_INVALID_COMMAND_ERR,
1682 		},
1683 	},
1684 	SCENARIO_SENTINEL,
1685 };
1686 
test_hiomap_get_info_error(void)1687 static void test_hiomap_get_info_error(void)
1688 {
1689 	struct blocklevel_device *bl;
1690 
1691 	scenario_enter(scenario_hiomap_get_info_error);
1692 	assert(ipmi_hiomap_init(&bl) > 0);
1693 	scenario_exit();
1694 }
1695 
1696 static const struct scenario_event
1697 scenario_hiomap_get_flash_info_error[] = {
1698 	{ .type = scenario_event_p, .p = &hiomap_ack_call, },
1699 	{ .type = scenario_event_p, .p = &hiomap_get_info_call, },
1700 	{
1701 		.type = scenario_cmd,
1702 		.c = {
1703 			.req = {
1704 				.cmd = HIOMAP_C_GET_FLASH_INFO,
1705 				.seq = 3,
1706 				.args = {
1707 					[0] = HIOMAP_V2,
1708 				},
1709 			},
1710 			.cc = IPMI_INVALID_COMMAND_ERR,
1711 		},
1712 	},
1713 	SCENARIO_SENTINEL,
1714 };
1715 
test_hiomap_get_flash_info_error(void)1716 static void test_hiomap_get_flash_info_error(void)
1717 {
1718 	struct blocklevel_device *bl;
1719 
1720 	scenario_enter(scenario_hiomap_get_flash_info_error);
1721 	assert(ipmi_hiomap_init(&bl) > 0);
1722 	scenario_exit();
1723 }
1724 
1725 static const struct scenario_event
1726 scenario_hiomap_create_read_window_error[] = {
1727 	{ .type = scenario_event_p, .p = &hiomap_ack_call, },
1728 	{ .type = scenario_event_p, .p = &hiomap_get_info_call, },
1729 	{ .type = scenario_event_p, .p = &hiomap_get_flash_info_call, },
1730 	{
1731 		.type = scenario_cmd,
1732 		.c = {
1733 			.req = {
1734 				.cmd = HIOMAP_C_CREATE_READ_WINDOW,
1735 				.seq = 4,
1736 				.args = {
1737 					[0] = 0x00, [1] = 0x00,
1738 					[2] = 0x01, [3] = 0x00,
1739 				},
1740 			},
1741 			.cc = IPMI_INVALID_COMMAND_ERR,
1742 		},
1743 	},
1744 	SCENARIO_SENTINEL,
1745 };
1746 
test_hiomap_create_read_window_error(void)1747 static void test_hiomap_create_read_window_error(void)
1748 {
1749 	struct blocklevel_device *bl;
1750 	struct ipmi_hiomap *ctx;
1751 	size_t len;
1752 	void *buf;
1753 
1754 	scenario_enter(scenario_hiomap_create_read_window_error);
1755 	assert(!ipmi_hiomap_init(&bl));
1756 	ctx = container_of(bl, struct ipmi_hiomap, bl);
1757 	len = 1 << ctx->block_size_shift;
1758 	buf = calloc(1, len);
1759 	assert(buf);
1760 	assert(bl->read(bl, 0, buf, len) > 0);
1761 	free(buf);
1762 	ipmi_hiomap_exit(bl);
1763 	scenario_exit();
1764 }
1765 
1766 static const struct scenario_event
1767 scenario_hiomap_create_write_window_error[] = {
1768 	{ .type = scenario_event_p, .p = &hiomap_ack_call, },
1769 	{ .type = scenario_event_p, .p = &hiomap_get_info_call, },
1770 	{ .type = scenario_event_p, .p = &hiomap_get_flash_info_call, },
1771 	{
1772 		.type = scenario_cmd,
1773 		.c = {
1774 			.req = {
1775 				.cmd = HIOMAP_C_CREATE_WRITE_WINDOW,
1776 				.seq = 4,
1777 				.args = {
1778 					[0] = 0x00, [1] = 0x00,
1779 					[2] = 0x01, [3] = 0x00,
1780 				},
1781 			},
1782 			.cc = IPMI_INVALID_COMMAND_ERR,
1783 		},
1784 	},
1785 	SCENARIO_SENTINEL,
1786 };
1787 
test_hiomap_create_write_window_error(void)1788 static void test_hiomap_create_write_window_error(void)
1789 {
1790 	struct blocklevel_device *bl;
1791 	struct ipmi_hiomap *ctx;
1792 	size_t len;
1793 	void *buf;
1794 
1795 	scenario_enter(scenario_hiomap_create_write_window_error);
1796 	assert(!ipmi_hiomap_init(&bl));
1797 	ctx = container_of(bl, struct ipmi_hiomap, bl);
1798 	len = 1 << ctx->block_size_shift;
1799 	buf = calloc(1, len);
1800 	assert(buf);
1801 	assert(bl->write(bl, 0, buf, len) > 0);
1802 	free(buf);
1803 	ipmi_hiomap_exit(bl);
1804 	scenario_exit();
1805 }
1806 
1807 static const struct scenario_event scenario_hiomap_mark_dirty_error[] = {
1808 	{ .type = scenario_event_p, .p = &hiomap_ack_call, },
1809 	{ .type = scenario_event_p, .p = &hiomap_get_info_call, },
1810 	{ .type = scenario_event_p, .p = &hiomap_get_flash_info_call, },
1811 	{
1812 		.type = scenario_event_p,
1813 		.p = &hiomap_create_write_window_qs0l1_rs0l1_call,
1814 	},
1815 	{
1816 		.type = scenario_cmd,
1817 		.c = {
1818 			.req = {
1819 				.cmd = HIOMAP_C_MARK_DIRTY,
1820 				.seq = 5,
1821 				.args = {
1822 					[0] = 0x00, [1] = 0x00,
1823 					[2] = 0x01, [3] = 0x00,
1824 				},
1825 			},
1826 			.cc = IPMI_INVALID_COMMAND_ERR,
1827 		},
1828 	},
1829 	SCENARIO_SENTINEL,
1830 };
1831 
test_hiomap_mark_dirty_error(void)1832 static void test_hiomap_mark_dirty_error(void)
1833 {
1834 	struct blocklevel_device *bl;
1835 	struct ipmi_hiomap *ctx;
1836 	size_t len;
1837 	void *buf;
1838 
1839 	scenario_enter(scenario_hiomap_mark_dirty_error);
1840 	assert(!ipmi_hiomap_init(&bl));
1841 	ctx = container_of(bl, struct ipmi_hiomap, bl);
1842 	len = 1 << ctx->block_size_shift;
1843 	buf = calloc(1, len);
1844 	assert(buf);
1845 	assert(bl->write(bl, 0, buf, len) > 0);
1846 	free(buf);
1847 	ipmi_hiomap_exit(bl);
1848 	scenario_exit();
1849 }
1850 
1851 static const struct scenario_event scenario_hiomap_flush_error[] = {
1852 	{ .type = scenario_event_p, .p = &hiomap_ack_call, },
1853 	{ .type = scenario_event_p, .p = &hiomap_get_info_call, },
1854 	{ .type = scenario_event_p, .p = &hiomap_get_flash_info_call, },
1855 	{
1856 		.type = scenario_event_p,
1857 		.p = &hiomap_create_write_window_qs0l1_rs0l1_call,
1858 	},
1859 	{ .type = scenario_event_p, .p = &hiomap_mark_dirty_qs0l1_call, },
1860 	{
1861 		.type = scenario_cmd,
1862 		.c = {
1863 			.req = {
1864 				.cmd = HIOMAP_C_FLUSH,
1865 				.seq = 6,
1866 			},
1867 			.cc = IPMI_INVALID_COMMAND_ERR,
1868 		},
1869 	},
1870 	SCENARIO_SENTINEL,
1871 };
1872 
test_hiomap_flush_error(void)1873 static void test_hiomap_flush_error(void)
1874 {
1875 	struct blocklevel_device *bl;
1876 	struct ipmi_hiomap *ctx;
1877 	size_t len;
1878 	void *buf;
1879 
1880 	scenario_enter(scenario_hiomap_flush_error);
1881 	assert(!ipmi_hiomap_init(&bl));
1882 	ctx = container_of(bl, struct ipmi_hiomap, bl);
1883 	len = 1 << ctx->block_size_shift;
1884 	buf = calloc(1, len);
1885 	assert(buf);
1886 	assert(bl->write(bl, 0, buf, len) > 0);
1887 	free(buf);
1888 	ipmi_hiomap_exit(bl);
1889 	scenario_exit();
1890 }
1891 
test_hiomap_ack_error(void)1892 static void test_hiomap_ack_error(void)
1893 {
1894 	/* Same thing at the moment */
1895 	test_hiomap_protocol_action_error();
1896 }
1897 
1898 static const struct scenario_event scenario_hiomap_erase_error[] = {
1899 	{ .type = scenario_event_p, .p = &hiomap_ack_call, },
1900 	{ .type = scenario_event_p, .p = &hiomap_get_info_call, },
1901 	{ .type = scenario_event_p, .p = &hiomap_get_flash_info_call, },
1902 	{
1903 		.type = scenario_event_p,
1904 		.p = &hiomap_create_write_window_qs0l1_rs0l1_call,
1905 	},
1906 	{
1907 		.type = scenario_cmd,
1908 		.c = {
1909 			.req = {
1910 				.cmd = HIOMAP_C_ERASE,
1911 				.seq = 5,
1912 				.args = {
1913 					[0] = 0x00, [1] = 0x00,
1914 					[2] = 0x01, [3] = 0x00,
1915 				},
1916 			},
1917 			.cc = IPMI_INVALID_COMMAND_ERR,
1918 		},
1919 	},
1920 	SCENARIO_SENTINEL,
1921 };
1922 
test_hiomap_erase_error(void)1923 static void test_hiomap_erase_error(void)
1924 {
1925 	struct blocklevel_device *bl;
1926 	struct ipmi_hiomap *ctx;
1927 	size_t len;
1928 
1929 	scenario_enter(scenario_hiomap_erase_error);
1930 	assert(!ipmi_hiomap_init(&bl));
1931 	ctx = container_of(bl, struct ipmi_hiomap, bl);
1932 	len = 1 << ctx->block_size_shift;
1933 	assert(bl->erase(bl, 0, len) > 0);
1934 	ipmi_hiomap_exit(bl);
1935 	scenario_exit();
1936 }
1937 
1938 static const struct scenario_event scenario_hiomap_ack_malformed_small[] = {
1939 	{
1940 		.type = scenario_cmd,
1941 		.c = {
1942 			.req = {
1943 				.cmd = HIOMAP_C_ACK,
1944 				.seq = 1,
1945 				.args = { [0] = 0x3 },
1946 			},
1947 			.cc = IPMI_CC_NO_ERROR,
1948 			.resp_size = 1
1949 		},
1950 	},
1951 	SCENARIO_SENTINEL,
1952 };
1953 
test_hiomap_ack_malformed_small(void)1954 static void test_hiomap_ack_malformed_small(void)
1955 {
1956 	struct blocklevel_device *bl;
1957 
1958 	scenario_enter(scenario_hiomap_ack_malformed_small);
1959 	assert(ipmi_hiomap_init(&bl) > 0);
1960 	scenario_exit();
1961 }
1962 
1963 static const struct scenario_event scenario_hiomap_ack_malformed_large[] = {
1964 	{
1965 		.type = scenario_cmd,
1966 		.c = {
1967 			.req = {
1968 				.cmd = HIOMAP_C_ACK,
1969 				.seq = 1,
1970 				.args = { [0] = 0x3 },
1971 			},
1972 			.cc = IPMI_CC_NO_ERROR,
1973 			.resp_size = 3,
1974 			.resp = {
1975 				.cmd = HIOMAP_C_ACK,
1976 				.seq = 1,
1977 			},
1978 		},
1979 	},
1980 	SCENARIO_SENTINEL,
1981 };
1982 
test_hiomap_ack_malformed_large(void)1983 static void test_hiomap_ack_malformed_large(void)
1984 {
1985 	struct blocklevel_device *bl;
1986 
1987 	scenario_enter(scenario_hiomap_ack_malformed_large);
1988 	assert(ipmi_hiomap_init(&bl) > 0);
1989 	scenario_exit();
1990 }
1991 
1992 static const struct scenario_event
1993 scenario_hiomap_get_info_malformed_small[] = {
1994 	{ .type = scenario_event_p, .p = &hiomap_ack_call, },
1995 	{
1996 		.type = scenario_cmd,
1997 		.c = {
1998 			.req = {
1999 				.cmd = HIOMAP_C_GET_INFO,
2000 				.seq = 2,
2001 				.args = { [0] = 0x2 },
2002 			},
2003 			.cc = IPMI_CC_NO_ERROR,
2004 			.resp_size = 7,
2005 			.resp = {
2006 				.cmd = HIOMAP_C_GET_INFO,
2007 				.seq = 2,
2008 			},
2009 		},
2010 	},
2011 	SCENARIO_SENTINEL,
2012 };
2013 
test_hiomap_get_info_malformed_small(void)2014 static void test_hiomap_get_info_malformed_small(void)
2015 {
2016 	struct blocklevel_device *bl;
2017 
2018 	scenario_enter(scenario_hiomap_get_info_malformed_small);
2019 	assert(ipmi_hiomap_init(&bl) > 0);
2020 	scenario_exit();
2021 }
2022 
2023 static const struct scenario_event
2024 scenario_hiomap_get_info_malformed_large[] = {
2025 	{ .type = scenario_event_p, .p = &hiomap_ack_call, },
2026 	{
2027 		.type = scenario_cmd,
2028 		.c = {
2029 			.req = {
2030 				.cmd = HIOMAP_C_GET_INFO,
2031 				.seq = 2,
2032 				.args = { [0] = 0x2 },
2033 			},
2034 			.cc = IPMI_CC_NO_ERROR,
2035 			.resp_size = 9,
2036 			.resp = {
2037 				.cmd = HIOMAP_C_GET_INFO,
2038 				.seq = 2,
2039 			},
2040 		},
2041 	},
2042 	SCENARIO_SENTINEL,
2043 };
2044 
test_hiomap_get_info_malformed_large(void)2045 static void test_hiomap_get_info_malformed_large(void)
2046 {
2047 	struct blocklevel_device *bl;
2048 
2049 	scenario_enter(scenario_hiomap_get_info_malformed_large);
2050 	assert(ipmi_hiomap_init(&bl) > 0);
2051 	scenario_exit();
2052 }
2053 
2054 static const struct scenario_event
2055 scenario_hiomap_get_flash_info_malformed_small[] = {
2056 	{ .type = scenario_event_p, .p = &hiomap_ack_call, },
2057 	{ .type = scenario_event_p, .p = &hiomap_get_info_call, },
2058 	{
2059 		.type = scenario_cmd,
2060 		.c = {
2061 			.req = {
2062 				.cmd = HIOMAP_C_GET_FLASH_INFO,
2063 				.seq = 3,
2064 			},
2065 			.cc = IPMI_CC_NO_ERROR,
2066 			.resp_size = 5,
2067 			.resp = {
2068 				.cmd = HIOMAP_C_GET_FLASH_INFO,
2069 				.seq = 3,
2070 			},
2071 		},
2072 	},
2073 	SCENARIO_SENTINEL,
2074 };
2075 
test_hiomap_get_flash_info_malformed_small(void)2076 static void test_hiomap_get_flash_info_malformed_small(void)
2077 {
2078 	struct blocklevel_device *bl;
2079 
2080 	scenario_enter(scenario_hiomap_get_flash_info_malformed_small);
2081 	assert(ipmi_hiomap_init(&bl) > 0);
2082 	scenario_exit();
2083 }
2084 
2085 static const struct scenario_event
2086 scenario_hiomap_get_flash_info_malformed_large[] = {
2087 	{ .type = scenario_event_p, .p = &hiomap_ack_call, },
2088 	{ .type = scenario_event_p, .p = &hiomap_get_info_call, },
2089 	{
2090 		.type = scenario_cmd,
2091 		.c = {
2092 			.req = {
2093 				.cmd = HIOMAP_C_GET_FLASH_INFO,
2094 				.seq = 3,
2095 			},
2096 			.cc = IPMI_CC_NO_ERROR,
2097 			.resp_size = 7,
2098 			.resp = {
2099 				.cmd = HIOMAP_C_GET_FLASH_INFO,
2100 				.seq = 3,
2101 			},
2102 		},
2103 	},
2104 	SCENARIO_SENTINEL,
2105 };
2106 
test_hiomap_get_flash_info_malformed_large(void)2107 static void test_hiomap_get_flash_info_malformed_large(void)
2108 {
2109 	struct blocklevel_device *bl;
2110 
2111 	scenario_enter(scenario_hiomap_get_flash_info_malformed_large);
2112 	assert(ipmi_hiomap_init(&bl) > 0);
2113 	scenario_exit();
2114 }
2115 
2116 static const struct scenario_event
2117 scenario_hiomap_create_read_window_malformed_small[] = {
2118 	{ .type = scenario_event_p, .p = &hiomap_ack_call, },
2119 	{ .type = scenario_event_p, .p = &hiomap_get_info_call, },
2120 	{ .type = scenario_event_p, .p = &hiomap_get_flash_info_call, },
2121 	{
2122 		.type = scenario_cmd,
2123 		.c = {
2124 			.req = {
2125 				.cmd = HIOMAP_C_CREATE_READ_WINDOW,
2126 				.seq = 4,
2127 				.args = {
2128 					[0] = 0x00, [1] = 0x00,
2129 					[2] = 0x01, [3] = 0x00,
2130 				},
2131 			},
2132 			.cc = IPMI_CC_NO_ERROR,
2133 			.resp_size = 7,
2134 			.resp = {
2135 				.cmd = HIOMAP_C_CREATE_READ_WINDOW,
2136 				.seq = 4,
2137 			},
2138 		},
2139 	},
2140 	SCENARIO_SENTINEL,
2141 };
2142 
test_hiomap_create_read_window_malformed_small(void)2143 static void test_hiomap_create_read_window_malformed_small(void)
2144 {
2145 	struct blocklevel_device *bl;
2146 	struct ipmi_hiomap *ctx;
2147 	size_t len;
2148 	void *buf;
2149 
2150 	scenario_enter(scenario_hiomap_create_read_window_malformed_small);
2151 	assert(!ipmi_hiomap_init(&bl));
2152 	ctx = container_of(bl, struct ipmi_hiomap, bl);
2153 	len = 1 << ctx->block_size_shift;
2154 	buf = calloc(1, len);
2155 	assert(buf);
2156 	assert(bl->read(bl, 0, buf, len) > 0);
2157 	free(buf);
2158 	ipmi_hiomap_exit(bl);
2159 	scenario_exit();
2160 
2161 }
2162 
2163 static const struct scenario_event
2164 scenario_hiomap_create_read_window_malformed_large[] = {
2165 	{ .type = scenario_event_p, .p = &hiomap_ack_call, },
2166 	{ .type = scenario_event_p, .p = &hiomap_get_info_call, },
2167 	{ .type = scenario_event_p, .p = &hiomap_get_flash_info_call, },
2168 	{
2169 		.type = scenario_cmd,
2170 		.c = {
2171 			.req = {
2172 				.cmd = HIOMAP_C_CREATE_READ_WINDOW,
2173 				.seq = 4,
2174 				.args = {
2175 					[0] = 0x00, [1] = 0x00,
2176 					[2] = 0x01, [3] = 0x00,
2177 				},
2178 			},
2179 			.cc = IPMI_CC_NO_ERROR,
2180 			.resp_size = 9,
2181 			.resp = {
2182 				.cmd = HIOMAP_C_CREATE_READ_WINDOW,
2183 				.seq = 4,
2184 			},
2185 		},
2186 	},
2187 	SCENARIO_SENTINEL,
2188 };
2189 
test_hiomap_create_read_window_malformed_large(void)2190 static void test_hiomap_create_read_window_malformed_large(void)
2191 {
2192 	struct blocklevel_device *bl;
2193 	struct ipmi_hiomap *ctx;
2194 	size_t len;
2195 	void *buf;
2196 
2197 	scenario_enter(scenario_hiomap_create_read_window_malformed_large);
2198 	assert(!ipmi_hiomap_init(&bl));
2199 	ctx = container_of(bl, struct ipmi_hiomap, bl);
2200 	len = 1 << ctx->block_size_shift;
2201 	buf = calloc(1, len);
2202 	assert(buf);
2203 	assert(bl->read(bl, 0, buf, len) > 0);
2204 	free(buf);
2205 	ipmi_hiomap_exit(bl);
2206 	scenario_exit();
2207 }
2208 
2209 static const struct scenario_event
2210 scenario_hiomap_create_write_window_malformed_small[] = {
2211 	{ .type = scenario_event_p, .p = &hiomap_ack_call, },
2212 	{ .type = scenario_event_p, .p = &hiomap_get_info_call, },
2213 	{ .type = scenario_event_p, .p = &hiomap_get_flash_info_call, },
2214 	{
2215 		.type = scenario_cmd,
2216 		.c = {
2217 			.req = {
2218 				.cmd = HIOMAP_C_CREATE_WRITE_WINDOW,
2219 				.seq = 4,
2220 				.args = {
2221 					[0] = 0x00, [1] = 0x00,
2222 					[2] = 0x01, [3] = 0x00,
2223 				},
2224 			},
2225 			.cc = IPMI_CC_NO_ERROR,
2226 			.resp_size = 7,
2227 			.resp = {
2228 				.cmd = HIOMAP_C_CREATE_WRITE_WINDOW,
2229 				.seq = 4,
2230 			},
2231 		},
2232 	},
2233 	SCENARIO_SENTINEL,
2234 };
2235 
test_hiomap_create_write_window_malformed_small(void)2236 static void test_hiomap_create_write_window_malformed_small(void)
2237 {
2238 	struct blocklevel_device *bl;
2239 	struct ipmi_hiomap *ctx;
2240 	size_t len;
2241 	void *buf;
2242 
2243 	scenario_enter(scenario_hiomap_create_write_window_malformed_small);
2244 	assert(!ipmi_hiomap_init(&bl));
2245 	ctx = container_of(bl, struct ipmi_hiomap, bl);
2246 	len = 1 << ctx->block_size_shift;
2247 	buf = calloc(1, len);
2248 	assert(buf);
2249 	assert(bl->write(bl, 0, buf, len) > 0);
2250 	free(buf);
2251 	ipmi_hiomap_exit(bl);
2252 	scenario_exit();
2253 
2254 }
2255 
2256 static const struct scenario_event
2257 scenario_hiomap_create_write_window_malformed_large[] = {
2258 	{ .type = scenario_event_p, .p = &hiomap_ack_call, },
2259 	{ .type = scenario_event_p, .p = &hiomap_get_info_call, },
2260 	{ .type = scenario_event_p, .p = &hiomap_get_flash_info_call, },
2261 	{
2262 		.type = scenario_cmd,
2263 		.c = {
2264 			.req = {
2265 				.cmd = HIOMAP_C_CREATE_WRITE_WINDOW,
2266 				.seq = 4,
2267 				.args = {
2268 					[0] = 0x00, [1] = 0x00,
2269 					[2] = 0x01, [3] = 0x00,
2270 				},
2271 			},
2272 			.cc = IPMI_CC_NO_ERROR,
2273 			.resp_size = 9,
2274 			.resp = {
2275 				.cmd = HIOMAP_C_CREATE_WRITE_WINDOW,
2276 				.seq = 4,
2277 			},
2278 		},
2279 	},
2280 	SCENARIO_SENTINEL,
2281 };
2282 
test_hiomap_create_write_window_malformed_large(void)2283 static void test_hiomap_create_write_window_malformed_large(void)
2284 {
2285 	struct blocklevel_device *bl;
2286 	struct ipmi_hiomap *ctx;
2287 	size_t len;
2288 	void *buf;
2289 
2290 	scenario_enter(scenario_hiomap_create_write_window_malformed_large);
2291 	assert(!ipmi_hiomap_init(&bl));
2292 	ctx = container_of(bl, struct ipmi_hiomap, bl);
2293 	len = 1 << ctx->block_size_shift;
2294 	buf = calloc(1, len);
2295 	assert(buf);
2296 	assert(bl->write(bl, 0, buf, len) > 0);
2297 	free(buf);
2298 	ipmi_hiomap_exit(bl);
2299 	scenario_exit();
2300 }
2301 
2302 static const struct scenario_event
2303 scenario_hiomap_mark_dirty_malformed_small[] = {
2304 	{ .type = scenario_event_p, .p = &hiomap_ack_call, },
2305 	{ .type = scenario_event_p, .p = &hiomap_get_info_call, },
2306 	{ .type = scenario_event_p, .p = &hiomap_get_flash_info_call, },
2307 	{
2308 		.type = scenario_event_p,
2309 		.p = &hiomap_create_write_window_qs0l1_rs0l1_call,
2310 	},
2311 	{
2312 		.type = scenario_cmd,
2313 		.c = {
2314 			.req = {
2315 				.cmd = HIOMAP_C_MARK_DIRTY,
2316 				.seq = 5,
2317 				.args = {
2318 					[0] = 0x00, [1] = 0x00,
2319 					[2] = 0x01, [3] = 0x00,
2320 				},
2321 			},
2322 			.resp_size = 1,
2323 			.resp = {
2324 				.cmd = HIOMAP_C_MARK_DIRTY,
2325 				.seq = 5,
2326 			},
2327 		},
2328 	},
2329 	SCENARIO_SENTINEL,
2330 };
2331 
test_hiomap_mark_dirty_malformed_small(void)2332 static void test_hiomap_mark_dirty_malformed_small(void)
2333 {
2334 	struct blocklevel_device *bl;
2335 	struct ipmi_hiomap *ctx;
2336 	size_t len;
2337 	void *buf;
2338 
2339 	scenario_enter(scenario_hiomap_mark_dirty_malformed_small);
2340 	assert(!ipmi_hiomap_init(&bl));
2341 	ctx = container_of(bl, struct ipmi_hiomap, bl);
2342 	len = 1 << ctx->block_size_shift;
2343 	buf = calloc(1, len);
2344 	assert(buf);
2345 	assert(bl->write(bl, 0, buf, len) > 0);
2346 	free(buf);
2347 	ipmi_hiomap_exit(bl);
2348 	scenario_exit();
2349 
2350 }
2351 
2352 static const struct scenario_event
2353 scenario_hiomap_mark_dirty_malformed_large[] = {
2354 	{ .type = scenario_event_p, .p = &hiomap_ack_call, },
2355 	{ .type = scenario_event_p, .p = &hiomap_get_info_call, },
2356 	{ .type = scenario_event_p, .p = &hiomap_get_flash_info_call, },
2357 	{
2358 		.type = scenario_event_p,
2359 		.p = &hiomap_create_write_window_qs0l1_rs0l1_call,
2360 	},
2361 	{
2362 		.type = scenario_cmd,
2363 		.c = {
2364 			.req = {
2365 				.cmd = HIOMAP_C_MARK_DIRTY,
2366 				.seq = 5,
2367 				.args = {
2368 					[0] = 0x00, [1] = 0x00,
2369 					[2] = 0x01, [3] = 0x00,
2370 				},
2371 			},
2372 			.resp_size = 3,
2373 			.resp = {
2374 				.cmd = HIOMAP_C_MARK_DIRTY,
2375 				.seq = 5,
2376 			},
2377 		},
2378 	},
2379 	SCENARIO_SENTINEL,
2380 };
2381 
test_hiomap_mark_dirty_malformed_large(void)2382 static void test_hiomap_mark_dirty_malformed_large(void)
2383 {
2384 	struct blocklevel_device *bl;
2385 	struct ipmi_hiomap *ctx;
2386 	size_t len;
2387 	void *buf;
2388 
2389 	scenario_enter(scenario_hiomap_mark_dirty_malformed_large);
2390 	assert(!ipmi_hiomap_init(&bl));
2391 	ctx = container_of(bl, struct ipmi_hiomap, bl);
2392 	len = 1 << ctx->block_size_shift;
2393 	buf = calloc(1, len);
2394 	assert(buf);
2395 	assert(bl->write(bl, 0, buf, len) > 0);
2396 	free(buf);
2397 	ipmi_hiomap_exit(bl);
2398 	scenario_exit();
2399 }
2400 
2401 static const struct scenario_event
2402 scenario_hiomap_flush_malformed_small[] = {
2403 	{ .type = scenario_event_p, .p = &hiomap_ack_call, },
2404 	{ .type = scenario_event_p, .p = &hiomap_get_info_call, },
2405 	{ .type = scenario_event_p, .p = &hiomap_get_flash_info_call, },
2406 	{
2407 		.type = scenario_event_p,
2408 		.p = &hiomap_create_write_window_qs0l1_rs0l1_call,
2409 	},
2410 	{ .type = scenario_event_p, .p = &hiomap_mark_dirty_qs0l1_call, },
2411 	{
2412 		.type = scenario_cmd,
2413 		.c = {
2414 			.req = {
2415 				.cmd = HIOMAP_C_FLUSH,
2416 				.seq = 6,
2417 			},
2418 			.resp_size = 1,
2419 			.resp = {
2420 				.cmd = HIOMAP_C_FLUSH,
2421 				.seq = 6,
2422 			},
2423 		},
2424 	},
2425 	SCENARIO_SENTINEL,
2426 };
2427 
test_hiomap_flush_malformed_small(void)2428 static void test_hiomap_flush_malformed_small(void)
2429 {
2430 	struct blocklevel_device *bl;
2431 	struct ipmi_hiomap *ctx;
2432 	size_t len;
2433 	void *buf;
2434 
2435 	scenario_enter(scenario_hiomap_flush_malformed_small);
2436 	assert(!ipmi_hiomap_init(&bl));
2437 	ctx = container_of(bl, struct ipmi_hiomap, bl);
2438 	len = 1 << ctx->block_size_shift;
2439 	buf = calloc(1, len);
2440 	assert(buf);
2441 	assert(bl->write(bl, 0, buf, len) > 0);
2442 	free(buf);
2443 	ipmi_hiomap_exit(bl);
2444 	scenario_exit();
2445 
2446 }
2447 
2448 static const struct scenario_event
2449 scenario_hiomap_flush_malformed_large[] = {
2450 	{ .type = scenario_event_p, .p = &hiomap_ack_call, },
2451 	{ .type = scenario_event_p, .p = &hiomap_get_info_call, },
2452 	{ .type = scenario_event_p, .p = &hiomap_get_flash_info_call, },
2453 	{
2454 		.type = scenario_event_p,
2455 		.p = &hiomap_create_write_window_qs0l1_rs0l1_call,
2456 	},
2457 	{ .type = scenario_event_p, .p = &hiomap_mark_dirty_qs0l1_call, },
2458 	{
2459 		.type = scenario_cmd,
2460 		.c = {
2461 			.req = {
2462 				.cmd = HIOMAP_C_FLUSH,
2463 				.seq = 6,
2464 			},
2465 			.resp_size = 3,
2466 			.resp = {
2467 				.cmd = HIOMAP_C_FLUSH,
2468 				.seq = 6,
2469 			},
2470 		},
2471 	},
2472 	SCENARIO_SENTINEL,
2473 };
2474 
test_hiomap_flush_malformed_large(void)2475 static void test_hiomap_flush_malformed_large(void)
2476 {
2477 	struct blocklevel_device *bl;
2478 	struct ipmi_hiomap *ctx;
2479 	size_t len;
2480 	void *buf;
2481 
2482 	scenario_enter(scenario_hiomap_flush_malformed_large);
2483 	assert(!ipmi_hiomap_init(&bl));
2484 	ctx = container_of(bl, struct ipmi_hiomap, bl);
2485 	len = 1 << ctx->block_size_shift;
2486 	buf = calloc(1, len);
2487 	assert(buf);
2488 	assert(bl->write(bl, 0, buf, len) > 0);
2489 	free(buf);
2490 	ipmi_hiomap_exit(bl);
2491 	scenario_exit();
2492 }
2493 
2494 static const struct scenario_event
2495 scenario_hiomap_erase_malformed_small[] = {
2496 	{ .type = scenario_event_p, .p = &hiomap_ack_call, },
2497 	{ .type = scenario_event_p, .p = &hiomap_get_info_call, },
2498 	{ .type = scenario_event_p, .p = &hiomap_get_flash_info_call, },
2499 	{
2500 		.type = scenario_event_p,
2501 		.p = &hiomap_create_write_window_qs0l1_rs0l1_call,
2502 	},
2503 	{
2504 		.type = scenario_cmd,
2505 		.c = {
2506 			.req = {
2507 				.cmd = HIOMAP_C_ERASE,
2508 				.seq = 5,
2509 				.args = {
2510 					[0] = 0x00, [1] = 0x00,
2511 					[2] = 0x01, [3] = 0x00,
2512 				},
2513 			},
2514 			.resp_size = 1,
2515 			.resp = {
2516 				.cmd = HIOMAP_C_ERASE,
2517 				.seq = 5,
2518 			},
2519 		},
2520 	},
2521 	SCENARIO_SENTINEL,
2522 };
2523 
test_hiomap_erase_malformed_small(void)2524 static void test_hiomap_erase_malformed_small(void)
2525 {
2526 	struct blocklevel_device *bl;
2527 	struct ipmi_hiomap *ctx;
2528 	size_t len;
2529 
2530 	scenario_enter(scenario_hiomap_erase_malformed_small);
2531 	assert(!ipmi_hiomap_init(&bl));
2532 	ctx = container_of(bl, struct ipmi_hiomap, bl);
2533 	len = 1 << ctx->block_size_shift;
2534 	assert(bl->erase(bl, 0, len) > 0);
2535 	ipmi_hiomap_exit(bl);
2536 	scenario_exit();
2537 }
2538 
2539 static const struct scenario_event
2540 scenario_hiomap_erase_malformed_large[] = {
2541 	{ .type = scenario_event_p, .p = &hiomap_ack_call, },
2542 	{ .type = scenario_event_p, .p = &hiomap_get_info_call, },
2543 	{ .type = scenario_event_p, .p = &hiomap_get_flash_info_call, },
2544 	{
2545 		.type = scenario_event_p,
2546 		.p = &hiomap_create_write_window_qs0l1_rs0l1_call,
2547 	},
2548 	{
2549 		.type = scenario_cmd,
2550 		.c = {
2551 			.req = {
2552 				.cmd = HIOMAP_C_ERASE,
2553 				.seq = 5,
2554 				.args = {
2555 					[0] = 0x00, [1] = 0x00,
2556 					[2] = 0x01, [3] = 0x00,
2557 				},
2558 			},
2559 			.resp_size = 3,
2560 			.resp = {
2561 				.cmd = HIOMAP_C_ERASE,
2562 				.seq = 5,
2563 			},
2564 		},
2565 	},
2566 	SCENARIO_SENTINEL,
2567 };
2568 
test_hiomap_erase_malformed_large(void)2569 static void test_hiomap_erase_malformed_large(void)
2570 {
2571 	struct blocklevel_device *bl;
2572 	struct ipmi_hiomap *ctx;
2573 	size_t len;
2574 
2575 	scenario_enter(scenario_hiomap_erase_malformed_large);
2576 	assert(!ipmi_hiomap_init(&bl));
2577 	ctx = container_of(bl, struct ipmi_hiomap, bl);
2578 	len = 1 << ctx->block_size_shift;
2579 	assert(bl->erase(bl, 0, len) > 0);
2580 	ipmi_hiomap_exit(bl);
2581 	scenario_exit();
2582 }
2583 
2584 /* Common recovery calls */
2585 
2586 static const struct scenario_event hiomap_recovery_ack_call = {
2587 	.type = scenario_cmd,
2588 	.c = {
2589 		.req = {
2590 			.cmd = HIOMAP_C_ACK,
2591 			.seq = 7,
2592 			.args = {
2593 				[0] = HIOMAP_E_PROTOCOL_RESET,
2594 			},
2595 		},
2596 		.cc = IPMI_CC_NO_ERROR,
2597 		.resp = {
2598 			.cmd = HIOMAP_C_ACK,
2599 			.seq = 7,
2600 		},
2601 	},
2602 };
2603 
2604 static const struct scenario_event hiomap_recovery_get_info_call = {
2605 	.type = scenario_cmd,
2606 	.c = {
2607 		.req = {
2608 			.cmd = HIOMAP_C_GET_INFO,
2609 			.seq = 8,
2610 			.args = {
2611 				[0] = HIOMAP_V2,
2612 			},
2613 		},
2614 		.cc = IPMI_CC_NO_ERROR,
2615 		.resp = {
2616 			.cmd = HIOMAP_C_GET_INFO,
2617 			.seq = 8,
2618 			.args = {
2619 				[0] = HIOMAP_V2,
2620 				[1] = 12,
2621 				[2] = 8, [3] = 0,
2622 			},
2623 		},
2624 	},
2625 };
2626 
2627 static const struct scenario_event
2628 scenario_hiomap_protocol_recovery_failure_ack[] = {
2629 	{ .type = scenario_event_p, .p = &hiomap_ack_call, },
2630 	{ .type = scenario_event_p, .p = &hiomap_get_info_call, },
2631 	{ .type = scenario_event_p, .p = &hiomap_get_flash_info_call, },
2632 	{
2633 		.type = scenario_event_p,
2634 		.p = &hiomap_create_write_window_qs0l1_rs0l1_call,
2635 	},
2636 	{ .type = scenario_event_p, .p = &hiomap_erase_qs0l1_call, },
2637 	{ .type = scenario_event_p, .p = &hiomap_flush_call, },
2638 	{ .type = scenario_delay },
2639 	{
2640 		.type = scenario_sel,
2641 		.s = {
2642 			.bmc_state = HIOMAP_E_DAEMON_READY |
2643 					HIOMAP_E_PROTOCOL_RESET
2644 		}
2645 	},
2646 	{
2647 		.type = scenario_cmd,
2648 		.c = {
2649 			.req = {
2650 				.cmd = HIOMAP_C_ACK,
2651 				.seq = 7,
2652 				.args = {
2653 					[0] = HIOMAP_E_PROTOCOL_RESET,
2654 				},
2655 			},
2656 			.cc = IPMI_ERR_UNSPECIFIED,
2657 		},
2658 	},
2659 	{
2660 		.type = scenario_cmd,
2661 		.c = {
2662 			.req = {
2663 				.cmd = HIOMAP_C_ACK,
2664 				.seq = 8,
2665 				.args = {
2666 					[0] = HIOMAP_E_PROTOCOL_RESET,
2667 				},
2668 			},
2669 			.cc = IPMI_CC_NO_ERROR,
2670 			.resp = {
2671 				.cmd = HIOMAP_C_ACK,
2672 				.seq = 8,
2673 			},
2674 		},
2675 	},
2676 	{
2677 		.type = scenario_cmd,
2678 		.c = {
2679 			.req = {
2680 				.cmd = HIOMAP_C_GET_INFO,
2681 				.seq = 9,
2682 				.args = {
2683 					[0] = HIOMAP_V2,
2684 				},
2685 			},
2686 			.cc = IPMI_CC_NO_ERROR,
2687 			.resp = {
2688 				.cmd = HIOMAP_C_GET_INFO,
2689 				.seq = 9,
2690 				.args = {
2691 					[0] = HIOMAP_V2,
2692 					[1] = 12,
2693 					[2] = 8, [3] = 0,
2694 				},
2695 			},
2696 		},
2697 	},
2698 	{
2699 		.type = scenario_cmd,
2700 		.c = {
2701 			.req = {
2702 				.cmd = HIOMAP_C_GET_FLASH_INFO,
2703 				.seq = 10,
2704 				.args = {
2705 				},
2706 			},
2707 			.cc = IPMI_CC_NO_ERROR,
2708 			.resp = {
2709 				.cmd = HIOMAP_C_GET_FLASH_INFO,
2710 				.seq = 10,
2711 				.args = {
2712 					[0] = 0x00, [1] = 0x20,
2713 					[2] = 0x01, [3] = 0x00,
2714 				},
2715 			},
2716 		},
2717 	},
2718 	{
2719 		.type = scenario_cmd,
2720 		.c = {
2721 			.req = {
2722 				.cmd = HIOMAP_C_CREATE_WRITE_WINDOW,
2723 				.seq = 11,
2724 				.args = {
2725 					[0] = 0x00, [1] = 0x00,
2726 					[2] = 0x01, [3] = 0x00,
2727 				},
2728 			},
2729 			.cc = IPMI_CC_NO_ERROR,
2730 			.resp = {
2731 				.cmd = HIOMAP_C_CREATE_WRITE_WINDOW,
2732 				.seq = 11,
2733 				.args = {
2734 					[0] = 0xff, [1] = 0x0f,
2735 					[2] = 0x01, [3] = 0x00,
2736 					[4] = 0x00, [5] = 0x00,
2737 				},
2738 			},
2739 		},
2740 	},
2741 	{
2742 		.type = scenario_cmd,
2743 		.c = {
2744 			.req = {
2745 				.cmd = HIOMAP_C_ERASE,
2746 				.seq = 12,
2747 				.args = {
2748 					[0] = 0x00, [1] = 0x00,
2749 					[2] = 0x01, [3] = 0x00,
2750 				},
2751 			},
2752 			.resp = {
2753 				.cmd = HIOMAP_C_ERASE,
2754 				.seq = 12,
2755 			},
2756 		},
2757 	},
2758 	{
2759 		.type = scenario_cmd,
2760 		.c = {
2761 			.req = {
2762 				.cmd = HIOMAP_C_FLUSH,
2763 				.seq = 13,
2764 			},
2765 			.resp = {
2766 				.cmd = HIOMAP_C_FLUSH,
2767 				.seq = 13,
2768 			},
2769 		},
2770 	},
2771 	SCENARIO_SENTINEL,
2772 };
2773 
test_hiomap_protocol_recovery_failure_ack(void)2774 static void test_hiomap_protocol_recovery_failure_ack(void)
2775 {
2776 	struct blocklevel_device *bl;
2777 	struct ipmi_hiomap *ctx;
2778 	size_t len;
2779 
2780 	scenario_enter(scenario_hiomap_protocol_recovery_failure_ack);
2781 	assert(!ipmi_hiomap_init(&bl));
2782 	ctx = container_of(bl, struct ipmi_hiomap, bl);
2783 	len = 1 << ctx->block_size_shift;
2784 	/*
2785 	 * We're erasing the same block 3 times - it's irrelevant, we're just
2786 	 * trying to manipulate window state
2787 	 */
2788 	assert(!bl->erase(bl, 0, len));
2789 	scenario_advance();
2790 	assert(bl->erase(bl, 0, len) > 0);
2791 	assert(!bl->erase(bl, 0, len));
2792 	ipmi_hiomap_exit(bl);
2793 	scenario_exit();
2794 }
2795 
2796 static const struct scenario_event
2797 scenario_hiomap_protocol_recovery_failure_get_info[] = {
2798 	{ .type = scenario_event_p, .p = &hiomap_ack_call, },
2799 	{ .type = scenario_event_p, .p = &hiomap_get_info_call, },
2800 	{ .type = scenario_event_p, .p = &hiomap_get_flash_info_call, },
2801 	{
2802 		.type = scenario_event_p,
2803 		.p = &hiomap_create_write_window_qs0l1_rs0l1_call,
2804 	},
2805 	{ .type = scenario_event_p, .p = &hiomap_erase_qs0l1_call, },
2806 	{ .type = scenario_event_p, .p = &hiomap_flush_call, },
2807 	{ .type = scenario_delay },
2808 	{
2809 		.type = scenario_sel,
2810 		.s = {
2811 			.bmc_state = HIOMAP_E_DAEMON_READY |
2812 					HIOMAP_E_PROTOCOL_RESET
2813 		}
2814 	},
2815 	{ .type = scenario_event_p, .p = &hiomap_recovery_ack_call, },
2816 	{
2817 		.type = scenario_cmd,
2818 		.c = {
2819 			.req = {
2820 				.cmd = HIOMAP_C_GET_INFO,
2821 				.seq = 8,
2822 				.args = {
2823 					[0] = HIOMAP_V2,
2824 				},
2825 			},
2826 			.cc = IPMI_ERR_UNSPECIFIED,
2827 		},
2828 	},
2829 	{
2830 		.type = scenario_cmd,
2831 		.c = {
2832 			.req = {
2833 				.cmd = HIOMAP_C_ACK,
2834 				.seq = 9,
2835 				.args = {
2836 					[0] = HIOMAP_E_PROTOCOL_RESET,
2837 				},
2838 			},
2839 			.cc = IPMI_CC_NO_ERROR,
2840 			.resp = {
2841 				.cmd = HIOMAP_C_ACK,
2842 				.seq = 9,
2843 			},
2844 		},
2845 	},
2846 	{
2847 		.type = scenario_cmd,
2848 		.c = {
2849 			.req = {
2850 				.cmd = HIOMAP_C_GET_INFO,
2851 				.seq = 10,
2852 				.args = {
2853 					[0] = HIOMAP_V2,
2854 				},
2855 			},
2856 			.cc = IPMI_CC_NO_ERROR,
2857 			.resp = {
2858 				.cmd = HIOMAP_C_GET_INFO,
2859 				.seq = 10,
2860 				.args = {
2861 					[0] = HIOMAP_V2,
2862 					[1] = 12,
2863 					[2] = 8, [3] = 0,
2864 				},
2865 			},
2866 		},
2867 	},
2868 	{
2869 		.type = scenario_cmd,
2870 		.c = {
2871 			.req = {
2872 				.cmd = HIOMAP_C_GET_FLASH_INFO,
2873 				.seq = 11,
2874 				.args = {
2875 				},
2876 			},
2877 			.cc = IPMI_CC_NO_ERROR,
2878 			.resp = {
2879 				.cmd = HIOMAP_C_GET_FLASH_INFO,
2880 				.seq = 11,
2881 				.args = {
2882 					[0] = 0x00, [1] = 0x20,
2883 					[2] = 0x01, [3] = 0x00,
2884 				},
2885 			},
2886 		},
2887 	},
2888 	{
2889 		.type = scenario_cmd,
2890 		.c = {
2891 			.req = {
2892 				.cmd = HIOMAP_C_CREATE_WRITE_WINDOW,
2893 				.seq = 12,
2894 				.args = {
2895 					[0] = 0x00, [1] = 0x00,
2896 					[2] = 0x01, [3] = 0x00,
2897 				},
2898 			},
2899 			.cc = IPMI_CC_NO_ERROR,
2900 			.resp = {
2901 				.cmd = HIOMAP_C_CREATE_WRITE_WINDOW,
2902 				.seq = 12,
2903 				.args = {
2904 					[0] = 0xff, [1] = 0x0f,
2905 					[2] = 0x01, [3] = 0x00,
2906 					[4] = 0x00, [5] = 0x00,
2907 				},
2908 			},
2909 		},
2910 	},
2911 	{
2912 		.type = scenario_cmd,
2913 		.c = {
2914 			.req = {
2915 				.cmd = HIOMAP_C_ERASE,
2916 				.seq = 13,
2917 				.args = {
2918 					[0] = 0x00, [1] = 0x00,
2919 					[2] = 0x01, [3] = 0x00,
2920 				},
2921 			},
2922 			.resp = {
2923 				.cmd = HIOMAP_C_ERASE,
2924 				.seq = 13,
2925 			},
2926 		},
2927 	},
2928 	{
2929 		.type = scenario_cmd,
2930 		.c = {
2931 			.req = {
2932 				.cmd = HIOMAP_C_FLUSH,
2933 				.seq = 14,
2934 			},
2935 			.resp = {
2936 				.cmd = HIOMAP_C_FLUSH,
2937 				.seq = 14,
2938 			},
2939 		},
2940 	},
2941 	SCENARIO_SENTINEL,
2942 };
2943 
test_hiomap_protocol_recovery_failure_get_info(void)2944 static void test_hiomap_protocol_recovery_failure_get_info(void)
2945 {
2946 	struct blocklevel_device *bl;
2947 	struct ipmi_hiomap *ctx;
2948 	size_t len;
2949 
2950 	scenario_enter(scenario_hiomap_protocol_recovery_failure_get_info);
2951 	assert(!ipmi_hiomap_init(&bl));
2952 	ctx = container_of(bl, struct ipmi_hiomap, bl);
2953 	len = 1 << ctx->block_size_shift;
2954 	/*
2955 	 * We're erasing the same block 3 times - it's irrelevant, we're just
2956 	 * trying to manipulate window state
2957 	 */
2958 	assert(!bl->erase(bl, 0, len));
2959 	scenario_advance();
2960 	assert(bl->erase(bl, 0, len) > 0);
2961 	assert(!bl->erase(bl, 0, len));
2962 	ipmi_hiomap_exit(bl);
2963 	scenario_exit();
2964 }
2965 
2966 static const struct scenario_event
2967 scenario_hiomap_protocol_recovery_failure_get_flash_info[] = {
2968 	{ .type = scenario_event_p, .p = &hiomap_ack_call, },
2969 	{ .type = scenario_event_p, .p = &hiomap_get_info_call, },
2970 	{ .type = scenario_event_p, .p = &hiomap_get_flash_info_call, },
2971 	{
2972 		.type = scenario_event_p,
2973 		.p = &hiomap_create_write_window_qs0l1_rs0l1_call,
2974 	},
2975 	{ .type = scenario_event_p, .p = &hiomap_erase_qs0l1_call, },
2976 	{ .type = scenario_event_p, .p = &hiomap_flush_call, },
2977 	{ .type = scenario_delay },
2978 	{
2979 		.type = scenario_sel,
2980 		.s = {
2981 			.bmc_state = HIOMAP_E_DAEMON_READY |
2982 					HIOMAP_E_PROTOCOL_RESET
2983 		}
2984 	},
2985 	{ .type = scenario_event_p, .p = &hiomap_recovery_ack_call, },
2986 	{ .type = scenario_event_p, .p = &hiomap_recovery_get_info_call},
2987 	{
2988 		.type = scenario_cmd,
2989 		.c = {
2990 			.req = {
2991 				.cmd = HIOMAP_C_GET_FLASH_INFO,
2992 				.seq = 9,
2993 			},
2994 			.cc = IPMI_ERR_UNSPECIFIED,
2995 		},
2996 
2997 	},
2998 	{
2999 		.type = scenario_cmd,
3000 		.c = {
3001 			.req = {
3002 				.cmd = HIOMAP_C_ACK,
3003 				.seq = 10,
3004 				.args = {
3005 					[0] = HIOMAP_E_PROTOCOL_RESET,
3006 				},
3007 			},
3008 			.cc = IPMI_CC_NO_ERROR,
3009 			.resp = {
3010 				.cmd = HIOMAP_C_ACK,
3011 				.seq = 10,
3012 			},
3013 		},
3014 	},
3015 	{
3016 		.type = scenario_cmd,
3017 		.c = {
3018 			.req = {
3019 				.cmd = HIOMAP_C_GET_INFO,
3020 				.seq = 11,
3021 				.args = {
3022 					[0] = HIOMAP_V2,
3023 				},
3024 			},
3025 			.cc = IPMI_CC_NO_ERROR,
3026 			.resp = {
3027 				.cmd = HIOMAP_C_GET_INFO,
3028 				.seq = 11,
3029 				.args = {
3030 					[0] = HIOMAP_V2,
3031 					[1] = 12,
3032 					[2] = 8, [3] = 0,
3033 				},
3034 			},
3035 		},
3036 	},
3037 	{
3038 		.type = scenario_cmd,
3039 		.c = {
3040 			.req = {
3041 				.cmd = HIOMAP_C_GET_FLASH_INFO,
3042 				.seq = 12,
3043 				.args = {
3044 				},
3045 			},
3046 			.cc = IPMI_CC_NO_ERROR,
3047 			.resp = {
3048 				.cmd = HIOMAP_C_GET_FLASH_INFO,
3049 				.seq = 12,
3050 				.args = {
3051 					[0] = 0x00, [1] = 0x20,
3052 					[2] = 0x01, [3] = 0x00,
3053 				},
3054 			},
3055 		},
3056 	},
3057 	{
3058 		.type = scenario_cmd,
3059 		.c = {
3060 			.req = {
3061 				.cmd = HIOMAP_C_CREATE_WRITE_WINDOW,
3062 				.seq = 13,
3063 				.args = {
3064 					[0] = 0x00, [1] = 0x00,
3065 					[2] = 0x01, [3] = 0x00,
3066 				},
3067 			},
3068 			.cc = IPMI_CC_NO_ERROR,
3069 			.resp = {
3070 				.cmd = HIOMAP_C_CREATE_WRITE_WINDOW,
3071 				.seq = 13,
3072 				.args = {
3073 					[0] = 0xff, [1] = 0x0f,
3074 					[2] = 0x01, [3] = 0x00,
3075 					[4] = 0x00, [5] = 0x00,
3076 				},
3077 			},
3078 		},
3079 	},
3080 	{
3081 		.type = scenario_cmd,
3082 		.c = {
3083 			.req = {
3084 				.cmd = HIOMAP_C_ERASE,
3085 				.seq = 14,
3086 				.args = {
3087 					[0] = 0x00, [1] = 0x00,
3088 					[2] = 0x01, [3] = 0x00,
3089 				},
3090 			},
3091 			.resp = {
3092 				.cmd = HIOMAP_C_ERASE,
3093 				.seq = 14,
3094 			},
3095 		},
3096 	},
3097 	{
3098 		.type = scenario_cmd,
3099 		.c = {
3100 			.req = {
3101 				.cmd = HIOMAP_C_FLUSH,
3102 				.seq = 15,
3103 			},
3104 			.resp = {
3105 				.cmd = HIOMAP_C_FLUSH,
3106 				.seq = 15,
3107 			},
3108 		},
3109 	},
3110 	SCENARIO_SENTINEL,
3111 };
3112 
test_hiomap_protocol_recovery_failure_get_flash_info(void)3113 static void test_hiomap_protocol_recovery_failure_get_flash_info(void)
3114 {
3115 	struct blocklevel_device *bl;
3116 	struct ipmi_hiomap *ctx;
3117 	size_t len;
3118 
3119 	scenario_enter(scenario_hiomap_protocol_recovery_failure_get_flash_info);
3120 	assert(!ipmi_hiomap_init(&bl));
3121 	ctx = container_of(bl, struct ipmi_hiomap, bl);
3122 	len = 1 << ctx->block_size_shift;
3123 	/*
3124 	 * We're erasing the same block 3 times - it's irrelevant, we're just
3125 	 * trying to manipulate window state
3126 	 */
3127 	assert(!bl->erase(bl, 0, len));
3128 	scenario_advance();
3129 	ctx = container_of(bl, struct ipmi_hiomap, bl);
3130 	len = 1 << ctx->block_size_shift;
3131 	assert(bl->erase(bl, 0, len) > 0);
3132 	assert(!bl->erase(bl, 0, len));
3133 	ipmi_hiomap_exit(bl);
3134 	scenario_exit();
3135 }
3136 
3137 struct test_case {
3138 	const char *name;
3139 	void (*fn)(void);
3140 };
3141 
3142 #define TEST_CASE(x) { #x, x }
3143 
3144 struct test_case test_cases[] = {
3145 	TEST_CASE(test_hiomap_init),
3146 	TEST_CASE(test_hiomap_event_daemon_ready),
3147 	TEST_CASE(test_hiomap_event_daemon_stopped),
3148 	TEST_CASE(test_hiomap_event_daemon_restarted),
3149 	TEST_CASE(test_hiomap_event_daemon_lost_flash_control),
3150 	TEST_CASE(test_hiomap_event_daemon_regained_flash_control_dirty),
3151 	TEST_CASE(test_hiomap_protocol_reset_recovery),
3152 	TEST_CASE(test_hiomap_protocol_read_one_block),
3153 	TEST_CASE(test_hiomap_protocol_read_one_byte),
3154 	TEST_CASE(test_hiomap_protocol_read_two_blocks),
3155 	TEST_CASE(test_hiomap_protocol_read_1block_1byte),
3156 	TEST_CASE(test_hiomap_protocol_read_one_block_twice),
3157 	TEST_CASE(test_hiomap_protocol_event_before_read),
3158 	TEST_CASE(test_hiomap_protocol_event_during_read),
3159 	TEST_CASE(test_hiomap_protocol_write_one_block),
3160 	TEST_CASE(test_hiomap_protocol_write_one_byte),
3161 	TEST_CASE(test_hiomap_protocol_write_two_blocks),
3162 	TEST_CASE(test_hiomap_protocol_write_1block_1byte),
3163 	TEST_CASE(test_hiomap_protocol_write_one_block_twice),
3164 	TEST_CASE(test_hiomap_protocol_event_before_write),
3165 	TEST_CASE(test_hiomap_protocol_event_during_write),
3166 	TEST_CASE(test_hiomap_protocol_erase_one_block),
3167 	TEST_CASE(test_hiomap_protocol_erase_two_blocks),
3168 	TEST_CASE(test_hiomap_protocol_erase_one_block_twice),
3169 	TEST_CASE(test_hiomap_protocol_event_before_erase),
3170 	TEST_CASE(test_hiomap_protocol_event_during_erase),
3171 	TEST_CASE(test_hiomap_protocol_bad_sequence),
3172 	TEST_CASE(test_hiomap_protocol_action_error),
3173 	TEST_CASE(test_hiomap_protocol_persistent_error),
3174 	TEST_CASE(test_hiomap_protocol_get_flash_info),
3175 	TEST_CASE(test_hiomap_get_info_error),
3176 	TEST_CASE(test_hiomap_get_flash_info_error),
3177 	TEST_CASE(test_hiomap_create_read_window_error),
3178 	TEST_CASE(test_hiomap_create_write_window_error),
3179 	TEST_CASE(test_hiomap_mark_dirty_error),
3180 	TEST_CASE(test_hiomap_flush_error),
3181 	TEST_CASE(test_hiomap_ack_error),
3182 	TEST_CASE(test_hiomap_erase_error),
3183 	TEST_CASE(test_hiomap_ack_malformed_small),
3184 	TEST_CASE(test_hiomap_ack_malformed_large),
3185 	TEST_CASE(test_hiomap_get_info_malformed_small),
3186 	TEST_CASE(test_hiomap_get_info_malformed_large),
3187 	TEST_CASE(test_hiomap_get_flash_info_malformed_small),
3188 	TEST_CASE(test_hiomap_get_flash_info_malformed_large),
3189 	TEST_CASE(test_hiomap_create_read_window_malformed_small),
3190 	TEST_CASE(test_hiomap_create_read_window_malformed_large),
3191 	TEST_CASE(test_hiomap_create_write_window_malformed_small),
3192 	TEST_CASE(test_hiomap_create_write_window_malformed_large),
3193 	TEST_CASE(test_hiomap_mark_dirty_malformed_small),
3194 	TEST_CASE(test_hiomap_mark_dirty_malformed_large),
3195 	TEST_CASE(test_hiomap_flush_malformed_small),
3196 	TEST_CASE(test_hiomap_flush_malformed_large),
3197 	TEST_CASE(test_hiomap_erase_malformed_small),
3198 	TEST_CASE(test_hiomap_erase_malformed_large),
3199 	TEST_CASE(test_hiomap_protocol_recovery_failure_ack),
3200 	TEST_CASE(test_hiomap_protocol_recovery_failure_get_info),
3201 	TEST_CASE(test_hiomap_protocol_recovery_failure_get_flash_info),
3202 	{ NULL, NULL },
3203 };
3204 
main(void)3205 int main(void)
3206 {
3207 	struct test_case *tc = &test_cases[0];
3208 
3209 	do {
3210 		printf("%s\n", tc->name);
3211 		tc->fn();
3212 		printf("\n");
3213 	} while ((++tc)->fn);
3214 
3215 	return 0;
3216 }
3217