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