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